update packages and add valign

This commit is contained in:
2026-04-05 20:00:27 +02:00
parent b062fb98e3
commit 03fb00e374
640 changed files with 109768 additions and 39311 deletions
+1 -1
View File
@@ -1,2 +1,2 @@
;; Generated package description from adaptive-wrap.el -*- no-byte-compile: t -*- ;; Generated package description from adaptive-wrap.el -*- no-byte-compile: t -*-
(define-package "adaptive-wrap" "0.8" "Smart line-wrapping with wrap-prefix" 'nil :commit "026c35f59174febab2bcdb3c50fb8344c248671c" :url "https://elpa.gnu.org/packages/adaptive-wrap.html" :authors '(("Stephen Berman" . "stephen.berman@gmx.net") ("Stefan Monnier" . "monnier@iro.umontreal.ca")) :maintainer '(("Stephen Berman" . "stephen.berman@gmx.net") ("Stefan Monnier" . "monnier@iro.umontreal.ca"))) (define-package "adaptive-wrap" "0.9" "Smart line-wrapping with wrap-prefix" '((emacs "24.1")) :commit "e929b38c12f17aa6f8d6270326301d61fbb09cab" :url "https://elpa.gnu.org/packages/adaptive-wrap.html" :authors '(("Stephen Berman" . "stephen.berman@gmx.net") ("Stefan Monnier" . "monnier@iro.umontreal.ca")) :maintainer '(("Stephen Berman" . "stephen.berman@gmx.net") ("Stefan Monnier" . "monnier@iro.umontreal.ca")))
+13 -5
View File
@@ -1,10 +1,11 @@
;;; adaptive-wrap.el --- Smart line-wrapping with wrap-prefix ;;; adaptive-wrap.el --- Smart line-wrapping with wrap-prefix -*- lexical-binding: t; -*-
;; Copyright (C) 2011-2021 Free Software Foundation, Inc. ;; Copyright (C) 2011-2026 Free Software Foundation, Inc.
;; Author: Stephen Berman <stephen.berman@gmx.net> ;; Author: Stephen Berman <stephen.berman@gmx.net>
;; Stefan Monnier <monnier@iro.umontreal.ca> ;; Stefan Monnier <monnier@iro.umontreal.ca>
;; Version: 0.8 ;; Package-Requires: ((emacs "24.1"))
;; Version: 0.9
;; This program is free software; you can redistribute it and/or modify ;; This program is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by ;; it under the terms of the GNU General Public License as published by
@@ -17,7 +18,7 @@
;; GNU General Public License for more details. ;; GNU General Public License for more details.
;; You should have received a copy of the GNU General Public License ;; You should have received a copy of the GNU General Public License
;; along with this program. If not, see <http://www.gnu.org/licenses/>. ;; along with this program. If not, see <https://www.gnu.org/licenses/>.
;;; Commentary: ;;; Commentary:
@@ -26,6 +27,12 @@
;; word-wrapped in a way similar to what you'd get with M-q using ;; word-wrapped in a way similar to what you'd get with M-q using
;; adaptive-fill-mode, but without actually changing the buffer's text. ;; adaptive-fill-mode, but without actually changing the buffer's text.
;;; News:
;; Since version 0.8:
;; - Use `lexical-binding'.
;;; Code: ;;; Code:
(defcustom adaptive-wrap-extra-indent 0 (defcustom adaptive-wrap-extra-indent 0
@@ -104,7 +111,8 @@ extra indent = 2
"")))) ""))))
(defun adaptive-wrap-fill-context-prefix (beg end) (defun adaptive-wrap-fill-context-prefix (beg end)
"Like `fill-context-prefix', but with length adjusted by `adaptive-wrap-extra-indent'." "Like `fill-context-prefix', but with length adjusted.
How much to adjust it is decided by `adaptive-wrap-extra-indent'."
(let* ((fcp (let* ((fcp
;; `fill-context-prefix' ignores prefixes that look like paragraph ;; `fill-context-prefix' ignores prefixes that look like paragraph
;; starts, in order to avoid inadvertently creating a new paragraph ;; starts, in order to avoid inadvertently creating a new paragraph
+1 -1
View File
@@ -3,7 +3,7 @@
"Alternative M-x with extra features." "Alternative M-x with extra features."
'((emacs "24.4") '((emacs "24.4")
(s "0")) (s "0"))
:url "http://github.com/DarwinAwardWinner/amx/" :url "https://github.com/DarwinAwardWinner/amx/"
:commit "1c2428d21e9d2ee8bee944b572a39ca8c91ca13b" :commit "1c2428d21e9d2ee8bee944b572a39ca8c91ca13b"
:revdesc "1c2428d21e9d" :revdesc "1c2428d21e9d"
:keywords '("convenience" "usability" "completion") :keywords '("convenience" "usability" "completion")
+3 -3
View File
@@ -1,10 +1,10 @@
;; -*- no-byte-compile: t; lexical-binding: nil -*- ;; -*- no-byte-compile: t; lexical-binding: nil -*-
(define-package "async" "20251005.634" (define-package "async" "20260318.1803"
"Asynchronous processing in Emacs." "Asynchronous processing in Emacs."
'((emacs "24.4")) '((emacs "24.4"))
:url "https://github.com/jwiegley/emacs-async" :url "https://github.com/jwiegley/emacs-async"
:commit "31cb2fea8f4bc7a593acd76187a89075d8075500" :commit "5faab28916603bb324d9faba057021ce028ca847"
:revdesc "31cb2fea8f4b" :revdesc "5faab2891660"
:keywords '("async") :keywords '("async")
:authors '(("John Wiegley" . "jwiegley@gmail.com")) :authors '(("John Wiegley" . "jwiegley@gmail.com"))
:maintainers '(("Thierry Volpiatto" . "thievol@posteo.net"))) :maintainers '(("Thierry Volpiatto" . "thievol@posteo.net")))
+11 -13
View File
@@ -6,12 +6,12 @@
;; Maintainer: Thierry Volpiatto <thievol@posteo.net> ;; Maintainer: Thierry Volpiatto <thievol@posteo.net>
;; Created: 18 Jun 2012 ;; Created: 18 Jun 2012
;; Package-Version: 20251005.634 ;; Package-Version: 20260318.1803
;; Package-Revision: 31cb2fea8f4b ;; Package-Revision: 5faab2891660
;; Package-Requires: ((emacs "24.4")) ;; Package-Requires: ((emacs "24.4"))
;; Keywords: async ;; Keywords: async
;; X-URL: https://github.com/jwiegley/emacs-async ;; URL: https://github.com/jwiegley/emacs-async
;; This program is free software; you can redistribute it and/or modify ;; This program is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by ;; it under the terms of the GNU General Public License as published by
@@ -284,15 +284,13 @@ is used."
(move-marker async-read-marker (point))))))) (move-marker async-read-marker (point)))))))
(defun async--receive-sexp (&optional stream) (defun async--receive-sexp (&optional stream)
;; FIXME: Why use `utf-8-auto' instead of `utf-8-unix'? This is ;; We use `utf-8-emacs-unix' for the communication channel between
;; a communication channel over which we have complete control, ;; parent and child Emacs processes. This encoding can represent any
;; so we get to choose exactly which encoding and EOL we use, isn't ;; character that Emacs is capable of processing and gives us full
;; it? ;; control over the EOL format. (See bug#165)
;; UPDATE: We use now `utf-8-emacs-unix' instead of `utf-8-auto' as
;; recommended in bug#165.
(let ((sexp (decode-coding-string (base64-decode-string (read stream)) (let ((sexp (decode-coding-string (base64-decode-string (read stream))
'utf-8-emacs-unix)) 'utf-8-emacs-unix))
;; Parent expects UTF-8 encoded text. ;; Parent expects utf-8-emacs-unix encoded text.
(coding-system-for-write 'utf-8-emacs-unix)) (coding-system-for-write 'utf-8-emacs-unix))
(if async-debug (if async-debug
(message "Received sexp {{{%s}}}" (pp-to-string sexp))) (message "Received sexp {{{%s}}}" (pp-to-string sexp)))
@@ -324,8 +322,8 @@ is used."
(defun async-batch-invoke () (defun async-batch-invoke ()
"Called from the child Emacs process' command line." "Called from the child Emacs process' command line."
;; Make sure 'message' and 'prin1' encode stuff in UTF-8, as parent ;; Make sure 'message' and 'prin1' encode stuff in utf-8-emacs-unix,
;; process expects. ;; as parent process expects.
(let ((coding-system-for-write 'utf-8-emacs-unix) (let ((coding-system-for-write 'utf-8-emacs-unix)
(args-left command-line-args-left)) (args-left command-line-args-left))
(setq async-in-child-emacs t (setq async-in-child-emacs t
@@ -560,7 +558,7 @@ passed to FINISH-FUNC). Call `async-get' on such a future always
returns nil. It can still be useful, however, as an argument to returns nil. It can still be useful, however, as an argument to
`async-ready' or `async-wait'." `async-ready' or `async-wait'."
(let ((sexp start-func) (let ((sexp start-func)
;; Subordinate Emacs will send text encoded in UTF-8. ;; Subordinate Emacs will send text encoded in utf-8-emacs-unix.
(coding-system-for-read 'utf-8-emacs-unix)) (coding-system-for-read 'utf-8-emacs-unix))
(setq async--procvar (setq async--procvar
(apply 'async-start-process (apply 'async-start-process
+1 -1
View File
@@ -237,7 +237,7 @@ CSL tests."
"<span style=\"text-decoration:underline;\">" x "</span>"))) "<span style=\"text-decoration:underline;\">" x "</span>")))
(vertical-align-sub . ,(lambda (x) (concat "<sub>" x "</sub>"))) (vertical-align-sub . ,(lambda (x) (concat "<sub>" x "</sub>")))
(vertical-align-sup . ,(lambda (x) (concat "<sup>" x "</sup>"))) (vertical-align-sup . ,(lambda (x) (concat "<sup>" x "</sup>")))
(vertical-align-baseline . ,(lambda (x) (concat "<span style=\"baseline\">" x "</span>"))) (vertical-align-baseline . ,(lambda (x) (concat "<span class=\"baseline\">" x "</span>")))
(display-left-margin . ,(lambda (x) (concat "\n <div class=\"csl-left-margin\">" (display-left-margin . ,(lambda (x) (concat "\n <div class=\"csl-left-margin\">"
x "</div>"))) x "</div>")))
(display-right-inline . ,(lambda (x) (concat "<div class=\"csl-right-inline\">" (display-right-inline . ,(lambda (x) (concat "<div class=\"csl-right-inline\">"
+3 -3
View File
@@ -1,5 +1,5 @@
;; -*- no-byte-compile: t; lexical-binding: nil -*- ;; -*- no-byte-compile: t; lexical-binding: nil -*-
(define-package "citeproc" "20251103.716" (define-package "citeproc" "20260113.1047"
"A CSL 1.0.2 Citation Processor." "A CSL 1.0.2 Citation Processor."
'((emacs "26") '((emacs "26")
(dash "2.13.0") (dash "2.13.0")
@@ -11,8 +11,8 @@
(parsebib "2.4") (parsebib "2.4")
(compat "28.1")) (compat "28.1"))
:url "https://github.com/andras-simonyi/citeproc-el" :url "https://github.com/andras-simonyi/citeproc-el"
:commit "a3d62ab8e40a75fcfc6e4c0c107e3137b4db6db8" :commit "4bde999a41803fe519ea80eab8b813d53503eebd"
:revdesc "a3d62ab8e40a" :revdesc "4bde999a4180"
:keywords '("bib") :keywords '("bib")
:authors '(("András Simonyi" . "andras.simonyi@gmail.com")) :authors '(("András Simonyi" . "andras.simonyi@gmail.com"))
:maintainers '(("András Simonyi" . "andras.simonyi@gmail.com"))) :maintainers '(("András Simonyi" . "andras.simonyi@gmail.com")))
+2 -2
View File
@@ -7,8 +7,8 @@
;; URL: https://github.com/andras-simonyi/citeproc-el ;; URL: https://github.com/andras-simonyi/citeproc-el
;; Keywords: bib ;; Keywords: bib
;; Package-Requires: ((emacs "26") (dash "2.13.0") (s "1.12.0") (f "0.18.0") (queue "0.2") (string-inflection "1.0") (org "9") (parsebib "2.4")(compat "28.1")) ;; Package-Requires: ((emacs "26") (dash "2.13.0") (s "1.12.0") (f "0.18.0") (queue "0.2") (string-inflection "1.0") (org "9") (parsebib "2.4")(compat "28.1"))
;; Package-Version: 20251103.716 ;; Package-Version: 20260113.1047
;; Package-Revision: a3d62ab8e40a ;; Package-Revision: 4bde999a4180
;; This program is free software; you can redistribute it and/or modify ;; This program is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by ;; it under the terms of the GNU General Public License as published by
+3 -3
View File
@@ -1,6 +1,6 @@
;;; company-dabbrev-code.el --- dabbrev-like company-mode backend for code -*- lexical-binding: t -*- ;;; company-dabbrev-code.el --- dabbrev-like company-mode backend for code -*- lexical-binding: t -*-
;; Copyright (C) 2009-2011, 2013-2016, 2021-2024 Free Software Foundation, Inc. ;; Copyright (C) 2009-2011, 2013-2016, 2021-2025 Free Software Foundation, Inc.
;; Author: Nikolaj Schumacher ;; Author: Nikolaj Schumacher
@@ -153,8 +153,8 @@ comments or strings."
(pcase company-dabbrev-code-other-buffers (pcase company-dabbrev-code-other-buffers
(`t (list major-mode)) (`t (list major-mode))
(`code company-dabbrev-code-modes) (`code company-dabbrev-code-modes)
((pred functionp) (funcall company-dabbrev-code-other-buffers (current-buffer))) (`all `all)
(`all `all)) ((pred functionp) (funcall company-dabbrev-code-other-buffers (current-buffer))))
(not company-dabbrev-code-everywhere))) (not company-dabbrev-code-everywhere)))
:expire t :expire t
:check-tag :check-tag
+3 -3
View File
@@ -1,9 +1,9 @@
;; -*- no-byte-compile: t; lexical-binding: nil -*- ;; -*- no-byte-compile: t; lexical-binding: nil -*-
(define-package "company" "20251021.2211" (define-package "company" "20260331.245"
"Modular text completion framework." "Modular text completion framework."
'((emacs "26.1")) '((emacs "26.1"))
:url "http://company-mode.github.io/" :url "http://company-mode.github.io/"
:commit "4ff89f7369227fbb89fe721d1db707f1af74cd0f" :commit "59626254bbac187fc2b8d7a189aca90976ab36a8"
:revdesc "4ff89f736922" :revdesc "59626254bbac"
:keywords '("abbrev" "convenience" "matching") :keywords '("abbrev" "convenience" "matching")
:maintainers '(("Dmitry Gutov" . "dmitry@gutov.dev"))) :maintainers '(("Dmitry Gutov" . "dmitry@gutov.dev")))
+11 -9
View File
@@ -5,8 +5,8 @@
;; Author: Nikolaj Schumacher ;; Author: Nikolaj Schumacher
;; Maintainer: Dmitry Gutov <dmitry@gutov.dev> ;; Maintainer: Dmitry Gutov <dmitry@gutov.dev>
;; URL: http://company-mode.github.io/ ;; URL: http://company-mode.github.io/
;; Package-Version: 20251021.2211 ;; Package-Version: 20260331.245
;; Package-Revision: 4ff89f736922 ;; Package-Revision: 59626254bbac
;; Keywords: abbrev, convenience, matching ;; Keywords: abbrev, convenience, matching
;; Package-Requires: ((emacs "26.1")) ;; Package-Requires: ((emacs "26.1"))
@@ -80,7 +80,7 @@
(defface company-tooltip (defface company-tooltip
'((((class color) (min-colors 88) (background light)) '((((class color) (min-colors 88) (background light))
(:foreground "black" :background "cornsilk")) (:foreground "black" :background "ghostwhite"))
(((class color) (min-colors 88) (background dark)) (((class color) (min-colors 88) (background dark))
(:background "gray26")) (:background "gray26"))
(t (:foreground "black" :background "yellow"))) (t (:foreground "black" :background "yellow")))
@@ -88,7 +88,7 @@
(defface company-tooltip-selection (defface company-tooltip-selection
'((((class color) (min-colors 88) (background light)) '((((class color) (min-colors 88) (background light))
(:background "light blue")) (:background "lavender"))
(((class color) (min-colors 88) (background dark)) (((class color) (min-colors 88) (background dark))
(:background "gray31")) (:background "gray31"))
(t (:background "green"))) (t (:background "green")))
@@ -149,7 +149,7 @@
(defface company-tooltip-scrollbar-thumb (defface company-tooltip-scrollbar-thumb
'((((background light)) '((((background light))
:background "indian red") :background "lightpink3")
(((background dark)) (((background dark))
:background "gray33")) :background "gray33"))
"Face used for the tooltip scrollbar thumb (bar).") "Face used for the tooltip scrollbar thumb (bar).")
@@ -161,7 +161,7 @@
(defface company-tooltip-scrollbar-track (defface company-tooltip-scrollbar-track
'((((background light)) '((((background light))
:background "wheat") :background "thistle")
(((background dark)) (((background dark))
:background "gray28")) :background "gray28"))
"Face used for the tooltip scrollbar track (trough).") "Face used for the tooltip scrollbar track (trough).")
@@ -4163,7 +4163,7 @@ but adjust the expected values appropriately."
left left
right) right)
(when scrollbar-bounds (when scrollbar-bounds
(company--scrollbar i scrollbar-bounds))) (company--scrollbar i scrollbar-bounds selected)))
new))) new)))
(when remainder (when remainder
@@ -4180,7 +4180,7 @@ but adjust the expected values appropriately."
(upper (+ lower size -1))) (upper (+ lower size -1)))
(cons lower upper)))) (cons lower upper))))
(defun company--scrollbar (i bounds) (defun company--scrollbar (i bounds selected)
(let* ((scroll-width (ceiling (* (default-font-width) (let* ((scroll-width (ceiling (* (default-font-width)
company-tooltip-scrollbar-width)))) company-tooltip-scrollbar-width))))
(propertize " " (propertize " "
@@ -4188,7 +4188,9 @@ but adjust the expected values appropriately."
'face 'face
(if (and (>= i (car bounds)) (<= i (cdr bounds))) (if (and (>= i (car bounds)) (<= i (cdr bounds)))
'company-tooltip-scrollbar-thumb 'company-tooltip-scrollbar-thumb
'company-tooltip-scrollbar-track)))) (if selected
'company-tooltip-selection
'company-tooltip)))))
(defun company--right-margin (limit length) (defun company--right-margin (limit length)
(if (or (not (eq company-tooltip-offset-display 'scrollbar)) (if (or (not (eq company-tooltip-offset-display 'scrollbar))
+32 -32
View File
@@ -1,4 +1,4 @@
This is company.info, produced by makeinfo version 7.2 from This is company.info, produced by makeinfo version 7.3 from
company.texi. company.texi.
This user manual is for Company version 1.0.3-snapshot This user manual is for Company version 1.0.3-snapshot
@@ -352,11 +352,11 @@ core settings that influence its overall behavior.
-- User Option: company-minimum-prefix-length -- User Option: company-minimum-prefix-length
This is one of the values (together with company-idle-delay), This is one of the values (together with company-idle-delay),
based on which Company auto-stars looking up completion candidates. based on which Company auto-starts looking up completion
This option configures how many characters have to be typed in by a candidates. This option configures how many characters have to be
user before candidates start to be collected and displayed. An typed in by a user before candidates start to be collected and
often choice nowadays is to configure this option to a lower number displayed. An often choice nowadays is to configure this option to
than the default value of 3. a lower number than the default value of 3.
-- User Option: company-idle-delay -- User Option: company-idle-delay
This is the second of the options that configure Company's This is the second of the options that configure Company's
@@ -1786,32 +1786,32 @@ Ref: Commands-Footnote-110079
Node: Customization10246 Node: Customization10246
Node: Customization Interface10718 Node: Customization Interface10718
Node: Configuration File11251 Node: Configuration File11251
Ref: company-selection-wrap-around13563 Ref: company-selection-wrap-around13565
Node: Frontends16052 Node: Frontends16054
Node: Tooltip Frontends17021 Node: Tooltip Frontends17023
Ref: Tooltip Frontends-Footnote-127717 Ref: Tooltip Frontends-Footnote-127719
Node: Preview Frontends27954 Node: Preview Frontends27956
Ref: Preview Frontends-Footnote-129212 Ref: Preview Frontends-Footnote-129214
Node: Echo Frontends29339 Node: Echo Frontends29341
Node: Candidates Search30868 Node: Candidates Search30870
Node: Filter Candidates32200 Node: Filter Candidates32202
Node: Quick Access a Candidate32980 Node: Quick Access a Candidate32982
Node: Backends34598 Node: Backends34600
Node: Backends Usage Basics35628 Node: Backends Usage Basics35630
Ref: Backends Usage Basics-Footnote-137060 Ref: Backends Usage Basics-Footnote-137062
Node: Grouped Backends37144 Node: Grouped Backends37146
Node: Package Backends38655 Node: Package Backends38657
Node: Code Completion39582 Node: Code Completion39584
Node: Text Completion45099 Node: Text Completion45101
Node: File Name Completion49523 Node: File Name Completion49525
Node: Template Expansion51069 Node: Template Expansion51071
Node: Candidates Post-Processing51788 Node: Candidates Post-Processing51790
Node: Troubleshooting54365 Node: Troubleshooting54367
Node: Index56036 Node: Index56038
Node: Key Index56199 Node: Key Index56201
Node: Variable Index57698 Node: Variable Index57700
Node: Function Index62551 Node: Function Index62553
Node: Concept Index67251 Node: Concept Index67253
 
End Tag Table End Tag Table
+3 -3
View File
@@ -1,8 +1,8 @@
;; -*- no-byte-compile: t; lexical-binding: nil -*- ;; -*- no-byte-compile: t; lexical-binding: nil -*-
(define-package "cond-let" "20251101.1942" (define-package "cond-let" "20260201.1500"
"Additional and improved binding conditionals." "Additional and improved binding conditionals."
'((emacs "28.1")) '((emacs "28.1"))
:url "https://github.com/tarsius/cond-let" :url "https://github.com/tarsius/cond-let"
:commit "288b7d36563223ebaf64cb220a3b270bdffb63f1" :commit "8bf87d45e169ebc091103b2aae325aece3aa804d"
:revdesc "288b7d365632" :revdesc "8bf87d45e169"
:keywords '("extensions")) :keywords '("extensions"))
+12 -9
View File
@@ -1,6 +1,6 @@
;;; cond-let.el --- Additional and improved binding conditionals -*- lexical-binding:t -*- ;;; cond-let.el --- Additional and improved binding conditionals -*- lexical-binding:t -*-
;; Copyright (C) 2025 Jonas Bernoulli ;; Copyright (C) 2025-2026 Jonas Bernoulli
;; May contain traces of Emacs, which is ;; May contain traces of Emacs, which is
;; Copyright (C) 1985-2025 Free Software Foundation, Inc. ;; Copyright (C) 1985-2025 Free Software Foundation, Inc.
@@ -9,8 +9,8 @@
;; Homepage: https://github.com/tarsius/cond-let ;; Homepage: https://github.com/tarsius/cond-let
;; Keywords: extensions ;; Keywords: extensions
;; Package-Version: 20251101.1942 ;; Package-Version: 20260201.1500
;; Package-Revision: 288b7d365632 ;; Package-Revision: 8bf87d45e169
;; Package-Requires: ((emacs "28.1")) ;; Package-Requires: ((emacs "28.1"))
;; SPDX-License-Identifier: GPL-3.0-or-later ;; SPDX-License-Identifier: GPL-3.0-or-later
@@ -30,14 +30,16 @@
;;; Commentary: ;;; Commentary:
;; This is an ALPHA release! ;; This is a BETA release!
;; Breaking changes are possible! ;; Breaking changes are unlikely but still possible!
;; See https://github.com/tarsius/cond-let/wiki.
;; Emacs provides the binding conditionals `if-let', `if-let*', ;; Emacs provides the binding conditionals `if-let', `if-let*',
;; `when-let', `when-let*', `and-let*' and `while-let'. ;; `when-let', `when-let*', `and-let*' and `while-let'.
;; This package implements the missing `and-let' and `while-let*', ;; This package implements the missing `and-let' and `while-let*',
;; and the original `cond-let', `cond-let*', `and$' and `and>'. ;; and the original `cond-let', `cond-let*', `when$', `and$' and
;; `and>'.
;; This package additionally provides more consistent and improved ;; This package additionally provides more consistent and improved
;; implementations of the binding conditionals already provided by ;; implementations of the binding conditionals already provided by
@@ -61,6 +63,7 @@
;; ("and>" . "cond-let--and>") ;; ("and>" . "cond-let--and>")
;; ("and-let" . "cond-let--and-let") ;; ("and-let" . "cond-let--and-let")
;; ("if-let" . "cond-let--if-let") ;; ("if-let" . "cond-let--if-let")
;; ("when$" . "cond-let--when$")
;; ("when-let" . "cond-let--when-let") ;; ("when-let" . "cond-let--when-let")
;; ("while-let" . "cond-let--while-let")) ;; ("while-let" . "cond-let--while-let"))
;; End: ;; End:
@@ -73,8 +76,8 @@
;; Due to limitations of the shorthand implementation this has to be ;; Due to limitations of the shorthand implementation this has to be
;; done for each individual library. "dir-locals.el" cannot be used. ;; done for each individual library. "dir-locals.el" cannot be used.
;; If you use `and$' and `and>', you might want to add this to your ;; If you use `when$', `and$' and `and>', you might want to add this
;; configuration: ;; to your configuration:
;; (with-eval-after-load 'cond-let ;; (with-eval-after-load 'cond-let
;; (font-lock-add-keywords 'emacs-lisp-mode ;; (font-lock-add-keywords 'emacs-lisp-mode
@@ -452,7 +455,7 @@ BODY must be one or more expressions. If VARLIST is empty, do nothing
and return nil. and return nil.
\(fn VARLIST BODY...)" \(fn VARLIST BODY...)"
(declare (debug (form form))) (declare (indent 1) (debug (form form)))
`(let (($ ,varform)) `(let (($ ,varform))
(when $ (when $
,bodyform ,@body))) ,bodyform ,@body)))
+3 -3
View File
@@ -1,12 +1,12 @@
;; -*- no-byte-compile: t; lexical-binding: nil -*- ;; -*- no-byte-compile: t; lexical-binding: nil -*-
(define-package "counsel" "20250329.1401" (define-package "counsel" "20260214.1004"
"Various completion functions using Ivy." "Various completion functions using Ivy."
'((emacs "24.5") '((emacs "24.5")
(ivy "0.15.1") (ivy "0.15.1")
(swiper "0.15.1")) (swiper "0.15.1"))
:url "https://github.com/abo-abo/swiper" :url "https://github.com/abo-abo/swiper"
:commit "e33b028ed4b1258a211c87fd5fe801bed25de429" :commit "ee79f68215ae7e2b8a38ba6bf7f82b3fe57dc16c"
:revdesc "e33b028ed4b1" :revdesc "ee79f68215ae"
:keywords '("convenience" "matching" "tools") :keywords '("convenience" "matching" "tools")
:authors '(("Oleh Krehel" . "ohwoeowho@gmail.com")) :authors '(("Oleh Krehel" . "ohwoeowho@gmail.com"))
:maintainers '(("Basil L. Contovounesios" . "basil@contovou.net"))) :maintainers '(("Basil L. Contovounesios" . "basil@contovou.net")))
+210 -153
View File
@@ -1,12 +1,12 @@
;;; counsel.el --- Various completion functions using Ivy -*- lexical-binding: t -*- ;;; counsel.el --- Various completion functions using Ivy -*- lexical-binding: t -*-
;; Copyright (C) 2015-2025 Free Software Foundation, Inc. ;; Copyright (C) 2015-2026 Free Software Foundation, Inc.
;; Author: Oleh Krehel <ohwoeowho@gmail.com> ;; Author: Oleh Krehel <ohwoeowho@gmail.com>
;; Maintainer: Basil L. Contovounesios <basil@contovou.net> ;; Maintainer: Basil L. Contovounesios <basil@contovou.net>
;; URL: https://github.com/abo-abo/swiper ;; URL: https://github.com/abo-abo/swiper
;; Package-Version: 20250329.1401 ;; Package-Version: 20260214.1004
;; Package-Revision: e33b028ed4b1 ;; Package-Revision: ee79f68215ae
;; Package-Requires: ((emacs "24.5") (ivy "0.15.1") (swiper "0.15.1")) ;; Package-Requires: ((emacs "24.5") (ivy "0.15.1") (swiper "0.15.1"))
;; Keywords: convenience, matching, tools ;; Keywords: convenience, matching, tools
@@ -42,6 +42,7 @@
;;; Code: ;;; Code:
(require 'cl-lib)
(require 'ivy) (require 'ivy)
(require 'swiper) (require 'swiper)
@@ -424,11 +425,10 @@ Update the minibuffer with the amount of lines collected every
(defun counsel-irony () (defun counsel-irony ()
"Inline C/C++ completion using Irony." "Inline C/C++ completion using Irony."
(interactive) (interactive)
(irony-completion-candidates-async 'counsel-irony-callback)) (irony-completion-candidates-async #'counsel-irony-callback))
(defun counsel-irony-callback (candidates) (defun counsel-irony-callback (candidates)
"Callback function for Irony to search among CANDIDATES." "Callback function for Irony to search among CANDIDATES."
(interactive)
(let* ((symbol-bounds (irony-completion-symbol-bounds)) (let* ((symbol-bounds (irony-completion-symbol-bounds))
(beg (car symbol-bounds)) (beg (car symbol-bounds))
(end (cdr symbol-bounds)) (end (cdr symbol-bounds))
@@ -456,7 +456,8 @@ Update the minibuffer with the amount of lines collected every
(let ((map (make-sparse-keymap))) (let ((map (make-sparse-keymap)))
(define-key map (kbd "C-.") #'counsel-find-symbol) (define-key map (kbd "C-.") #'counsel-find-symbol)
(define-key map (kbd "C-,") #'counsel--info-lookup-symbol) (define-key map (kbd "C-,") #'counsel--info-lookup-symbol)
map)) map)
"Keymap for Counsel commands that describe symbols.")
(ivy-set-actions (ivy-set-actions
'counsel-describe-variable 'counsel-describe-variable
@@ -472,12 +473,15 @@ Used by commands `counsel-describe-symbol',
"Jump to the definition of the current symbol." "Jump to the definition of the current symbol."
(interactive) (interactive)
(ivy-exit-with-action #'counsel--find-symbol)) (ivy-exit-with-action #'counsel--find-symbol))
(function-put #'counsel-find-symbol 'no-counsel-M-x t) (ivy--no-M-x #'counsel-find-symbol #'ivy--minibuffer-p)
(defun counsel--info-lookup-symbol () (defun counsel--info-lookup-symbol ()
"Lookup the current symbol in the info docs." "Lookup the current symbol in the info docs."
(interactive) (interactive)
(ivy-exit-with-action #'counsel-info-lookup-symbol)) (ivy-exit-with-action
(lambda (x)
(counsel-info-lookup-symbol (ivy--action-cand-to-str x)))))
(ivy--no-M-x #'counsel--info-lookup-symbol #'ivy--minibuffer-p)
(defun counsel--push-xref-marker (&optional m) (defun counsel--push-xref-marker (&optional m)
"Compatibility shim for `xref-push-marker-stack'." "Compatibility shim for `xref-push-marker-stack'."
@@ -496,10 +500,11 @@ Used by commands `counsel-describe-symbol',
(ring-insert find-tag-marker-ring (or m (point-marker))))) (ring-insert find-tag-marker-ring (or m (point-marker)))))
(defun counsel--find-symbol (x) (defun counsel--find-symbol (x)
"Find symbol definition that corresponds to string X." "Find symbol definition that corresponds to action candidate X."
(with-ivy-window (with-ivy-window
(counsel--push-xref-marker) (counsel--push-xref-marker)
(let ((full-name (get-text-property 0 'full-name x))) (let* ((x (ivy--action-cand-to-str x))
(full-name (get-text-property 0 'full-name x)))
(if full-name (if full-name
(find-library full-name) (find-library full-name)
(let ((sym (read x))) (let ((sym (read x)))
@@ -532,7 +537,7 @@ Used by commands `counsel-describe-symbol',
(defun counsel-describe-variable-transformer (var) (defun counsel-describe-variable-transformer (var)
"Propertize VAR if it's a custom variable." "Propertize VAR if it's a custom variable."
(if (custom-variable-p (intern var)) (if (custom-variable-p (intern-soft var))
(ivy-append-face var 'ivy-highlight-face) (ivy-append-face var 'ivy-highlight-face)
var)) var))
@@ -551,7 +556,8 @@ Variables declared using `defcustom' are highlighted according to
:keymap counsel-describe-map :keymap counsel-describe-map
:preselect (ivy-thing-at-point) :preselect (ivy-thing-at-point)
:action (lambda (x) :action (lambda (x)
(funcall counsel-describe-variable-function (intern x))) (funcall counsel-describe-variable-function
(counsel--action-cand-to-interned x)))
:caller 'counsel-describe-variable))) :caller 'counsel-describe-variable)))
(ivy-configure 'counsel-describe-variable (ivy-configure 'counsel-describe-variable
@@ -571,7 +577,7 @@ Variables declared using `defcustom' are highlighted according to
(defun counsel-describe-function-transformer (function-name) (defun counsel-describe-function-transformer (function-name)
"Propertize FUNCTION-NAME if it's an interactive function." "Propertize FUNCTION-NAME if it's an interactive function."
(if (commandp (intern function-name)) (if (commandp (intern-soft function-name))
(ivy-append-face function-name 'ivy-highlight-face) (ivy-append-face function-name 'ivy-highlight-face)
function-name)) function-name))
@@ -585,9 +591,15 @@ Variables declared using `defcustom' are highlighted according to
(function-item ivy-thing-at-point) (function-item ivy-thing-at-point)
(function-item ivy-function-called-at-point))) (function-item ivy-function-called-at-point)))
(defun counsel--action-cand-to-interned (x)
"Try to return Ivy action argument X as an existing symbol.
Not quite the dual of `ivy--action-cand-to-str'."
(intern-soft (if (consp x) (car x) x)))
(defun counsel--describe-function (candidate) (defun counsel--describe-function (candidate)
"Pass string CANDIDATE to `counsel-describe-function-function'." "Pass string CANDIDATE to `counsel-describe-function-function'."
(funcall counsel-describe-function-function (intern candidate))) (funcall counsel-describe-function-function
(counsel--action-cand-to-interned candidate)))
;;;###autoload ;;;###autoload
(defun counsel-describe-function () (defun counsel-describe-function ()
@@ -600,7 +612,7 @@ to `ivy-highlight-face'."
(ivy-read "Describe function: " obarray (ivy-read "Describe function: " obarray
:predicate (lambda (sym) :predicate (lambda (sym)
(or (fboundp sym) (or (fboundp sym)
(get sym 'function-documentation))) (function-get sym 'function-documentation)))
:require-match t :require-match t
:history 'counsel-describe-symbol-history :history 'counsel-describe-symbol-history
:keymap counsel-describe-map :keymap counsel-describe-map
@@ -637,7 +649,8 @@ to `ivy-highlight-face'."
:keymap counsel-describe-map :keymap counsel-describe-map
:preselect (ivy-thing-at-point) :preselect (ivy-thing-at-point)
:action (lambda (x) :action (lambda (x)
(funcall counsel-describe-symbol-function (intern x))) (funcall counsel-describe-symbol-function
(counsel--action-cand-to-interned x)))
:caller 'counsel-describe-symbol))) :caller 'counsel-describe-symbol)))
(ivy-configure 'counsel-describe-symbol (ivy-configure 'counsel-describe-symbol
@@ -846,6 +859,7 @@ With prefix arg MODE a query for the symbol help mode is offered."
;;;; `counsel-M-x' ;;;; `counsel-M-x'
(defface counsel-key-binding (defface counsel-key-binding
;; Default Emacs 28 `help-key-binding' doesn't look great in parentheses.
'((t :inherit font-lock-keyword-face)) '((t :inherit font-lock-keyword-face))
"Face used by `counsel-M-x' for key bindings." "Face used by `counsel-M-x' for key bindings."
:group 'ivy-faces) :group 'ivy-faces)
@@ -874,7 +888,7 @@ With prefix arg MODE a query for the symbol help mode is offered."
(concat cmd (concat cmd
(when (and (symbolp alias) counsel-alias-expand) (when (and (symbolp alias) counsel-alias-expand)
(format " (%s)" alias)) (format " (%s)" alias))
(when key (when (and key suggest-key-bindings)
;; Prefer `<f2>' over `C-x 6' where applicable ;; Prefer `<f2>' over `C-x 6' where applicable
(let ((i (cl-search [?\C-x ?6] key))) (let ((i (cl-search [?\C-x ?6] key)))
(when i (when i
@@ -884,114 +898,149 @@ With prefix arg MODE a query for the symbol help mode is offered."
(lookup-key map dup)) (lookup-key map dup))
(setq key dup))))) (setq key dup)))))
(setq key (key-description key)) (setq key (key-description key))
(put-text-property 0 (length key) 'face 'counsel-key-binding key) (setq key (propertize key 'face 'counsel-key-binding))
(format " (%s)" key))))) (format " (%s)" key)))))
(defvar amx-initialized) (defcustom counsel-M-x-collection 'auto
(defvar amx-cache) "Where to source `counsel-M-x' completion candidates from.
(declare-function amx-initialize "ext:amx") `obarray' - Use the default M-x collection built into Emacs.
(declare-function amx-detect-new-commands "ext:amx") `amx' - Source candidates from the external `amx' package.
(declare-function amx-update "ext:amx") `smex' - Source candidates from the external `smex' package.
(declare-function amx-rank "ext:amx") `auto' - Automatically detect one of the previous options,
(defvar smex-initialized-p) falling back to `obarray'. This is the default.
(defvar smex-ido-cache) The value can alternatively be a function of no arguments
(declare-function smex-initialize "ext:smex") that returns a completion table suitable for `ivy-read'."
(declare-function smex-detect-new-commands "ext:smex") :package-version '(counsel . "0.16.0")
(declare-function smex-update "ext:smex") :type '(choice (const :tag "Built-in" obarray)
(declare-function smex-rank "ext:smex") (const :tag "Amx package" amx)
(const :tag "Smex package" smex)
(const :tag "Auto-detect" auto)
(function :tag "Custom function")))
(defun counsel--M-x-externs () (defun counsel--M-x-collection ()
"Return `counsel-M-x' candidates from external packages. "Return a completion table obeying `counsel-M-x-collection'."
The return value is a list of strings. The currently supported (let ((src counsel-M-x-collection))
packages are, in order of precedence, `amx' and `smex'." (cond ((eq src 'obarray) obarray)
(cond ((require 'amx nil t) ((eq src 'auto)
(cond ((ivy--feature-p 'amx)
(counsel--amx-collection))
((ivy--feature-p 'smex)
(counsel--smex-collection))
(obarray)))
((eq src 'amx)
(unless (ivy--feature-p 'amx)
(user-error "Package `amx' not installed"))
(counsel--amx-collection))
((eq src 'smex)
(unless (ivy--feature-p 'smex)
(user-error "Package `smex' not installed"))
(counsel--smex-collection))
((functionp src) (funcall src))
((user-error "Unknown `counsel-M-x-collection': %S" src)))))
(defun counsel--M-x-extern-rank (cmd)
"Tell external `counsel-M-x-collection' that CMD was selected."
(declare-function amx-rank "ext:amx")
(declare-function smex-rank "ext:smex")
(let ((src counsel-M-x-collection))
(cond ((and (memq src '(auto amx))
(bound-and-true-p amx-initialized))
(amx-rank cmd))
((and (memq src '(auto smex))
(bound-and-true-p smex-initialized-p))
(smex-rank cmd)))))
(defun counsel--amx-collection ()
"Return `counsel-M-x' candidates from the `amx' package."
(declare-function amx-detect-new-commands "ext:amx")
(declare-function amx-initialize "ext:amx")
(declare-function amx-update "ext:amx")
(defvar amx-cache)
(defvar amx-initialized)
(unless amx-initialized (unless amx-initialized
(amx-initialize)) (amx-initialize))
(when (amx-detect-new-commands) (when (amx-detect-new-commands)
(amx-update)) (amx-update))
(mapcar (lambda (entry) amx-cache)
(symbol-name (car entry)))
amx-cache)) (defun counsel--smex-collection ()
((require 'smex nil t) "Return `counsel-M-x' candidates from the `smex' package."
(declare-function smex-detect-new-commands "ext:smex")
(declare-function smex-initialize "ext:smex")
(declare-function smex-update "ext:smex")
(defvar smex-ido-cache)
(defvar smex-initialized-p)
(unless smex-initialized-p (unless smex-initialized-p
(smex-initialize)) (smex-initialize))
(when (smex-detect-new-commands) (when (smex-detect-new-commands)
(smex-update)) (smex-update))
smex-ido-cache))) smex-ido-cache)
(defun counsel--M-x-externs-predicate (cand) (defun counsel--M-x-predicate ()
"Return non-nil if `counsel-M-x' should complete CAND.
CAND is a string returned by `counsel--M-x-externs'."
(not (get (intern cand) 'no-counsel-M-x)))
(defun counsel--M-x-make-predicate ()
"Return a predicate for `counsel-M-x' in the current buffer." "Return a predicate for `counsel-M-x' in the current buffer."
(defvar read-extended-command-predicate)
(let ((buf (current-buffer))) (let ((buf (current-buffer)))
(lambda (sym) ;; Should work with all completion table types.
(and (commandp sym) (lambda (key &optional _val)
(not (get sym 'byte-obsolete-info)) (when (consp key) (setq key (car key)))
(not (get sym 'no-counsel-M-x)) (when (stringp key) (setq key (intern key)))
(cond ((not (bound-and-true-p read-extended-command-predicate))) (and (commandp key)
((functionp read-extended-command-predicate) (not (function-get key 'byte-obsolete-info))
(not (function-get key 'no-counsel-M-x))
;; New in Emacs 28.
(let ((pred (bound-and-true-p read-extended-command-predicate)))
(or (not (functionp pred))
(condition-case-unless-debug err (condition-case-unless-debug err
(funcall read-extended-command-predicate sym buf) (funcall pred key buf)
(error (message "read-extended-command-predicate: %s: %s" (error (message "read-extended-command-predicate: %s: %s"
sym (error-message-string err)))))))))) key (error-message-string err))))))))))
(defun counsel--M-x-prompt () (defun counsel--M-x-prompt (arg)
"String for `M-x' plus the string representation of `current-prefix-arg'." "Prompt for `counsel-M-x' preceded by a printed form of prefix ARG."
(concat (cond ((null current-prefix-arg) (concat (cond ((null arg) ())
nil) ((eq (car-safe arg) 4) "C-u ")
((eq current-prefix-arg '-) ((or (eq arg '-)
"- ") (integerp (or (car-safe arg) arg)))
((integerp current-prefix-arg) (format "%s " (or (car-safe arg) arg))))
(format "%d " current-prefix-arg))
((= (car current-prefix-arg) 4)
"C-u ")
(t
(format "%d " (car current-prefix-arg))))
"M-x ")) "M-x "))
(defvar counsel-M-x-history nil (defvar counsel-M-x-history nil
"History for `counsel-M-x'.") "History for `counsel-M-x'.")
(defun counsel-M-x-action (cmd) (defun counsel-M-x-action (cmd)
"Execute CMD." "Execute CMD from `counsel-M-x'."
(setq cmd (intern ;; Currently CMD is a string either following `ivy-immediate-done',
(subst-char-in-string ?\s ?- (string-remove-prefix "^" cmd)))) ;; or for all collection types but alist, where CMD is the original
(cond ((bound-and-true-p amx-initialized) ;; cons. There is no harm in allowing other atoms through.
(amx-rank cmd)) (setq cmd (cond ((stringp cmd)
((bound-and-true-p smex-initialized-p) (or (intern-soft cmd)
(smex-rank cmd))) ;; For the benefit of `ivy-immediate-done'.
(setq prefix-arg current-prefix-arg) (intern (subst-char-in-string
?\s ?- (string-remove-prefix "^" cmd)))))
((consp cmd) (intern-soft (car cmd)))
(cmd)))
(counsel--M-x-extern-rank cmd)
;; As per `execute-extended-command'.
(setq this-command cmd) (setq this-command cmd)
(setq real-this-command cmd) (setq real-this-command cmd)
(command-execute cmd 'record)) (let ((prefix-arg (or ivy-current-prefix-arg current-prefix-arg)))
(command-execute cmd 'record)))
;;;###autoload ;;;###autoload
(defun counsel-M-x (&optional initial-input) (defun counsel-M-x (&optional initial-input)
"Ivy version of `execute-extended-command'. "Ivy version of `execute-extended-command'.
Optional INITIAL-INPUT is the initial input in the minibuffer. Optional INITIAL-INPUT is the initial input in the minibuffer.
This function integrates with either the `amx' or `smex' package This function integrates with either the `amx' or `smex' package when
when available, in that order of precedence." available, in that order of precedence; see `counsel-M-x-collection'."
(interactive) (interactive)
;; When `counsel-M-x' returns, `last-command' would be set to (ivy-read (counsel--M-x-prompt current-prefix-arg)
;; `counsel-M-x' because :action hasn't been invoked yet. (counsel--M-x-collection)
;; Instead, preserve the old value of `this-command'. :predicate (counsel--M-x-predicate)
(setq this-command last-command)
(setq real-this-command real-last-command)
(let ((externs (counsel--M-x-externs)))
(ivy-read (counsel--M-x-prompt) (or externs obarray)
:predicate (if externs
#'counsel--M-x-externs-predicate
(counsel--M-x-make-predicate))
:require-match t :require-match t
:history 'counsel-M-x-history :history 'counsel-M-x-history
:action #'counsel-M-x-action :action #'counsel-M-x-action
:keymap counsel-describe-map :keymap counsel-describe-map
:initial-input initial-input :initial-input initial-input
:caller 'counsel-M-x))) :caller 'counsel-M-x))
(ivy-configure 'counsel-M-x (ivy-configure 'counsel-M-x
:initial-input "^" :initial-input "^"
@@ -1208,13 +1257,13 @@ See `execute-extended-command' for further information."
"Find symbol definition of candidate X. "Find symbol definition of candidate X.
See `counsel--find-symbol' for further information." See `counsel--find-symbol' for further information."
(let ((cmd (cddr x))) (let ((cmd (cddr x)))
(counsel--find-symbol (symbol-name cmd)))) (counsel--find-symbol cmd)))
(defun counsel-descbinds-action-info (x) (defun counsel-descbinds-action-info (x)
"Display symbol definition of candidate X, as found in the relevant manual. "Display symbol definition of candidate X, as found in the relevant manual.
See `info-lookup-symbol' for further information." See `info-lookup-symbol' for further information."
(let ((cmd (cddr x))) (let ((cmd (cddr x)))
(counsel-info-lookup-symbol (symbol-name cmd)))) (counsel-info-lookup-symbol cmd)))
;;;###autoload ;;;###autoload
(defun counsel-descbinds (&optional prefix buffer) (defun counsel-descbinds (&optional prefix buffer)
@@ -1752,6 +1801,7 @@ When CMD is non-nil, prompt for a specific \"git grep\" command."
(unless (ivy-state-dynamic-collection ivy-last) (unless (ivy-state-dynamic-collection ivy-last)
(setq ivy--all-candidates (setq ivy--all-candidates
(all-completions "" #'counsel-git-grep-function)))) (all-completions "" #'counsel-git-grep-function))))
(ivy--no-M-x #'counsel-git-grep-switch-cmd #'ivy--minibuffer-p t)
(defun counsel--normalize-grep-match (str) (defun counsel--normalize-grep-match (str)
;; Prepend ./ if necessary: ;; Prepend ./ if necessary:
@@ -1809,6 +1859,7 @@ When CMD is non-nil, prompt for a specific \"git grep\" command."
(find-file file-name) (find-file file-name)
(goto-char (point-min))) (goto-char (point-min)))
(perform-replace from to t t nil)))))))))) (perform-replace from to t t nil))))))))))
(ivy--no-M-x #'counsel-git-grep-query-replace #'ivy--minibuffer-p)
;;;; `counsel-git-stash' ;;;; `counsel-git-stash'
@@ -1974,20 +2025,12 @@ currently checked out."
;;; File ;;; File
;;;; `counsel-find-file' ;;;; `counsel-find-file'
(defvar counsel-find-file-map
(let ((map (make-sparse-keymap)))
(define-key map (kbd "C-DEL") #'counsel-up-directory)
(define-key map (kbd "C-<backspace>") #'counsel-up-directory)
(define-key map (kbd "`") #'counsel-file-jump-from-find)
(define-key map (kbd "C-`") (ivy-make-magic-action #'counsel-find-file "b"))
(define-key map `[remap ,#'undo] #'counsel-find-file-undo)
map))
(defun counsel-file-jump-from-find () (defun counsel-file-jump-from-find ()
"Switch to `counsel-file-jump' from `counsel-find-file'." "Switch to `counsel-file-jump' from `counsel-find-file'."
(interactive) (interactive)
(ivy-quit-and-run (ivy-quit-and-run
(counsel-file-jump ivy-text (ivy-state-directory ivy-last)))) (counsel-file-jump ivy-text (ivy-state-directory ivy-last))))
(ivy--no-M-x #'counsel-file-jump-from-find #'ivy--minibuffer-p)
(when (executable-find "git") (when (executable-find "git")
(add-to-list 'ivy-ffap-url-functions 'counsel-github-url-p) (add-to-list 'ivy-ffap-url-functions 'counsel-github-url-p)
@@ -2084,18 +2127,29 @@ choose between `yes-or-no-p' and `y-or-n-p'; otherwise default to
(when win (with-selected-window win (ivy--cd dir))))) (when win (with-selected-window win (ivy--cd dir)))))
(ivy-set-actions (ivy-set-actions
'counsel-find-file #'counsel-find-file
'(("j" find-file-other-window "other window") `(("j" ,#'find-file-other-window "other window")
("f" find-file-other-frame "other frame") ("f" ,#'find-file-other-frame "other frame")
("b" counsel-find-file-cd-bookmark-action "cd bookmark") ("b" ,#'counsel-find-file-cd-bookmark-action "cd bookmark")
("x" counsel-find-file-extern "open externally") ("x" ,#'counsel-find-file-extern "open externally")
("r" counsel-find-file-as-root "open as root") ("r" ,#'counsel-find-file-as-root "open as root")
("R" find-file-read-only "read only") ("R" ,#'find-file-read-only "read only")
("l" find-file-literally "open literally") ("l" ,#'find-file-literally "open literally")
("k" counsel-find-file-delete "delete") ("k" ,#'counsel-find-file-delete "delete")
("c" counsel-find-file-copy "copy file") ("c" ,#'counsel-find-file-copy "copy file")
("m" counsel-find-file-move "move or rename") ("m" ,#'counsel-find-file-move "move or rename")
("d" counsel-find-file-mkdir-action "mkdir"))) ("d" ,#'counsel-find-file-mkdir-action "mkdir")))
(defvar counsel-find-file-map
(let ((map (make-sparse-keymap)))
(define-key map (kbd "C-DEL") #'counsel-up-directory)
(define-key map (kbd "C-<backspace>") #'counsel-up-directory)
(define-key map (kbd "`") #'counsel-file-jump-from-find)
;; Needs to come after "b" action is defined.
(define-key map (kbd "C-`") (ivy-make-magic-action #'counsel-find-file "b"))
(define-key map `[remap ,#'undo] #'counsel-find-file-undo)
map)
"Keymap used during Counsel file name completion.")
(defcustom counsel-find-file-at-point nil (defcustom counsel-find-file-at-point nil
"When non-nil, add file-at-point to the list of candidates." "When non-nil, add file-at-point to the list of candidates."
@@ -2247,10 +2301,10 @@ If USE-IGNORE is non-nil, try to generate a command that respects
(let ((regex ivy--old-re)) (let ((regex ivy--old-re))
(if (= 0 (length regex)) (if (= 0 (length regex))
"cat" "cat"
(let ((filter-cmd (cl-find-if (let ((filter-cmd (cl-assoc-if
(lambda (x) (lambda (cmd)
(executable-find (executable-find
(car (split-string (car x))))) (car (split-string cmd))))
counsel-file-name-filter-alist)) counsel-file-name-filter-alist))
cmd) cmd)
(when (and use-ignore ivy-use-ignore (when (and use-ignore ivy-use-ignore
@@ -2339,11 +2393,13 @@ See variable `counsel-up-directory-level'."
(ivy--cd up-dir) (ivy--cd up-dir)
(setf (ivy-state-preselect ivy-last) (setf (ivy-state-preselect ivy-last)
(file-name-as-directory (file-name-nondirectory cur-dir))))))) (file-name-as-directory (file-name-nondirectory cur-dir)))))))
(ivy--no-M-x #'counsel-up-directory #'ivy--minibuffer-p)
(defun counsel-down-directory () (defun counsel-down-directory ()
"Descend into the current directory." "Descend into the current directory."
(interactive) (interactive)
(ivy--directory-enter)) (ivy--directory-enter))
(ivy--no-M-x #'counsel-down-directory #'ivy--minibuffer-p)
(defun counsel-find-file-undo () (defun counsel-find-file-undo ()
(interactive) (interactive)
@@ -2354,6 +2410,7 @@ See variable `counsel-up-directory-level'."
(when dir (when dir
(ivy--cd dir))) (ivy--cd dir)))
(undo))) (undo)))
(ivy--no-M-x #'counsel-find-file-undo #'ivy--minibuffer-p)
(defun counsel-at-git-issue-p () (defun counsel-at-git-issue-p ()
"When point is at an issue in a Git-versioned file, return the issue string." "When point is at an issue in a Git-versioned file, return the issue string."
@@ -2562,10 +2619,8 @@ This function uses the `dom' library from Emacs 25.1 or later."
"Return candidates for `counsel-buffer-or-recentf'." "Return candidates for `counsel-buffer-or-recentf'."
(recentf-mode) (recentf-mode)
(let ((buffers (delq nil (mapcar #'buffer-file-name (buffer-list))))) (let ((buffers (delq nil (mapcar #'buffer-file-name (buffer-list)))))
(nconc (nconc buffers (cl-set-difference (counsel-recentf-candidates)
buffers buffers :test #'equal))))
(cl-remove-if (lambda (f) (member f buffers))
(counsel-recentf-candidates)))))
;;;###autoload ;;;###autoload
(defun counsel-buffer-or-recentf () (defun counsel-buffer-or-recentf ()
@@ -2648,24 +2703,24 @@ By default `counsel-bookmark' opens a dired buffer for directories."
;;;; `counsel-bookmarked-directory' ;;;; `counsel-bookmarked-directory'
(defun counsel-bookmarked-directory--candidates () (defun counsel--bookmarked-dirs ()
"Get a list of bookmarked directories sorted by file path." "Return a list of bookmarked directories sorted by file name."
(bookmark-maybe-load-default-file) (bookmark-maybe-load-default-file)
(sort (cl-delete-if-not (sort (cl-mapcan (lambda (bm)
#'ivy--dirname-p (let ((dir (bookmark-get-filename bm)))
(delq nil (mapcar #'bookmark-get-filename bookmark-alist))) (and dir (ivy--dirname-p dir) (list dir))))
bookmark-alist)
#'string<)) #'string<))
;;;###autoload ;;;###autoload
(defun counsel-bookmarked-directory () (defun counsel-bookmarked-directory ()
"Ivy interface for bookmarked directories. "Ivy interface for bookmarked directories.
With a prefix argument, this command creates a new bookmark which points to the With a prefix argument, this command creates a new bookmark which points
current value of `default-directory'." to the current value of `default-directory'."
(interactive) (interactive)
(require 'bookmark) (require 'bookmark)
(ivy-read "Bookmarked directory: " (ivy-read "Bookmarked directory: " (counsel--bookmarked-dirs)
(counsel-bookmarked-directory--candidates)
:caller 'counsel-bookmarked-directory :caller 'counsel-bookmarked-directory
:action #'dired)) :action #'dired))
@@ -2829,17 +2884,19 @@ library, which see."
"Location where to put the locatedb in case your home folder is encrypted." "Location where to put the locatedb in case your home folder is encrypted."
:type 'file) :type 'file)
(defun counsel-file-stale-p (fname seconds) (defun counsel-file-stale-p (file seconds)
"Return non-nil if FNAME was modified more than SECONDS ago." "Return non-nil if FILE was modified more than SECONDS ago.
(> (float-time (time-since (nth 5 (file-attributes fname)))) Also return non-nil if FILE does not exist."
seconds)) (let ((mtime (nth 5 (file-attributes file))))
(or (not mtime)
(> (float-time (time-since mtime))
seconds))))
(defun counsel--locate-updatedb () (defun counsel--locate-updatedb ()
(when (file-exists-p "~/.Private") (when (file-exists-p "~/.Private")
(let ((db-fname (expand-file-name counsel-locate-db-path))) (let ((db-fname (expand-file-name counsel-locate-db-path)))
(setenv "LOCATE_PATH" db-fname) (setenv "LOCATE_PATH" db-fname)
(when (or (not (file-exists-p db-fname)) (when (counsel-file-stale-p db-fname 60)
(counsel-file-stale-p db-fname 60))
(message "Updating %s..." db-fname) (message "Updating %s..." db-fname)
(counsel--command (counsel--command
"updatedb" "-l" "0" "-o" db-fname "-U" (expand-file-name "~")))))) "updatedb" "-l" "0" "-o" db-fname "-U" (expand-file-name "~"))))))
@@ -3050,6 +3107,7 @@ FZF-PROMPT, if non-nil, is passed as `ivy-read' prompt argument."
(interactive) (interactive)
(ivy-quit-and-run (ivy-quit-and-run
(counsel-find-file ivy-text (ivy-state-directory ivy-last)))) (counsel-find-file ivy-text (ivy-state-directory ivy-last))))
(ivy--no-M-x #'counsel-find-file-from-jump #'ivy--minibuffer-p)
;;;###autoload ;;;###autoload
(defun counsel-file-jump (&optional initial-input initial-directory) (defun counsel-file-jump (&optional initial-input initial-directory)
@@ -3115,9 +3173,9 @@ INITIAL-DIRECTORY, if non-nil, is used as the root directory for search."
(let ((map (make-sparse-keymap))) (let ((map (make-sparse-keymap)))
(define-key map (kbd "C-l") #'ivy-call-and-recenter) (define-key map (kbd "C-l") #'ivy-call-and-recenter)
(define-key map (kbd "M-q") #'counsel-git-grep-query-replace) (define-key map (kbd "M-q") #'counsel-git-grep-query-replace)
(define-key map (kbd "C-'") #'swiper-avy)
(define-key map (kbd "C-x C-d") #'counsel-cd) (define-key map (kbd "C-x C-d") #'counsel-cd)
map)) map)
"Keymap for `counsel-ag'.")
(defcustom counsel-ag-base-command (list "ag" "--vimgrep" "%s") (defcustom counsel-ag-base-command (list "ag" "--vimgrep" "%s")
"Template for default `counsel-ag' command. "Template for default `counsel-ag' command.
@@ -3290,6 +3348,7 @@ Works for `counsel-git-grep', `counsel-ag', etc."
(new-dir (counsel-read-directory-name "cd: " def-dir))) (new-dir (counsel-read-directory-name "cd: " def-dir)))
(ivy-quit-and-run (ivy-quit-and-run
(funcall (ivy-state-caller ivy-last) input new-dir)))) (funcall (ivy-state-caller ivy-last) input new-dir))))
(ivy--no-M-x #'counsel-cd #'ivy--minibuffer-p)
(defun counsel--grep-smart-case-flag () (defun counsel--grep-smart-case-flag ()
(if (ivy--case-fold-p ivy-text) (if (ivy--case-fold-p ivy-text)
@@ -3457,8 +3516,8 @@ Example input with inclusion and exclusion file patterns:
(let ((map (make-sparse-keymap))) (let ((map (make-sparse-keymap)))
(define-key map (kbd "C-l") #'ivy-call-and-recenter) (define-key map (kbd "C-l") #'ivy-call-and-recenter)
(define-key map (kbd "M-q") #'swiper-query-replace) (define-key map (kbd "M-q") #'swiper-query-replace)
(define-key map (kbd "C-'") #'swiper-avy) map)
map)) "Keymap for `counsel-grep'.")
(defcustom counsel-grep-base-command "grep -E -n -e %s %s" (defcustom counsel-grep-base-command "grep -E -n -e %s %s"
"Format string used by `counsel-grep' to build a shell command. "Format string used by `counsel-grep' to build a shell command.
@@ -4469,14 +4528,12 @@ When ARG is non-nil, display all active evil registers."
"Return completion alist for `counsel-package'." "Return completion alist for `counsel-package'."
(unless package--initialized (unless package--initialized
(package-initialize t)) (package-initialize t))
(if (or (not package-archive-contents) (when (or (null package-archive-contents)
(cl-find-if (lambda (package-archive) (cl-some (lambda (archive)
(let ((fname (let* ((fname (format "archives/%s/archive-contents"
(format (car archive)))
"%s/archives/%s/archive-contents" (fname (expand-file-name fname package-user-dir)))
package-user-dir (car package-archive)))) (counsel-file-stale-p fname (* 4 60 60))))
(or (not (file-exists-p fname))
(counsel-file-stale-p fname (* 4 60 60)))))
package-archives)) package-archives))
(package-refresh-contents)) (package-refresh-contents))
(sort (mapcar (lambda (entry) (sort (mapcar (lambda (entry)
@@ -5099,6 +5156,7 @@ An extra action allows to switch to the process buffer."
(delete-minibuffer-contents) (delete-minibuffer-contents)
(insert (substring-no-properties (car x)))) (insert (substring-no-properties (car x))))
:caller 'counsel-minibuffer-history))) :caller 'counsel-minibuffer-history)))
(ivy--no-M-x #'counsel-minibuffer-history '(minibuffer-mode) t)
;;;; `counsel-esh-history' ;;;; `counsel-esh-history'
@@ -5863,8 +5921,6 @@ You can insert or kill the name of the selected font."
(define-key map (kbd "C-k") #'counsel-kmacro-kill) (define-key map (kbd "C-k") #'counsel-kmacro-kill)
map)) map))
;; Avoid (declare (modes ...)) warnings in Emacs < 28.
(function-put #'counsel-kmacro-kill 'command-modes '(minibuffer-mode))
(defun counsel-kmacro-kill () (defun counsel-kmacro-kill ()
"Kill the line, or delete the currently selected keyboard macro." "Kill the line, or delete the currently selected keyboard macro."
(interactive) (interactive)
@@ -5877,6 +5933,7 @@ You can insert or kill the name of the selected font."
(ivy-state-current ivy-last) (ivy-state-current ivy-last)
(ivy-state-collection ivy-last))) (ivy-state-collection ivy-last)))
(ivy--kill-current-candidate))) (ivy--kill-current-candidate)))
(ivy--no-M-x #'counsel-kmacro-kill #'ivy--minibuffer-p)
(defvar kmacro-counter) (defvar kmacro-counter)
(defvar kmacro-counter-format-start) (defvar kmacro-counter-format-start)
@@ -6492,12 +6549,11 @@ Any desktop entries that fail to parse are recorded in
(eq counsel-linux-app-format-function (eq counsel-linux-app-format-function
counsel--linux-apps-cache-format-function) counsel--linux-apps-cache-format-function)
(equal new-files counsel--linux-apps-cached-files) (equal new-files counsel--linux-apps-cached-files)
(null (cl-find-if (cl-notany (lambda (file)
(lambda (file)
(time-less-p (time-less-p
counsel--linux-apps-cache-timestamp counsel--linux-apps-cache-timestamp
(nth 5 (file-attributes file)))) (nth 5 (file-attributes file))))
new-files))) new-files))
(setq counsel--linux-apps-cache (counsel-linux-apps-parse new-desktop-alist)) (setq counsel--linux-apps-cache (counsel-linux-apps-parse new-desktop-alist))
(setq counsel--linux-apps-cache-format-function counsel-linux-app-format-function) (setq counsel--linux-apps-cache-format-function counsel-linux-app-format-function)
(setq counsel--linux-apps-cache-timestamp (current-time)) (setq counsel--linux-apps-cache-timestamp (current-time))
@@ -7010,15 +7066,16 @@ handling for the `counsel-compile' metadata."
(insert (substring-no-properties (insert (substring-no-properties
cmd 0 (and (get-text-property 0 'cmd cmd) cmd 0 (and (get-text-property 0 'cmd cmd)
(next-single-property-change 0 'cmd cmd)))))) (next-single-property-change 0 'cmd cmd))))))
(ivy--no-M-x #'counsel-compile-edit-command #'ivy--minibuffer-p)
;; Currently the only thing we do is override ivy's default insert ;; Currently the only thing we do is override Ivy's default insert
;; operation which doesn't include the metadata we want. ;; operation which doesn't include the metadata we want.
(defvar counsel-compile-map (defvar counsel-compile-map
(let ((map (make-sparse-keymap))) (let ((map (make-sparse-keymap)))
(define-key map `[remap ,#'ivy-insert-current] (define-key map `[remap ,#'ivy-insert-current]
#'counsel-compile-edit-command) #'counsel-compile-edit-command)
map) map)
"Additional ivy keybindings during command selection.") "Additional Ivy keybindings during command selection.")
;;;###autoload ;;;###autoload
(defun counsel-compile (&optional dir) (defun counsel-compile (&optional dir)
+3 -3
View File
@@ -1,10 +1,10 @@
;; -*- no-byte-compile: t; lexical-binding: nil -*- ;; -*- no-byte-compile: t; lexical-binding: nil -*-
(define-package "dash" "20250312.1307" (define-package "dash" "20260221.1346"
"A modern list library for Emacs." "A modern list library for Emacs."
'((emacs "24")) '((emacs "24"))
:url "https://github.com/magnars/dash.el" :url "https://github.com/magnars/dash.el"
:commit "fcb5d831fc08a43f984242c7509870f30983c27c" :commit "d3a84021dbe48dba63b52ef7665651e0cf02e915"
:revdesc "fcb5d831fc08" :revdesc "d3a84021dbe4"
:keywords '("extensions" "lisp") :keywords '("extensions" "lisp")
:authors '(("Magnar Sveen" . "magnars@gmail.com")) :authors '(("Magnar Sveen" . "magnars@gmail.com"))
:maintainers '(("Basil L. Contovounesios" . "basil@contovou.net"))) :maintainers '(("Basil L. Contovounesios" . "basil@contovou.net")))
+17 -5
View File
@@ -1,11 +1,11 @@
;;; dash.el --- A modern list library for Emacs -*- lexical-binding: t -*- ;;; dash.el --- A modern list library for Emacs -*- lexical-binding: t -*-
;; Copyright (C) 2012-2025 Free Software Foundation, Inc. ;; Copyright (C) 2012-2026 Free Software Foundation, Inc.
;; Author: Magnar Sveen <magnars@gmail.com> ;; Author: Magnar Sveen <magnars@gmail.com>
;; Maintainer: Basil L. Contovounesios <basil@contovou.net> ;; Maintainer: Basil L. Contovounesios <basil@contovou.net>
;; Package-Version: 20250312.1307 ;; Package-Version: 20260221.1346
;; Package-Revision: fcb5d831fc08 ;; Package-Revision: d3a84021dbe4
;; Package-Requires: ((emacs "24")) ;; Package-Requires: ((emacs "24"))
;; Keywords: extensions, lisp ;; Keywords: extensions, lisp
;; URL: https://github.com/magnars/dash.el ;; URL: https://github.com/magnars/dash.el
@@ -27,7 +27,19 @@
;; A modern list API for Emacs. ;; A modern list API for Emacs.
;; ;;
;; See its overview at https://github.com/magnars/dash.el#functions. ;; Dash is a utility library that affords functional programming
;; patterns inspired by Clojure, particularly in the realm of list
;; manipulation. Examples include higher-order functions (map, reduce,
;; filter) and derivatives (drop, flatten, sum); function combinators
;; (partial application, argument flipping, composition); and threading
;; and anaphoric macros with destructuring support.
;;
;; Dash is particularly useful in providing a broad and consistent API
;; across many Emacs versions.
;;
;; Documentation and examples are in the manual at Info node `(dash) Top'
;; and on the web at https://elpa.gnu.org/packages/doc/dash.html, as well
;; as in the projects README.md file.
;;; Code: ;;; Code:
@@ -1882,7 +1894,7 @@ LISTS, it is generally recommended to use `-unzip-lists' instead."
"Return an infinite circular copy of LIST. "Return an infinite circular copy of LIST.
The returned list cycles through the elements of LIST and repeats The returned list cycles through the elements of LIST and repeats
from the beginning." from the beginning."
(declare (pure t) (side-effect-free t)) (declare (side-effect-free t))
;; Also works with sequences that aren't lists. ;; Also works with sequences that aren't lists.
(let ((newlist (append list ()))) (let ((newlist (append list ())))
(nconc newlist newlist))) (nconc newlist newlist)))
+3 -3
View File
@@ -1,8 +1,8 @@
This is dash.info, produced by makeinfo version 7.2 from dash.texi. This is dash.info, produced by makeinfo version 7.3 from dash.texi.
This manual is for Dash version 2.20.0. This manual is for Dash version 2.20.0.
Copyright © 2012-2025 Free Software Foundation, Inc. Copyright © 2012-2026 Free Software Foundation, Inc.
Permission is granted to copy, distribute and/or modify this Permission is granted to copy, distribute and/or modify this
document under the terms of the GNU Free Documentation License, document under the terms of the GNU Free Documentation License,
@@ -24,7 +24,7 @@ Dash
This manual is for Dash version 2.20.0. This manual is for Dash version 2.20.0.
Copyright © 2012-2025 Free Software Foundation, Inc. Copyright © 2012-2026 Free Software Foundation, Inc.
Permission is granted to copy, distribute and/or modify this Permission is granted to copy, distribute and/or modify this
document under the terms of the GNU Free Documentation License, document under the terms of the GNU Free Documentation License,
+15
View File
@@ -0,0 +1,15 @@
▁▂▃▄▄▄▄▃▂▁
 ▃▅▆ ▇▆▃
▁▅   ▁▂▃▄▄▂   ▅▁
 ▄    ▇▆▆▄╸ ▊  ▄
▘  ▅▆▆▇ ▁▁▂▂▂▃▃▘ ▝
▐ ▅▁ ▂  ▊
▎  ▆▄▂▁▆▄▂ █
▉  ▂▄▅▆▆▆ ▁▂▃╴ ▎
  ▅▇  ▂▄▆   ▎
▐ ▝  ▌  ▗
▖ ▇▄▂▂ ▆▆▆▅▅▅▅▅▅▄▃▖ ▗
▂  ▇▆▆▆▄━⎻▁▁▃▅  ▗
▅▁ ──▅▅▅▆▇   ▁▅
▆▃▂ ▂▃▅
▇▅▄▃▃▃▃▃▃▄▅▇
+14
View File
@@ -0,0 +1,14 @@
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⣀⣤⣤⣤⣤⣤⣤⣀⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⢀⣤⣶⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣶⣤⡀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⣠⣾⣿⣿⣿⣿⣿⣿⣿⠿⠟⠛⠛⠉⠉⠛⢿⣿⣿⣿⣷⣄⠀⠀⠀⠀
⠀⠀⢀⣼⣿⣿⣿⣿⣿⡿⠿⠿⠿⠟⠛⠛⠛⠃⠀⠀⢈⣿⣿⣿⣿⣿⣧⡀⠀⠀
⠀⠀⣾⣿⣿⣿⣿⣿⠁⠀⠀⠀⢀⣀⣤⣤⣤⣤⣶⣶⣿⣿⣿⣿⣿⣿⣿⣷⡀⠀
⠀⣸⣿⣿⣿⣿⣿⣿⣷⣤⡀⠀⠙⠻⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣧⠀
⠀⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⠷⠦⠤⠀⠀⠉⠛⠿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠀
⠀⣿⣿⣿⣿⣿⠿⠋⠁⠀⠀⠀⢀⣀⣤⣤⣶⣶⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠀
⠀⢻⣿⣿⣿⡏⠀⠀⠀⠀⢠⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⠀
⠀⠈⢿⣿⣿⣿⣤⣀⠀⠀⠈⠙⠛⠛⠛⠿⠿⠿⠿⠿⠿⠿⣿⣿⣿⣿⣿⣿⠃⠀
⠀⠀⠈⢿⣿⣿⣿⣿⣿⣶⣶⣤⣤⣤⣤⣤⠤⠄⠀⠀⢀⣠⣼⣿⣿⣿⡿⠃⠀⠀
⠀⠀⠀⠀⠙⢿⣿⣿⣿⣿⣟⣛⣩⣭⣤⣤⣴⣶⣶⣿⣿⣿⣿⣿⡿⠋⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠙⠻⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠟⠋⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠉⠛⠛⠿⠿⠿⠟⠛⠛⠋⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀
+15
View File
@@ -0,0 +1,15 @@
▁▁▂▂▁▁
▁▃▅▇▅▄▄▃▄▄▄ ▇▅▃
▂▆▘  ▃▃ ▁▂▃▄▄▄▂ ▃ ▅
▘▘ ▗▃▃▁▁▁▁▁▂▂╸╴ ▊▄▅▄▄▅
▗ ▂▄▅ ▆▄▅▆━▄▅▃▃▃▃▄ ▄▄▄▄▅▝
▘▄▄▄▄▇▅▄▁▌▂ ▄▄▄▅▄▄▄▄▄▄▄▄▄▝
▊▄▃▅▄▄▅▅ ▆▄▂▁▆▄▂ ▁▅▃▃▅▄▄▄▄▄▎
▌▄▄▄▄▄▁▃▄▆▄▅━━▄▂▃▘ ▄▄▃▅▄▂▃▂▌
▊▃▅▅▗▗▆ ▃▃▅▇ ▅▃▅▅▄▅▅▃▂▃▄▃▃▎
▖▃▄▝▃ ▊▌ ▁▃▄▄▃▃▅ ▂▄▃▂▃▄▅▗
 ▃▅ ▄▃▄▃▆▄▆▃▆▆▆▅▅▅▄▖▄▃▄▗
▂▄▄▄▄▄ ▇▆▆▁▃▄⎺▁▂▃▅ ▄ ▂
▂ ▅ ⎻▅▅▅▆▇▇ ▘▃▃▃ ▂▆
▅▃▁▁▗▂▄▅▃▃▁▁▃▅
▇▇▇▇
+4 -4
View File
@@ -1,10 +1,10 @@
;; -*- no-byte-compile: t; lexical-binding: nil -*- ;; -*- no-byte-compile: t; lexical-binding: nil -*-
(define-package "dashboard" "20250708.57" (define-package "dashboard" "20260402.436"
"A startup screen extracted from Spacemacs." "A startup screen extracted from Spacemacs."
'((emacs "27.1")) '((emacs "27.1"))
:url "https://github.com/emacs-dashboard/emacs-dashboard" :url "https://github.com/emacs-dashboard/dashboard"
:commit "8c2cf0cfde4f5dac8c477f755380fffef6824108" :commit "176d641a55543bda1f0c7506fb954702350c1857"
:revdesc "8c2cf0cfde4f" :revdesc "176d641a5554"
:keywords '("startup" "screen" "tools" "dashboard") :keywords '("startup" "screen" "tools" "dashboard")
:authors '(("Rakan Al-Hneiti" . "rakan.alhneiti@gmail.com")) :authors '(("Rakan Al-Hneiti" . "rakan.alhneiti@gmail.com"))
:maintainers '(("Jen-Chieh" . "jcs090218@gmail.com") :maintainers '(("Jen-Chieh" . "jcs090218@gmail.com")
+169 -63
View File
@@ -1,6 +1,6 @@
;;; dashboard-widgets.el --- A startup screen extracted from Spacemacs -*- lexical-binding: t -*- ;;; dashboard-widgets.el --- A startup screen extracted from Spacemacs -*- lexical-binding: t -*-
;; Copyright (c) 2016-2025 emacs-dashboard maintainers ;; Copyright (c) 2016-2026 emacs-dashboard maintainers
;; This file is not part of GNU Emacs. ;; This file is not part of GNU Emacs.
;; ;;
@@ -27,6 +27,7 @@
(declare-function all-the-icons-icon-for-file "ext:all-the-icons.el") (declare-function all-the-icons-icon-for-file "ext:all-the-icons.el")
(declare-function all-the-icons-fileicon "ext:data-fileicons.el") (declare-function all-the-icons-fileicon "ext:data-fileicons.el")
(declare-function all-the-icons-octicon "ext:data-octicons.el") (declare-function all-the-icons-octicon "ext:data-octicons.el")
(declare-function ansi-color-apply-on-region "ext:ansi-color.el")
(declare-function nerd-icons-icon-for-dir "ext:nerd-icons.el") (declare-function nerd-icons-icon-for-dir "ext:nerd-icons.el")
(declare-function nerd-icons-icon-for-file "ext:nerd-icons.el") (declare-function nerd-icons-icon-for-file "ext:nerd-icons.el")
(declare-function nerd-icons-sucicon "ext:nerd-icons.el") (declare-function nerd-icons-sucicon "ext:nerd-icons.el")
@@ -35,6 +36,8 @@
(declare-function bookmark-get-filename "ext:bookmark.el") (declare-function bookmark-get-filename "ext:bookmark.el")
(declare-function bookmark-all-names "ext:bookmark.el") (declare-function bookmark-all-names "ext:bookmark.el")
(declare-function calendar-date-compare "ext:calendar.el") (declare-function calendar-date-compare "ext:calendar.el")
(declare-function dashboard-cycle-section-forward "ext:dashboard.el")
(declare-function dashboard-cycle-section-backward "ext:dashboard.el")
(declare-function projectile-cleanup-known-projects "ext:projectile.el") (declare-function projectile-cleanup-known-projects "ext:projectile.el")
(declare-function projectile-load-known-projects "ext:projectile.el") (declare-function projectile-load-known-projects "ext:projectile.el")
(declare-function projectile-mode "ext:projectile.el") (declare-function projectile-mode "ext:projectile.el")
@@ -62,6 +65,8 @@
(declare-function org-time-string-to-time "ext:org.el") (declare-function org-time-string-to-time "ext:org.el")
(declare-function org-today "ext:org.el") (declare-function org-today "ext:org.el")
(declare-function recentf-cleanup "ext:recentf.el") (declare-function recentf-cleanup "ext:recentf.el")
(declare-function ansi-color-apply-on-region "ext:ansi-color")
(defvar dashboard-mode-map)
(defvar org-level-faces) (defvar org-level-faces)
(defvar org-agenda-new-buffers) (defvar org-agenda-new-buffers)
(defvar org-agenda-prefix-format) (defvar org-agenda-prefix-format)
@@ -251,6 +256,18 @@ nerd-icons or (all-the-icons-faicon \"newspaper-o\") using all-the-icons."
(concat dashboard-banners-directory "emacs.png") (concat dashboard-banners-directory "emacs.png")
"Emacs banner image.") "Emacs banner image.")
(defconst dashboard-banner-logo-ansi-256color
(concat dashboard-banners-directory "logo-256color.ans")
"Emacs banner image.")
(defconst dashboard-banner-logo-ansi-truecolor
(concat dashboard-banners-directory "logo-truecolor.ans")
"Emacs banner image.")
(defconst dashboard-banner-logo-braille
(concat dashboard-banners-directory "logo-braille.txt")
"Emacs banner image.")
(defconst dashboard-banner-logo-png (defconst dashboard-banner-logo-png
(concat dashboard-banners-directory "logo.png") (concat dashboard-banners-directory "logo.png")
"Emacs banner image.") "Emacs banner image.")
@@ -261,7 +278,7 @@ nerd-icons or (all-the-icons-faicon \"newspaper-o\") using all-the-icons."
:group 'dashboard) :group 'dashboard)
(defcustom dashboard-banner-ascii "EMACS" (defcustom dashboard-banner-ascii "EMACS"
"String to be shown in place of the startup banner "String to be shown in place of the startup banner.
if `dashboard-startup-banner' is set to `ascii'." if `dashboard-startup-banner' is set to `ascii'."
:type 'string :type 'string
:group 'dashboard) :group 'dashboard)
@@ -409,6 +426,29 @@ It can be a string or a string list for display random icons."
Value can be Value can be
- \\='official displays the official Emacs logo. - \\='official displays the official Emacs logo.
- \\='logo displays an alternative Emacs logo. - \\='logo displays an alternative Emacs logo.
The logo can be displayed as a PNG image, or
using unicode braille, depending on if Emacs is
running as a GUI or in no-window mode.
Assumes that the installed font includes braille.
- \\='ascii: displays the logo using ASCII characters.
- \\='logo-ansi-truecolor displays the logo using 24 bit
ANSI color escape sequences, or using unicode braille,
depending on what your device supports.
Assumes that the installed font includes braille.
Assumes the installed font includes block characters,
without adding gaps around the edges of the cell.
See Terminal Image Viewer README for more information:
https://github.com/stefanhaustein/TerminalImageViewer
- \\='logo-ansi-256color displays the logo using 256 color
ANSI color escape sequences, or using unicode braille,
depending on what your device supports.
Assumes that the installed font includes braille.
Assumes the installed font includes block characters,
without adding gaps around the edges of the cell.
See Terminal Image Viewer README for more information:
https://github.com/stefanhaustein/TerminalImageViewer
- \\='logo-braille displays the logo using unicode braille.
Assumes that the installed font includes braille.
- an integer which displays one of the text banners. - an integer which displays one of the text banners.
- a string that specifies the path of an custom banner - a string that specifies the path of an custom banner
supported files types are gif/image/text/xbm. supported files types are gif/image/text/xbm.
@@ -419,6 +459,9 @@ Value can be
:type '(choice (const :tag "official" official) :type '(choice (const :tag "official" official)
(const :tag "logo" logo) (const :tag "logo" logo)
(const :tag "ascii" ascii) (const :tag "ascii" ascii)
(const :tag "logo-ansi-truecolor" logo-ansi-truecolor)
(const :tag "logo-ansi-256color" logo-ansi-256color)
(const :tag "logo-braille" logo-braille)
(integer :tag "index of a text banner") (integer :tag "index of a text banner")
(string :tag "path to an image or text banner") (string :tag "path to an image or text banner")
(cons :tag "image and text banner" (cons :tag "image and text banner"
@@ -429,6 +472,9 @@ Value can be
(const :tag "official" official) (const :tag "official" official)
(const :tag "logo" logo) (const :tag "logo" logo)
(const :tag "ascii" ascii) (const :tag "ascii" ascii)
(const :tag "logo-ansi-truecolor" logo-ansi-truecolor)
(const :tag "logo-ansi-256color" logo-ansi-256color)
(const :tag "logo-braille" logo-braille)
(integer :tag "index of a text banner")))) (integer :tag "index of a text banner"))))
:group 'dashboard) :group 'dashboard)
@@ -589,7 +635,7 @@ Set to nil for unbounded."
;; TODO: Use function `string-pixel-width' after 29.1 ;; TODO: Use function `string-pixel-width' after 29.1
(defun dashboard-string-pixel-width (str) (defun dashboard-string-pixel-width (str)
"Return the width of STR in pixels." "Return the width of STR in pixels."
(if (fboundp #'string-pixel-width) (if (fboundp 'string-pixel-width)
(string-pixel-width str) (string-pixel-width str)
(require 'shr) (require 'shr)
(shr-string-pixel-width str))) (shr-string-pixel-width str)))
@@ -623,9 +669,7 @@ Set to nil for unbounded."
search-label search-label
&optional no-next-line) &optional no-next-line)
"Insert a shortcut SHORTCUT-CHAR for a given SEARCH-LABEL. "Insert a shortcut SHORTCUT-CHAR for a given SEARCH-LABEL.
SHORTCUT-ID is the section identifier. SHORTCUT-ID is the section identifier.
Optionally, provide NO-NEXT-LINE to move the cursor forward a line." Optionally, provide NO-NEXT-LINE to move the cursor forward a line."
(let* (;; Ensure punctuation and upper case in search string is not (let* (;; Ensure punctuation and upper case in search string is not
;; used to construct the `defun' ;; used to construct the `defun'
@@ -633,7 +677,6 @@ Optionally, provide NO-NEXT-LINE to move the cursor forward a line."
;; remove symbol quote ;; remove symbol quote
(sym (intern (replace-regexp-in-string "'" "" (format "dashboard-jump-to-%s" shortcut-id))))) (sym (intern (replace-regexp-in-string "'" "" (format "dashboard-jump-to-%s" shortcut-id)))))
`(progn `(progn
(eval-when-compile (defvar dashboard-mode-map))
(defun ,sym nil (defun ,sym nil
,(concat "Jump to " name ". ,(concat "Jump to " name ".
This code is dynamically generated in `dashboard-insert-shortcut'.") This code is dynamically generated in `dashboard-insert-shortcut'.")
@@ -643,7 +686,16 @@ This code is dynamically generated in `dashboard-insert-shortcut'.")
,@(unless no-next-line '((forward-line 1))) ,@(unless no-next-line '((forward-line 1)))
(back-to-indentation)) (back-to-indentation))
(eval-after-load 'dashboard (eval-after-load 'dashboard
(define-key dashboard-mode-map ,shortcut-char ',sym))))) (dashboard--define-shorcut-key-binding ,shortcut-id ,shortcut-char)))))
(defun dashboard--define-shorcut-key-binding (section keybinding)
"Set `cycle-section's function for SECTION to KEYBINDING.
in `dashboard-mode-map'."
(define-key dashboard-mode-map (kbd keybinding)
(dashboard-cycle-section-forward section))
(define-key dashboard-mode-map
(kbd (upcase keybinding))
(dashboard-cycle-section-backward section)))
(defun dashboard-append (msg &optional _messagebuf) (defun dashboard-append (msg &optional _messagebuf)
"Append MSG to dashboard buffer. "Append MSG to dashboard buffer.
@@ -735,7 +787,17 @@ When called with TIMES return a function that insert TIMES number of newlines."
('logo ('logo
(append (when (image-type-available-p 'png) (append (when (image-type-available-p 'png)
(list :image dashboard-banner-logo-png)) (list :image dashboard-banner-logo-png))
(list :text (dashboard-get-banner-path 1)))) (list :text dashboard-banner-logo-braille)))
('logo-ansi-truecolor
(append (when (>= (display-color-cells) (expt 2 24))
(list :text dashboard-banner-logo-ansi-truecolor))
(list :text dashboard-banner-logo-braille)))
('logo-ansi-256color
(append (when (>= (display-color-cells) 256)
(list :text dashboard-banner-logo-ansi-256color))
(list :text dashboard-banner-logo-braille)))
('logo-braille
(append (list :text dashboard-banner-logo-braille)))
('ascii ('ascii
(append (list :text dashboard-banner-ascii))) (append (list :text dashboard-banner-ascii)))
((pred integerp) ((pred integerp)
@@ -809,6 +871,10 @@ Argument IMAGE-PATH path to the image."
(if (file-exists-p txt) (if (file-exists-p txt)
(insert-file-contents txt) (insert-file-contents txt)
(insert txt))) (insert txt)))
;; escape sequences will throw off text-width, must be done before
(when (member txt (list dashboard-banner-logo-ansi-256color
dashboard-banner-logo-ansi-truecolor))
(ansi-color-apply-on-region start (point-max)))
(put-text-property start (point-max) 'face 'dashboard-text-banner) (put-text-property start (point-max) 'face 'dashboard-text-banner)
(setq text-width (dashboard--find-max-width start (point-max))) (setq text-width (dashboard--find-max-width start (point-max)))
(goto-char (point-max))) (goto-char (point-max)))
@@ -955,33 +1021,39 @@ Return a space if icon is not found."
;;; Section list ;;; Section list
(defmacro dashboard-insert-section-list (section-name list action &rest rest) (defmacro dashboard-insert-section-list (section-name list action &rest rest)
"Insert into SECTION-NAME a LIST of items, expanding ACTION and passing REST "Insert into SECTION-NAME a LIST of items, expanding ACTION.
to widget creation." REST is for widget creation."
`(when (car ,list) `(when (car ,list)
(mapc (mapc
(lambda (el) (lambda (el)
(let ((tag ,@rest)) (let* ((tag ,@rest)
(item tag))
(insert "\n") (insert "\n")
(insert (spaces-string (or standard-indent tab-width 4))) (insert (spaces-string (or standard-indent tab-width 4)))
(when (and (dashboard-display-icons-p) (when (and (dashboard-display-icons-p)
dashboard-set-file-icons) dashboard-set-file-icons)
(let* ((path (car (last (split-string ,@rest " - ")))) (let* ((path (get-text-property 0 'dashboard-path item))
(icon (if (and (not (file-remote-p path)) (icon (cond
(file-directory-p path))
(dashboard-icon-for-dir path
:height dashboard-icon-file-height
:v-adjust dashboard-icon-file-v-adjust)
(cond
((or (string-equal ,section-name "Agenda for today:") ((or (string-equal ,section-name "Agenda for today:")
(string-equal ,section-name "Agenda for the coming week:")) (string-equal ,section-name "Agenda for the coming week:"))
dashboard-agenda-item-icon) dashboard-agenda-item-icon)
((file-remote-p path) ((and (stringp path)
(file-remote-p path))
dashboard-remote-path-icon) dashboard-remote-path-icon)
(t (dashboard-icon-for-file (file-name-nondirectory path) ((and (stringp path)
(file-directory-p path))
(dashboard-icon-for-dir
path
:height dashboard-icon-file-height :height dashboard-icon-file-height
:v-adjust dashboard-icon-file-v-adjust)))))) :v-adjust dashboard-icon-file-v-adjust))
(setq tag (concat icon " " ,@rest)))) ((stringp path)
(dashboard-icon-for-file
(file-name-nondirectory path)
:height dashboard-icon-file-height
:v-adjust dashboard-icon-file-v-adjust))
(t ""))))
(setq tag (concat icon " " item))))
(widget-create 'item (widget-create 'item
:tag tag :tag tag
@@ -992,7 +1064,6 @@ to widget creation."
:button-suffix "" :button-suffix ""
:format "%[%t%]"))) :format "%[%t%]")))
,list))) ,list)))
;; ;;
;;; Footer ;;; Footer
@@ -1198,6 +1269,26 @@ to widget creation."
(defvar dashboard--recentf-cache-item-format nil (defvar dashboard--recentf-cache-item-format nil
"Cache to record the new generated align format.") "Cache to record the new generated align format.")
(defun dashboard-recentf--propertize-item (el)
"Format EL from `dashboard-recentf-alist' and attach its real path."
(let* ((file (dashboard-expand-path-alist el dashboard-recentf-alist))
(filename (dashboard-f-filename file))
(path (dashboard-extract-key-path-alist el dashboard-recentf-alist))
(display
(cl-case dashboard-recentf-show-base
(`align
(unless dashboard--recentf-cache-item-format
(let* ((len-align (dashboard--align-length-by-type 'recents))
(new-fmt (dashboard--generate-align-format
dashboard-recentf-item-format len-align)))
(setq dashboard--recentf-cache-item-format new-fmt)))
(format dashboard--recentf-cache-item-format filename path))
(`nil path)
(t (format dashboard-recentf-item-format filename path)))))
(if file
(propertize display 'dashboard-path file)
display)))
(defun dashboard-insert-recents (list-size) (defun dashboard-insert-recents (list-size)
"Add the list of LIST-SIZE items from recently edited files." "Add the list of LIST-SIZE items from recently edited files."
(setq dashboard--recentf-cache-item-format nil) (setq dashboard--recentf-cache-item-format nil)
@@ -1212,20 +1303,9 @@ to widget creation."
'recents 'recents
(dashboard-get-shortcut 'recents) (dashboard-get-shortcut 'recents)
`(lambda (&rest _) `(lambda (&rest _)
(find-file-existing (dashboard-expand-path-alist ,el dashboard-recentf-alist))) (find-file-existing
(let* ((file (dashboard-expand-path-alist el dashboard-recentf-alist)) (dashboard-expand-path-alist ,el dashboard-recentf-alist)))
(filename (dashboard-f-filename file)) (dashboard-recentf--propertize-item el)))
(path (dashboard-extract-key-path-alist el dashboard-recentf-alist)))
(cl-case dashboard-recentf-show-base
(`align
(unless dashboard--recentf-cache-item-format
(let* ((len-align (dashboard--align-length-by-type 'recents))
(new-fmt (dashboard--generate-align-format
dashboard-recentf-item-format len-align)))
(setq dashboard--recentf-cache-item-format new-fmt)))
(format dashboard--recentf-cache-item-format filename path))
(`nil path)
(t (format dashboard-recentf-item-format filename path))))))
;; ;;
;;; Bookmarks ;;; Bookmarks
@@ -1246,6 +1326,31 @@ to widget creation."
(defvar dashboard--bookmarks-cache-item-format nil (defvar dashboard--bookmarks-cache-item-format nil
"Cache to record the new generated align format.") "Cache to record the new generated align format.")
(defun dashboard-bookmarks--format-name-and-path (filename short-path)
"Format FILENAME and SHORT-PATH according to `dashboard-bookmarks-show-base'.
Populate cache if needed."
(cl-case dashboard-bookmarks-show-base
(`align
(unless dashboard--bookmarks-cache-item-format
(let* ((len-align (dashboard--align-length-by-type 'bookmarks))
(new-fmt (dashboard--generate-align-format
dashboard-bookmarks-item-format len-align)))
(setq dashboard--bookmarks-cache-item-format new-fmt)))
(format dashboard--bookmarks-cache-item-format filename short-path))
(`nil short-path)
(t (format dashboard-bookmarks-item-format filename short-path))))
(defun dashboard-bookmarks--propertize-name-and-path (bookmark)
"Format BOOKMARK before insertion.
Get path and name from bookmark and add `dashboard-bookmarks-name' to properties"
(if-let* ((path (bookmark-get-filename bookmark))
(short-path (dashboard-shorten-path path 'bookmarks)))
(propertize (dashboard-bookmarks--format-name-and-path
bookmark short-path)
'dashboard-bookmarks-name bookmark
'dashboard-path path)
bookmark))
(defun dashboard-insert-bookmarks (list-size) (defun dashboard-insert-bookmarks (list-size)
"Add the list of LIST-SIZE items of bookmarks." "Add the list of LIST-SIZE items of bookmarks."
(require 'bookmark) (require 'bookmark)
@@ -1256,20 +1361,7 @@ to widget creation."
'bookmarks 'bookmarks
(dashboard-get-shortcut 'bookmarks) (dashboard-get-shortcut 'bookmarks)
`(lambda (&rest _) (bookmark-jump ,el)) `(lambda (&rest _) (bookmark-jump ,el))
(if-let* ((filename el) (dashboard-bookmarks--propertize-name-and-path el)))
(path (bookmark-get-filename el))
(path-shorten (dashboard-shorten-path path 'bookmarks)))
(cl-case dashboard-bookmarks-show-base
(`align
(unless dashboard--bookmarks-cache-item-format
(let* ((len-align (dashboard--align-length-by-type 'bookmarks))
(new-fmt (dashboard--generate-align-format
dashboard-bookmarks-item-format len-align)))
(setq dashboard--bookmarks-cache-item-format new-fmt)))
(format dashboard--bookmarks-cache-item-format filename path-shorten))
(`nil path-shorten)
(t (format dashboard-bookmarks-item-format filename path-shorten)))
el)))
;; ;;
;;; Projects ;;; Projects
@@ -1318,16 +1410,21 @@ be called with the root directory of the project to switch to."
(let* ((file (dashboard-expand-path-alist el dashboard-projects-alist)) (let* ((file (dashboard-expand-path-alist el dashboard-projects-alist))
(filename (dashboard-f-base file)) (filename (dashboard-f-base file))
(path (dashboard-extract-key-path-alist el dashboard-projects-alist))) (path (dashboard-extract-key-path-alist el dashboard-projects-alist)))
(let ((display
(cl-case dashboard-projects-show-base (cl-case dashboard-projects-show-base
(`align (`align
(unless dashboard--projects-cache-item-format (unless dashboard--projects-cache-item-format
(let* ((len-align (dashboard--align-length-by-type 'projects)) (let* ((len-align (dashboard--align-length-by-type
'projects))
(new-fmt (dashboard--generate-align-format (new-fmt (dashboard--generate-align-format
dashboard-projects-item-format len-align))) dashboard-projects-item-format len-align)))
(setq dashboard--projects-cache-item-format new-fmt))) (setq dashboard--projects-cache-item-format new-fmt)))
(format dashboard--projects-cache-item-format filename path)) (format dashboard--projects-cache-item-format filename path))
(`nil path) (`nil path)
(t (format dashboard-projects-item-format filename path)))))) (t (format dashboard-projects-item-format filename path)))))
(if file
(propertize display 'dashboard-path file)
display)))))
(defun dashboard-projects-backend-load-projects () (defun dashboard-projects-backend-load-projects ()
"Depending on `dashboard-projects-backend' load corresponding backend. "Depending on `dashboard-projects-backend' load corresponding backend.
@@ -1344,8 +1441,8 @@ Return function that returns a list of projects."
(when dashboard-remove-missing-entry (when dashboard-remove-missing-entry
(dashboard-mute-apply (dashboard-mute-apply
(ignore-errors (ignore-errors
(dashboard-funcall-fboundp #'project-forget-zombie-projects)))) (dashboard-funcall-fboundp 'project-forget-zombie-projects))))
(project-known-project-roots)) (dashboard-funcall-fboundp 'project-known-project-roots))
(t (t
(display-warning '(dashboard) (display-warning '(dashboard)
"Invalid value for `dashboard-projects-backend'" "Invalid value for `dashboard-projects-backend'"
@@ -1358,11 +1455,7 @@ over custom backends."
(or dashboard-projects-switch-function (or dashboard-projects-switch-function
(cl-case dashboard-projects-backend (cl-case dashboard-projects-backend
(`projectile 'projectile-switch-project-by-name) (`projectile 'projectile-switch-project-by-name)
(`project-el (`project-el 'project-switch-project)
(lambda (project)
"This function is used to switch to `PROJECT'."
(let ((default-directory project))
(project-find-file))))
(t (t
(display-warning '(dashboard) (display-warning '(dashboard)
"Invalid value for `dashboard-projects-backend'" "Invalid value for `dashboard-projects-backend'"
@@ -1419,13 +1512,21 @@ each agenda entry."
(defcustom dashboard-agenda-tags-format 'identity (defcustom dashboard-agenda-tags-format 'identity
"Function to format the org agenda tags. "Function to format the org agenda tags.
Any custom function would receives the tags from `org-get-tags'" Any custom function would receives the local tags from `org-get-tags'"
:type '(choice :type '(choice
(const :tag "Show tags" identity) (const :tag "Show tags" identity)
(const :tag "Hide tags" ignore) (const :tag "Hide tags" ignore)
(function :tag "Custom function")) (function :tag "Custom function"))
:group 'dashboard) :group 'dashboard)
(defcustom dashboard-agenda-tags-scope 'local
"Scope when getting agenda tags for headline using `org-get-tags'."
:type '(choice
(const :tag "No tags" nil)
(const :tag "Local tags (default)" local)
(const :tag "Inherited tags" inherited))
:group 'dashboard)
(defun dashboard-agenda-entry-format () (defun dashboard-agenda-entry-format ()
"Format agenda entry to show it on dashboard. "Format agenda entry to show it on dashboard.
@@ -1481,9 +1582,14 @@ If not height is found on FACE or `dashboard-items-face' use `default'."
(format-time-string dashboard-agenda-time-string-format time))) (format-time-string dashboard-agenda-time-string-format time)))
(defun dashboard-agenda--formatted-tags () (defun dashboard-agenda--formatted-tags ()
"Apply `dashboard-agenda-tags-format' to org-element tags." "Apply `dashboard-agenda-tags-format' to the list of local `org-get-tags'."
(when dashboard-agenda-tags-format (when dashboard-agenda-tags-format
(funcall dashboard-agenda-tags-format (org-get-tags)))) (let ((tags (pcase dashboard-agenda-tags-scope
((pred null) nil)
('local (org-get-tags (point) t))
('inherited (org-get-tags))
(_ (user-error "Wrong value for `dashboard-agenda-tags-scope'")))))
(funcall dashboard-agenda-tags-format tags))))
(defun dashboard-due-date-for-agenda () (defun dashboard-due-date-for-agenda ()
"Return due-date for agenda period." "Return due-date for agenda period."
+44 -26
View File
@@ -1,19 +1,19 @@
;;; dashboard.el --- A startup screen extracted from Spacemacs -*- lexical-binding: t -*- ;;; dashboard.el --- A startup screen extracted from Spacemacs -*- lexical-binding: t -*-
;; Copyright (c) 2016-2025 emacs-dashboard maintainers ;; Copyright (c) 2016-2026 emacs-dashboard maintainers
;; ;;
;; Author : Rakan Al-Hneiti <rakan.alhneiti@gmail.com> ;; Author : Rakan Al-Hneiti <rakan.alhneiti@gmail.com>
;; Maintainer : Shen, Jen-Chieh <jcs090218@gmail.com> ;; Maintainer : Shen, Jen-Chieh <jcs090218@gmail.com>
;; Ricardo Arredondo <ricardo.richo@gmail.com> ;; Ricardo Arredondo <ricardo.richo@gmail.com>
;; URL : https://github.com/emacs-dashboard/emacs-dashboard ;; URL : https://github.com/emacs-dashboard/dashboard
;; ;;
;; This file is not part of GNU Emacs. ;; This file is not part of GNU Emacs.
;; ;;
;;; License: GPLv3 ;;; License: GPLv3
;; ;;
;; Created: October 05, 2016 ;; Created: October 05, 2016
;; Package-Version: 20250708.57 ;; Package-Version: 20260402.436
;; Package-Revision: 8c2cf0cfde4f ;; Package-Revision: 176d641a5554
;; Keywords: startup, screen, tools, dashboard ;; Keywords: startup, screen, tools, dashboard
;; Package-Requires: ((emacs "27.1")) ;; Package-Requires: ((emacs "27.1"))
@@ -32,8 +32,9 @@
;; ;;
;;; Externals ;;; Externals
(declare-function bookmark-get-filename "ext:bookmark.el")
(declare-function bookmark-all-names "ext:bookmark.el") (declare-function bookmark-all-names "ext:bookmark.el")
(declare-function bookmark-get-filename "ext:bookmark.el")
(declare-function bookmark-delete "ext:bookmark.el")
(declare-function dashboard-ls--dirs "ext:dashboard-ls.el") (declare-function dashboard-ls--dirs "ext:dashboard-ls.el")
(declare-function dashboard-ls--files "ext:dashboard-ls.el") (declare-function dashboard-ls--files "ext:dashboard-ls.el")
(declare-function page-break-lines-mode "ext:page-break-lines.el") (declare-function page-break-lines-mode "ext:page-break-lines.el")
@@ -50,7 +51,6 @@
"Extensible startup screen." "Extensible startup screen."
:group 'applications) :group 'applications)
;; Custom splash screen
(defvar dashboard-mode-map (defvar dashboard-mode-map
(let ((map (make-sparse-keymap))) (let ((map (make-sparse-keymap)))
(define-key map (kbd "C-p") #'dashboard-previous-line) (define-key map (kbd "C-p") #'dashboard-previous-line)
@@ -273,32 +273,46 @@ example:
(defun dashboard-cycle-section-forward (&optional section) (defun dashboard-cycle-section-forward (&optional section)
"Cycle forward through the entries in SECTION. "Cycle forward through the entries in SECTION.
If SECTION is nil, cycle in the current section." If SECTION is nil, cycle in the current section."
(let ((target-section (or section (dashboard--current-section)))) (if section
(if target-section (lambda () "Cycle section forwards"
(condition-case nil (interactive)
(progn
(widget-forward 1) (widget-forward 1)
(unless (eq target-section (dashboard--current-section)) (unless (eq section (ignore-errors (dashboard--current-section)))
(dashboard--goto-section target-section))) (dashboard--goto-section section)))
(widget-forward 1)) (lambda ()
(widget-forward 1)))) (interactive) "Cycle current-section forwards"
(if (widget-at (point))
(let ((current-section (ignore-errors (dashboard--current-section))))
(widget-forward 1)
(unless (eq current-section (ignore-errors (dashboard--current-section)))
(dashboard--goto-section current-section)))
(widget-forward 1)))))
(defun dashboard-cycle-section-backward (&optional section) (defun dashboard-cycle-section-backward (&optional section)
"Cycle backward through the entries in SECTION. "Cycle backward through the entries in SECTION.
If SECTION is nil, cycle in the current section." If SECTION is nil, cycle in the current section."
(let ((target-section (or section (dashboard--current-section)))) (if section
(if target-section (lambda () "Cycle section backwards"
(condition-case nil (interactive)
(progn
(widget-backward 1) (widget-backward 1)
(unless (eq target-section (dashboard--current-section)) (unless (eq section (ignore-errors (dashboard--current-section)))
(progn (dashboard--goto-section section)
(dashboard--goto-section target-section) (while (eq section (ignore-errors (dashboard--current-section)))
(while (eq target-section (dashboard--current-section)) (widget-forward 1))
(widget-backward 1)))
(lambda () "Cycle current-section backwards"
(interactive)
(if (widget-at (point))
(let ((current-section (ignore-errors (dashboard--current-section))))
(widget-backward 1)
(unless (eq current-section (ignore-errors (dashboard--current-section)))
(dashboard--goto-section current-section)
(unless (eq section (ignore-errors (dashboard--current-section)))
(dashboard--goto-section section)
(while (eq section (ignore-errors (dashboard--current-section)))
(widget-forward 1)) (widget-forward 1))
(widget-backward 1)))) (widget-backward 1))))
(widget-backward 1)) (widget-backward 1)))))
(widget-backward 1))))
(defun dashboard-section-1 () (defun dashboard-section-1 ()
"Navigate to section 1." (interactive) (dashboard--goto-section-by-index 1)) "Navigate to section 1." (interactive) (dashboard--goto-section-by-index 1))
@@ -429,7 +443,9 @@ Optional argument ARGS adviced function arguments."
(defun dashboard-remove-item-bookmarks () (defun dashboard-remove-item-bookmarks ()
"Remove a bookmarks from `bookmark-alist'." "Remove a bookmarks from `bookmark-alist'."
(interactive)) ; TODO: .. (interactive)
(let ((bookmark-name (get-text-property (point) 'dashboard-bookmarks-name)))
(bookmark-delete bookmark-name)))
(defun dashboard-remove-item-agenda () (defun dashboard-remove-item-agenda ()
"Remove an agenda from `org-agenda-files'." "Remove an agenda from `org-agenda-files'."
@@ -526,7 +542,9 @@ See `dashboard-item-generators' for all items available."
"Insert the list of widgets into the buffer, FORCE-REFRESH is optional." "Insert the list of widgets into the buffer, FORCE-REFRESH is optional."
(interactive) (interactive)
(let ((inhibit-redisplay t) (let ((inhibit-redisplay t)
(recentf-is-on (recentf-enabled-p)) (recentf-is-on (or (recentf-enabled-p)
(and (assq 'recents dashboard-items)
(dashboard-mute-apply (recentf-mode 1)))))
(origial-recentf-list recentf-list) (origial-recentf-list recentf-list)
(dashboard-num-recents (or (cdr (assoc 'recents dashboard-items)) 0))) (dashboard-num-recents (or (cdr (assoc 'recents dashboard-items)) 0)))
(when recentf-is-on (when recentf-is-on
+3 -3
View File
@@ -1,11 +1,11 @@
;; -*- no-byte-compile: t; lexical-binding: nil -*- ;; -*- no-byte-compile: t; lexical-binding: nil -*-
(define-package "diff-hl" "20251216.242" (define-package "diff-hl" "20260328.1925"
"Highlight uncommitted changes using VC." "Highlight uncommitted changes using VC."
'((cl-lib "0.2") '((cl-lib "0.2")
(emacs "26.1")) (emacs "26.1"))
:url "https://github.com/dgutov/diff-hl" :url "https://github.com/dgutov/diff-hl"
:commit "e79aa49ad3cbbe85379cf6646db3aaacd3b04708" :commit "b965e19e6e7f9933199e421849a49229207c1c9f"
:revdesc "e79aa49ad3cb" :revdesc "b965e19e6e7f"
:keywords '("vc" "diff") :keywords '("vc" "diff")
:authors '(("Dmitry Gutov" . "dmitry@gutov.dev")) :authors '(("Dmitry Gutov" . "dmitry@gutov.dev"))
:maintainers '(("Dmitry Gutov" . "dmitry@gutov.dev"))) :maintainers '(("Dmitry Gutov" . "dmitry@gutov.dev")))
+27 -18
View File
@@ -5,8 +5,8 @@
;; Author: Dmitry Gutov <dmitry@gutov.dev> ;; Author: Dmitry Gutov <dmitry@gutov.dev>
;; URL: https://github.com/dgutov/diff-hl ;; URL: https://github.com/dgutov/diff-hl
;; Keywords: vc, diff ;; Keywords: vc, diff
;; Package-Version: 20251216.242 ;; Package-Version: 20260328.1925
;; Package-Revision: e79aa49ad3cb ;; Package-Revision: b965e19e6e7f
;; Package-Requires: ((cl-lib "0.2") (emacs "26.1")) ;; Package-Requires: ((cl-lib "0.2") (emacs "26.1"))
;; This file is part of GNU Emacs. ;; This file is part of GNU Emacs.
@@ -143,6 +143,11 @@ enclosed in a `progn' form. ELSE-FORMS may be empty."
:group 'diff-hl :group 'diff-hl
:type 'boolean) :type 'boolean)
(defcustom diff-hl-next-previous-hunk-auto-recenter nil
"Non-nil to `recenter' after `diff-hl-next-hunk' and `diff-hl-previous-hunk'."
:group 'diff-hl
:type 'boolean)
(defcustom diff-hl-fallback-to-margin t (defcustom diff-hl-fallback-to-margin t
"Non-nil to use margin instead of fringe on non-graphic displays. "Non-nil to use margin instead of fringe on non-graphic displays.
@@ -316,10 +321,13 @@ It can be a relative expression as well, such as \"HEAD^\" with Git, or
(expt text-scale-mode-step text-scale-mode-amount) (expt text-scale-mode-step text-scale-mode-amount)
1)) 1))
(spacing (or (and (display-graphic-p) (default-value 'line-spacing)) 0)) (spacing (or (and (display-graphic-p) (default-value 'line-spacing)) 0))
(total-spacing (pcase spacing
((pred numberp) spacing)
(`(,above . ,below) (+ above below))))
(h (+ (ceiling (* (frame-char-height) scale)) (h (+ (ceiling (* (frame-char-height) scale))
(if (floatp spacing) (if (floatp total-spacing)
(truncate (* (frame-char-height) spacing)) (truncate (* (frame-char-height) total-spacing))
spacing))) total-spacing)))
(w (min (frame-parameter nil (intern (format "%s-fringe" diff-hl-side))) (w (min (frame-parameter nil (intern (format "%s-fringe" diff-hl-side)))
diff-hl-bmp-max-width)) diff-hl-bmp-max-width))
(_ (when (zerop w) (setq w diff-hl-bmp-max-width))) (_ (when (zerop w) (setq w diff-hl-bmp-max-width)))
@@ -483,11 +491,13 @@ It can be a relative expression as well, such as \"HEAD^\" with Git, or
(hide-staged (and (eq backend 'Git) (not diff-hl-show-staged-changes)))) (hide-staged (and (eq backend 'Git) (not diff-hl-show-staged-changes))))
(when backend (when backend
(let ((state (vc-state file backend)) (let ((state (vc-state file backend))
;; Workaround for debbugs#78946. ;; Workaround for debbugs#78946 for the `thread' async update method.
;; This is fiddly, but we basically allow the thread to start, while ;; This is fiddly, but we basically allow the thread to start, while
;; prohibiting the async process call inside. ;; prohibiting the async process call inside.
;; That still makes it partially async. ;; That still makes it partially async on macOS.
(diff-hl-update-async (and (not (eq window-system 'ns)) ;; Or just use "simple async" if your Emacs is new enough.
(diff-hl-update-async (or (and (eq diff-hl-update-async 'thread)
(not (eq window-system 'ns)))
(eq diff-hl-update-async t)))) (eq diff-hl-update-async t))))
(cond (cond
((and ((and
@@ -581,11 +591,6 @@ contents as they are (or would be) after applying the changes in NEW."
(setq old (cdr old))) (setq old (cdr old)))
ref)) ref))
(defun diff-hl-process-wait (buf)
(let ((proc (get-buffer-process buf)))
(while (process-live-p proc)
(accept-process-output proc 0.01))))
(defun diff-hl-changes-from-buffer (buf) (defun diff-hl-changes-from-buffer (buf)
(with-current-buffer buf (with-current-buffer buf
(let (res) (let (res)
@@ -765,8 +770,9 @@ Return a list of line overlays used."
((eq (process-status proc) 'signal)) ((eq (process-status proc) 'signal))
;; If a process is running, set the sentinel. ;; If a process is running, set the sentinel.
((eq (process-status proc) 'run) ((eq (process-status proc) 'run)
(set-process-sentinel (add-function
proc :after
(process-sentinel proc)
(lambda (proc _status) (lambda (proc _status)
;; Delegate to the parent cond for decision logic. ;; Delegate to the parent cond for decision logic.
(diff-hl--when-done buffer get-value callback proc)))) (diff-hl--when-done buffer get-value callback proc))))
@@ -1110,9 +1116,11 @@ its end position."
"Go to the beginning of the next hunk in the current buffer." "Go to the beginning of the next hunk in the current buffer."
(interactive) (interactive)
(let ((overlay (diff-hl-search-next-hunk backward))) (let ((overlay (diff-hl-search-next-hunk backward)))
(if overlay (unless overlay
(user-error "No further hunks found"))
(goto-char (overlay-start overlay)) (goto-char (overlay-start overlay))
(user-error "No further hunks found")))) (when diff-hl-next-previous-hunk-auto-recenter
(recenter))))
(defun diff-hl-previous-hunk () (defun diff-hl-previous-hunk ()
"Go to the beginning of the previous hunk in the current buffer." "Go to the beginning of the previous hunk in the current buffer."
@@ -1120,7 +1128,8 @@ its end position."
(diff-hl-next-hunk t)) (diff-hl-next-hunk t))
(defun diff-hl-find-current-hunk () (defun diff-hl-find-current-hunk ()
(let (o) (let ((o)
(diff-hl-next-previous-hunk-auto-recenter nil))
(cond (cond
((diff-hl-hunk-overlay-at (point))) ((diff-hl-hunk-overlay-at (point)))
((setq o (diff-hl-search-next-hunk t)) ((setq o (diff-hl-search-next-hunk t))
+3 -3
View File
@@ -1,9 +1,9 @@
;; -*- no-byte-compile: t; lexical-binding: nil -*- ;; -*- no-byte-compile: t; lexical-binding: nil -*-
(define-package "emacsql" "20251130.1841" (define-package "emacsql" "20260401.1220"
"High-level SQL database front-end." "High-level SQL database front-end."
'((emacs "26.1")) '((emacs "26.1"))
:url "https://github.com/magit/emacsql" :url "https://github.com/magit/emacsql"
:commit "f177a41e93b92a4b1139a553eed5415ca33f439c" :commit "2fe6d4562b32a170a750d5e80514fbb6b6694803"
:revdesc "f177a41e93b9" :revdesc "2fe6d4562b32"
:authors '(("Christopher Wellons" . "wellons@nullprogram.com")) :authors '(("Christopher Wellons" . "wellons@nullprogram.com"))
:maintainers '(("Jonas Bernoulli" . "emacs.emacsql@jonas.bernoulli.dev"))) :maintainers '(("Jonas Bernoulli" . "emacs.emacsql@jonas.bernoulli.dev")))
+3 -3
View File
@@ -6,8 +6,8 @@
;; Maintainer: Jonas Bernoulli <emacs.emacsql@jonas.bernoulli.dev> ;; Maintainer: Jonas Bernoulli <emacs.emacsql@jonas.bernoulli.dev>
;; Homepage: https://github.com/magit/emacsql ;; Homepage: https://github.com/magit/emacsql
;; Package-Version: 20251130.1841 ;; Package-Version: 20260401.1220
;; Package-Revision: f177a41e93b9 ;; Package-Revision: 2fe6d4562b32
;; Package-Requires: ((emacs "26.1")) ;; Package-Requires: ((emacs "26.1"))
;; SPDX-License-Identifier: Unlicense ;; SPDX-License-Identifier: Unlicense
@@ -38,7 +38,7 @@
"The EmacSQL SQL database front-end." "The EmacSQL SQL database front-end."
:group 'comm) :group 'comm)
(defconst emacsql-version "4.3.3") (defconst emacsql-version "4.3.6")
(defvar emacsql-global-timeout 30 (defvar emacsql-global-timeout 30
"Maximum number of seconds to wait before bailing out on a SQL command. "Maximum number of seconds to wait before bailing out on a SQL command.
+1 -1
View File
@@ -2,7 +2,7 @@
(define-package "epl" "20180205.2049" (define-package "epl" "20180205.2049"
"Emacs Package Library." "Emacs Package Library."
'((cl-lib "0.3")) '((cl-lib "0.3"))
:url "http://github.com/cask/epl" :url "https://github.com/cask/epl"
:commit "78ab7a85c08222cd15582a298a364774e3282ce6" :commit "78ab7a85c08222cd15582a298a364774e3282ce6"
:revdesc "78ab7a85c082" :revdesc "78ab7a85c082"
:keywords '("convenience") :keywords '("convenience")
+1 -1
View File
@@ -16,4 +16,4 @@ File: dir, Node: Top This is the top of the INFO tree
Emacs Emacs
* ESS: (ess). Emacs Speaks Statistics (R/S/S+, SAS, * ESS: (ess). Emacs Speaks Statistics (R/S/S+, SAS,
BUGS/JAGS and Stata). BUGS/NIMBLE and Stata).
+20 -10
View File
@@ -58,18 +58,28 @@
(cons "^[ \t]*\\(model\\|var\\)\\>" (cons "^[ \t]*\\(model\\|var\\)\\>"
font-lock-keyword-face) font-lock-keyword-face)
(cons (concat "\\<d\\(bern\\|beta\\|bin\\|cat\\|chisq\\|" (cons (concat "\\<d\\(bern\\|beta\\|bin\\|binom\\|"
"dexp\\|dirch\\|exp\\|\\(gen[.]\\)?gamma\\|hyper\\|" "cat\\|chisq\\|chisqr\\|CRP\\|"
"interval\\|lnorm\\|logis\\|mnorm\\|mt\\|multi\\|" "dexp\\|dirch\\|dirich\\|"
"negbin\\|norm\\(mix\\)?\\|par\\|pois\\|sum\\|t\\|" "exp\\|\\(gen[.]\\|inv\\)?gamma\\|hyper\\|"
"unif\\|weib\\|wish\\)[ \t\n]*(") "interval\\|lkj_corr_cholesky\\|laplace\\|lnorm\\|logis\\|"
"mnorm\\|mt\\|multi\\|multinom\\|mvt\\|"
"negbin\\|nbinom\\|norm\\(mix\\)?\\|par\\|pois\\|sum\\|t\\|"
"unif\\|weib\\|weibull\\|\\(inv\\)?wish\\|wishart\\)[ \t\n]*(")
font-lock-constant-face) font-lock-constant-face)
(cons (concat "\\<\\(abs\\|cos\\|C\\|dim\\|\\(i\\)?cloglog\\|equals\\|" (cons (concat "\\<\\(abs\\|acos\\|acosh\\|asin\\|asinh\\|atan\\|atanh\\|"
"exp\\|for\\|inprod\\|interp[.]line\\|inverse\\|length\\|" "asCol\\|asRow\\|backsolve\\|besselK\\|ceiling\\|chol\\|"
"\\(i\\)?logit\\|logdet\\|logfact\\|loggam\\|max\\|mean\\|" "cos\\|C\\|dim\\|\\(i\\)?cloglog\\|cube\\|"
"mexp\\|min\\|phi\\|pow\\|probit\\|prod\\|rank\\|round\\|" "equals\\|exp\\|expm\\|expAv\\|expit\\|"
"sd\\|sin\\|sort\\|sqrt\\|step\\|sum\\|t\\|trunc\\|T\\)[ \t\n]*(") "floor\\|for\\|forwardsolve\\|"
"inprod\\|interp[.]lin\\(e\\)?\\|inverse\\|"
"lgamma\\|length\\|lfactorial\\|"
"log\\|log1p\\|\\(i\\)?logit\\|logdet\\|logfact\\|loggam\\|"
"max\\|mean\\|mexp\\|min\\|pmax\\|pmin\\|"
"phi\\|pow\\|\\(i\\)?probit\\|prod\\|rank\\|ranked\\|round\\|"
"sd\\|sin\\|solve\\|sort\\|sqrt\\|step\\|sum\\|"
"t\\|tan\\|trunc\\|T\\)[ \t\n]*(")
font-lock-function-name-face) font-lock-function-name-face)
;; .bmd files ;; .bmd files
+20 -19
View File
@@ -29,14 +29,14 @@
(require 'ess-utils) (require 'ess-utils)
(defvar ess-bugs-command) (defvar ess-bugs-command)
(defvar ess-bugs-chains) (defvar ess-bugs-chains)
(defvar ess-jags-command) ;;(defvar ess-jags-command)
(defvar ess-jags-chains) ;;(defvar ess-jags-chains)
(defvar ess-bugs-default-bins) (defvar ess-bugs-default-bins)
(declare-function ess-bugs-na-bug "ess-bugs-d") (declare-function ess-bugs-na-bug "ess-bugs-d")
(declare-function ess-jags-na-bug "ess-jags-d") ;;(declare-function ess-jags-na-bug "ess-jags-d")
(declare-function ess-bugs-na-bmd "ess-bugs-d") (declare-function ess-bugs-na-bmd "ess-bugs-d")
(declare-function ess-jags-na-jmd "ess-jags-d") ;;(declare-function ess-jags-na-jmd "ess-jags-d")
(defgroup ess-bugs nil (defgroup ess-bugs nil
"ESS: BUGS." "ESS: BUGS."
@@ -140,8 +140,9 @@ Users whose default is not \\='sh, but are accessing a remote machine with
(defvar ess-bugs-mode-map (defvar ess-bugs-mode-map
(let ((map (make-sparse-keymap))) (let ((map (make-sparse-keymap)))
(define-key map (quote [f2]) #'ess-revert-wisely) (define-key map (quote [f2]) #'ess-revert-wisely)
(define-key map "\C-c\C-c" #'ess-bugs-next-action) ;;(define-key map "\C-c\C-c" #'ess-bugs-next-action)
(define-key map "=" #'ess-bugs-hot-arrow) (define-key map "<" #'ess-bugs-hot-arrow) ;; NIMBLE needs equals character
;; (define-key map "=" #'ess-bugs-hot-arrow)
;; (define-key map "_" #'ess-bugs-hot-arrow) ;; (define-key map "_" #'ess-bugs-hot-arrow)
map) map)
"ESS[BUGS]: Keymap for mode.") "ESS[BUGS]: Keymap for mode.")
@@ -191,20 +192,20 @@ and `ess-bugs-file-dir'."
(interactive) (interactive)
(insert " <- ")) (insert " <- "))
(defun ess-bugs-next-action () ;; (defun ess-bugs-next-action ()
"ESS[BUGS/JAGS]: Perform the appropriate next action." ;; "ESS[BUGS/JAGS]: Perform the appropriate next action."
(interactive) ;; (interactive)
(ess-bugs-file) ;; (ess-bugs-file)
(cond ((equal ".bug" ess-bugs-file-suffix) (ess-bugs-na-bug)) ;; (cond ((equal ".bug" ess-bugs-file-suffix) (ess-bugs-na-bug))
((equal ".jag" ess-bugs-file-suffix) (ess-jags-na-bug)) ;; ((equal ".jag" ess-bugs-file-suffix) (ess-jags-na-bug))
((equal ".bmd" ess-bugs-file-suffix) ;; ((equal ".bmd" ess-bugs-file-suffix)
(ess-save-and-set-local-variables) ;; (ess-save-and-set-local-variables)
(ess-bugs-na-bmd ess-bugs-command ess-bugs-chains)) ;; (ess-bugs-na-bmd ess-bugs-command ess-bugs-chains))
((equal ".jmd" ess-bugs-file-suffix) ;; ((equal ".jmd" ess-bugs-file-suffix)
(ess-save-and-set-local-variables) ;; (ess-save-and-set-local-variables)
(ess-jags-na-jmd ess-jags-command ess-jags-chains))) ;; (ess-jags-na-jmd ess-jags-command ess-jags-chains)))
) ;; )
(defun ess-bugs-sci-to-round-4-dp () (defun ess-bugs-sci-to-round-4-dp ()
"ESS[BUGS]: round output from +/-0.000E+/-0 to 4 decimal places." "ESS[BUGS]: round output from +/-0.000E+/-0 to 4 decimal places."
+15 -5
View File
@@ -1,6 +1,6 @@
;;; ess-custom.el --- Customize variables for ESS -*- lexical-binding: t; -*- ;;; ess-custom.el --- Customize variables for ESS -*- lexical-binding: t; -*-
;; Copyright (C) 1997-2025 Free Software Foundation, Inc. ;; Copyright (C) 1997-2026 Free Software Foundation, Inc.
;; Author: Rodney Sparapani ;; Author: Rodney Sparapani
;; Maintainer: ESS-help <ess-help@r-project.org> ;; Maintainer: ESS-help <ess-help@r-project.org>
@@ -1571,11 +1571,21 @@ by `ess-function-template'."
:group 'ess :group 'ess
:type 'regexp) :type 'regexp)
(defcustom ess-r-outline-regexp (defcustom ess-r-outline-style 'none
"^[ \t]*#+ +.*\\(?:----\\|====\\|####\\)\\s-*$" "Outline convention used by `ess-r-mode'.
"Regexp used to detect the beginning of R headings." Choose between comment rulers like RStudio (\"### Section title ----\"),
\"Org-like\" headings (\"### *** Section title\"), or no outline support.
When using the RStudio outline style, `ess-indent-with-fancy-comments'
is automatically set to nil locally in the buffer. When switching back,
the original local binding is restored; if the variable was not
buffer-local, the current global default applies. You can also use
(setq ess-style \\='RStudio) to achieve the same effect globally."
:group 'ess-R :group 'ess-R
:type 'regexp) :type '(choice (const :tag "No outline support" none)
(const :tag "RStudio comment rulers" RStudio)
(const :tag "Org-Like (### *** headings)" Org-like))
:safe #'symbolp)
; ess-inf: variables for inferior-ess. ; ess-inf: variables for inferior-ess.
+3 -3
View File
@@ -1,10 +1,10 @@
;; -*- no-byte-compile: t; lexical-binding: nil -*- ;; -*- no-byte-compile: t; lexical-binding: nil -*-
(define-package "ess" "20251212.937" (define-package "ess" "20260322.1703"
"Emacs Speaks Statistics." "Emacs Speaks Statistics."
'((emacs "25.1")) '((emacs "25.1"))
:url "https://ess.r-project.org/" :url "https://ess.r-project.org/"
:commit "e39ca8fa7fce703aa2851e83987a412737d575f0" :commit "4e112590d1c13cfe464ca7de77837f1b956e4a9f"
:revdesc "e39ca8fa7fce" :revdesc "4e112590d1c1"
:authors '(("David Smith" . "dsmith@stats.adelaide.edu.au") :authors '(("David Smith" . "dsmith@stats.adelaide.edu.au")
("A.J. Rossini" . "blindglobe@gmail.com") ("A.J. Rossini" . "blindglobe@gmail.com")
("Richard M. Heiberger" . "rmh@temple.edu") ("Richard M. Heiberger" . "rmh@temple.edu")
+103 -5
View File
@@ -1,6 +1,6 @@
;;; ess-r-mode.el --- R customization -*- lexical-binding: t; -*- ;;; ess-r-mode.el --- R customization -*- lexical-binding: t; -*-
;; Copyright (C) 1997-2025 Free Software Foundation, Inc. ;; Copyright (C) 1997-2026 Free Software Foundation, Inc.
;; Author: A.J. Rossini ;; Author: A.J. Rossini
;; Created: 12 Jun 1997 ;; Created: 12 Jun 1997
;; Maintainer: ESS-core <ESS-core@r-project.org> ;; Maintainer: ESS-core <ESS-core@r-project.org>
@@ -299,14 +299,111 @@ When t, loading a file into a namespaced will output information
about which objects are exported and which stay hidden in the about which objects are exported and which stay hidden in the
namespace.") namespace.")
(defun ess-r-outline-level () (defconst ess-r--outline-rstudio-regexp
"R mode `outline-level` function." "^[ \t]*#+ +.*\\(?:----\\|====\\|####\\)\\s-*$"
"R outline Regexp when `ess-r-outline-style' is `RStudio'.")
(defconst ess-r--outline-org-like-regexp
"^\\(?:> \\)?###\\s-+\\(\\*+\\)\\s-+.*$"
"R outline regexp used when `ess-r-outline-style' is `Org-like'.")
(defconst ess-r-outline-style-alist
`((none
(outline-regexp . "\\`a\\`")
(outline-level . ,#'ess-r--outline-level-none))
(RStudio
(outline-regexp . ,ess-r--outline-rstudio-regexp)
(outline-level . ,#'ess-r--outline-level-rstudio))
(Org-like
(outline-regexp . ,ess-r--outline-org-like-regexp)
(outline-level . ,#'ess-r--outline-level-org-like)))
"Mapping between outline styles and their regexp/level helpers.")
(defun ess-r--outline-style-definition (&optional style)
"Return the style definition for STYLE, defaulting to `ess-r-outline-style'."
(let ((style (or style ess-r-outline-style)))
(or (assq style ess-r-outline-style-alist)
(error "Unknown ESS outline style: %s" style))))
(defun ess-r--outline-style-value (key &optional style)
"Return value for KEY in STYLE's definition."
(cdr (assq key (cdr (ess-r--outline-style-definition style)))))
(defun ess-r--outline-level-rstudio ()
"Compute outline level for `RStudio` style headings."
(save-excursion (save-excursion
(beginning-of-line) (beginning-of-line)
(if (looking-at "^[ \t]*\\(#+\\)\\s-") (if (looking-at "^[ \t]*\\(#+\\)\\s-")
(length (match-string 1)) (length (match-string 1))
1000))) 1000)))
(defun ess-r--outline-level-org-like ()
"Compute outline level for `Org-like` style headings."
(save-excursion
(beginning-of-line)
(if (looking-at "^\\(?:> \\)?###\\s-+\\(\\*+\\)\\s-+")
(length (match-string 1))
1000)))
(defun ess-r--outline-level-none ()
"Dummy outline level function for no outline support."
1000)
(defun ess-r-outline-level ()
"R mode `outline-level` dispatcher for the current outline style."
(funcall (ess-r--outline-style-value 'outline-level)))
(defvar-local ess-r--saved-indent-with-fancy-comments nil
"Saved state of `ess-indent-with-fancy-comments' before RStudio style.
Stored as (VALUE . WAS-LOCAL) to restore both value and local binding.")
(defun ess-r-set-outline-style (&optional style)
"Apply STYLE (or `ess-r-outline-style') to the current buffer.
When switching to RStudio style, `ess-indent-with-fancy-comments' is
automatically set to nil locally. The previous value is saved and
restored when switching to a different style."
(interactive
(list (intern (completing-read
"Outline style"
(mapcar (lambda (entry) (symbol-name (car entry)))
ess-r-outline-style-alist)
nil t nil nil
(symbol-name (or ess-r-outline-style 'none))))))
(let* ((style (or style ess-r-outline-style))
(entry (ess-r--outline-style-definition style))
(old-style ess-r-outline-style)
(new-style (car entry)))
;; Handle ess-indent-with-fancy-comments adjustment
(cond
;; Switching TO RStudio style
((and (eq new-style 'RStudio)
(not (eq old-style 'RStudio)))
;; Save current value if not already saved
(unless ess-r--saved-indent-with-fancy-comments
(setq ess-r--saved-indent-with-fancy-comments
(cons (if (local-variable-p 'ess-indent-with-fancy-comments)
ess-indent-with-fancy-comments
(default-value 'ess-indent-with-fancy-comments))
(local-variable-p 'ess-indent-with-fancy-comments))))
(setq-local ess-indent-with-fancy-comments nil))
;; Switching FROM RStudio style to another
((and (eq old-style 'RStudio)
(not (eq new-style 'RStudio))
ess-r--saved-indent-with-fancy-comments)
;; Restore saved value and local state
(let ((saved-value (car ess-r--saved-indent-with-fancy-comments))
(saved-local (cdr ess-r--saved-indent-with-fancy-comments)))
(if saved-local
(setq-local ess-indent-with-fancy-comments saved-value)
(when (local-variable-p 'ess-indent-with-fancy-comments)
(kill-local-variable 'ess-indent-with-fancy-comments))))
(setq ess-r--saved-indent-with-fancy-comments nil)))
;; Apply outline style
(setq-local ess-r-outline-style new-style)
(setq-local outline-regexp (ess-r--outline-style-value 'outline-regexp style))
(setq-local outline-level #'ess-r-outline-level)))
;; The syntax class for '\' is punctuation character to handle R 4.1 ;; The syntax class for '\' is punctuation character to handle R 4.1
;; lambdas. Inside strings it should be treated as an escape ;; lambdas. Inside strings it should be treated as an escape
;; character which we ensure here. ;; character which we ensure here.
@@ -843,6 +940,8 @@ top level functions only."
(setq-local electric-layout-rules '((?{ . after))) (setq-local electric-layout-rules '((?{ . after)))
;; indentation ;; indentation
(add-hook 'hack-local-variables-hook #'ess-set-style nil t) (add-hook 'hack-local-variables-hook #'ess-set-style nil t)
;; outline
(add-hook 'hack-local-variables-hook #'ess-r-set-outline-style nil t)
;; eldoc ;; eldoc
(ess--setup-eldoc #'ess-r-eldoc-function) (ess--setup-eldoc #'ess-r-eldoc-function)
;; auto-complete ;; auto-complete
@@ -864,8 +963,7 @@ top level functions only."
(when ess-imenu-use-S (when ess-imenu-use-S
(imenu-add-to-menubar "Imenu-R")) (imenu-add-to-menubar "Imenu-R"))
;; outline ;; outline
(setq-local outline-level #'ess-r-outline-level) (ess-r-set-outline-style)
(setq-local outline-regexp ess-r-outline-regexp)
(setq-local beginning-of-defun-function #'ess-r-beginning-of-defun) (setq-local beginning-of-defun-function #'ess-r-beginning-of-defun)
(setq-local end-of-defun-function #'ess-r-end-of-defun) (setq-local end-of-defun-function #'ess-r-end-of-defun)
(ess-roxy-mode)) (ess-roxy-mode))
+1 -1
View File
@@ -137,7 +137,7 @@ All Rd mode abbrevs start with a grave accent (`)."
"dontshow" "donttest" "dots" "email" "emph" "enc" "env" "eqn" "figure" "file" "dontshow" "donttest" "dots" "email" "emph" "enc" "env" "eqn" "figure" "file"
"href" "href"
"ifelse" "if" "ifelse" "if"
"item" "kbd" "ldots" "linkS4class" "link" "method" "item" "kbd" "ldots" "linkS4class" "linkS4methods" "link" "method"
"manual" "manual"
"newcommand" "option" "out" "newcommand" "option" "out"
"pkg" "sQuote" "renewcommand" "pkg" "sQuote" "renewcommand"
+2 -2
View File
@@ -17,8 +17,8 @@
;; ;;
;; Maintainer: ESS Core Team <ESS-core@r-project.org> ;; Maintainer: ESS Core Team <ESS-core@r-project.org>
;; Created: 7 Jan 1994 ;; Created: 7 Jan 1994
;; Package-Version: 20251212.937 ;; Package-Version: 20260322.1703
;; Package-Revision: e39ca8fa7fce ;; Package-Revision: 4e112590d1c1
;; URL: https://ess.r-project.org/ ;; URL: https://ess.r-project.org/
;; Package-Requires: ((emacs "25.1")) ;; Package-Requires: ((emacs "25.1"))
;; ESSR-Version: 1.8 ;; ESSR-Version: 1.8
+165 -285
View File
@@ -1,8 +1,8 @@
This is ess.info, produced by makeinfo version 7.2 from ess.texi. This is ess.info, produced by makeinfo version 7.3 from ess.texi.
INFO-DIR-SECTION Emacs INFO-DIR-SECTION Emacs
START-INFO-DIR-ENTRY START-INFO-DIR-ENTRY
* ESS: (ess). Emacs Speaks Statistics (R/S/S+, SAS, BUGS/JAGS and Stata). * ESS: (ess). Emacs Speaks Statistics (R/S/S+, SAS, BUGS/NIMBLE and Stata).
END-INFO-DIR-ENTRY END-INFO-DIR-ENTRY
ESS -- Emacs Speaks Statistics ESS -- Emacs Speaks Statistics
@@ -14,7 +14,7 @@ File: ess.info, Node: Top, Next: Introduction, Up: (dir)
ESS: Emacs Speaks Statistics ESS: Emacs Speaks Statistics
**************************** ****************************
ESS version 25.01.0 ESS version 26.01.0
by A.J. Rossini, by A.J. Rossini,
R.M. Heiberger, R.M. Heiberger,
@@ -30,7 +30,7 @@ ESS version 25.01.0
Emacs Speaks Statistics (ESS) provides an intelligent, consistent Emacs Speaks Statistics (ESS) provides an intelligent, consistent
interface between the user and the software. ESS interfaces with interface between the user and the software. ESS interfaces with
R, SAS, S-PLUS, BUGS/JAGS and other statistical analysis packages R, SAS, S-PLUS, BUGS/NIMBLE and other statistical analysis packages
on GNU/Linux, other Unix-like systems such as macOS, and Microsoft on GNU/Linux, other Unix-like systems such as macOS, and Microsoft
Windows. ESS is itself a package within the Emacs text editor and Windows. ESS is itself a package within the Emacs text editor and
uses Emacs features to streamline the creation and use of uses Emacs features to streamline the creation and use of
@@ -66,7 +66,6 @@ the file COPYING in the same directory as this file for more details.
* ESS for R:: Overview of ESS features for the S family * ESS for R:: Overview of ESS features for the S family
* ESS for SAS:: * ESS for SAS::
* ESS for BUGS:: * ESS for BUGS::
* ESS for JAGS::
* Mailing lists/bug reports:: How to get assistance with ESS * Mailing lists/bug reports:: How to get assistance with ESS
* Customization:: Customizing ESS * Customization:: Customizing ESS
* Indices:: * Indices::
@@ -79,7 +78,7 @@ File: ess.info, Node: Introduction, Next: Installation, Prev: Top, Up: Top
ESS provides a generic interface, through Emacs, to statistical ESS provides a generic interface, through Emacs, to statistical
packages. It currently supports R (and the rest of the S family), SAS, packages. It currently supports R (and the rest of the S family), SAS,
BUGS/JAGS, Stata, and Julia with the level of support roughly in that BUGS/NIMBLE, Stata, and Julia with the level of support roughly in that
order. order.
Throughout this manual, _Emacs_ refers to _GNU Emacs_ by the Free Throughout this manual, _Emacs_ refers to _GNU Emacs_ by the Free
@@ -249,6 +248,13 @@ File: ess.info, Node: New features, Next: Credits, Prev: Features, Up: Intro
1.2 New features in ESS 1.2 New features in ESS
======================= =======================
Changes and New Features in 26.01.0:
• ESS[BUGS] is still relevant due to NIMBLE keeping the language
alive. However, only syntax highlighting and key-presses will be
supported moving forward. For example, the < key now generates
<- rather than the former = since equals is a valid character
in NIMBLE BUGS.
Changes and New Features in 25.01.0: Changes and New Features in 25.01.0:
• polymode: In our transition from literate libraries (such as noweb • polymode: In our transition from literate libraries (such as noweb
@@ -3510,29 +3516,48 @@ File: ess.info, Node: Outline, Next: Toolbar, Prev: Imenu, Up: Extras
R editing buffers integrate with outline-minor-mode. When you toggle R editing buffers integrate with outline-minor-mode. When you toggle
the minor mode (for example via M-x outline-minor-mode or by adding it the minor mode (for example via M-x outline-minor-mode or by adding it
to ess-r-mode-hook), ESS assigns ess-r-outline-level to to ess-r-mode-hook), ESS assigns ess-r-outline-level to
outline-level and installs ess-r-outline-regexp so that comment outline-level and configures outline-regexp according to
headings drive folding. Lines that begin with one or more #, followed ess-r-outline-style so that comment headings drive folding. By
by text and a trailing marker of ----, ====, or ####, are treated default, outline support is disabled (none), but you can enable it by
as outline headings. This matches the section markers convention setting ess-r-outline-style to RStudio or Org-like. With the
adopted by RStudio. RStudio style, lines that begin with one or more #, followed by text
and a trailing marker of ----, ====, or ####, are treated as
outline headings. This matches the section markers convention adopted
by RStudio.
# Setup ---- # Setup ----
## Data ---- ## Data ----
### Models ==== ### Models ====
#### Helpers #### #### Helpers ####
The number of leading # characters sets the outline depth. Use The number of leading # characters sets the outline depth. When
standard Outline commands (such as C-c C-t) to cycle visibility once using the RStudio outline style, ess-indent-with-fancy-comments is
the minor mode is active. To enable Outlining automatically, add it to automatically set to nil locally in the buffer to prevent single-hash
the R mode hook: comments from being treated as right-margin comments with
comment-column 40. When switching back to a different outline style,
the original local binding is restored; if the variable was not
buffer-local, the current global default applies.
Use standard Outline commands (such as C-c C-t) to cycle
visibility once the minor mode is active. To enable Outlining
automatically, add it to the R mode hook:
(add-hook 'ess-r-mode-hook #'outline-minor-mode) (add-hook 'ess-r-mode-hook #'outline-minor-mode)
-- User Option: ess-r-outline-regexp -- User Option: ess-r-outline-style
Regular expression used by ESS to recognise outline headings in R Select which outline convention ess-r-mode should use. The
buffers. The default matches the RStudio-style sections shown default none disables outline support to preserve backward
above, but you can customise it if you prefer a different comment compatibility. Set to RStudio to recognise the comment rulers
convention. shown above, or choose Org-like to match the ### * Section
pattern, inspired from org-mode:
### * Setup
### ** Data
### *** Models
### **** Helpers
You can switch styles via M-x ess-r-set-outline-style or by
customizing this option.
 
File: ess.info, Node: Toolbar, Next: Xref, Prev: Outline, Up: Extras File: ess.info, Node: Toolbar, Next: Xref, Prev: Outline, Up: Extras
@@ -3662,48 +3687,6 @@ polymode <https://github.com/polymode/poly-R/>,
<https://polymode.github.io/>, or markdown-mode with edit-indirect <https://polymode.github.io/>, or markdown-mode with edit-indirect
<https://jblevins.org/projects/markdown-mode>. <https://jblevins.org/projects/markdown-mode>.
ESS provides support for writing and processing Sweave
(<https://leisch.userweb.mwn.de/Sweave/>), building up on Emacs'
ess-noweb-mode for literate programming. When working on an Sweave
document, the following key bindings are available:
-- Command: ess-swv-weave CHOOSE
M-n s Run Sweave on the current .Rnw file. If CHOOSE is
non-nil, offer a menu of available weavers.
-- Command: ess-swv-latex
M-n l Run LaTeX after Sweave'ing.
-- Command: ess-swv-PS
M-n p Generate and display a postscript file after LaTeX'ing.
-- Command: ess-swv-PDF PDFLATEX-CMD
M-n P Generate and display a PDF file after LaTeX'ing. Optional
argument PDFLATEX-CMD is the command to use, which by default, is
the command used to generate the PDF file is the first element of
ess-swv-pdflatex-commands.
-- User Option: ess-swv-pdflatex-commands
Commands used by ess-swv-PDF to run a version of pdflatex; the
first entry is the default command.
Sweave'ing with ess-swv-weave starts an inferior-ESS process, if
one is not available. Other commands are available from the Sweaving,
Tangling, ... submenu of the Noweb menu.
AUCTeX (<https://www.gnu.org/software/auctex>) users may prefer to
set the variable ess-swv-plug-into-AUCTeX-p (available from the "ESS
Sweave" customization group) to t. Alternatively, the same can be
achieved by activating the entry "AUCTeX Interface" from the Sweaving,
Tangling, ... submenu, which toggles this variable on or off. When the
interface is activated, new entries for Sweave'ing and LaTeX'ing
thereafter are available from AUCTeX's "Command" menu. Sweave'ing can,
thus, be done by C-c C-c Sweave RET without an inferior-ESS process.
Similarly, LaTeX'ing can be done by C-c C-c LaTeXSweave RET. In both
cases, the process can be monitored with C-c C-l
(TeX-recenter-output-buffer). Open the viewer with C-c C-v
(TeX-view), as usual in AUCTeX.
 
File: ess.info, Node: ESS for R, Next: ESS for SAS, Prev: Extras, Up: Top File: ess.info, Node: ESS for R, Next: ESS for SAS, Prev: Extras, Up: Top
@@ -4403,120 +4386,26 @@ File: ess.info, Node: ESS(SAS)--Windows, Prev: ESS(SAS)--Graphics, Up: ESS fo
'submit-region' or paste them into SAS Display Manager. 'submit-region' or paste them into SAS Display Manager.
 
File: ess.info, Node: ESS for BUGS, Next: ESS for JAGS, Prev: ESS for SAS, Up: Top File: ess.info, Node: ESS for BUGS, Next: Mailing lists/bug reports, Prev: ESS for SAS, Up: Top
14 ESS for BUGS 14 ESS for BUGS
*************** ***************
ESS[BUGS] provides 5 features. First, BUGS syntax is described to allow ESS[BUGS] NIMBLE has re-vitalized the BUGS language. All previous
for proper fontification of statements, distributions, functions, instances of BUGS such as OpenBUGS and JAGS are now deprecated.
commands and comments in BUGS model files, command files and log files. Therefore, ESS suppors BUGS syntax to allow for proper fontification of
Second, ESS creates templates for the command file from the model file statements, distributions, functions, commands and comments in
so that a BUGS batch process can be defined by a single file. Third, BUGS/NIMBLE model files.
ESS provides a BUGS batch script that allows ESS to set BUGS batch
parameters. Fourth, key sequences are defined to create a command file
and submit a BUGS batch process. Lastly, interactive submission of BUGS
commands is also supported.
14.1 ESS[BUGS]-Model files 14.1 ESS[BUGS]-Model files
========================== ==========================
Model files with the .bug extension are edited in ESS[BUGS] mode. Model files with the .bug extension are edited in ESS[BUGS] mode.
Three keys are bound for your use in ESS[BUGS], F2, C-c C-c and =.
F2 performs the same action as it does in ESS[SAS], *Note
ESS(SAS)--Function keys for batch processing::. C-c C-c performs the
function ess-bugs-next-action which you will use a lot. Pressing it
in an empty buffer for a model file will produce a template for you.
= inserts the set operator, <-.
14.2 ESS[BUGS]-Command files
============================
Files ending in .bmd are used for BUGS command files. When you have
finished editing your model file and press C-c C-c, a command file is
created if one does not already exist. When you are finished editing
your command file, pressing C-c C-c again will submit your command
file as a batch job.
14.3 ESS[BUGS]-Log files
========================
The .bog extension is used for BUGS log files. The command line
generated by ESS creates the .bog transcript file.
 
File: ess.info, Node: ESS for JAGS, Next: Mailing lists/bug reports, Prev: ESS for BUGS, Up: Top File: ess.info, Node: Mailing lists/bug reports, Next: Customization, Prev: ESS for BUGS, Up: Top
15 ESS for JAGS 15 Bugs and Bug Reporting, Mailing Lists
***************
ESS[JAGS] provides 4 features. First, JAGS syntax is described to allow
for proper fontification of statements, distributions, functions,
commands and comments in JAGS model files, command files and log files.
Second, ESS creates templates for the command file from the model file
so that a JAGS batch process can be defined by a single file. Third,
ESS provides a JAGS batch script that allows ESS to set JAGS batch
parameters. Fourth, key sequences are defined to create a command file
and submit a JAGS batch process.
15.1 ESS[JAGS]-Model files
==========================
Files with the .jag extension are edited in ESS[JAGS] mode. Three
keys are bound for your use in ESS[JAGS], F2, C-c C-c and =. F2
performs the same action as it does in ESS[SAS], *Note
ESS(SAS)--Function keys for batch processing::. C-c C-c performs the
function ess-bugs-next-action which you will use a lot. Pressing it
in an empty buffer for a model file will produce a template for you.
= inserts the set operator, <-.
The first press of C-c C-c will set up a template, including some
necessary file-local variables in an empty buffer. These variables are
ess-jags-chains, ess-jags-monitor, ess-jags-thin,
ess-jags-burnin and ess-jags-update; they appear in the Local
Variables section. When you are finished editing your model file,
pressing C-c C-c will perform the necessary actions to build your
command file for you.
The ess-jags-chains variable is the number of chains that you want
to initialize and sample from; defaults to 1. The ess-jags-monitor
variable is a list of variables that you want monitored: encase each
variable in double quotes. When you press C-c C-c, the appropriate
statements are created in the command file to monitor the list of
variables. By default, no variables are explicitly monitored which
means JAGS will implicitly monitor all "default" variables. The
ess-jags-thin variable is the thinning parameter. By default, the
thinning parameter is set to 1, i.e. no thinning. The
ess-jags-burnin variable is the number of initial samples to discard.
By default, the burnin parameter is set to 10000. The ess-jags-update
variable is the number of post-burnin samples to keep. By default, the
update parameter is set to 10000. Both ess-jags-burnin and
ess-jags-update are multiplied by ess-jags-thin since JAGS does not
do it automatically.
15.2 ESS[JAGS]-Command files
============================
Files ending in .jmd are for JAGS command files. For your .jmd
file, there is only one variable, ess-jags-command, in the Local
Variables section. When you have finished editing your model file and
press C-c C-c, a command file is created if one does not already
exist. When you are finished editing your command file, pressing C-c
C-c again will submit your command file as a batch job. The
ess-jags-command variable allows you to specify a different JAGS
program to use to run your model; defaults to "jags".
15.3 ESS[JAGS]-Log files
========================
The .jog extension is used for JAGS log files. You may find F2
useful to refresh the .jog if the batch process over-writes or appends
it.

File: ess.info, Node: Mailing lists/bug reports, Next: Customization, Prev: ESS for JAGS, Up: Top
16 Bugs and Bug Reporting, Mailing Lists
**************************************** ****************************************
* Menu: * Menu:
@@ -4529,7 +4418,7 @@ File: ess.info, Node: Mailing lists/bug reports, Next: Customization, Prev: E
 
File: ess.info, Node: Bugs, Next: Reporting Bugs, Up: Mailing lists/bug reports File: ess.info, Node: Bugs, Next: Reporting Bugs, Up: Mailing lists/bug reports
16.1 Bugs 15.1 Bugs
========= =========
• Commands like ess-display-help-on-object and list completion • Commands like ess-display-help-on-object and list completion
@@ -4569,7 +4458,7 @@ File: ess.info, Node: Bugs, Next: Reporting Bugs, Up: Mailing lists/bug repor
 
File: ess.info, Node: Reporting Bugs, Next: Mailing Lists, Prev: Bugs, Up: Mailing lists/bug reports File: ess.info, Node: Reporting Bugs, Next: Mailing Lists, Prev: Bugs, Up: Mailing lists/bug reports
16.2 Reporting Bugs 15.2 Reporting Bugs
=================== ===================
Please post bug reports, suggestions etc. on our github issue tracker Please post bug reports, suggestions etc. on our github issue tracker
@@ -4594,7 +4483,7 @@ donations are also more than welcome.
 
File: ess.info, Node: Mailing Lists, Next: Help with Emacs, Prev: Reporting Bugs, Up: Mailing lists/bug reports File: ess.info, Node: Mailing Lists, Next: Help with Emacs, Prev: Reporting Bugs, Up: Mailing lists/bug reports
16.3 Mailing Lists 15.3 Mailing Lists
================== ==================
There is a mailing list for discussions and announcements relating to There is a mailing list for discussions and announcements relating to
@@ -4614,7 +4503,7 @@ this is a fairly low-volume mailing list.
 
File: ess.info, Node: Help with Emacs, Prev: Mailing Lists, Up: Mailing lists/bug reports File: ess.info, Node: Help with Emacs, Prev: Mailing Lists, Up: Mailing lists/bug reports
16.4 Help with Emacs 15.4 Help with Emacs
==================== ====================
Emacs is a complex editor with many abilities that we do not have space Emacs is a complex editor with many abilities that we do not have space
@@ -4726,9 +4615,6 @@ Key index
* M-;: Indenting. (line 65) * M-;: Indenting. (line 65)
* M-?: Object names. (line 33) * M-?: Object names. (line 33)
* M-C-q: Indenting. (line 49) * M-C-q: Indenting. (line 49)
* M-n l: Sweave and AUCTeX. (line 24)
* M-n P: Sweave and AUCTeX. (line 30)
* M-n s: Sweave and AUCTeX. (line 20)
* M-RET: Resubmit. (line 10) * M-RET: Resubmit. (line 10)
* RET: Command-line editing. (line 10) * RET: Command-line editing. (line 10)
* RET <1>: Resubmit. (line 18) * RET <1>: Resubmit. (line 18)
@@ -4770,7 +4656,7 @@ Function and program index
* dump(): Edit buffer. (line 35) * dump(): Edit buffer. (line 35)
* ess-change-directory: Package listing. (line 29) * ess-change-directory: Package listing. (line 29)
* ess-cleanup: Hot keys. (line 71) * ess-cleanup: Hot keys. (line 71)
* ess-cleanup <1>: Help. (line 170) * ess-cleanup <1>: Help. (line 169)
* ess-complete-object-name: Object names. (line 32) * ess-complete-object-name: Object names. (line 32)
* ess-describe-help-mode: Help. (line 21) * ess-describe-help-mode: Help. (line 21)
* ess-display-help-on-object: Hot keys. (line 65) * ess-display-help-on-object: Hot keys. (line 65)
@@ -4810,7 +4696,7 @@ Function and program index
* ess-parse-errors: Hot keys. (line 54) * ess-parse-errors: Hot keys. (line 54)
* ess-parse-errors <1>: Error Checking. (line 9) * ess-parse-errors <1>: Error Checking. (line 9)
* ess-quit: Hot keys. (line 70) * ess-quit: Hot keys. (line 70)
* ess-quit <1>: Help. (line 170) * ess-quit <1>: Help. (line 169)
* ess-R-complete-object-name: roxygen2. (line 80) * ess-R-complete-object-name: roxygen2. (line 80)
* ess-r-outline-level: Outline. (line 6) * ess-r-outline-level: Outline. (line 6)
* ess-r-package-list-available-packages: Package listing. (line 12) * ess-r-package-list-available-packages: Package listing. (line 12)
@@ -4843,10 +4729,6 @@ Function and program index
* ess-submit-bug-report: Reporting Bugs. (line 6) * ess-submit-bug-report: Reporting Bugs. (line 6)
* ess-switch-to-end-of-ESS: Help. (line 117) * ess-switch-to-end-of-ESS: Help. (line 117)
* ess-switch-to-inferior-or-script-buffer: Other. (line 12) * ess-switch-to-inferior-or-script-buffer: Other. (line 12)
* ess-swv-latex: Sweave and AUCTeX. (line 23)
* ess-swv-PDF: Sweave and AUCTeX. (line 29)
* ess-swv-PS: Sweave and AUCTeX. (line 26)
* ess-swv-weave: Sweave and AUCTeX. (line 19)
* ess-tracebug: ESS tracebug. (line 6) * ess-tracebug: ESS tracebug. (line 6)
* ess-transcript-clean-region: Clean. (line 10) * ess-transcript-clean-region: Clean. (line 10)
* ess-transcript-copy-command: Resubmit. (line 13) * ess-transcript-copy-command: Resubmit. (line 13)
@@ -4913,14 +4795,13 @@ Variable index
* ess-r-flymake-linters: ESS Flymake. (line 16) * ess-r-flymake-linters: ESS Flymake. (line 16)
* ess-r-flymake-lintr-cache: ESS Flymake. (line 23) * ess-r-flymake-lintr-cache: ESS Flymake. (line 23)
* ess-R-font-lock-keywords: Highlighting. (line 19) * ess-R-font-lock-keywords: Highlighting. (line 19)
* ess-r-outline-regexp: Outline. (line 6) * ess-r-outline-style: Outline. (line 6)
* ess-r-outline-regexp <1>: Outline. (line 27) * ess-r-outline-style <1>: Outline. (line 37)
* ess-search-list: Source Directories. (line 62) * ess-search-list: Source Directories. (line 62)
* ess-source-directory: Source Directories. (line 22) * ess-source-directory: Source Directories. (line 22)
* ess-style: Styles. (line 21) * ess-style: Styles. (line 21)
* ess-style-alist: Styles. (line 28) * ess-style-alist: Styles. (line 28)
* ess-switch-to-end-of-proc-buffer: Other. (line 21) * ess-switch-to-end-of-proc-buffer: Other. (line 21)
* ess-swv-pdflatex-commands: Sweave and AUCTeX. (line 35)
* ess-use-eldoc: ESS ElDoc. (line 13) * ess-use-eldoc: ESS ElDoc. (line 13)
* ess-use-flymake: ESS Flymake. (line 12) * ess-use-flymake: ESS Flymake. (line 12)
* iESS program arguments: Customizing startup. (line 48) * iESS program arguments: Customizing startup. (line 48)
@@ -5091,111 +4972,110 @@ Concept Index
 
Tag Table: Tag Table:
Node: Top268 Node: Top270
Node: Introduction2906 Node: Introduction2893
Node: Features5692 Node: Features5681
Node: Current Features6518 Node: Current Features6507
Node: New features10065 Node: New features10054
Node: Credits37885 Node: Credits38231
Node: Manual41544 Node: Manual41890
Node: Installation44254 Node: Installation44600
Node: Installing from a third-party repository45191 Node: Installing from a third-party repository45537
Node: Installing from source46138 Node: Installing from source46484
Node: Activating and Loading ESS47762 Node: Activating and Loading ESS48108
Node: Check Installation48844 Node: Check Installation49190
Node: Interactive ESS49068 Node: Interactive ESS49414
Node: Starting up49913 Node: Starting up50259
Node: Multiple ESS processes50673 Node: Multiple ESS processes51019
Node: ESS processes on Remote Computers51786 Node: ESS processes on Remote Computers52132
Node: Customizing startup56013 Node: Customizing startup56359
Node: Controlling buffer display58995 Node: Controlling buffer display59341
Node: Entering commands61632 Node: Entering commands61978
Node: Command-line editing62794 Node: Command-line editing63140
Node: Transcript64059 Node: Transcript64405
Node: Last command65856 Node: Last command66202
Node: Process buffer motion67314 Node: Process buffer motion67660
Node: Transcript resubmit68857 Node: Transcript resubmit69203
Node: Saving transcripts70854 Node: Saving transcripts71200
Node: Command History72688 Node: Command History73034
Node: Saving History76189 Node: Saving History76535
Node: History expansion76970 Node: History expansion77316
Node: Hot keys80361 Node: Hot keys80707
Node: Statistical Process running in ESS?84531 Node: Statistical Process running in ESS?84877
Node: Emacsclient85878 Node: Emacsclient86224
Node: Other86698 Node: Other87044
Node: Evaluating code87741 Node: Evaluating code88087
Node: Transcript Mode91673 Node: Transcript Mode92019
Node: Resubmit92846 Node: Resubmit93192
Node: Clean93921 Node: Clean94267
Node: Editing objects94921 Node: Editing objects95267
Node: Edit buffer96039 Node: Edit buffer96385
Node: Loading98129 Node: Loading98475
Node: Error Checking99184 Node: Error Checking99530
Node: Indenting100257 Node: Indenting100603
Node: Styles103409 Node: Styles103755
Node: Other edit buffer commands105911 Node: Other edit buffer commands106257
Node: Source Files107623 Node: Source Files107969
Node: Source Directories112339 Node: Source Directories112685
Node: Help115548 Node: Help115894
Node: Completion120250 Node: Completion120596
Node: Object names120465 Node: Object names120811
Node: Function arguments123179 Node: Function arguments123525
Node: Minibuffer completion124158 Node: Minibuffer completion124504
Node: Company124656 Node: Company125002
Node: Icicles125055 Node: Icicles125401
Node: Developing with ESS126431 Node: Developing with ESS126777
Node: ESS tracebug126877 Node: ESS tracebug127223
Node: Getting started with tracebug129934 Node: Getting started with tracebug130280
Node: Editing documentation132220 Node: Editing documentation132566
Node: R documentation files132772 Node: R documentation files133118
Node: roxygen2136587 Node: roxygen2136933
Node: Namespaced Evaluation141110 Node: Namespaced Evaluation141456
Node: Extras143124 Node: Extras143470
Node: ESS ElDoc144216 Node: ESS ElDoc144562
Node: ESS Flymake145796 Node: ESS Flymake146142
Node: Handy commands146926 Node: Handy commands147272
Node: Highlighting148203 Node: Highlighting148549
Node: Parens149254 Node: Parens149600
Node: Graphics149730 Node: Graphics150076
Node: printer150401 Node: printer150747
Node: X11151173 Node: X11151519
Node: winjava151512 Node: winjava151858
Node: Imenu151924 Node: Imenu152270
Node: Outline152779 Node: Outline153125
Node: Toolbar154091 Node: Toolbar155358
Node: Xref154501 Node: Xref155768
Node: Rdired154831 Node: Rdired156098
Node: Package listing155910 Node: Package listing157177
Node: Org157358 Node: Org158625
Node: Sweave and AUCTeX158312 Node: Sweave and AUCTeX159579
Node: ESS for R160944 Node: ESS for R160176
Node: ESS(R)--Editing files161244 Node: ESS(R)--Editing files160476
Node: iESS(R)--Inferior ESS processes161749 Node: iESS(R)--Inferior ESS processes160981
Node: Philosophies for using ESS(R)164468 Node: Philosophies for using ESS(R)163700
Node: Example ESS usage165395 Node: Example ESS usage164627
Node: ESS for SAS166799 Node: ESS for SAS166031
Node: ESS(SAS)--Design philosophy167526 Node: ESS(SAS)--Design philosophy166758
Node: ESS(SAS)--Editing files168463 Node: ESS(SAS)--Editing files167695
Node: ESS(SAS)--TAB key170407 Node: ESS(SAS)--TAB key169639
Node: ESS(SAS)--Batch SAS processes171821 Node: ESS(SAS)--Batch SAS processes171053
Node: ESS(SAS)--Function keys for batch processing177041 Node: ESS(SAS)--Function keys for batch processing176273
Node: iESS(SAS)--Interactive SAS processes186948 Node: iESS(SAS)--Interactive SAS processes186180
Node: iESS(SAS)--Common problems190890 Node: iESS(SAS)--Common problems190122
Node: ESS(SAS)--Graphics192504 Node: ESS(SAS)--Graphics191736
Node: ESS(SAS)--Windows193303 Node: ESS(SAS)--Windows192535
Node: ESS for BUGS193887 Node: ESS for BUGS193119
Node: ESS for JAGS195699 Node: Mailing lists/bug reports193675
Node: Mailing lists/bug reports199195 Node: Bugs193939
Node: Bugs199459 Node: Reporting Bugs195615
Node: Reporting Bugs201135 Node: Mailing Lists196534
Node: Mailing Lists202054 Node: Help with Emacs197272
Node: Help with Emacs202792 Node: Customization197808
Node: Customization203328 Node: Indices198586
Node: Indices204106 Node: Key index198761
Node: Key index204281 Node: Function and program index203674
Node: Function and program index209413 Node: Variable index212948
Node: Variable index218979 Node: Concept index216582
Node: Concept index222686
 
End Tag Table End Tag Table
+1 -1
View File
@@ -4,7 +4,7 @@
'((emacs "24.1") '((emacs "24.1")
(s "1.7.0") (s "1.7.0")
(dash "2.2.0")) (dash "2.2.0"))
:url "http://github.com/rejeep/f.el" :url "https://github.com/rejeep/f.el"
:commit "931b6d0667fe03e7bf1c6c282d6d8d7006143c52" :commit "931b6d0667fe03e7bf1c6c282d6d8d7006143c52"
:revdesc "931b6d0667fe" :revdesc "931b6d0667fe"
:keywords '("files" "directories") :keywords '("files" "directories")
+2 -7
View File
@@ -254,7 +254,7 @@ argument to `flycheck-define-checker'.
(fn SYMBOL CHECKER &optional FILE-NAME &rest CUSTOM-ARGS)" nil t) (fn SYMBOL CHECKER &optional FILE-NAME &rest CUSTOM-ARGS)" nil t)
(function-put 'flycheck-def-config-file-var 'lisp-indent-function 3) (function-put 'flycheck-def-config-file-var 'lisp-indent-function 3)
(autoload 'flycheck-def-option-var "flycheck" "\ (autoload 'flycheck-def-option-var "flycheck" "\
Define SYMBOL as option variable with INIT-VALUE for CHECKER. Define SYMBOL as option variable with INIT-VALUE for CHECKERS.
SYMBOL is declared as customizable variable using `defcustom', to SYMBOL is declared as customizable variable using `defcustom', to
provide an option for the given syntax CHECKERS (a checker or a provide an option for the given syntax CHECKERS (a checker or a
@@ -284,12 +284,7 @@ SYMBOL with `flycheck-def-executable-var'.
;;; Generated autoloads from flycheck-buttercup.el ;;; Generated autoloads from flycheck-buttercup.el
(register-definition-prefixes "flycheck-buttercup" '("flycheck-buttercup-format-error-list")) (register-definition-prefixes "flycheck-buttercup" '("flycheck-buttercup-"))
;;; Generated autoloads from flycheck-ert.el
(register-definition-prefixes "flycheck-ert" '("flycheck-er"))
;;; End of scraped data ;;; End of scraped data
+434 -5
View File
@@ -42,6 +42,8 @@
(require 'buttercup) (require 'buttercup)
(require 'flycheck) (require 'flycheck)
(require 'seq) (require 'seq)
(require 'cl-lib)
(require 'macroexp)
;;; Buttercup helpers ;;; Buttercup helpers
@@ -55,12 +57,14 @@
;;; Data matchers ;;; Data matchers
(buttercup-define-matcher :to-be-empty-string (s) (buttercup-define-matcher :to-be-empty-string (s)
"Match that S is an empty string."
(let ((s (funcall s))) (let ((s (funcall s)))
(if (equal s "") (if (equal s "")
(cons t (format "Expected %S not be an empty string" s)) (cons t (format "Expected %S not to be an empty string" s))
(cons nil (format "Expected %S to be an empty string" s))))) (cons nil (format "Expected %S to be an empty string" s)))))
(buttercup-define-matcher :to-match-with-group (re s index match) (buttercup-define-matcher :to-match-with-group (re s index match)
"Match that regexp RE matches string S with MATCH in group INDEX."
(let* ((re (funcall re)) (let* ((re (funcall re))
(s (funcall s)) (s (funcall s))
(index (funcall index)) (index (funcall index))
@@ -81,6 +85,7 @@
;;; Emacs feature matchers ;;; Emacs feature matchers
(buttercup-define-matcher :to-be-live (buffer) (buttercup-define-matcher :to-be-live (buffer)
"Match that BUFFER is a live buffer."
(let ((buffer (get-buffer (funcall buffer)))) (let ((buffer (get-buffer (funcall buffer))))
(if (buffer-live-p buffer) (if (buffer-live-p buffer)
(cons t (format "Expected %S not to be a live buffer, but it is" (cons t (format "Expected %S not to be a live buffer, but it is"
@@ -89,6 +94,7 @@
buffer))))) buffer)))))
(buttercup-define-matcher :to-be-visible (buffer) (buttercup-define-matcher :to-be-visible (buffer)
"Match that BUFFER is displayed in a window."
(let ((buffer (get-buffer (funcall buffer)))) (let ((buffer (get-buffer (funcall buffer))))
(cond (cond
((and buffer (get-buffer-window buffer)) ((and buffer (get-buffer-window buffer))
@@ -104,6 +110,7 @@
buffer)))))) buffer))))))
(buttercup-define-matcher :to-be-local (symbol) (buttercup-define-matcher :to-be-local (symbol)
"Match that SYMBOL is a buffer-local variable in the current buffer."
(let ((symbol (funcall symbol))) (let ((symbol (funcall symbol)))
(if (local-variable-p symbol) (if (local-variable-p symbol)
(cons t (format "Expected %S not to be a local variable, but it is" (cons t (format "Expected %S not to be a local variable, but it is"
@@ -112,6 +119,7 @@
symbol))))) symbol)))))
(buttercup-define-matcher :to-contain-match (buffer re) (buttercup-define-matcher :to-contain-match (buffer re)
"Match that BUFFER contains text matching regexp RE."
(let ((buffer (funcall buffer)) (let ((buffer (funcall buffer))
(re (funcall re))) (re (funcall re)))
(if (not (get-buffer buffer)) (if (not (get-buffer buffer))
@@ -121,15 +129,16 @@ but is not a buffer" buffer re))
(save-excursion (save-excursion
(goto-char (point-min)) (goto-char (point-min))
(if (re-search-forward re nil 'noerror) (if (re-search-forward re nil 'noerror)
(cons t (format "Expected %S to contain a match \ (cons t (format "Expected %S not to contain a match \
for %s, but it did not" buffer re)) for %s, but it did" buffer re))
(cons nil (format "Expected %S not to contain a match for \ (cons nil (format "Expected %S to contain a match for \
%s but it did not." buffer re)))))))) %s, but it did not." buffer re))))))))
;;; Flycheck matchers ;;; Flycheck matchers
(buttercup-define-matcher :to-be-equal-flycheck-errors (a b) (buttercup-define-matcher :to-be-equal-flycheck-errors (a b)
"Match that flycheck error lists A and B are equal."
(let* ((a (funcall a)) (let* ((a (funcall a))
(b (funcall b)) (b (funcall b))
(a-formatted (flycheck-buttercup-format-error-list a)) (a-formatted (flycheck-buttercup-format-error-list a))
@@ -144,6 +153,426 @@ not to be equal to
to be equal to to be equal to
%s" a-formatted b-formatted))))) %s" a-formatted b-formatted)))))
;;; Internal variables
(defvar flycheck-buttercup--resource-directory nil
"The directory to get resources from in this test suite.")
;;; Resource management
(defun flycheck-buttercup-resource-filename (resource-file)
"Determine the absolute file name of a RESOURCE-FILE.
Relative file names are expanded against
`flycheck-buttercup--resource-directory'."
(expand-file-name resource-file flycheck-buttercup--resource-directory))
(defun flycheck-buttercup-initialize (resource-dir)
"Initialize a test suite with RESOURCE-DIR.
RESOURCE-DIR is the directory, `flycheck-buttercup-resource-filename'
should use to lookup resource files."
(when flycheck-buttercup--resource-directory
(error "Test suite already initialized"))
(setq flycheck-buttercup--resource-directory resource-dir))
;;; Buffer utility macros
(defmacro flycheck-buttercup-with-temp-buffer (&rest body)
"Eval BODY within a temporary buffer.
Like `with-temp-buffer', but resets the modification state of the
temporary buffer to make sure that it is properly killed even if
it has a backing file and is modified."
(declare (indent 0) (debug t))
`(with-temp-buffer
(unwind-protect
,(macroexp-progn body)
;; Reset modification state of the buffer, and unlink it from its
;; backing file, if any, because Emacs refuses to kill modified
;; buffers with backing files, even if they are temporary.
(set-buffer-modified-p nil)
(set-visited-file-name nil 'no-query))))
(defmacro flycheck-buttercup-with-file-buffer (file-name &rest body)
"Create a buffer from FILE-NAME and eval BODY.
BODY is evaluated with `current-buffer' being a buffer with the
contents of FILE-NAME, its `visited-file-name' set to FILE-NAME,
and `default-directory' set to the file's directory."
(declare (indent 1) (debug t))
`(let ((file-name ,file-name))
(unless (file-exists-p file-name)
(error "%s does not exist" file-name))
(flycheck-buttercup-with-temp-buffer
(insert-file-contents file-name 'visit)
(set-visited-file-name file-name 'no-query)
(cd (file-name-directory file-name))
;; Mark the buffer as not modified, because we just loaded the
;; file up to now.
(set-buffer-modified-p nil)
,@body)))
(defmacro flycheck-buttercup-with-help-buffer (&rest body)
"Execute BODY and kill the help buffer afterwards.
Use this macro to test functions that create a Help buffer."
(declare (indent 0))
`(unwind-protect
,(macroexp-progn body)
(when (buffer-live-p (get-buffer (help-buffer)))
(kill-buffer (help-buffer)))))
(defmacro flycheck-buttercup-with-global-mode (&rest body)
"Execute BODY with Global Flycheck Mode enabled.
After BODY, restore the old state of Global Flycheck Mode."
(declare (indent 0))
`(let ((old-state global-flycheck-mode))
(unwind-protect
(progn
(global-flycheck-mode 1)
,@body)
(global-flycheck-mode (if old-state 1 -1)))))
(defmacro flycheck-buttercup-with-env (env &rest body)
"Add ENV to `process-environment' in BODY.
Execute BODY with a `process-environment' which contains all
variables from ENV added.
ENV is an alist, where each cons cell `(VAR . VALUE)' is a
environment variable VAR to be added to `process-environment'
with VALUE."
(declare (indent 1))
`(let ((process-environment (copy-sequence process-environment)))
(pcase-dolist (`(,var . ,value) ,env)
(setenv var value))
,@body))
(defmacro flycheck-buttercup-with-resource-buffer (resource-file &rest body)
"Create a temp buffer from a RESOURCE-FILE and execute BODY.
The absolute file name of RESOURCE-FILE is determined with
`flycheck-buttercup-resource-filename'."
(declare (indent 1))
`(flycheck-buttercup-with-file-buffer
(flycheck-buttercup-resource-filename ,resource-file)
,@body))
;;; Syntax checking in tests
(defvar-local flycheck-buttercup-syntax-checker-finished nil
"Non-nil if the current checker has finished.")
(add-hook 'flycheck-after-syntax-check-hook
(lambda ()
(setq flycheck-buttercup-syntax-checker-finished t)))
(defconst flycheck-buttercup-checker-wait-time 10
"Time to wait until a checker is finished in seconds.
After this time has elapsed, the checker is considered to have
failed, and the test aborted with failure.")
(define-error 'flycheck-buttercup-syntax-check-timed-out
"Syntax check timed out.")
(define-error 'flycheck-buttercup-suspicious-checker
"Suspicious state from checker")
(defun flycheck-buttercup-wait-for-syntax-checker ()
"Wait until the syntax check in the current buffer is finished.
Signal `flycheck-buttercup-syntax-check-timed-out' if the check
does not complete within `flycheck-buttercup-checker-wait-time'
seconds."
(let ((starttime (float-time)))
(while (and (not flycheck-buttercup-syntax-checker-finished)
(< (- (float-time) starttime)
flycheck-buttercup-checker-wait-time))
(accept-process-output nil 0.02))
(unless (< (- (float-time) starttime)
flycheck-buttercup-checker-wait-time)
(flycheck-stop)
(signal 'flycheck-buttercup-syntax-check-timed-out nil)))
(setq flycheck-buttercup-syntax-checker-finished nil))
(defun flycheck-buttercup-buffer-sync ()
"Like `flycheck-buffer', but synchronously."
(setq flycheck-buttercup-syntax-checker-finished nil)
(expect (flycheck-running-p) :not :to-be-truthy)
(flycheck-mode) ;; This will only start a deferred check,
(expect (flycheck-get-checker-for-buffer) :to-be-truthy)
(flycheck-buffer) ;; …so we need an explicit manual check
;; After starting the check, the checker should either be running now, or
;; already be finished (if it was fast).
(expect (or flycheck-current-syntax-check
flycheck-buttercup-syntax-checker-finished)
:to-be-truthy)
;; Also there should be no deferred check pending anymore
(expect (flycheck-deferred-check-p) :not :to-be-truthy)
(flycheck-buttercup-wait-for-syntax-checker))
(defun flycheck-buttercup-ensure-clear ()
"Clear Flycheck errors and overlays from the current buffer.
Raise an assertion error if errors or overlays remain afterwards."
(flycheck-clear)
(expect flycheck-current-errors :not :to-be-truthy)
(expect (seq-find (lambda (ov) (overlay-get ov 'flycheck-overlay))
(overlays-in (point-min) (point-max)))
:not :to-be-truthy))
;;; Error utilities
(defun flycheck-buttercup-error-without-group (err)
"Return a copy of ERR with the `group' property set to nil."
(let ((copy (copy-flycheck-error err)))
(setf (flycheck-error-group copy) nil)
copy))
(defun flycheck-buttercup-sort-errors (errors)
"Sort ERRORS by `flycheck-error-<'."
(seq-sort #'flycheck-error-< errors))
;;; Test assertions
(defun flycheck-buttercup-should-overlay (error)
"Test that ERROR has a proper overlay in the current buffer.
ERROR is a Flycheck error object."
(let* ((overlay (seq-find
(lambda (ov)
(equal (flycheck-buttercup-error-without-group
(overlay-get ov 'flycheck-error))
(flycheck-buttercup-error-without-group error)))
(flycheck-overlays-in 0 (+ 1 (buffer-size)))))
(region
;; Overlays of errors from other files are on the first line
(if (flycheck-relevant-error-other-file-p error)
(cons (point-min)
(save-excursion (goto-char (point-min))
(line-end-position)))
(flycheck-error-region-for-mode error 'symbols)))
(level (flycheck-error-level error))
(category (flycheck-error-level-overlay-category level))
(face (get category 'face))
(fringe-bitmap (flycheck-error-level-fringe-bitmap level))
(fringe-face (flycheck-error-level-fringe-face level))
(fringe-icon (list 'left-fringe fringe-bitmap fringe-face)))
(expect overlay :to-be-truthy)
(expect (overlay-get overlay 'flycheck-overlay) :to-be-truthy)
(expect (overlay-start overlay) :to-equal (car region))
(expect (overlay-end overlay) :to-equal (cdr region))
(expect (overlay-get overlay 'face) :to-equal face)
(expect (get-char-property 0 'display
(overlay-get overlay 'before-string))
:to-equal fringe-icon)
(expect (overlay-get overlay 'category) :to-equal category)
(expect (flycheck-buttercup-error-without-group
(overlay-get overlay 'flycheck-error))
:to-equal
(flycheck-buttercup-error-without-group error))))
(defun flycheck-buttercup-should-errors (&rest errors)
"Test that the current buffer has ERRORS.
ERRORS is a list of errors expected to be present in the current
buffer. Each error is given as a list of arguments to
`flycheck-error-new-at'.
If ERRORS are omitted, test that there are no errors at all in
the current buffer.
With ERRORS, test that each error in ERRORS is present in the
current buffer, and that the number of errors in the current
buffer is equal to the number of given ERRORS. In other words,
check that the buffer has all ERRORS, and no other errors."
(let ((expected (flycheck-buttercup-sort-errors
(mapcar (apply-partially #'apply #'flycheck-error-new-at)
errors)))
(current (flycheck-buttercup-sort-errors flycheck-current-errors)))
(expect (mapcar #'flycheck-buttercup-error-without-group expected)
:to-equal
(mapcar #'flycheck-buttercup-error-without-group current))
;; Check that related errors are the same
(cl-mapcar
(lambda (err1 err2)
(expect (flycheck-buttercup-sort-errors
(mapcar #'flycheck-buttercup-error-without-group
(flycheck-related-errors err1 expected)))
:to-equal
(flycheck-buttercup-sort-errors
(mapcar #'flycheck-buttercup-error-without-group
(flycheck-related-errors err2)))))
expected current)
(mapc #'flycheck-buttercup-should-overlay expected))
(expect (length errors)
:to-equal
(length (flycheck-overlays-in (point-min) (point-max)))))
(defun flycheck-buttercup-should-syntax-check-in-buffer (&rest errors)
"Test a syntax check in the current buffer, expecting ERRORS.
This is like `flycheck-buttercup-should-syntax-check', but with a
buffer in the right mode instead of a file."
;; Load safe file-local variables because some tests depend on them
(let ((enable-local-variables :safe)
;; Disable all hooks at this place, to prevent 3rd party packages
;; from interfering
(hack-local-variables-hook))
(hack-local-variables))
;; Configure config file locating for unit tests
(let ((process-hook-called 0)
(suspicious nil))
(add-hook 'flycheck-process-error-functions
(lambda (_err)
(setq process-hook-called (1+ process-hook-called))
nil)
nil :local)
(add-hook 'flycheck-status-changed-functions
(lambda (status)
(when (eq status 'suspicious)
(setq suspicious t)))
nil :local)
(flycheck-buttercup-buffer-sync)
(when suspicious
(signal 'flycheck-buttercup-suspicious-checker nil))
(apply #'flycheck-buttercup-should-errors errors)
(expect process-hook-called :to-equal (length errors)))
(flycheck-buttercup-ensure-clear))
(defun flycheck-buttercup-should-syntax-check (resource-file modes &rest errors)
"Test a syntax check in RESOURCE-FILE with MODES.
RESOURCE-FILE is the file to check. MODES is a single major mode
symbol or a list thereof, specifying the major modes to syntax
check with. If more than one major mode is specified, the test
is run for each mode separately, so if you give three major
modes, the entire test will run three times. ERRORS is the list
of expected errors, as in `flycheck-buttercup-should-errors'. If
omitted, the syntax check must not emit any errors. The errors
are cleared after each test.
The syntax checker is selected via standard syntax checker
selection. To test a specific checker, you need to set
`flycheck-checker' or `flycheck-disabled-checkers' accordingly
before using this predicate, depending on whether you want to use
manual or automatic checker selection.
During the syntax check, configuration files of syntax checkers
are also searched in the `config-files' sub-directory of the
resource directory."
(when (symbolp modes)
(setq modes (list modes)))
(dolist (mode modes)
(unless (fboundp mode)
(buttercup-skip (format "%S missing" mode)))
(flycheck-buttercup-with-resource-buffer resource-file
(funcall mode)
(apply #'flycheck-buttercup-should-syntax-check-in-buffer errors))))
;;; Additional matchers
(buttercup-define-matcher :to-be-at-flycheck-error (point-val n-val)
"Match that POINT-VAL is at the N-VAL'th Flycheck error."
(let* ((pt (funcall point-val))
(n (funcall n-val))
(error (nth (1- n) flycheck-current-errors))
(mode flycheck-highlighting-mode)
(region (flycheck-error-region-for-mode error mode))
(at-error (and (member error (flycheck-overlay-errors-at pt))
(= pt (car region)))))
(if at-error
(cons t (format "Expected point %s not to be at error %s, but it is"
pt n))
(let ((errors (flycheck-overlay-errors-at pt)))
(if (null errors)
(cons nil
(format "Expected to be at error %s, but no error at point %s"
n pt))
(let ((pos (cl-position (car errors) flycheck-current-errors)))
(cons nil
(format "Expected to be at point %s and error %s, \
but point %s is at error %s"
(car (flycheck-error-region-for-mode
(nth (1- n) flycheck-current-errors)
flycheck-highlighting-mode))
n pt (1+ pos)))))))))
;;; Test case definitions
(defun flycheck-buttercup--parse-keys-and-body (keys-and-body)
"Parse KEYS-AND-BODY into keyword-value pairs and body forms.
KEYS-AND-BODY is a list of alternating keyword-value pairs
followed by body forms. Return a cons cell (KEYS . BODY)."
(let ((keys nil)
(body keys-and-body))
(while (keywordp (car body))
(let ((key (pop body))
(val (pop body)))
(push key keys)
(push val keys)))
(cons (nreverse keys) body)))
(defmacro flycheck-buttercup-def-checker-test (checker language name
&rest keys-and-body)
"Define a buttercup test case for a syntax CHECKER for LANGUAGE.
CHECKER is a symbol or a list of symbols denoting syntax checkers
being tested by the test. The test case is skipped, if any of
these checkers cannot be used. LANGUAGE is a symbol or a list of
symbols denoting the programming languages supported by the
syntax checkers. This is currently only used for naming the test
appropriately.
NAME is a symbol denoting the local name of the test. The test
itself is ultimately named
`flycheck-define-checker/CHECKER/NAME'.
Optionally, the keyword arguments `:tags' and `:expected-result'
may be given. `:expected-result :failed' will generate an `xit'
instead of `it' to mark the test as pending.
The remaining forms KEYS-AND-BODY denote the body of the test
case, including assertions and setup code."
(declare (indent 3))
(unless checker
(error "No syntax checkers specified"))
(unless language
(error "No languages specified"))
(let* ((checkers (if (symbolp checker) (list checker) checker))
(checker (car checkers))
(local-name (or name 'default))
(full-name (format "flycheck-define-checker/%s/%s"
checker local-name))
(parsed (flycheck-buttercup--parse-keys-and-body keys-and-body))
(keys (car parsed))
(body (cdr parsed))
(expected-result (plist-get keys :expected-result))
(it-fn (if (eq expected-result :failed) 'xit 'it))
(skip-forms (mapcar (lambda (c)
`(assume
;; Ignore non-command checkers
(or (not (flycheck-checker-get ',c 'command))
(executable-find
(flycheck-checker-executable ',c)))))
checkers)))
`(,it-fn ,full-name
(lambda ()
,@skip-forms
,@body))))
(provide 'flycheck-buttercup) (provide 'flycheck-buttercup)
;; Disable byte compilation for this library, to prevent package.el choking on a ;; Disable byte compilation for this library, to prevent package.el choking on a
-451
View File
@@ -1,451 +0,0 @@
;;; flycheck-ert.el --- Flycheck: ERT extensions -*- lexical-binding: t; -*-
;; Copyright (C) 2017-2018 Flycheck contributors
;; Copyright (C) 2013-2016 Sebastian Wiesner and Flycheck contributors
;; Author: Sebastian Wiesner <swiesner@lunaryorn.com>
;; Maintainer: Clément Pit-Claudel <clement.pitclaudel@live.com>
;; fmdkdd <fmdkdd@gmail.com>
;; URL: https://github.com/flycheck/flycheck
;; This file is not part of GNU Emacs.
;; This program is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation, either version 3 of the License, or
;; (at your option) any later version.
;; This program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;; You should have received a copy of the GNU General Public License
;; along with this program. If not, see <http://www.gnu.org/licenses/>.
;;; Commentary:
;; Unit testing library for Flycheck, the modern on-the-fly syntax checking
;; extension for GNU Emacs.
;; Provide various utility functions and unit test helpers to test Flycheck and
;; Flycheck extensions.
;;; Code:
(require 'flycheck)
(require 'ert)
(require 'macroexp) ; For macro utilities
;;; Internal variables
(defvar flycheck-ert--resource-directory nil
"The directory to get resources from in this test suite.")
;;; Resource management macros
(defmacro flycheck-ert-with-temp-buffer (&rest body)
"Eval BODY within a temporary buffer.
Like `with-temp-buffer', but resets the modification state of the
temporary buffer to make sure that it is properly killed even if
it has a backing file and is modified."
(declare (indent 0) (debug t))
`(with-temp-buffer
(unwind-protect
,(macroexp-progn body)
;; Reset modification state of the buffer, and unlink it from its backing
;; file, if any, because Emacs refuses to kill modified buffers with
;; backing files, even if they are temporary.
(set-buffer-modified-p nil)
(set-visited-file-name nil 'no-query))))
(defmacro flycheck-ert-with-file-buffer (file-name &rest body)
"Create a buffer from FILE-NAME and eval BODY.
BODY is evaluated with `current-buffer' being a buffer with the
contents FILE-NAME."
(declare (indent 1) (debug t))
`(let ((file-name ,file-name))
(unless (file-exists-p file-name)
(error "%s does not exist" file-name))
(flycheck-ert-with-temp-buffer
(insert-file-contents file-name 'visit)
(set-visited-file-name file-name 'no-query)
(cd (file-name-directory file-name))
;; Mark the buffer as not modified, because we just loaded the file up to
;; now.
(set-buffer-modified-p nil)
,@body)))
(defmacro flycheck-ert-with-help-buffer (&rest body)
"Execute BODY and kill the help buffer afterwards.
Use this macro to test functions that create a Help buffer."
(declare (indent 0))
`(unwind-protect
,(macroexp-progn body)
(when (buffer-live-p (get-buffer (help-buffer)))
(kill-buffer (help-buffer)))))
(defmacro flycheck-ert-with-global-mode (&rest body)
"Execute BODY with Global Flycheck Mode enabled.
After BODY, restore the old state of Global Flycheck Mode."
(declare (indent 0))
`(let ((old-state global-flycheck-mode))
(unwind-protect
(progn
(global-flycheck-mode 1)
,@body)
(global-flycheck-mode (if old-state 1 -1)))))
(defmacro flycheck-ert-with-env (env &rest body)
"Add ENV to `process-environment' in BODY.
Execute BODY with a `process-environment' which contains all
variables from ENV added.
ENV is an alist, where each cons cell `(VAR . VALUE)' is a
environment variable VAR to be added to `process-environment'
with VALUE."
(declare (indent 1))
`(let ((process-environment (copy-sequence process-environment)))
(pcase-dolist (`(,var . ,value) ,env)
(setenv var value))
,@body))
;;; Test resources
(defun flycheck-ert-resource-filename (resource-file)
"Determine the absolute file name of a RESOURCE-FILE.
Relative file names are expanded against
`flycheck-ert--resource-directory'."
(expand-file-name resource-file flycheck-ert--resource-directory))
(defmacro flycheck-ert-with-resource-buffer (resource-file &rest body)
"Create a temp buffer from a RESOURCE-FILE and execute BODY.
The absolute file name of RESOURCE-FILE is determined with
`flycheck-ert-resource-filename'."
(declare (indent 1))
`(flycheck-ert-with-file-buffer
(flycheck-ert-resource-filename ,resource-file)
,@body))
;;; Test suite initialization
(defun flycheck-ert-initialize (resource-dir)
"Initialize a test suite with RESOURCE-DIR.
RESOURCE-DIR is the directory, `flycheck-ert-resource-filename'
should use to lookup resource files."
(when flycheck-ert--resource-directory
(error "Test suite already initialized"))
(let ((tests (ert-select-tests t t)))
;; Select all tests
(unless tests
(error "No tests defined. \
Call `flycheck-ert-initialize' after defining all tests!"))
(setq flycheck-ert--resource-directory resource-dir)))
;;; Test case definitions
(defmacro flycheck-ert-def-checker-test (checker language name
&rest keys-and-body)
"Define a test case for a syntax CHECKER for LANGUAGE.
CHECKER is a symbol or a list of symbols denoting syntax checkers
being tested by the test. The test case is skipped, if any of
these checkers cannot be used. LANGUAGE is a symbol or a list of
symbols denoting the programming languages supported by the
syntax checkers. This is currently only used for tagging the
test appropriately.
NAME is a symbol denoting the local name of the test. The test
itself is ultimately named
`flycheck-define-checker/CHECKER/NAME'. If CHECKER is a list,
the first checker in the list is used for naming the test.
Optionally, the keyword arguments `:tags' and `:expected-result'
may be given. They have the same meaning as in `ert-deftest.',
and are added to the tags and result expectations set up by this
macro.
The remaining forms KEYS-AND-BODY denote the body of the test
case, including assertions and setup code."
(declare (indent 3))
(unless checker
(error "No syntax checkers specified"))
(unless language
(error "No languages specified"))
(let* ((checkers (if (symbolp checker) (list checker) checker))
(checker (car checkers))
(languages (if (symbolp language) (list language) language))
(language-tags (mapcar (lambda (l) (intern (format "language-%s" l)))
languages))
(checker-tags (mapcar (lambda (c) (intern (format "checker-%s" c)))
checkers))
(local-name (or name 'default))
(full-name (intern (format "flycheck-define-checker/%s/%s"
checker local-name)))
(keys-and-body (ert--parse-keys-and-body keys-and-body))
(body (cadr keys-and-body))
(keys (car keys-and-body))
(default-tags '(syntax-checker external-tool)))
`(ert-deftest ,full-name ()
:expected-result ,(or (plist-get keys :expected-result) :passed)
:tags (append ',(append default-tags language-tags checker-tags)
,(plist-get keys :tags))
,@(mapcar (lambda (c)
`(skip-unless
;; Ignore non-command checkers
(or (not (flycheck-checker-get ',c 'command))
(executable-find (flycheck-checker-executable ',c)))))
checkers)
,@body)))
;;; Test case results
(defun flycheck-ert-syntax-check-timed-out-p (result)
"Whether RESULT denotes a timed-out test.
RESULT is an ERT test result object."
(and (ert-test-failed-p result)
(eq (car (ert-test-failed-condition result))
'flycheck-ert-syntax-check-timed-out)))
;;; Syntax checking in tests
(defvar-local flycheck-ert-syntax-checker-finished nil
"Non-nil if the current checker has finished.")
(add-hook 'flycheck-after-syntax-check-hook
(lambda () (setq flycheck-ert-syntax-checker-finished t)))
(defconst flycheck-ert-checker-wait-time 10
"Time to wait until a checker is finished in seconds.
After this time has elapsed, the checker is considered to have
failed, and the test aborted with failure.")
(define-error 'flycheck-ert-syntax-check-timed-out "Syntax check timed out.")
(defun flycheck-ert-wait-for-syntax-checker ()
"Wait until the syntax check in the current buffer is finished."
(let ((starttime (float-time)))
(while (and (not flycheck-ert-syntax-checker-finished)
(< (- (float-time) starttime) flycheck-ert-checker-wait-time))
(accept-process-output nil 0.02))
(unless (< (- (float-time) starttime) flycheck-ert-checker-wait-time)
(flycheck-stop)
(signal 'flycheck-ert-syntax-check-timed-out nil)))
(setq flycheck-ert-syntax-checker-finished nil))
(defun flycheck-ert-buffer-sync ()
"Like `flycheck-buffer', but synchronously."
(setq flycheck-ert-syntax-checker-finished nil)
(should (not (flycheck-running-p)))
(flycheck-mode) ;; This will only start a deferred check,
(should (flycheck-get-checker-for-buffer))
(flycheck-buffer) ;; …so we need an explicit manual check
;; After starting the check, the checker should either be running now, or
;; already be finished (if it was fast).
(should (or flycheck-current-syntax-check
flycheck-ert-syntax-checker-finished))
;; Also there should be no deferred check pending anymore
(should-not (flycheck-deferred-check-p))
(flycheck-ert-wait-for-syntax-checker))
(defun flycheck-ert-ensure-clear ()
"Clear the current buffer.
Raise an assertion error if the buffer is not clear afterwards."
(flycheck-clear)
(should (not flycheck-current-errors))
(should (not (seq-find (lambda (ov) (overlay-get ov 'flycheck-overlay))
(overlays-in (point-min) (point-max))))))
;;; Test assertions
(defun flycheck-error-without-group (err)
"Return a copy ERR with the `group' property set to nil."
(let ((copy (copy-flycheck-error err)))
(setf (flycheck-error-group copy) nil)
copy))
(defun flycheck-ert-should-overlay (error)
"Test that ERROR has a proper overlay in the current buffer.
ERROR is a Flycheck error object."
(let* ((overlay (seq-find (lambda (ov)
(equal (flycheck-error-without-group
(overlay-get ov 'flycheck-error))
(flycheck-error-without-group error)))
(flycheck-overlays-in 0 (+ 1 (buffer-size)))))
(region
;; Overlays of errors from other files are on the first line
(if (flycheck-relevant-error-other-file-p error)
(cons (point-min)
(save-excursion (goto-char (point-min))
(line-end-position)))
(flycheck-error-region-for-mode error 'symbols)))
(level (flycheck-error-level error))
(category (flycheck-error-level-overlay-category level))
(face (get category 'face))
(fringe-bitmap (flycheck-error-level-fringe-bitmap level))
(fringe-face (flycheck-error-level-fringe-face level))
(fringe-icon (list 'left-fringe fringe-bitmap fringe-face)))
(should overlay)
(should (overlay-get overlay 'flycheck-overlay))
(should (= (overlay-start overlay) (car region)))
(should (= (overlay-end overlay) (cdr region)))
(should (eq (overlay-get overlay 'face) face))
(should (equal (get-char-property 0 'display
(overlay-get overlay 'before-string))
fringe-icon))
(should (eq (overlay-get overlay 'category) category))
(should (equal (flycheck-error-without-group (overlay-get overlay
'flycheck-error))
(flycheck-error-without-group error)))))
(defun flycheck-ert-sort-errors (errors)
"Sort ERRORS by `flycheck-error-<'."
(seq-sort #'flycheck-error-< errors))
(defun flycheck-ert-should-errors (&rest errors)
"Test that the current buffers has ERRORS.
ERRORS is a list of errors expected to be present in the current
buffer. Each error is given as a list of arguments to
`flycheck-error-new-at'.
If ERRORS are omitted, test that there are no errors at all in
the current buffer.
With ERRORS, test that each error in ERRORS is present in the
current buffer, and that the number of errors in the current
buffer is equal to the number of given ERRORS. In other words,
check that the buffer has all ERRORS, and no other errors."
(let ((expected (flycheck-ert-sort-errors
(mapcar (apply-partially #'apply #'flycheck-error-new-at)
errors)))
(current (flycheck-ert-sort-errors flycheck-current-errors)))
(should (equal (mapcar #'flycheck-error-without-group expected)
(mapcar #'flycheck-error-without-group current)))
;; Check that related errors are the same
(cl-mapcar
(lambda (err1 err2)
(should (equal (flycheck-ert-sort-errors
(mapcar #'flycheck-error-without-group
(flycheck-related-errors err1 expected)))
(flycheck-ert-sort-errors
(mapcar #'flycheck-error-without-group
(flycheck-related-errors err2))))))
expected current)
(mapc #'flycheck-ert-should-overlay expected))
(should (= (length errors)
(length (flycheck-overlays-in (point-min) (point-max))))))
(define-error 'flycheck-ert-suspicious-checker "Suspicious state from checker")
(defun flycheck-ert-should-syntax-check-in-buffer (&rest errors)
"Test a syntax check in BUFFER, expecting ERRORS.
This is like `flycheck-ert-should-syntax-check', but with a
buffer in the right mode instead of a file."
;; Load safe file-local variables because some tests depend on them
(let ((enable-local-variables :safe)
;; Disable all hooks at this place, to prevent 3rd party packages
;; from interfering
(hack-local-variables-hook))
(hack-local-variables))
;; Configure config file locating for unit tests
(let ((process-hook-called 0)
(suspicious nil))
(add-hook 'flycheck-process-error-functions
(lambda (_err)
(setq process-hook-called (1+ process-hook-called))
nil)
nil :local)
(add-hook 'flycheck-status-changed-functions
(lambda (status)
(when (eq status 'suspicious)
(setq suspicious t)))
nil :local)
(flycheck-ert-buffer-sync)
(when suspicious
(signal 'flycheck-ert-suspicious-checker nil))
(apply #'flycheck-ert-should-errors errors)
(should (= process-hook-called (length errors))))
(flycheck-ert-ensure-clear))
(defun flycheck-ert-should-syntax-check (resource-file modes &rest errors)
"Test a syntax check in RESOURCE-FILE with MODES.
RESOURCE-FILE is the file to check. MODES is a single major mode
symbol or a list thereof, specifying the major modes to syntax
check with. If more than one major mode is specified, the test
is run for each mode separately, so if you give three major
modes, the entire test will run three times. ERRORS is the list
of expected errors, as in `flycheck-ert-should-errors'. If
omitted, the syntax check must not emit any errors. The errors
are cleared after each test.
The syntax checker is selected via standard syntax checker
selection. To test a specific checker, you need to set
`flycheck-checker' or `flycheck-disabled-checkers' accordingly
before using this predicate, depending on whether you want to use
manual or automatic checker selection.
During the syntax check, configuration files of syntax checkers
are also searched in the `config-files' sub-directory of the
resource directory."
(when (symbolp modes)
(setq modes (list modes)))
(dolist (mode modes)
(unless (fboundp mode)
(ert-skip (format "%S missing" mode)))
(flycheck-ert-with-resource-buffer resource-file
(funcall mode)
(apply #'flycheck-ert-should-syntax-check-in-buffer errors))))
(defun flycheck-ert-at-nth-error (n)
"Determine whether point is at the N'th Flycheck error.
Return non-nil if the point is at the N'th Flycheck error in the
current buffer. Otherwise return nil."
(let* ((error (nth (1- n) flycheck-current-errors))
(mode flycheck-highlighting-mode)
(region (flycheck-error-region-for-mode error mode)))
(and (member error (flycheck-overlay-errors-at (point)))
(= (point) (car region)))))
(defun flycheck-ert-explain--at-nth-error (n)
"Explain a failed at-nth-error predicate at N."
(let ((errors (flycheck-overlay-errors-at (point))))
(if (null errors)
(format "Expected to be at error %s, but no error at point %s"
n (point))
(let ((pos (cl-position (car errors) flycheck-current-errors)))
(format "Expected to be at point %s and error %s, \
but point %s is at error %s"
(car (flycheck-error-region-for-mode
(nth (1- n) flycheck-current-errors)
flycheck-highlighting-mode))
n (point) (1+ pos))))))
(put 'flycheck-ert-at-nth-error 'ert-explainer
'flycheck-ert-explain--at-nth-error)
(provide 'flycheck-ert)
;;; flycheck-ert.el ends here
+4 -4
View File
@@ -1,11 +1,11 @@
;; -*- no-byte-compile: t; lexical-binding: nil -*- ;; -*- no-byte-compile: t; lexical-binding: nil -*-
(define-package "flycheck" "20251128.1706" (define-package "flycheck" "20260320.1715"
"On-the-fly syntax checking." "On-the-fly syntax checking."
'((emacs "27.1") '((emacs "27.1")
(seq "2.24")) (seq "2.24"))
:url "https://www.flycheck.org" :url "https://github.com/flycheck/flycheck"
:commit "62570fafbedb8fa3f7d75a50a9364feca3b294ef" :commit "0e5eb8300d32fd562724216c19eaf199ee1451ab"
:revdesc "62570fafbedb" :revdesc "0e5eb8300d32"
:keywords '("convenience" "languages" "tools") :keywords '("convenience" "languages" "tools")
:authors '(("Sebastian Wiesner" . "swiesner@lunaryorn.com")) :authors '(("Sebastian Wiesner" . "swiesner@lunaryorn.com"))
:maintainers '(("Clément Pit-Claudel" . "clement.pitclaudel@live.com") :maintainers '(("Clément Pit-Claudel" . "clement.pitclaudel@live.com")
+624 -1031
View File
File diff suppressed because it is too large Load Diff
@@ -1,11 +1,11 @@
;; -*- no-byte-compile: t; lexical-binding: nil -*- ;; -*- no-byte-compile: t; lexical-binding: nil -*-
(define-package "flyspell-correct-ivy" "20220520.630" (define-package "flyspell-correct-ivy" "20260106.955"
"Correcting words with flyspell via ivy interface." "Correcting words with flyspell via ivy interface."
'((flyspell-correct "0.6.1") '((flyspell-correct "1.0.0")
(ivy "0.8.0") (ivy "0.8.0")
(emacs "24.4")) (emacs "29.1"))
:url "https://github.com/d12frosted/flyspell-correct" :url "https://github.com/d12frosted/flyspell-correct"
:commit "7d7b6b01188bd28e20a13736ac9f36c3367bd16e" :commit "a5a41c0f3a7881bd3eba07bee424ecb7c7d5061e"
:revdesc "7d7b6b01188b" :revdesc "a5a41c0f3a78"
:authors '(("Boris Buliga" . "boris@d12frosted.io")) :authors '(("Boris Buliga" . "boris@d12frosted.io"))
:maintainers '(("Boris Buliga" . "boris@d12frosted.io"))) :maintainers '(("Boris Buliga" . "boris@d12frosted.io")))
@@ -1,12 +1,12 @@
;;; flyspell-correct-ivy.el --- Correcting words with flyspell via ivy interface -*- lexical-binding: t; -*- ;;; flyspell-correct-ivy.el --- Correcting words with flyspell via ivy interface -*- lexical-binding: t; -*-
;; ;;
;; Copyright (c) 2016-2022 Boris Buliga ;; Copyright (c) 2016-2026 Boris Buliga
;; ;;
;; Author: Boris Buliga <boris@d12frosted.io> ;; Author: Boris Buliga <boris@d12frosted.io>
;; URL: https://github.com/d12frosted/flyspell-correct ;; URL: https://github.com/d12frosted/flyspell-correct
;; Package-Version: 20220520.630 ;; Package-Version: 20260106.955
;; Package-Revision: 7d7b6b01188b ;; Package-Revision: a5a41c0f3a78
;; Package-Requires: ((flyspell-correct "0.6.1") (ivy "0.8.0") (emacs "24.4")) ;; Package-Requires: ((flyspell-correct "1.0.0") (ivy "0.8.0") (emacs "29.1"))
;; ;;
;; This file is not part of GNU Emacs. ;; This file is not part of GNU Emacs.
;; ;;
@@ -1,10 +1,10 @@
;;; flyspell-correct-ido.el --- Correcting words with flyspell via ido interface -*- lexical-binding: t; -*- ;;; flyspell-correct-ido.el --- Correcting words with flyspell via ido interface -*- lexical-binding: t; -*-
;; ;;
;; Copyright (c) 2016-2022 Boris Buliga ;; Copyright (c) 2016-2026 Boris Buliga
;; ;;
;; Author: Boris Buliga <boris@d12frosted.io> ;; Author: Boris Buliga <boris@d12frosted.io>
;; URL: https://github.com/d12frosted/flyspell-correct ;; URL: https://github.com/d12frosted/flyspell-correct
;; Package-Requires: ((flyspell-correct "0.6.1") (emacs "24.1")) ;; Package-Requires: ((flyspell-correct "1.0.0") (emacs "29.1"))
;; ;;
;; This file is not part of GNU Emacs. ;; This file is not part of GNU Emacs.
;; ;;
@@ -1,9 +1,9 @@
;; -*- no-byte-compile: t; lexical-binding: nil -*- ;; -*- no-byte-compile: t; lexical-binding: nil -*-
(define-package "flyspell-correct" "20220520.630" (define-package "flyspell-correct" "20260106.955"
"Correcting words with flyspell via custom interface." "Correcting words with flyspell via custom interface."
'((emacs "24")) '((emacs "29.1"))
:url "https://github.com/d12frosted/flyspell-correct" :url "https://github.com/d12frosted/flyspell-correct"
:commit "7d7b6b01188bd28e20a13736ac9f36c3367bd16e" :commit "a5a41c0f3a7881bd3eba07bee424ecb7c7d5061e"
:revdesc "7d7b6b01188b" :revdesc "a5a41c0f3a78"
:authors '(("Boris Buliga" . "boris@d12frosted.io")) :authors '(("Boris Buliga" . "boris@d12frosted.io"))
:maintainers '(("Boris Buliga" . "boris@d12frosted.io"))) :maintainers '(("Boris Buliga" . "boris@d12frosted.io")))
+94 -62
View File
@@ -1,12 +1,12 @@
;;; flyspell-correct.el --- Correcting words with flyspell via custom interface -*- lexical-binding: t; -*- ;;; flyspell-correct.el --- Correcting words with flyspell via custom interface -*- lexical-binding: t; -*-
;; ;;
;; Copyright (c) 2016-2022 Boris Buliga ;; Copyright (c) 2016-2026 Boris Buliga
;; ;;
;; Author: Boris Buliga <boris@d12frosted.io> ;; Author: Boris Buliga <boris@d12frosted.io>
;; URL: https://github.com/d12frosted/flyspell-correct ;; URL: https://github.com/d12frosted/flyspell-correct
;; Package-Version: 20220520.630 ;; Package-Version: 20260106.955
;; Package-Revision: 7d7b6b01188b ;; Package-Revision: a5a41c0f3a78
;; Package-Requires: ((emacs "24")) ;; Package-Requires: ((emacs "29.1"))
;; ;;
;; This file is not part of GNU Emacs. ;; This file is not part of GNU Emacs.
;; ;;
@@ -63,31 +63,22 @@
(defcustom flyspell-correct-interface #'flyspell-correct-completing-read (defcustom flyspell-correct-interface #'flyspell-correct-completing-read
"Interface for `flyspell-correct-at-point'. "Interface for `flyspell-correct-at-point'.
`flyspell-correct-interface' is a function accepting two arguments: `flyspell-correct-interface' is a function accepting two arguments:
- candidates for correction (list of strings) - candidates for correction (list of strings)
- misspelled word (string) - misspelled word (string)
Result must be either a string (replacement word) or a cons of a Result must be either a string (replacement word) or a cons of a
command and a string (replacement word), where the command is one command and a string (replacement word), where the command is one
of the following: of the following:
- skip - do nothing to misspelled word, in rapid mode used for - skip - do nothing to misspelled word, in rapid mode used for
jumping to the next (or previous) misspelled word jumping to the next (or previous) misspelled word
- break - do nothing to misspelled word, break from rapid mode - break - do nothing to misspelled word, break from rapid mode
- stop - do nothing to misspelled word, break from rapid - stop - do nothing to misspelled word, break from rapid
mode (if enabled) and leave the point at the misspelled word mode (if enabled) and leave the point at the misspelled word
- save - replace misspelled word with replacement word and save - save - replace misspelled word with replacement word and save
it to the personal dictionary it to the personal dictionary
- session - replace misspelled word with replacement word and - session - replace misspelled word with replacement word and
save it to the session dictionary (correction will be save it to the session dictionary (correction will be
discarded upon quitting Emacs) discarded upon quitting Emacs)
- buffer - replace misspelled word with replacement word and - buffer - replace misspelled word with replacement word and
save it to the buffer dictionary (added to the bottom of save it to the buffer dictionary (added to the bottom of
buffer)" buffer)"
@@ -96,12 +87,27 @@ of the following:
(defcustom flyspell-correct-highlight t (defcustom flyspell-correct-highlight t
"When non-nil highlight the word while correcting. "When non-nil highlight the word while correcting.
The face `flyspell-correct-highlight-face' is used for The face `flyspell-correct-highlight-face' is used for
highlighting." highlighting."
:group 'flyspell-correct :group 'flyspell-correct
:type 'boolean) :type 'boolean)
(defcustom flyspell-correct-default-direction 'backward
"Default direction for `flyspell-correct-wrapper'.
When set to `backward' (the default), search for misspelled words
before point. When set to `forward', search for misspelled words
after point."
:group 'flyspell-correct
:type '(choice (const :tag "Backward" backward)
(const :tag "Forward" forward)))
(defcustom flyspell-correct-abort-on-quit t
"When non-nil, restore point when quitting correction.
When set to nil, leave point at the misspelled word when quitting
with \\[keyboard-quit] (similar to the `stop' action)."
:group 'flyspell-correct
:type 'boolean)
(defface flyspell-correct-highlight-face (defface flyspell-correct-highlight-face
'((t (:inherit isearch))) '((t (:inherit isearch)))
"Face used for highlighting the word while correcting." "Face used for highlighting the word while correcting."
@@ -125,7 +131,6 @@ highlighting."
(defun flyspell-correct--cr-index (n) (defun flyspell-correct--cr-index (n)
"Generate a short unique index string for N. "Generate a short unique index string for N.
The index string is used to prefix suggestion candidates. The digits 12345 The index string is used to prefix suggestion candidates. The digits 12345
encode (mod n 5) and occur as suffix of the index string. If one of the keys encode (mod n 5) and occur as suffix of the index string. If one of the keys
12345 is pressed, the selected candidate is automatically submitted. The 12345 is pressed, the selected candidate is automatically submitted. The
@@ -141,9 +146,7 @@ prefix of the index string."
(defun flyspell-correct-completing-read (candidates word) (defun flyspell-correct-completing-read (candidates word)
"Run `completing-read' for the given CANDIDATES. "Run `completing-read' for the given CANDIDATES.
List of CANDIDATES is given by flyspell for the WORD. List of CANDIDATES is given by flyspell for the WORD.
Return a selected word to use as a replacement or a tuple Return a selected word to use as a replacement or a tuple
of (command, word) to be used by `flyspell-do-correct'." of (command, word) to be used by `flyspell-do-correct'."
(let* ((idx 0) (let* ((idx 0)
@@ -212,7 +215,7 @@ of (command, word) to be used by `flyspell-do-correct'."
(define-obsolete-function-alias (define-obsolete-function-alias
'flyspell-correct-dummy 'flyspell-correct-dummy
'flyspell-correct-completing-read 'flyspell-correct-completing-read
"0.6.1") "1.0.0")
;;; On point word correction ;;; On point word correction
;; ;;
@@ -225,7 +228,9 @@ Adapted from `flyspell-correct-word-before-point'."
(unless flyspell-correct-interface (unless flyspell-correct-interface
(error "Could not correct word because `flyspell-correct-interface' is not set")) (error "Could not correct word because `flyspell-correct-interface' is not set"))
(let ((res)) (let ((res))
;; use the correct dictionary ;; Initialize spell checker and use the correct dictionary.
;; This allows flyspell-correct-at-point to work without flyspell-mode.
(ispell-set-spellchecker-params)
(flyspell-accept-buffer-local-defs) (flyspell-accept-buffer-local-defs)
(flyspell-correct--highlight-add) (flyspell-correct--highlight-add)
(unwind-protect (unwind-protect
@@ -293,10 +298,9 @@ Adapted from `flyspell-correct-word-before-point'."
(defun flyspell-correct-previous (position) (defun flyspell-correct-previous (position)
"Correct the first misspelled word that occurs before POSITION. "Correct the first misspelled word that occurs before POSITION.
But don't look beyond what's visible on the screen. But don't look beyond what's visible on the screen.
Uses `flyspell-correct-at-point' function for correction. Uses `flyspell-correct-at-point' function for correction.
With a prefix argument, automatically continues to all prior
With a prefix argument, automatically continues to all prior misspelled words in the buffer." misspelled words in the buffer."
(interactive "d") (interactive "d")
(flyspell-correct-move position nil current-prefix-arg)) (flyspell-correct-move position nil current-prefix-arg))
@@ -306,9 +310,7 @@ With a prefix argument, automatically continues to all prior misspelled words in
;;;###autoload ;;;###autoload
(defun flyspell-correct-next (position) (defun flyspell-correct-next (position)
"Correct the first misspelled word that occurs after POSITION. "Correct the first misspelled word that occurs after POSITION.
Uses `flyspell-correct-at-point' function for correction. Uses `flyspell-correct-at-point' function for correction.
With a prefix argument, automatically continues to all further With a prefix argument, automatically continues to all further
misspelled words in the buffer." misspelled words in the buffer."
(interactive "d") (interactive "d")
@@ -320,48 +322,84 @@ misspelled words in the buffer."
;;;###autoload ;;;###autoload
(defun flyspell-correct-wrapper () (defun flyspell-correct-wrapper ()
"Correct spelling error in a dwim fashion based on universal argument. "Correct spelling error in a dwim fashion based on universal argument.
- One \\[universal-argument] enables rapid mode. - One \\[universal-argument] enables rapid mode.
- Two \\[universal-argument]'s changes direction of spelling - Two \\[universal-argument]'s changes direction of spelling
errors search. errors search.
- Three \\[universal-argument]'s changes direction of spelling - Three \\[universal-argument]'s changes direction of spelling
errors search and enables rapid mode." errors search and enables rapid mode.
The default direction is controlled by `flyspell-correct-default-direction'."
(interactive) (interactive)
(let ((forward-direction nil) (let ((forward-direction (eq flyspell-correct-default-direction 'forward))
(rapid nil)) (rapid nil))
(cond (cond
((equal current-prefix-arg '(4)) ; C-u = rapid ((equal current-prefix-arg '(4)) ; C-u = rapid
(setq rapid t)) (setq rapid t))
((equal current-prefix-arg '(16)) ; C-u C-u = change direction ((equal current-prefix-arg '(16)) ; C-u C-u = change direction
(setq forward-direction t)) (setq forward-direction (not forward-direction)))
((equal current-prefix-arg '(64)) ; C-u C-u C-u = do both ((equal current-prefix-arg '(64)) ; C-u C-u C-u = do both
(setq rapid t) (setq rapid t)
(setq forward-direction t))) (setq forward-direction (not forward-direction))))
(flyspell-correct-move (point) forward-direction rapid))) (flyspell-correct-move (point) forward-direction rapid)))
;;;###autoload
(defun flyspell-correct-region (beg end)
"Correct all misspelled words in region between BEG and END.
Runs `flyspell-region' first to find misspelled words, then
corrects them one by one using `flyspell-correct-at-point'.
This is useful for spell-checking a specific portion of the buffer
without affecting the rest."
(interactive "r")
(flyspell-region beg end)
(let ((overlay-list (seq-filter
#'flyspell-overlay-p
(overlays-in beg end))))
;; Sort by position
(setq overlay-list (sort overlay-list
(lambda (o1 o2)
(< (overlay-start o1)
(overlay-start o2)))))
(when (or (not (mark t))
(/= (mark t) (point)))
(push-mark (point) t))
(unwind-protect
(save-excursion
(catch 'break
(dolist (overlay overlay-list)
(when (flyspell-overlay-p overlay) ; Check again, might be deleted
(goto-char (overlay-start overlay))
(let ((scroll (> (point) (window-end))))
(when scroll (ignore-errors (recenter))))
(let ((res (condition-case nil
(flyspell-correct-at-point)
(quit 'break))))
(when (or (eq res 'break)
(eq (car-safe res) 'break)
(eq (car-safe res) 'stop))
(throw 'break nil)))))))
(goto-char (mark t)))))
;;;###autoload ;;;###autoload
(defun flyspell-correct-move (position &optional forward rapid) (defun flyspell-correct-move (position &optional forward rapid)
"Correct the first misspelled word that occurs before POSITION. "Correct the first misspelled word that occurs before POSITION.
Uses `flyspell-correct-at-point' function for correction. Uses `flyspell-correct-at-point' function for correction.
With FORWARD set non-nil, check forward instead of backward. With FORWARD set non-nil, check forward instead of backward.
With RAPID set non-nil, automatically continues in direction With RAPID set non-nil, automatically continues in direction
until all errors in buffer have been addressed." until all errors in buffer have been addressed."
;; NOTE: The way I may be pushing the mark may possibly be more ;; NOTE: The way I may be pushing the mark may possibly be more
;; idiomatically done using the opoint arg of ;; idiomatically done using the opoint arg of
;; `flyspell-correct-word-before-point'. ;; `flyspell-correct-word-before-point'.
(interactive "d") (interactive "d")
;; push mark when starting
(when (or (not (mark t))
(/= (mark t) (point)))
(push-mark (point) t))
(let ((original-pos (point)) (let ((original-pos (point))
(target-pos (point)) (target-pos (point))
(hard-move-point) (hard-move-point)
(mark-opos)) (original-mark-ring mark-ring)
(preserve-mark))
(when (or (not (mark t))
(/= (mark t) (point)))
(push-mark (point) t))
(unwind-protect (unwind-protect
(save-excursion (save-excursion
(let ((incorrect-word-pos)) (let ((incorrect-word-pos))
@@ -403,13 +441,19 @@ until all errors in buffer have been addressed."
(<= original-pos (overlay-end overlay)))) (<= original-pos (overlay-end overlay))))
;; Correct a word using `flyspell-correct-at-point'. ;; Correct a word using `flyspell-correct-at-point'.
(let ((res (flyspell-correct-at-point))) (let ((res (condition-case nil
(flyspell-correct-at-point)
(quit
;; Handle C-g based on configuration
(if flyspell-correct-abort-on-quit
'break
'stop)))))
(when res (when res
;; stop at misspelled word ;; stop at misspelled word
(when (eq (car-safe res) 'stop) (when (eq (car-safe res) 'stop)
(setq target-pos incorrect-word-pos (setq target-pos incorrect-word-pos)
hard-move-point t (setq hard-move-point t)
mark-opos t)) (setq preserve-mark t))
;; break from rapid mode ;; break from rapid mode
(when (or (when (or
@@ -420,23 +464,15 @@ until all errors in buffer have been addressed."
;; explicit rapid mode disablers ;; explicit rapid mode disablers
(eq (car-safe res) 'break) (eq (car-safe res) 'break)
(eq (car-safe res) 'stop)) (eq (car-safe res) 'stop))
(setq overlay nil)) (setq overlay nil)))))))))
(when (and (if hard-move-point
;; don't push mark if there is no change (goto-char target-pos)
(not (memq (car-safe res) '(stop break skip))) (goto-char (mark t)))
(/= (mark t) (point)))
;; `flyspell-correct-at-point' may move point, use
;; original `incorrect-word-pos' instead
(push-mark incorrect-word-pos t)))))))))
(when hard-move-point
(when mark-opos
(push-mark (point) t))
(goto-char target-pos))
;; We pushed the mark when starting, but if the operation is canceled ;; We pushed the mark when starting, but if the operation is canceled
;; without any change that mark is redundant and needs to be cleaned-up. ;; without any change that mark is redundant and needs to be cleaned-up.
(when (= (mark t) (point)) (pop-mark))))) (unless preserve-mark
(setq mark-ring original-mark-ring)))))
;;; Overlays ;;; Overlays
@@ -461,7 +497,6 @@ until all errors in buffer have been addressed."
(defun flyspell-correct--overlay-loc () (defun flyspell-correct--overlay-loc ()
"Return `cons' with start and end of `flyspell' overlay at point. "Return `cons' with start and end of `flyspell' overlay at point.
Returns nil if no overlay is found." Returns nil if no overlay is found."
(let ((ovs (overlays-at (point))) (let ((ovs (overlays-at (point)))
ov) ov)
@@ -488,12 +523,11 @@ Use floating point numbers to express fractions of seconds."
"Interface to use in `flyspell-correct-auto-mode'. "Interface to use in `flyspell-correct-auto-mode'.
When set to nil `flyspell-correct-interface' is used.") When set to nil `flyspell-correct-interface' is used.")
(defvar flyspell-correct--auto-timer nil (defvar-local flyspell-correct--auto-timer nil
"Timer to automatically call `flyspell-correct-previous'.") "Timer to automatically call `flyspell-correct-previous'.")
(make-variable-buffer-local 'flyspell-correct--auto-timer)
(defvar flyspell-correct--auto-active-p nil) (defvar-local flyspell-correct--auto-active-p nil
(make-variable-buffer-local 'flyspell-correct--auto-active-p) "Non-nil when auto-correction is active.")
(defun flyspell-correct-auto-cancel-timer () (defun flyspell-correct-auto-cancel-timer ()
"Cancel auto correct timer." "Cancel auto correct timer."
@@ -527,12 +561,10 @@ When set to nil `flyspell-correct-interface' is used.")
;;;###autoload ;;;###autoload
(define-minor-mode flyspell-correct-auto-mode (define-minor-mode flyspell-correct-auto-mode
"Minor mode for automatically correcting word at point. "Minor mode for automatically correcting word at point.
Take my advice and don't use this functionality unless you find Take my advice and don't use this functionality unless you find
`flyspell-correct-previous' function useless for your purposes. `flyspell-correct-previous' function useless for your purposes.
Seriously, just try named function for completion. You can find Seriously, just try named function for completion. You can find
more info in comment[1]. more info in comment[1].
[1]: [1]:
https://github.com/syl20bnr/spacemacs/issues/6209#issuecomment-274320376" https://github.com/syl20bnr/spacemacs/issues/6209#issuecomment-274320376"
:group 'flyspell :group 'flyspell
+1 -1
View File
@@ -3,7 +3,7 @@
"Dim the font color of text in surrounding sections." "Dim the font color of text in surrounding sections."
'((emacs "24.3") '((emacs "24.3")
(cl-lib "0.5")) (cl-lib "0.5"))
:url "http://github.com/larstvei/Focus" :url "https://github.com/larstvei/Focus"
:commit "29b412b209c3542a7932c201f0166e48c9fd7fee" :commit "29b412b209c3542a7932c201f0166e48c9fd7fee"
:revdesc "29b412b209c3" :revdesc "29b412b209c3"
:authors '(("Lars Tveito" . "larstvei@ifi.uio.no")) :authors '(("Lars Tveito" . "larstvei@ifi.uio.no"))
+8 -10
View File
@@ -4,8 +4,6 @@
;; Author: Jon Oddie <jonxfield@gmail.com> ;; Author: Jon Oddie <jonxfield@gmail.com>
;; This file is not part of GNU Emacs.
;; This program is free software: you can redistribute it and/or modify ;; This program is free software: you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by ;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation, either version 3 of the License, or ;; the Free Software Foundation, either version 3 of the License, or
@@ -472,7 +470,7 @@ name; otherwise continues tokenizing up to the token at point. FIXME."
(t ; two patterns (t ; two patterns
(let* ((pat1 (cadr pat)) (let* ((pat1 (cadr pat))
(pat2 (cl-caddr pat)) (pat2 (caddr pat))
(pat1-c (gnuplot-context--compile-pattern pat1)) (pat1-c (gnuplot-context--compile-pattern pat1))
(pat2-c (gnuplot-context--compile-pattern pat2)) (pat2-c (gnuplot-context--compile-pattern pat2))
(pat1-l (length pat1-c)) (pat1-l (length pat1-c))
@@ -509,7 +507,7 @@ name; otherwise continues tokenizing up to the token at point. FIXME."
;; Syntactic sugar for delimited lists ;; Syntactic sugar for delimited lists
((delimited-list) ((delimited-list)
(let* ((item (cadr pat)) (let* ((item (cadr pat))
(sep (cl-caddr pat))) (sep (caddr pat)))
(gnuplot-context--compile-pattern (gnuplot-context--compile-pattern
`(sequence ,item (many (sequence ,sep ,item)))))) `(sequence ,item (many (sequence ,sep ,item))))))
@@ -1799,7 +1797,7 @@ there."
;; (literal LITERAL NO-COMPLETE) ;; (literal LITERAL NO-COMPLETE)
((literal) ((literal)
(let ((expect (cadr inst)) (let ((expect (cadr inst))
(no-complete (cl-caddr inst))) (no-complete (caddr inst)))
(cond (end-of-tokens (cond (end-of-tokens
(unless no-complete (unless no-complete
(gnuplot-context--trace "\tpushing \"%s\" to completions\n" expect) (gnuplot-context--trace "\tpushing \"%s\" to completions\n" expect)
@@ -1824,7 +1822,7 @@ there."
;; regexp-matches REGEXP, use NAME for completions ;; regexp-matches REGEXP, use NAME for completions
((keyword) ((keyword)
(let ((regexp (cadr inst)) (let ((regexp (cadr inst))
(name (cl-caddr inst))) (name (caddr inst)))
(cond (end-of-tokens (cond (end-of-tokens
(gnuplot-context--trace "\tpushing \"%s\" to completions\n" name) (gnuplot-context--trace "\tpushing \"%s\" to completions\n" name)
(push name gnuplot-context--completions) (push name gnuplot-context--completions)
@@ -1901,7 +1899,7 @@ there."
;; onto the stack ;; onto the stack
((push) ((push)
(let* ((type (cadr inst)) (let* ((type (cadr inst))
(value (cl-caddr inst))) (value (caddr inst)))
(push `(,type ,value ,tokens) stack))) (push `(,type ,value ,tokens) stack)))
;; (pop TYPE): pop something off the stack ;; (pop TYPE): pop something off the stack
@@ -1925,7 +1923,7 @@ there."
(record (assoc name gnuplot-context--captures))) (record (assoc name gnuplot-context--captures)))
(if (not record) (if (not record)
(error "Gnuplot-match-tokens: no open capture group named %s" name) (error "Gnuplot-match-tokens: no open capture group named %s" name)
(setf (cl-caddr record) tokens) (setf (caddr record) tokens)
(gnuplot-context--debug (gnuplot-dump-captures))))) (gnuplot-context--debug (gnuplot-dump-captures)))))
;; (check-progress): make sure not stuck in an infinite loop ;; (check-progress): make sure not stuck in an infinite loop
@@ -1975,7 +1973,7 @@ there."
(not (and gnuplot-context--info-at-point gnuplot-context--eldoc))) (not (and gnuplot-context--info-at-point gnuplot-context--eldoc)))
(let* ((item (car stack)) (let* ((item (car stack))
(type (car item)) (type (car item))
(position (cl-caddr item))) ; must progress by at least one token (position (caddr item))) ; must progress by at least one token
(if (and (memq type '(info eldoc no-scan)) (if (and (memq type '(info eldoc no-scan))
(not (eq position tokens))) (not (eq position tokens)))
(cl-case type (cl-case type
@@ -2013,7 +2011,7 @@ there."
(let ((record (assoc name gnuplot-context--captures))) (let ((record (assoc name gnuplot-context--captures)))
(if (not record) nil (if (not record) nil
(let ((begin (cadr record)) (let ((begin (cadr record))
(end (cl-caddr record)) (end (caddr record))
(accum '())) (accum '()))
(while (and begin (not (eq begin end))) (while (and begin (not (eq begin end)))
(push (pop begin) accum)) (push (pop begin) accum))
+23 -27
View File
@@ -4,8 +4,6 @@
;; Author: Bruce Ravel <ravel@phys.washington.edu> ;; Author: Bruce Ravel <ravel@phys.washington.edu>
;; This file is not part of GNU Emacs.
;; This program is free software: you can redistribute it and/or modify ;; This program is free software: you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by ;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation, either version 3 of the License, or ;; the Free Software Foundation, either version 3 of the License, or
@@ -872,16 +870,14 @@ Note that \"cntrparam\" is not currently supported."
(old-top (gnuplot-gui-get-frame-param 'top))) (old-top (gnuplot-gui-get-frame-param 'top)))
(when (or (when (or
(and (equal gnuplot-gui-plot-splot-fit-style 'complete) (and (equal gnuplot-gui-plot-splot-fit-style 'complete)
(cl-member word '("plot" "splot" "fit") (member word '("plot" "splot" "fit")))
:test 'equal))
(equal word "test")) (equal word "test"))
(gnuplot-gui-set-frame-param 'height 32) (gnuplot-gui-set-frame-param 'height 32)
(gnuplot-gui-set-frame-param 'top 50)) (gnuplot-gui-set-frame-param 'top 50))
(gnuplot-gui-prompt-for-frame word) (gnuplot-gui-prompt-for-frame word)
(when (or (when (or
(and (equal gnuplot-gui-plot-splot-fit-style 'complete) (and (equal gnuplot-gui-plot-splot-fit-style 'complete)
(cl-member word '("plot" "splot" "fit") (member word '("plot" "splot" "fit")))
:test 'equal))
(equal word "test")) (equal word "test"))
(gnuplot-gui-set-frame-param 'height old-height) (gnuplot-gui-set-frame-param 'height old-height)
(gnuplot-gui-set-frame-param 'top old-top)) )) (gnuplot-gui-set-frame-param 'top old-top)) ))
@@ -946,8 +942,8 @@ argument, for example an axis label or a font name. It also replaces
bounding single quotes with double quotes, since double quotes are bounding single quotes with double quotes, since double quotes are
used in `gnuplot-gui-all-types'." used in `gnuplot-gui-all-types'."
(let (fixed-list quote quoted) ; remove blanks (let (fixed-list quote quoted) ; remove blanks
(setq list (cl-remove "\\s-+" list :test 'string-match) (setq list (cl-remove "\\s-+" list :test #'string-match)
list (cl-remove "" list :test 'equal)) list (remove "" list))
(while list ; concatinate parts of quoted string (while list ; concatinate parts of quoted string
(if (not (string-match "^\\([\]\[()'\"]\\)" (car list))) (if (not (string-match "^\\([\]\[()'\"]\\)" (car list)))
(setq fixed-list (append fixed-list (list (car list)))) (setq fixed-list (append fixed-list (list (car list))))
@@ -998,15 +994,15 @@ arguments."
(while temp-list (while temp-list
(cond (cond
;; ---------------------------- list ;; ---------------------------- list
((cl-member symbol '(list list*) :test 'equal) ((memq symbol '(list list*))
(let* ((case-fold-search nil) (let* ((case-fold-search nil)
(match-cons (cl-member (concat "^" (car temp-list)) (match-cons (cl-member (concat "^" (car temp-list))
values :test 'string-match))) values :test #'string-match)))
(if (and (car match-cons) ; " " may be first elem. of list (if (and (car match-cons) ; " " may be first elem. of list
(not (equal " " (car match-cons)))) (not (equal " " (car match-cons))))
(setq this-cons (cons tag (car match-cons)) (setq this-cons (cons tag (car match-cons))
arg-list (cl-remove (car temp-list) arg-list arg-list (cl-remove (car temp-list) arg-list
:test 'equal :count 1) :test #'equal :count 1)
temp-list nil) temp-list nil)
(setq temp-list (cdr temp-list))))) (setq temp-list (cdr temp-list)))))
;; ---------------------------- tag (first number in list) ;; ---------------------------- tag (first number in list)
@@ -1027,16 +1023,16 @@ arguments."
(string-match "^[-0-9.]+$" (cadr temp-list))) (string-match "^[-0-9.]+$" (cadr temp-list)))
(setq this-cons (cons tag (cadr temp-list)) (setq this-cons (cons tag (cadr temp-list))
arg-list (cl-remove (car temp-list) arg-list arg-list (cl-remove (car temp-list) arg-list
:test 'equal :count 1) :test #'equal :count 1)
arg-list (cl-remove (cadr temp-list) arg-list arg-list (cl-remove (cadr temp-list) arg-list
:test 'equal :count 1) :test #'equal :count 1)
temp-list nil)) temp-list nil))
;; --------------------- number without prefix ;; --------------------- number without prefix
((and (not prefix) ((and (not prefix)
(string-match "^[-0-9.]+$" (car temp-list))) (string-match "^[-0-9.]+$" (car temp-list)))
(setq this-cons (cons tag (car temp-list)) (setq this-cons (cons tag (car temp-list))
arg-list (cl-remove (car temp-list) arg-list arg-list (cl-remove (car temp-list) arg-list
:test 'equal :count 1) :test #'equal :count 1)
temp-list nil)) temp-list nil))
(t (t
(setq temp-list (cdr temp-list))))) (setq temp-list (cdr temp-list)))))
@@ -1045,8 +1041,8 @@ arguments."
(if (and (equal prefix (car temp-list)) (if (and (equal prefix (car temp-list))
(string-match "^[-0-9.]+$" (cadr temp-list))) (string-match "^[-0-9.]+$" (cadr temp-list)))
(let ((this-car (cadr temp-list)) (let ((this-car (cadr temp-list))
(this-cdr (if (string-match "^[-0-9.]+$" (cl-caddr temp-list)) (this-cdr (if (string-match "^[-0-9.]+$" (caddr temp-list))
(cl-caddr temp-list) ""))) (caddr temp-list) "")))
(setq this-cons (cons tag (cons this-car this-cdr)) (setq this-cons (cons tag (cons this-car this-cdr))
temp-list nil)) temp-list nil))
(setq temp-list (cdr temp-list)))) (setq temp-list (cdr temp-list))))
@@ -1062,7 +1058,7 @@ arguments."
(cons tag (cons (match-string 1 (car temp-list)) (cons tag (cons (match-string 1 (car temp-list))
(match-string 2 (car temp-list)))) (match-string 2 (car temp-list))))
arg-list (cl-remove (car temp-list) arg-list arg-list (cl-remove (car temp-list) arg-list
:test 'equal :count 1) :test #'equal :count 1)
temp-list nil) temp-list nil)
(setq temp-list (cdr temp-list)) )) (setq temp-list (cdr temp-list)) ))
;; ---------------------------- labels ;; ---------------------------- labels
@@ -1072,7 +1068,7 @@ arguments."
")") ; closing paren ")") ; closing paren
(car temp-list)) (car temp-list))
(let* ((list (split-string (car temp-list) "[ \t(),]+")) (let* ((list (split-string (car temp-list) "[ \t(),]+"))
(list (cl-remove "" list :test 'equal)) (list (remove "" list))
(return ())) (return ()))
(while list (while list
(if (string-match "['\"]\\([^'\"]*\\)['\"]" (car list)) (if (string-match "['\"]\\([^'\"]*\\)['\"]" (car list))
@@ -1084,18 +1080,18 @@ arguments."
(setq list (cdr list)) ) (setq list (cdr list)) )
(setq this-cons (cons tag return) (setq this-cons (cons tag return)
arg-list (cl-remove (car temp-list) arg-list arg-list (cl-remove (car temp-list) arg-list
:test 'equal :count 1) :test #'equal :count 1)
temp-list nil)) temp-list nil))
(setq temp-list (cdr temp-list))) ) (setq temp-list (cdr temp-list))) )
;; ---------------------------- string, file, format ;; ---------------------------- string, file, format
((cl-member symbol '(string file format) :test 'equal) ((memq symbol '(string file format))
(if (string-match (concat "['\"]" ; opening quote (if (string-match (concat "['\"]" ; opening quote
"\\([^'\"]*\\)" ; string "\\([^'\"]*\\)" ; string
"['\"]") ; closing quote "['\"]") ; closing quote
(car temp-list)) (car temp-list))
(setq this-cons (cons tag (match-string 0 (car temp-list))) (setq this-cons (cons tag (match-string 0 (car temp-list)))
arg-list (cl-remove (car temp-list) arg-list arg-list (cl-remove (car temp-list) arg-list
:test 'equal :count 1) :test #'equal :count 1)
temp-list nil) temp-list nil)
(setq temp-list (cdr temp-list)) )) (setq temp-list (cdr temp-list)) ))
;; ---------------------------- string* ;; ---------------------------- string*
@@ -1103,9 +1099,9 @@ arguments."
(if (equal prefix (car temp-list)) (if (equal prefix (car temp-list))
(setq this-cons (cons tag (cadr temp-list)) (setq this-cons (cons tag (cadr temp-list))
arg-list (cl-remove (car temp-list) arg-list arg-list (cl-remove (car temp-list) arg-list
:test 'equal :count 1) :test #'equal :count 1)
arg-list (cl-remove (cadr temp-list) arg-list arg-list (cl-remove (cadr temp-list) arg-list
:test 'equal :count 1) :test #'equal :count 1)
temp-list nil) temp-list nil)
(setq temp-list (cdr temp-list)) ) ) (setq temp-list (cdr temp-list)) ) )
;; ---------------------------- other or unknown ;; ---------------------------- other or unknown
@@ -1237,19 +1233,19 @@ SAVE-FRAME is non-nil when the widgets are being reset."
(widget-insert "\t") ; insert the appropriate widget (widget-insert "\t") ; insert the appropriate widget
(cond (cond
;;------------------------------ list, list* ------------ ;;------------------------------ list, list* ------------
((cl-member (eval wtype) '(list list*) :test 'equal) ((memq (eval wtype) '(list list*))
(let ((starred (if (equal (eval wtype) 'list*) t nil))) (let ((starred (if (equal (eval wtype) 'list*) t nil)))
(gnuplot-gui-menu-choice tag default list starred))) (gnuplot-gui-menu-choice tag default list starred)))
;;------------------------------ number, tag, fontsize -- ;;------------------------------ number, tag, fontsize --
((cl-member (eval wtype) '(number tag fontsize) :test 'equal) ((memq (eval wtype) '(number tag fontsize))
(gnuplot-gui-number tag default prefix)) (gnuplot-gui-number tag default prefix))
;;------------------------------ position --------------- ;;------------------------------ position ---------------
;;------------------------------ range, pair ------------ ;;------------------------------ range, pair ------------
((cl-member (eval wtype) '(range pair) :test 'equal) ((memq (eval wtype) '(range pair))
(let ((is-range (equal (eval wtype) 'range))) (let ((is-range (equal (eval wtype) 'range)))
(gnuplot-gui-range tag default prefix is-range))) (gnuplot-gui-range tag default prefix is-range)))
;;------------------------------ string, string* -------- ;;------------------------------ string, string* --------
((cl-member (eval wtype) '(string string*) :test 'equal) ((memq (eval wtype) '(string string*))
(let ((starred (if (equal (eval wtype) 'string) nil t))) (let ((starred (if (equal (eval wtype) 'string) nil t)))
(gnuplot-gui-string tag default prefix starred))) (gnuplot-gui-string tag default prefix starred)))
;;------------------------------ format ----------------- ;;------------------------------ format -----------------
+3 -3
View File
@@ -1,11 +1,11 @@
;; -*- no-byte-compile: t; lexical-binding: nil -*- ;; -*- no-byte-compile: t; lexical-binding: nil -*-
(define-package "gnuplot" "20250724.1531" (define-package "gnuplot" "20260322.20"
"Major-mode and interactive frontend for gnuplot." "Major-mode and interactive frontend for gnuplot."
'((emacs "28.1") '((emacs "28.1")
(compat "30")) (compat "30"))
:url "https://github.com/emacs-gnuplot/gnuplot" :url "https://github.com/emacs-gnuplot/gnuplot"
:commit "43e9674b869475b1c2a32f045c167673eb2faae0" :commit "39ba1dec5e8e227ba093a30ca07b20d8eb038f29"
:revdesc "43e9674b8694" :revdesc "39ba1dec5e8e"
:keywords '("data" "gnuplot" "plotting") :keywords '("data" "gnuplot" "plotting")
:maintainers '(("Maxime Tréca" . "maxime@gmail.com") :maintainers '(("Maxime Tréca" . "maxime@gmail.com")
("Daniel Mendler" . "mail@daniel-mendler.de"))) ("Daniel Mendler" . "mail@daniel-mendler.de")))
+2 -4
View File
@@ -5,14 +5,12 @@
;; Author: Jon Oddie, Bruce Ravel, Phil Type ;; Author: Jon Oddie, Bruce Ravel, Phil Type
;; Maintainer: Maxime Tréca <maxime@gmail.com>, Daniel Mendler <mail@daniel-mendler.de> ;; Maintainer: Maxime Tréca <maxime@gmail.com>, Daniel Mendler <mail@daniel-mendler.de>
;; Created: 1998 ;; Created: 1998
;; Package-Version: 20250724.1531 ;; Package-Version: 20260322.20
;; Package-Revision: 43e9674b8694 ;; Package-Revision: 39ba1dec5e8e
;; Keywords: data gnuplot plotting ;; Keywords: data gnuplot plotting
;; URL: https://github.com/emacs-gnuplot/gnuplot ;; URL: https://github.com/emacs-gnuplot/gnuplot
;; Package-Requires: ((emacs "28.1") (compat "30")) ;; Package-Requires: ((emacs "28.1") (compat "30"))
;; This file is not part of GNU Emacs.
;; This program is free software: you can redistribute it and/or modify ;; This program is free software: you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by ;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation, either version 3 of the License, or ;; the Free Software Foundation, either version 3 of the License, or
+6 -6
View File
@@ -1,4 +1,4 @@
This is gnuplot.info, produced by makeinfo version 7.2 from This is gnuplot.info, produced by makeinfo version 7.3 from
gnuplot.texi. gnuplot.texi.
INFO-DIR-SECTION Math INFO-DIR-SECTION Math
@@ -23499,7 +23499,7 @@ Concept Index
* ? <3>: gamma. (line 9) * ? <3>: gamma. (line 9)
* ? <4>: inverf. (line 7) * ? <4>: inverf. (line 7)
* ? <5>: imag. (line 7) * ? <5>: imag. (line 7)
* ? <6>: invnorm. (line 10) * ? <6>: invnorm. (line 9)
* ? <7>: invnorm. (line 9) * ? <7>: invnorm. (line 9)
* ? <8>: real. (line 6) * ? <8>: real. (line 6)
* ? <9>: sqrt. (line 8) * ? <9>: sqrt. (line 8)
@@ -23519,13 +23519,13 @@ Concept Index
* ? <23>: words. (line 33) * ? <23>: words. (line 33)
* ? <24>: words. (line 35) * ? <24>: words. (line 35)
* ? <25>: words. (line 38) * ? <25>: words. (line 38)
* ? <26>: words. (line 40) * ? <26>: words. (line 39)
* ? <27>: words. (line 40) * ? <27>: words. (line 39)
* ? <28>: words. (line 40) * ? <28>: words. (line 39)
* ? <29>: words. (line 39) * ? <29>: words. (line 39)
* ? <30>: hsv2rgb. (line 7) * ? <30>: hsv2rgb. (line 7)
* ? <31>: rgbcolor. (line 11) * ? <31>: rgbcolor. (line 11)
* ? <32>: rgbcolor. (line 13) * ? <32>: rgbcolor. (line 12)
* ? <33>: rgbcolor. (line 12) * ? <33>: rgbcolor. (line 12)
* .gnuplot: Start-up_(initialization). * .gnuplot: Start-up_(initialization).
(line 6) (line 6)
+3 -3
View File
@@ -1,7 +1,7 @@
;; -*- no-byte-compile: t; lexical-binding: nil -*- ;; -*- no-byte-compile: t; lexical-binding: nil -*-
(define-package "indent-guide" "20210115.400" (define-package "indent-guide" "20260211.1005"
"Show vertical lines to guide indentation." "Show vertical lines to guide indentation."
() ()
:url "http://hins11.yu-yake.com/" :url "http://hins11.yu-yake.com/"
:commit "d388c3387781a370ca13233ff445d03f3c5cf12f" :commit "f3455c6c798b568a6ea1013b7eea1153d2e092be"
:revdesc "d388c3387781") :revdesc "f3455c6c798b")
+59 -21
View File
@@ -18,8 +18,8 @@
;; Author: zk_phi ;; Author: zk_phi
;; URL: http://hins11.yu-yake.com/ ;; URL: http://hins11.yu-yake.com/
;; Package-Version: 20210115.400 ;; Package-Version: 20260211.1005
;; Package-Revision: d388c3387781 ;; Package-Revision: f3455c6c798b
;;; Commentary: ;;; Commentary:
@@ -76,7 +76,7 @@
(require 'cl-lib) (require 'cl-lib)
(defconst indent-guide-version "2.3.1") (defconst indent-guide-version "2.4")
;; * customs ;; * customs
@@ -85,7 +85,17 @@
:group 'environment) :group 'environment)
(defcustom indent-guide-char "|" (defcustom indent-guide-char "|"
"Character used as vertical line." "Character used for the guide line."
:type 'string
:group 'indent-guide)
(defcustom indent-guide-char-top nil
"when non-nil, character used for the top of the guide line."
:type 'string
:group 'indent-guide)
(defcustom indent-guide-char-bottom nil
"when non-nil, character used for the bottom of the guide line."
:type 'string :type 'string
:group 'indent-guide) :group 'indent-guide)
@@ -178,9 +188,21 @@ the point. When no such points are found, just return nil."
(and (search-backward-regexp regex nil t) (and (search-backward-regexp regex nil t)
(goto-char (match-end 1)))))) (goto-char (match-end 1))))))
;;; NOTE(arka): custom fn for decorated guide line
(defun indent-guide--choose-char (line line-start line-end)
"Return the appropriate guide character for LINE."
(if (= line-start line-end)
indent-guide-char
(cond
((= line line-start) (or indent-guide-char-top indent-guide-char))
((= line line-end) (or indent-guide-char-bottom indent-guide-char))
(t indent-guide-char)))
)
;; * generate guides ;; * generate guides
(defun indent-guide--make-overlay (line col) ;;; NOTE(arka): extra `line-start` and `line-end` are parameters added for decorated guide line
(defun indent-guide--make-overlay (line col line-start line-end)
"draw line at (line, col)" "draw line at (line, col)"
(let (diff string ov prop) (let (diff string ov prop)
(save-excursion (save-excursion
@@ -204,10 +226,14 @@ the point. When no such points are found, just return nil."
(setq string (let ((str (overlay-get ov 'before-string))) (setq string (let ((str (overlay-get ov 'before-string)))
(concat str (concat str
(make-string (- diff (length str)) ?\s) (make-string (- diff (length str)) ?\s)
(propertize indent-guide-char 'face 'indent-guide-face))) ;;; NOTE(arka): automatic indentaiton guide character selection
;;; based on line number count.
(propertize (indent-guide--choose-char line line-start line-end)
'face 'indent-guide-face)))
prop 'before-string) prop 'before-string)
(setq string (concat (make-string diff ?\s) (setq string (concat (make-string diff ?\s)
(propertize indent-guide-char 'face 'indent-guide-face)) (propertize (indent-guide--choose-char line line-start line-end)
'face 'indent-guide-face))
prop 'before-string prop 'before-string
ov (make-overlay (point) (point))))) ov (make-overlay (point) (point)))))
((< diff 0) ; the column is inside a tab ((< diff 0) ; the column is inside a tab
@@ -226,19 +252,22 @@ the point. When no such points are found, just return nil."
str) str)
prop 'display) prop 'display)
(setq string (concat (make-string (+ tab-width diff) ?\s) (setq string (concat (make-string (+ tab-width diff) ?\s)
(propertize indent-guide-char 'face 'indent-guide-face) (propertize (indent-guide--choose-char line line-start line-end)
'face 'indent-guide-face)
(make-string (1- (- diff)) ?\s)) (make-string (1- (- diff)) ?\s))
prop 'display prop 'display
ov (make-overlay (point) (1- (point)))))) ov (make-overlay (point) (1- (point))))))
((looking-at "\t") ; okay but looking at tab ((looking-at "\t") ; okay but looking at tab
;; <-tab-width-> ;; <-tab-width->
;; [|] ;; [|]
(setq string (concat (propertize indent-guide-char 'face 'indent-guide-face) (setq string (concat (propertize (indent-guide--choose-char line line-start line-end)
'face 'indent-guide-face)
(make-string (1- tab-width) ?\s)) (make-string (1- tab-width) ?\s))
prop 'display prop 'display
ov (make-overlay (point) (1+ (point))))) ov (make-overlay (point) (1+ (point)))))
(t ; okay and looking at a space (t ; okay and looking at a space
(setq string (propertize indent-guide-char 'face 'indent-guide-face) (setq string (propertize (indent-guide--choose-char line line-start line-end)
'face 'indent-guide-face)
prop 'display prop 'display
ov (make-overlay (point) (1+ (point)))))) ov (make-overlay (point) (1+ (point))))))
(when ov (when ov
@@ -247,8 +276,10 @@ the point. When no such points are found, just return nil."
(defun indent-guide-show () (defun indent-guide-show ()
(interactive) (interactive)
(unless (or (indent-guide--active-overlays) ;;; NOTE(arka): redraw only when needed
(active-minibuffer-window)) (unless (active-minibuffer-window)
(indent-guide-remove)
(let ((win-start (window-start)) (let ((win-start (window-start))
(win-end (window-end nil t)) (win-end (window-end nil t))
line-col line-start line-end) line-col line-start line-end)
@@ -279,7 +310,7 @@ the point. When no such points are found, just return nil."
(setq line-end (line-number-at-pos))))) (setq line-end (line-number-at-pos)))))
;; draw line ;; draw line
(dotimes (tmp (- (1+ line-end) line-start)) (dotimes (tmp (- (1+ line-end) line-start))
(indent-guide--make-overlay (+ line-start tmp) line-col)) (indent-guide--make-overlay (+ line-start tmp) line-col line-start line-end))
(remove-overlays (point) (point) 'category 'indent-guide))))) (remove-overlays (point) (point) 'category 'indent-guide)))))
(defun indent-guide-remove () (defun indent-guide-remove ()
@@ -298,10 +329,16 @@ the point. When no such points are found, just return nil."
(indent-guide-show) (indent-guide-show)
(setq indent-guide--timer-object nil))))))) (setq indent-guide--timer-object nil)))))))
(defun indent-guide-pre-command-hook () ;;; NOTE(arka): root cause of flickering effect. we don't actually need
;; some commands' behavior may affected by indent-guide overlays, so ;;; pre-hook to redraw guides on each command.
;; remove all overlays in pre-command-hook. ;; (defun indent-guide-pre-command-hook ()
(indent-guide-remove)) ;; ;; some commands' behavior may affected by indent-guide overlays, so
;; ;; remove all overlays in pre-command-hook.
;; (indent-guide-remove))
;;; NOTE(arka): fn to fix flickering effect when scrolling.
(defun indent-guide--window-scroll-hook (&rest _)
(indent-guide-show))
;;;###autoload ;;;###autoload
(define-minor-mode indent-guide-mode (define-minor-mode indent-guide-mode
@@ -311,10 +348,11 @@ the point. When no such points are found, just return nil."
:global nil :global nil
(if indent-guide-mode (if indent-guide-mode
(progn (progn
(add-hook 'pre-command-hook 'indent-guide-pre-command-hook nil t) ;;; NOTE(arka): only use post-hook. pre-hook is now depricated
(add-hook 'post-command-hook 'indent-guide-post-command-hook nil t)) (add-hook 'post-command-hook 'indent-guide-post-command-hook nil t)
(remove-hook 'pre-command-hook 'indent-guide-pre-command-hook t) (add-hook 'window-scroll-functions 'indent-guide--window-scroll-hook nil t))
(remove-hook 'post-command-hook 'indent-guide-post-command-hook t))) (remove-hook 'post-command-hook 'indent-guide-post-command-hook t)
(remove-hook 'window-scroll-functions 'indent-guide--window-scroll-hook t)))
;;;###autoload ;;;###autoload
(define-globalized-minor-mode indent-guide-global-mode (define-globalized-minor-mode indent-guide-global-mode
+1 -1
View File
@@ -1,6 +1,6 @@
;;; colir.el --- Color blending library -*- lexical-binding: t -*- ;;; colir.el --- Color blending library -*- lexical-binding: t -*-
;; Copyright (C) 2015-2025 Free Software Foundation, Inc. ;; Copyright (C) 2015-2026 Free Software Foundation, Inc.
;; Author: Oleh Krehel <ohwoeowho@gmail.com> ;; Author: Oleh Krehel <ohwoeowho@gmail.com>
+1 -1
View File
@@ -1,6 +1,6 @@
;;; ivy-faces.el --- Faces for Ivy -*- lexical-binding: t -*- ;;; ivy-faces.el --- Faces for Ivy -*- lexical-binding: t -*-
;; Copyright (C) 2020-2025 Free Software Foundation, Inc. ;; Copyright (C) 2020-2026 Free Software Foundation, Inc.
;; Author: Oleh Krehel <ohwoeowho@gmail.com> ;; Author: Oleh Krehel <ohwoeowho@gmail.com>
;; Keywords: convenience ;; Keywords: convenience
+1 -1
View File
@@ -1,6 +1,6 @@
;;; ivy-overlay.el --- Overlay display functions for Ivy -*- lexical-binding: t -*- ;;; ivy-overlay.el --- Overlay display functions for Ivy -*- lexical-binding: t -*-
;; Copyright (C) 2016-2025 Free Software Foundation, Inc. ;; Copyright (C) 2016-2026 Free Software Foundation, Inc.
;; Author: Oleh Krehel <ohwoeowho@gmail.com> ;; Author: Oleh Krehel <ohwoeowho@gmail.com>
;; Keywords: convenience ;; Keywords: convenience
+3 -3
View File
@@ -1,10 +1,10 @@
;; -*- no-byte-compile: t; lexical-binding: nil -*- ;; -*- no-byte-compile: t; lexical-binding: nil -*-
(define-package "ivy" "20251123.1023" (define-package "ivy" "20260318.1355"
"Incremental Vertical completYon." "Incremental Vertical completYon."
'((emacs "24.5")) '((emacs "24.5"))
:url "https://github.com/abo-abo/swiper" :url "https://github.com/abo-abo/swiper"
:commit "ec9421340c88ebe08f05680e22308ed57ed68a3d" :commit "1005bff8a700b92dc464f770aff8a0db5b4a1c0b"
:revdesc "ec9421340c88" :revdesc "1005bff8a700"
:keywords '("matching") :keywords '("matching")
:authors '(("Oleh Krehel" . "ohwoeowho@gmail.com")) :authors '(("Oleh Krehel" . "ohwoeowho@gmail.com"))
:maintainers '(("Basil L. Contovounesios" . "basil@contovou.net"))) :maintainers '(("Basil L. Contovounesios" . "basil@contovou.net")))
+365 -217
View File
File diff suppressed because it is too large Load Diff
+2 -2
View File
@@ -1,4 +1,4 @@
This is ivy.info, produced by makeinfo version 7.2 from ivy.texi. This is ivy.info, produced by makeinfo version 7.3 from ivy.texi.
Ivy manual, version 0.15.1 Ivy manual, version 0.15.1
@@ -11,7 +11,7 @@ available choices while previewing in the minibuffer. Selecting the
final candidate is either through simple keyboard character inputs or final candidate is either through simple keyboard character inputs or
through powerful regular expressions. through powerful regular expressions.
Copyright (C) 2015-2025 Free Software Foundation, Inc. Copyright (C) 2015-2026 Free Software Foundation, Inc.
Permission is granted to copy, distribute and/or modify this Permission is granted to copy, distribute and/or modify this
document under the terms of the GNU Free Documentation License, document under the terms of the GNU Free Documentation License,
+1 -1
View File
@@ -1,4 +1,4 @@
This is ledger-mode.info, produced by makeinfo version 7.2 from This is ledger-mode.info, produced by makeinfo version 7.3 from
ledger-mode.texi. ledger-mode.texi.
Copyright © 2013, Craig Earls. All rights reserved. Copyright © 2013, Craig Earls. All rights reserved.
+2
View File
@@ -1,5 +1,7 @@
((nil ((nil
(indent-tabs-mode . nil)) (indent-tabs-mode . nil))
(emacs-lisp-mode
(lisp-indent-local-overrides . ((cond . 0) (interactive . 0))))
(makefile-mode (makefile-mode
(indent-tabs-mode . t)) (indent-tabs-mode . t))
(git-commit-mode (git-commit-mode
+3 -3
View File
@@ -1,9 +1,9 @@
;; -*- no-byte-compile: t; lexical-binding: nil -*- ;; -*- no-byte-compile: t; lexical-binding: nil -*-
(define-package "llama" "20251101.2002" (define-package "llama" "20260301.1253"
"Compact syntax for short lambda." "Compact syntax for short lambda."
'((emacs "26.1") '((emacs "26.1")
(compat "30.1")) (compat "30.1"))
:url "https://github.com/tarsius/llama" :url "https://github.com/tarsius/llama"
:commit "e4803de8ab85991b6a944430bb4f543ea338636d" :commit "d430d48e0b5afd2a34b5531f103dcb110c3539c4"
:revdesc "e4803de8ab85" :revdesc "d430d48e0b5a"
:keywords '("extensions")) :keywords '("extensions"))
+5 -4
View File
@@ -1,13 +1,13 @@
;;; llama.el --- Compact syntax for short lambda -*- lexical-binding:t -*- ;;; llama.el --- Compact syntax for short lambda -*- lexical-binding:t -*-
;; Copyright (C) 2020-2025 Jonas Bernoulli ;; Copyright (C) 2020-2026 Jonas Bernoulli
;; Authors: Jonas Bernoulli <emacs.llama@jonas.bernoulli.dev> ;; Authors: Jonas Bernoulli <emacs.llama@jonas.bernoulli.dev>
;; Homepage: https://github.com/tarsius/llama ;; Homepage: https://github.com/tarsius/llama
;; Keywords: extensions ;; Keywords: extensions
;; Package-Version: 20251101.2002 ;; Package-Version: 20260301.1253
;; Package-Revision: e4803de8ab85 ;; Package-Revision: d430d48e0b5a
;; Package-Requires: ( ;; Package-Requires: (
;; (emacs "26.1") ;; (emacs "26.1")
;; (compat "30.1")) ;; (compat "30.1"))
@@ -355,7 +355,8 @@ expansion, and the looks of this face should hint at that.")
(prog1 t (prog1 t
(save-excursion (save-excursion
(goto-char (match-beginning 0)) (goto-char (match-beginning 0))
(when-let ((_(save-match-data (not (nth 8 (syntax-ppss))))) (when-let*
((_(save-match-data (not (nth 8 (syntax-ppss)))))
(expr (ignore-errors (expr (ignore-errors
(read-positioning-symbols (current-buffer))))) (read-positioning-symbols (current-buffer)))))
(put-text-property (match-beginning 0) (point) (put-text-property (match-beginning 0) (point)
+4 -4
View File
@@ -1,14 +1,14 @@
;; -*- no-byte-compile: t; lexical-binding: nil -*- ;; -*- no-byte-compile: t; lexical-binding: nil -*-
(define-package "magit-section" "20251220.917" (define-package "magit-section" "20260330.1102"
"Sections for read-only buffers." "Sections for read-only buffers."
'((emacs "28.1") '((emacs "28.1")
(compat "30.1") (compat "30.1")
(cond-let "0.1") (cond-let "0.2")
(llama "1.0") (llama "1.0")
(seq "2.24")) (seq "2.24"))
:url "https://github.com/magit/magit" :url "https://github.com/magit/magit"
:commit "649b4c972151c0ee495876c0d4c8c13787614886" :commit "89a51310bd8f8087c44f7ac5c902cc82dddbbe2a"
:revdesc "649b4c972151" :revdesc "89a51310bd8f"
:keywords '("tools") :keywords '("tools")
:authors '(("Jonas Bernoulli" . "emacs.magit@jonas.bernoulli.dev")) :authors '(("Jonas Bernoulli" . "emacs.magit@jonas.bernoulli.dev"))
:maintainers '(("Jonas Bernoulli" . "emacs.magit@jonas.bernoulli.dev"))) :maintainers '(("Jonas Bernoulli" . "emacs.magit@jonas.bernoulli.dev")))
+12 -10
View File
@@ -1,6 +1,6 @@
;;; magit-section.el --- Sections for read-only buffers -*- lexical-binding:t; coding:utf-8 -*- ;;; magit-section.el --- Sections for read-only buffers -*- lexical-binding:t; coding:utf-8 -*-
;; Copyright (C) 2008-2025 The Magit Project Contributors ;; Copyright (C) 2008-2026 The Magit Project Contributors
;; Author: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev> ;; Author: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
;; Maintainer: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev> ;; Maintainer: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
@@ -8,12 +8,12 @@
;; Homepage: https://github.com/magit/magit ;; Homepage: https://github.com/magit/magit
;; Keywords: tools ;; Keywords: tools
;; Package-Version: 20251220.917 ;; Package-Version: 20260330.1102
;; Package-Revision: 649b4c972151 ;; Package-Revision: 89a51310bd8f
;; Package-Requires: ( ;; Package-Requires: (
;; (emacs "28.1") ;; (emacs "28.1")
;; (compat "30.1") ;; (compat "30.1")
;; (cond-let "0.1") ;; (cond-let "0.2")
;; (llama "1.0") ;; (llama "1.0")
;; (seq "2.24")) ;; (seq "2.24"))
@@ -106,7 +106,8 @@ similar defect.")
'magit-section-keep-region-overlay "Magit-Section 4.0.0") 'magit-section-keep-region-overlay "Magit-Section 4.0.0")
(make-obsolete-variable 'magit-section-visibility-indicator (make-obsolete-variable 'magit-section-visibility-indicator
'magit-section-visibility-indicators "Magit-Section 4.5.0") 'magit-section-visibility-indicators
"Magit-Section 4.5.0")
;;; Hooks ;;; Hooks
@@ -885,10 +886,10 @@ If there is no previous sibling section, then move to the parent."
(defun magit-section-goto (arg) (defun magit-section-goto (arg)
"Run `magit-section-movement-hook'. "Run `magit-section-movement-hook'.
See info node `(magit)Section Movement'." See info node `(magit)Section Movement'."
(if (integerp arg) (cond ((integerp arg)
(progn (forward-line arg) (forward-line arg)
(setq arg (magit-current-section))) (setq arg (magit-current-section)))
(goto-char (oref arg start))) ((goto-char (oref arg start))))
(run-hook-with-args 'magit-section-movement-hook arg)) (run-hook-with-args 'magit-section-movement-hook arg))
(defun magit-section-set-window-start (section) (defun magit-section-set-window-start (section)
@@ -936,8 +937,8 @@ With a prefix argument also expand it." heading)
(oset section hidden nil) (oset section hidden nil)
(magit-section--opportunistic-wash section) (magit-section--opportunistic-wash section)
(magit-section--opportunistic-paint section) (magit-section--opportunistic-paint section)
(when-let ((beg (oref section content))) (when$ (oref section content)
(remove-overlays beg (oref section end) 'invisible t)) (remove-overlays $ (oref section end) 'invisible t))
(magit-section-maybe-update-visibility-indicator section) (magit-section-maybe-update-visibility-indicator section)
(magit-section-maybe-cache-visibility section) (magit-section-maybe-cache-visibility section)
(dolist (child (oref section children)) (dolist (child (oref section children))
@@ -2677,6 +2678,7 @@ with the variables' values as arguments, which were recorded by
;; ("and>" . "cond-let--and>") ;; ("and>" . "cond-let--and>")
;; ("and-let" . "cond-let--and-let") ;; ("and-let" . "cond-let--and-let")
;; ("if-let" . "cond-let--if-let") ;; ("if-let" . "cond-let--if-let")
;; ("when$" . "cond-let--when$")
;; ("when-let" . "cond-let--when-let") ;; ("when-let" . "cond-let--when-let")
;; ("while-let" . "cond-let--while-let") ;; ("while-let" . "cond-let--while-let")
;; ("match-string" . "match-string") ;; ("match-string" . "match-string")
+4 -4
View File
@@ -1,7 +1,7 @@
This is magit-section.info, produced by makeinfo version 7.2 from This is magit-section.info, produced by makeinfo version 7.3 from
magit-section.texi. magit-section.texi.
Copyright (C) 2015-2025 Jonas Bernoulli Copyright (C) 2015-2026 Jonas Bernoulli
<emacs.magit@jonas.bernoulli.dev> <emacs.magit@jonas.bernoulli.dev>
You can redistribute this document and/or modify it under the terms You can redistribute this document and/or modify it under the terms
@@ -34,9 +34,9 @@ packages that have nothing to do with Magit or Git.
and user options see *note (magit)Sections::. This manual documents how and user options see *note (magit)Sections::. This manual documents how
you can use sections in your own packages. you can use sections in your own packages.
This manual is for Magit-Section version 4.4.2. This manual is for Magit-Section version 4.5.0.
Copyright (C) 2015-2025 Jonas Bernoulli Copyright (C) 2015-2026 Jonas Bernoulli
<emacs.magit@jonas.bernoulli.dev> <emacs.magit@jonas.bernoulli.dev>
You can redistribute this document and/or modify it under the terms You can redistribute this document and/or modify it under the terms
+5 -4
View File
@@ -1,11 +1,12 @@
((nil ((nil
(indent-tabs-mode . nil)) (indent-tabs-mode . nil))
(emacs-lisp-mode
(checkdoc-allow-quoting-nil-and-t . t)
(lisp-indent-local-overrides . ((cond . 0) (interactive . 0))))
(makefile-mode (makefile-mode
(indent-tabs-mode . t) (indent-tabs-mode . t)
(outline-regexp . "#\\(#+\\)") (mode . outline-minor)
(mode . outline-minor)) (outline-regexp . "#\\(#+\\)"))
(emacs-lisp-mode
(checkdoc-allow-quoting-nil-and-t . t))
(git-commit-mode (git-commit-mode
(git-commit-major-mode . git-commit-elisp-text-mode)) (git-commit-major-mode . git-commit-elisp-text-mode))
(".github/PULL_REQUEST_TEMPLATE" (".github/PULL_REQUEST_TEMPLATE"
+2
View File
@@ -49,6 +49,7 @@ All Contributors
- Alex Kreisher - Alex Kreisher
- Alex Ott - Alex Ott
- Allen Li - Allen Li
- Andrea Alberti
- Andreas Fuchs - Andreas Fuchs
- Andreas Liljeqvist - Andreas Liljeqvist
- Andreas Rottmann - Andreas Rottmann
@@ -230,6 +231,7 @@ All Contributors
- Lele Gaifax - Lele Gaifax
- Lénaïc Huard - Lénaïc Huard
- Leo Liu - Leo Liu
- Leonard Lausen
- Leonardo Etcheverry - Leonardo Etcheverry
- Leo Vivier - Leo Vivier
- Li Chen - Li Chen
+187 -58
View File
@@ -1,6 +1,6 @@
;;; git-commit.el --- Edit Git commit messages -*- lexical-binding:t; coding:utf-8 -*- ;;; git-commit.el --- Edit Git commit messages -*- lexical-binding:t; coding:utf-8 -*-
;; Copyright (C) 2008-2025 The Magit Project Contributors ;; Copyright (C) 2008-2026 The Magit Project Contributors
;; Author: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev> ;; Author: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
;; Sebastian Wiesner <lunaryorn@gmail.com> ;; Sebastian Wiesner <lunaryorn@gmail.com>
@@ -110,6 +110,7 @@
(require 'transient) (require 'transient)
(require 'with-editor) (require 'with-editor)
(defvar dabbrev--abbrev-char-regexp)
(defvar diff-default-read-only) (defvar diff-default-read-only)
(defvar flyspell-generic-check-word-predicate) (defvar flyspell-generic-check-word-predicate)
(defvar font-lock-beg) (defvar font-lock-beg)
@@ -118,6 +119,12 @@
(defvar git-commit-need-summary-line) (defvar git-commit-need-summary-line)
(declare-function dabbrev--reset-global-variables "dabbrev" ())
(declare-function dabbrev-capf "dabbrev" ())
(declare-function magit-commit-diff--args "magit-commit" ())
(declare-function magit-diff--modified-defuns "magit-diff" ())
(declare-function magit-diff-arguments "magit-diff" (&optional mode))
(define-obsolete-variable-alias (define-obsolete-variable-alias
'git-commit-known-pseudo-headers 'git-commit-known-pseudo-headers
'git-commit-trailers 'git-commit-trailers
@@ -132,42 +139,6 @@
:link '(info-link "(magit)Editing Commit Messages") :link '(info-link "(magit)Editing Commit Messages")
:group 'tools) :group 'tools)
(define-minor-mode global-git-commit-mode
"Edit Git commit messages.
This global mode arranges for `git-commit-setup' to be called
when a Git commit message file is opened. That usually happens
when Git uses the Emacsclient as $GIT_EDITOR to have the user
provide such a commit message.
Loading the library `git-commit' by default enables this mode,
but the library is not automatically loaded because doing that
would pull in many dependencies and increase startup time too
much. You can either rely on `magit' loading this library or
you can load it explicitly. Autoloading is not an alternative
because in this case autoloading would immediately trigger
full loading."
:group 'git-commit
:type 'boolean
:global t
:init-value t
:initialize
(lambda (symbol exp)
(custom-initialize-default symbol exp)
(when global-git-commit-mode
(add-hook 'find-file-hook #'git-commit-setup-check-buffer)
(remove-hook 'after-change-major-mode-hook
#'git-commit-setup-font-lock-in-buffer)))
(cond
(global-git-commit-mode
(add-hook 'find-file-hook #'git-commit-setup-check-buffer)
(add-hook 'after-change-major-mode-hook
#'git-commit-setup-font-lock-in-buffer))
(t
(remove-hook 'find-file-hook #'git-commit-setup-check-buffer)
(remove-hook 'after-change-major-mode-hook
#'git-commit-setup-font-lock-in-buffer))))
(defcustom git-commit-major-mode #'text-mode (defcustom git-commit-major-mode #'text-mode
"Major mode used to edit Git commit messages. "Major mode used to edit Git commit messages.
@@ -198,9 +169,11 @@ Also note that `git-commit-mode' (which see) is not a major-mode.")
(defcustom git-commit-setup-hook (defcustom git-commit-setup-hook
(list #'git-commit-ensure-comment-gap (list #'git-commit-ensure-comment-gap
#'git-commit-save-message #'git-commit-save-message
#'git-commit-setup-capf
#'git-commit-setup-changelog-support #'git-commit-setup-changelog-support
#'git-commit-turn-on-auto-fill #'git-commit-setup-auto-fill
#'git-commit-propertize-diff #'git-commit-propertize-diff
#'git-commit-collapse-diff
#'bug-reference-mode) #'bug-reference-mode)
"Hook run at the end of `git-commit-setup'." "Hook run at the end of `git-commit-setup'."
:group 'git-commit :group 'git-commit
@@ -208,12 +181,14 @@ Also note that `git-commit-mode' (which see) is not a major-mode.")
:get #'magit-hook-custom-get :get #'magit-hook-custom-get
:options '(git-commit-ensure-comment-gap :options '(git-commit-ensure-comment-gap
git-commit-save-message git-commit-save-message
git-commit-setup-capf
git-commit-setup-changelog-support git-commit-setup-changelog-support
magit-generate-changelog magit-generate-changelog
git-commit-turn-on-auto-fill git-commit-setup-auto-fill
git-commit-turn-on-orglink git-commit-setup-orglink
git-commit-turn-on-flyspell git-commit-setup-flyspell
git-commit-propertize-diff git-commit-propertize-diff
git-commit-collapse-diff
bug-reference-mode)) bug-reference-mode))
(defcustom git-commit-finish-query-functions (defcustom git-commit-finish-query-functions
@@ -363,6 +338,11 @@ In this context a \"keyword\" is text surrounded by brackets."
"Face used for headings in commit message comments." "Face used for headings in commit message comments."
:group 'git-commit-faces) :group 'git-commit-faces)
(defface git-commit-comment-button
'((t :inherit git-commit-comment-heading :underline t))
"Face used for buttons in commit message comments."
:group 'git-commit-faces)
(defface git-commit-comment-file (defface git-commit-comment-file
'((t :inherit git-commit-trailer-value)) '((t :inherit git-commit-trailer-value))
"Face used for file names in commit message comments." "Face used for file names in commit message comments."
@@ -437,7 +417,43 @@ the redundant bindings, then set this to nil, before loading
["Cancel" with-editor-cancel t] ["Cancel" with-editor-cancel t]
["Commit" with-editor-finish t])) ["Commit" with-editor-finish t]))
;;; Hooks ;;; Global Mode
(define-minor-mode global-git-commit-mode
"Edit Git commit messages.
This global mode arranges for `git-commit-setup' to be called
when a Git commit message file is opened. That usually happens
when Git uses the Emacsclient as $GIT_EDITOR to have the user
provide such a commit message.
Loading the library `git-commit' by default enables this mode,
but the library is not automatically loaded because doing that
would pull in many dependencies and increase startup time too
much. You can either rely on `magit' loading this library or
you can load it explicitly. Autoloading is not an alternative
because in this case autoloading would immediately trigger
full loading."
:group 'git-commit
:type 'boolean
:global t
:init-value t
:initialize
(lambda (symbol exp)
(custom-initialize-default symbol exp)
(when global-git-commit-mode
(add-hook 'find-file-hook #'git-commit-setup-check-buffer)
(remove-hook 'after-change-major-mode-hook
#'git-commit-setup-font-lock-in-buffer)))
(cond
(global-git-commit-mode
(add-hook 'find-file-hook #'git-commit-setup-check-buffer)
(add-hook 'after-change-major-mode-hook
#'git-commit-setup-font-lock-in-buffer))
(t
(remove-hook 'find-file-hook #'git-commit-setup-check-buffer)
(remove-hook 'after-change-major-mode-hook
#'git-commit-setup-font-lock-in-buffer))))
(defconst git-commit-filename-regexp "/\\(\ (defconst git-commit-filename-regexp "/\\(\
\\(\\(COMMIT\\|NOTES\\|PULLREQ\\|MERGEREQ\\|TAG\\)_EDIT\\|MERGE_\\|\\)MSG\ \\(\\(COMMIT\\|NOTES\\|PULLREQ\\|MERGEREQ\\|TAG\\)_EDIT\\|MERGE_\\|\\)MSG\
@@ -458,8 +474,6 @@ the redundant bindings, then set this to nil, before loading
(string-match-p git-commit-filename-regexp buffer-file-name)) (string-match-p git-commit-filename-regexp buffer-file-name))
(git-commit-setup))) (git-commit-setup)))
(defvar git-commit-mode)
(defun git-commit-file-not-found () (defun git-commit-file-not-found ()
;; cygwin git will pass a cygwin path (/cygdrive/c/foo/.git/...), ;; cygwin git will pass a cygwin path (/cygdrive/c/foo/.git/...),
;; try to handle this in window-nt Emacs. ;; try to handle this in window-nt Emacs.
@@ -480,6 +494,10 @@ the redundant bindings, then set this to nil, before loading
(when (eq system-type 'windows-nt) (when (eq system-type 'windows-nt)
(add-hook 'find-file-not-found-functions #'git-commit-file-not-found)) (add-hook 'find-file-not-found-functions #'git-commit-file-not-found))
;;; Local Mode
(defvar git-commit-mode)
(defconst git-commit-default-usage-message "\ (defconst git-commit-default-usage-message "\
Type \\[with-editor-finish] to finish, \ Type \\[with-editor-finish] to finish, \
\\[with-editor-cancel] to cancel, and \ \\[with-editor-cancel] to cancel, and \
@@ -504,6 +522,12 @@ Used as the local value of `header-line-format', in buffer using
(setq git-commit-usage-message nil) ; show a shorter message") (setq git-commit-usage-message nil) ; show a shorter message")
(defun git-commit-setup () (defun git-commit-setup ()
;; If an error occurs when `emacsclient' is used, and it turns out
;; to not be triggered by something in this function, then another
;; likely source are functions on `server-switch-hook'. Debugging
;; is suppressed while running that hook, so it may be necessary to
;; force debugging by modifying those functions directly. Enabling
;; `magit-process-record-invocations' may also help.
(let ((gitdir default-directory) (let ((gitdir default-directory)
(cd (and git-commit-cd-to-toplevel (cd (and git-commit-cd-to-toplevel
(or (car (rassoc default-directory magit--separated-gitdirs)) (or (car (rassoc default-directory magit--separated-gitdirs))
@@ -568,9 +592,9 @@ Used as the local value of `header-line-format', in buffer using
(with-demoted-errors "Error running git-commit-setup-hook: %S" (with-demoted-errors "Error running git-commit-setup-hook: %S"
(run-hooks 'git-commit-setup-hook)) (run-hooks 'git-commit-setup-hook))
(set-buffer-modified-p nil) (set-buffer-modified-p nil)
(when-let ((format git-commit-header-line-format)) (when$ git-commit-header-line-format
(setq header-line-format (setq header-line-format
(if (stringp format) (substitute-command-keys format) format))) (if (stringp $) (substitute-command-keys $) $)))
(when git-commit-usage-message (when git-commit-usage-message
(setq with-editor-usage-message git-commit-usage-message)) (setq with-editor-usage-message git-commit-usage-message))
(with-editor-usage-message)) (with-editor-usage-message))
@@ -585,6 +609,8 @@ used."
(put 'git-commit-mode 'permanent-local t) (put 'git-commit-mode 'permanent-local t)
;;; Setup
(defun git-commit-ensure-comment-gap () (defun git-commit-ensure-comment-gap ()
"Separate initial empty line from initial comment. "Separate initial empty line from initial comment.
If the buffer begins with an empty line followed by a comment, insert If the buffer begins with an empty line followed by a comment, insert
@@ -595,25 +621,36 @@ the input isn't tacked to the comment."
(when (looking-at (format "\\`\n%s" comment-start)) (when (looking-at (format "\\`\n%s" comment-start))
(open-line 1)))) (open-line 1))))
(defun git-commit-setup-capf ()
"Teach `complete-symbol' about `dabbrev-capf'.
When \"git commit\"'s \"--verbose\" argument is used, this allows
completing modified symbols and other text appearing in the diff."
(require 'dabbrev)
(unless dabbrev--abbrev-char-regexp
;; Initialize (not "reset") variables. See #5545.
(dabbrev--reset-global-variables))
(add-hook 'completion-at-point-functions #'dabbrev-capf -90 t))
(defun git-commit-setup-changelog-support () (defun git-commit-setup-changelog-support ()
"Treat ChangeLog entries as unindented paragraphs." "Treat ChangeLog entries as unindented paragraphs."
(setq-local fill-paragraph-function #'log-edit-fill-entry) (setq-local fill-paragraph-function #'log-edit-fill-entry)
(setq-local fill-indent-according-to-mode t) (setq-local fill-indent-according-to-mode t)
(setq-local paragraph-start (concat paragraph-start "\\|\\*\\|("))) (setq-local paragraph-start (concat paragraph-start "\\|\\*\\|(")))
(defun git-commit-turn-on-auto-fill () (defun git-commit-setup-auto-fill ()
"Unconditionally turn on Auto Fill mode. "Unconditionally turn on Auto Fill mode.
Ensure auto filling happens everywhere, except in the summary line." Ensure auto filling happens everywhere, except in the summary line."
(auto-fill-mode 1) (auto-fill-mode 1)
(setq-local comment-auto-fill-only-comments nil) (setq-local comment-auto-fill-only-comments nil)
(when git-commit-need-summary-line (when git-commit-need-summary-line
(setq-local auto-fill-function #'git-commit-auto-fill-except-summary))) (setq-local auto-fill-function #'git-commit--auto-fill-except-summary)))
(defun git-commit-auto-fill-except-summary () (defun git-commit--auto-fill-except-summary ()
"Do not fill summary line."
(unless (eq (line-beginning-position) 1) (unless (eq (line-beginning-position) 1)
(do-auto-fill))) (do-auto-fill)))
(defun git-commit-turn-on-orglink () (defun git-commit-setup-orglink ()
"Turn on Orglink mode if it is available. "Turn on Orglink mode if it is available.
If `git-commit-major-mode' is `org-mode', then silently forgo If `git-commit-major-mode' is `org-mode', then silently forgo
turning on `orglink-mode'." turning on `orglink-mode'."
@@ -623,15 +660,14 @@ turning on `orglink-mode'."
(setq-local orglink-match-anywhere t) (setq-local orglink-match-anywhere t)
(orglink-mode 1))) (orglink-mode 1)))
(defun git-commit-turn-on-flyspell () (defun git-commit-setup-flyspell ()
"Unconditionally turn on Flyspell mode. "Unconditionally turn on Flyspell mode.
Also check text that is already in the buffer, while avoiding to check Also check text that is already in the buffer, while avoiding to check
most text that Git will strip from the final message, such as the last most text that Git will strip from the final message, such as the last
comment and anything below the cut line (\"--- >8 ---\")." comment and anything below the cut line (\"--- >8 ---\")."
(require 'flyspell) (require 'flyspell)
(flyspell-mode 1) (flyspell-mode 1)
(setq flyspell-generic-check-word-predicate (setq flyspell-generic-check-word-predicate #'git-commit--flyspell-verify)
#'git-commit-flyspell-verify)
(let ((end nil) (let ((end nil)
;; The "cut line" is defined in "git/wt-status.c". It appears ;; The "cut line" is defined in "git/wt-status.c". It appears
;; in the commit message when `commit.verbose' is set to true. ;; in the commit message when `commit.verbose' is set to true.
@@ -647,10 +683,37 @@ comment and anything below the cut line (\"--- >8 ---\")."
(setq end (point))) (setq end (point)))
(flyspell-region (point-min) end))) (flyspell-region (point-min) end)))
(defun git-commit-flyspell-verify () (defun git-commit--flyspell-verify ()
"Do not check spelling in comments."
(not (= (char-after (line-beginning-position)) (not (= (char-after (line-beginning-position))
(aref comment-start 0)))) (aref comment-start 0))))
(defun git-commit-collapse-diff ()
"Collapse inline diff and add button to allow expanding it."
(save-excursion
(goto-char (point-min))
(when (re-search-forward (format "%s -+ >8 -+" comment-start) nil t)
(let ((elt '(git-commit-diff t)))
(add-to-invisibility-spec elt)
(make-button (line-beginning-position) (point)
'face 'git-commit-comment-button
'keymap (define-keymap :parent button-map
"<return>" #'push-button
"<tab>" #'push-button)
'action (lambda (_)
(if (memq elt buffer-invisibility-spec)
(remove-from-invisibility-spec elt)
(add-to-invisibility-spec elt))
;; KLUDGE Force "redisplay".
(when-let ((w1 (selected-window))
(w2 (next-window)))
(select-window w2)
(select-window w1)))))
(let ((ov (make-overlay (point) (point-max))))
(overlay-put ov 'invisible 'git-commit-diff)))))
;;; Finish
(defun git-commit-finish-query-functions (force) (defun git-commit-finish-query-functions (force)
(run-hook-with-args-until-failure (run-hook-with-args-until-failure
'git-commit-finish-query-functions force)) 'git-commit-finish-query-functions force))
@@ -784,6 +847,55 @@ Save current message first."
(setq str (replace-match "\n" t t str))) (setq str (replace-match "\n" t t str)))
str)))) str))))
;;; Changelog
(defun git-commit--modified-defuns ()
(if (save-excursion
(goto-char (point-min))
(re-search-forward "^diff --git" nil t))
(magit-diff--modified-defuns)
(with-temp-buffer
(pcase-let ((`(,rev ,arg) (magit-commit-diff--args)))
(save-excursion
(magit-git-insert "diff" "-p" arg (car (magit-diff-arguments)) rev)))
(magit-diff--modified-defuns))))
;;;###autoload
(defun git-commit-insert-changelog-gnu ()
"Insert a GNU-style changelog at point while authorig a commit message.
The modified definitions are extracted from the diff in the message
buffer, which is only available if \"git commit\" was invoked with
\"--verbose\"."
(interactive)
(unless git-commit-mode
(user-error "Not in a commit message buffer"))
;; Like `change-log-insert-entries'.
(pcase-dolist (`(,file . ,defuns) (git-commit--modified-defuns))
(if (not defuns)
(insert "* " file ":\n")
(insert "* " file " ")
(dolist (def defuns)
(insert "(" def "):\n")))))
;;;###autoload
(defun git-commit-insert-changelog-plain ()
"Insert a simple changelog at point while authorig a commit message.
Defuns are slightly indented and quoted like in elisp docstrings.
The exact format is still subject to change.
The modified definitions are extracted from the diff in the message
buffer, which is only available if \"git commit\" was invoked with
\"--verbose\"."
(interactive)
(unless git-commit-mode
(user-error "Not in a commit message buffer"))
(pcase-dolist (`(,file . ,defuns) (git-commit--modified-defuns))
(insert file ":\n")
(dolist (def defuns)
(insert " `" def "'\n"))))
;;; Trailers ;;; Trailers
(transient-define-prefix git-commit-insert-trailer () (transient-define-prefix git-commit-insert-trailer ()
@@ -793,19 +905,22 @@ See also manpage git-interpret-trailer(1). This command does
not use that Git command, but the initial description still not use that Git command, but the initial description still
serves as a good introduction." serves as a good introduction."
[[:description (##cond (prefix-arg [[:description (##cond (prefix-arg
"Insert ... by someone ") "Insert trailer ... by someone ")
("Insert ... by yourself")) ("Insert trailer ... by yourself"))
("a" "Ack" git-commit-ack) ("a" "Ack" git-commit-ack)
("m" "Modified" git-commit-modified) ("m" "Modified" git-commit-modified)
("r" "Reviewed" git-commit-review) ("r" "Reviewed" git-commit-review)
("s" "Signed-off" git-commit-signoff) ("s" "Signed-off" git-commit-signoff)
("t" "Tested" git-commit-test)] ("t" "Tested" git-commit-test)]
["Insert ... by someone" ["Insert trailer ... by someone"
("C-c" "Cc" git-commit-cc) ("C-c" "Cc" git-commit-cc)
("C-r" "Reported" git-commit-reported) ("C-r" "Reported" git-commit-reported)
("C-i" "Suggested" git-commit-suggested) ("C-i" "Suggested" git-commit-suggested)
("C-a" "Co-authored" git-commit-co-authored) ("C-a" "Co-authored" git-commit-co-authored)
("C-d" "Co-developed" git-commit-co-developed)]]) ("C-d" "Co-developed" git-commit-co-developed)]]
["Insert changelog"
("l g" "GNU-style" git-commit-insert-changelog-gnu)
("l p" "plain" git-commit-insert-changelog-plain)])
(defun git-commit-ack (name mail) (defun git-commit-ack (name mail)
"Insert a trailer acknowledging that you have looked at the commit." "Insert a trailer acknowledging that you have looked at the commit."
@@ -1225,6 +1340,19 @@ commit, then the hook is not run at all."
'git-commit-trailer-token 'git-commit-trailer-token
"git-commit 4.0.0") "git-commit 4.0.0")
(define-obsolete-function-alias
'git-commit-turn-on-auto-fill
'git-commit-setup-auto-fill
"git-commit 4.6.0")
(define-obsolete-function-alias
'git-commit-turn-on-flyspell
'git-commit-setup-flyspell
"git-commit 4.6.0")
(define-obsolete-function-alias
'git-commit-turn-on-orglink
'git-commit-setup-orglink
"git-commit 4.6.0")
(provide 'git-commit) (provide 'git-commit)
;; Local Variables: ;; Local Variables:
;; read-symbol-shorthands: ( ;; read-symbol-shorthands: (
@@ -1232,6 +1360,7 @@ commit, then the hook is not run at all."
;; ("and>" . "cond-let--and>") ;; ("and>" . "cond-let--and>")
;; ("and-let" . "cond-let--and-let") ;; ("and-let" . "cond-let--and-let")
;; ("if-let" . "cond-let--if-let") ;; ("if-let" . "cond-let--if-let")
;; ("when$" . "cond-let--when$")
;; ("when-let" . "cond-let--when-let") ;; ("when-let" . "cond-let--when-let")
;; ("while-let" . "cond-let--while-let") ;; ("while-let" . "cond-let--while-let")
;; ("match-string" . "match-string") ;; ("match-string" . "match-string")
+2 -1
View File
@@ -1,6 +1,6 @@
;;; git-rebase.el --- Edit Git rebase files -*- lexical-binding:t -*- ;;; git-rebase.el --- Edit Git rebase files -*- lexical-binding:t -*-
;; Copyright (C) 2008-2025 The Magit Project Contributors ;; Copyright (C) 2008-2026 The Magit Project Contributors
;; Author: Phil Jackson <phil@shellarchive.co.uk> ;; Author: Phil Jackson <phil@shellarchive.co.uk>
;; Maintainer: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev> ;; Maintainer: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
@@ -948,6 +948,7 @@ is used as a value for `imenu-extract-index-name-function'."
;; ("and>" . "cond-let--and>") ;; ("and>" . "cond-let--and>")
;; ("and-let" . "cond-let--and-let") ;; ("and-let" . "cond-let--and-let")
;; ("if-let" . "cond-let--if-let") ;; ("if-let" . "cond-let--if-let")
;; ("when$" . "cond-let--when$")
;; ("when-let" . "cond-let--when-let") ;; ("when-let" . "cond-let--when-let")
;; ("while-let" . "cond-let--while-let") ;; ("while-let" . "cond-let--while-let")
;; ("match-string" . "match-string") ;; ("match-string" . "match-string")
+29 -28
View File
@@ -1,6 +1,6 @@
;;; magit-apply.el --- Apply Git diffs -*- lexical-binding:t -*- ;;; magit-apply.el --- Apply Git diffs -*- lexical-binding:t -*-
;; Copyright (C) 2008-2025 The Magit Project Contributors ;; Copyright (C) 2008-2026 The Magit Project Contributors
;; Author: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev> ;; Author: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
;; Maintainer: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev> ;; Maintainer: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
@@ -115,19 +115,19 @@ is a member of `magit-post-unstage-hook-commands'."
With a prefix argument fallback to a 3-way merge. Doing With a prefix argument fallback to a 3-way merge. Doing
so causes the change to be applied to the index as well." so causes the change to be applied to the index as well."
(interactive (and current-prefix-arg (list "--3way"))) (interactive (and current-prefix-arg (list "--3way")))
(when-let ((s (magit-apply--get-selection))) (when$ (magit-apply--get-selection)
(pcase (list (magit-diff-type) (magit-diff-scope)) (pcase (list (magit-diff-type) (magit-diff-scope))
(`(,(or 'unstaged 'staged) ,_) (`(,(or 'unstaged 'staged) ,_)
(user-error "Change is already in the working tree")) (user-error "Change is already in the working tree"))
(`(untracked ,(or 'file 'files)) (`(untracked ,(or 'file 'files))
(call-interactively #'magit-am)) (call-interactively #'magit-am))
(`(,_ region) (magit-apply-region s args)) (`(,_ region) (magit-apply-region $ args))
(`(,_ hunk) (magit-apply-hunk s args)) (`(,_ hunk) (magit-apply-hunk $ args))
(`(,_ hunks) (magit-apply-hunks s args)) (`(,_ hunks) (magit-apply-hunks $ args))
(`(rebase-sequence file) (`(rebase-sequence file)
(call-interactively #'magit-patch-apply)) (call-interactively #'magit-patch-apply))
(`(,_ file) (magit-apply-diff s args)) (`(,_ file) (magit-apply-diff $ args))
(`(,_ files) (magit-apply-diffs s args))))) (`(,_ files) (magit-apply-diffs $ args)))))
(defun magit-apply--section-content (section) (defun magit-apply--section-content (section)
(buffer-substring-no-properties (if (magit-hunk-section-p section) (buffer-substring-no-properties (if (magit-hunk-section-p section)
@@ -488,17 +488,17 @@ On a hunk or file with unresolved conflicts prompt which side to
keep (while discarding the other). If point is within the text keep (while discarding the other). If point is within the text
of a side, then keep that side without prompting." of a side, then keep that side without prompting."
(interactive) (interactive)
(when-let ((s (magit-apply--get-selection))) (when$ (magit-apply--get-selection)
(pcase (list (magit-diff-type) (magit-diff-scope)) (pcase (list (magit-diff-type) (magit-diff-scope))
(`(committed ,_) (user-error "Cannot discard committed changes")) (`(committed ,_) (user-error "Cannot discard committed changes"))
(`(undefined ,_) (user-error "Cannot discard this change")) (`(undefined ,_) (user-error "Cannot discard this change"))
(`(untracked list) (magit-discard-untracked)) (`(untracked list) (magit-discard-untracked))
(`(,_ region) (magit-discard-region s)) (`(,_ region) (magit-discard-region $))
(`(,_ hunk) (magit-discard-hunk s)) (`(,_ hunk) (magit-discard-hunk $))
(`(,_ hunks) (magit-discard-hunks s)) (`(,_ hunks) (magit-discard-hunks $))
(`(,_ file) (magit-discard-file s)) (`(,_ file) (magit-discard-file $))
(`(,_ files) (magit-discard-files s)) (`(,_ files) (magit-discard-files $))
(`(,_ list) (magit-discard-files s))))) (`(,_ list) (magit-discard-files $)))))
(defun magit-discard-untracked () (defun magit-discard-untracked ()
(magit-discard-files--delete (magit-discard-files--delete
@@ -642,13 +642,13 @@ of a side, then keep that side without prompting."
files)) files))
(dolist (file files) (dolist (file files)
(let ((orig (cadr (assoc file status)))) (let ((orig (cadr (assoc file status))))
(if (file-exists-p file) (cond ((file-exists-p file)
(progn (when$ (file-name-directory orig)
(when-let ((path (file-name-directory orig))) (make-directory $ t))
(make-directory path t))
(magit-call-git "mv" file orig)) (magit-call-git "mv" file orig))
(t
(magit-call-git "rm" "--cached" "--" file) (magit-call-git "rm" "--cached" "--" file)
(magit-call-git "reset" "--" orig))))) (magit-call-git "reset" "--" orig))))))
(defun magit-discard-files--discard (sections new-files) (defun magit-discard-files--discard (sections new-files)
(let ((files (mapcar (##oref % value) sections))) (let ((files (mapcar (##oref % value) sections)))
@@ -684,16 +684,16 @@ of a side, then keep that side without prompting."
With a prefix argument fallback to a 3-way merge. Doing With a prefix argument fallback to a 3-way merge. Doing
so causes the change to be applied to the index as well." so causes the change to be applied to the index as well."
(interactive (and current-prefix-arg (list "--3way"))) (interactive (and current-prefix-arg (list "--3way")))
(when-let ((s (magit-apply--get-selection))) (when$ (magit-apply--get-selection)
(pcase (list (magit-diff-type) (magit-diff-scope)) (pcase (list (magit-diff-type) (magit-diff-scope))
(`(untracked ,_) (user-error "Cannot reverse untracked changes")) (`(untracked ,_) (user-error "Cannot reverse untracked changes"))
(`(unstaged ,_) (user-error "Cannot reverse unstaged changes")) (`(unstaged ,_) (user-error "Cannot reverse unstaged changes"))
(`(,_ region) (magit-reverse-region s args)) (`(,_ region) (magit-reverse-region $ args))
(`(,_ hunk) (magit-reverse-hunk s args)) (`(,_ hunk) (magit-reverse-hunk $ args))
(`(,_ hunks) (magit-reverse-hunks s args)) (`(,_ hunks) (magit-reverse-hunks $ args))
(`(,_ file) (magit-reverse-file s args)) (`(,_ file) (magit-reverse-file $ args))
(`(,_ files) (magit-reverse-files s args)) (`(,_ files) (magit-reverse-files $ args))
(`(,_ list) (magit-reverse-files s args))))) (`(,_ list) (magit-reverse-files $ args)))))
(defun magit-reverse-region (section args) (defun magit-reverse-region (section args)
(magit-confirm 'reverse "Reverse region") (magit-confirm 'reverse "Reverse region")
@@ -717,9 +717,9 @@ so causes the change to be applied to the index as well."
(pcase-let ((`(,binaries ,sections) (pcase-let ((`(,binaries ,sections)
(let ((bs (magit-binary-files (let ((bs (magit-binary-files
(cond ((derived-mode-p 'magit-revision-mode) (cond ((derived-mode-p 'magit-revision-mode)
magit-buffer-range) magit-buffer-diff-range)
((derived-mode-p 'magit-diff-mode) ((derived-mode-p 'magit-diff-mode)
magit-buffer-range) magit-buffer-diff-range)
("--cached"))))) ("--cached")))))
(magit--separate (##member (oref % value) bs) (magit--separate (##member (oref % value) bs)
sections)))) sections))))
@@ -822,6 +822,7 @@ a separate commit. A typical workflow would be:
;; ("and>" . "cond-let--and>") ;; ("and>" . "cond-let--and>")
;; ("and-let" . "cond-let--and-let") ;; ("and-let" . "cond-let--and-let")
;; ("if-let" . "cond-let--if-let") ;; ("if-let" . "cond-let--if-let")
;; ("when$" . "cond-let--when$")
;; ("when-let" . "cond-let--when-let") ;; ("when-let" . "cond-let--when-let")
;; ("while-let" . "cond-let--while-let") ;; ("while-let" . "cond-let--while-let")
;; ("match-string" . "match-string") ;; ("match-string" . "match-string")
+1 -1
View File
@@ -1,6 +1,6 @@
;;; magit-autorevert.el --- Revert buffers when files in repository change -*- lexical-binding:t -*- ;;; magit-autorevert.el --- Revert buffers when files in repository change -*- lexical-binding:t -*-
;; Copyright (C) 2008-2025 The Magit Project Contributors ;; Copyright (C) 2008-2026 The Magit Project Contributors
;; Author: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev> ;; Author: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
;; Maintainer: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev> ;; Maintainer: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
+32 -3
View File
@@ -1,6 +1,6 @@
;;; magit-base.el --- Early birds -*- lexical-binding:t; coding:utf-8 -*- ;;; magit-base.el --- Early birds -*- lexical-binding:t; coding:utf-8 -*-
;; Copyright (C) 2008-2025 The Magit Project Contributors ;; Copyright (C) 2008-2026 The Magit Project Contributors
;; Author: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev> ;; Author: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
;; Maintainer: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev> ;; Maintainer: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
@@ -494,7 +494,7 @@ and delay of your graphical environment or operating system."
(defclass magit-hunk-section (magit-diff-section) (defclass magit-hunk-section (magit-diff-section)
((keymap :initform 'magit-hunk-section-map) ((keymap :initform 'magit-hunk-section-map)
(painted :initform nil) (painted :initform nil)
(fontified :initform nil) ;TODO (fontified :initform nil)
(refined :initform nil) (refined :initform nil)
(combined :initform nil :initarg :combined) (combined :initform nil :initarg :combined)
(from-range :initform nil :initarg :from-range) (from-range :initform nil :initarg :from-range)
@@ -824,7 +824,7 @@ ACTION is a member of option `magit-slow-confirm'."
(or (cond ((and (not (eq action t)) (or (cond ((and (not (eq action t))
(or (eq magit-no-confirm t) (or (eq magit-no-confirm t)
(memq action magit-no-confirm) (memq action magit-no-confirm)
(cl-member-if (pcase-lambda (`(,key ,var . ,sub)) (magit--any (pcase-lambda (`(,key ,var . ,sub))
(and (memq key magit-no-confirm) (and (memq key magit-no-confirm)
(memq action sub) (memq action sub)
(or (not var) (or (not var)
@@ -1013,6 +1013,24 @@ This function should be named `version>' and be part of Emacs."
This function should be named `version>=' and be part of Emacs." This function should be named `version>=' and be part of Emacs."
(version-list-<= (version-to-list v2) (version-to-list v1))) (version-list-<= (version-to-list v2) (version-to-list v1)))
(defun magit--delete-text-properties (string &optional props)
"Delete text properties PROPS from STRING and return it.
If PROPS is nil, remove all properties. To leave STRING unchanged
and return a new string, instead use `magit--remove-text-properties'."
(set-text-properties 0 (length string) props string)
string)
(defun magit--remove-text-properties (string &optional props)
"Return a copy of STRING with text properties PROPS removed.
If PROPS is nil, remove all properties."
(magit--delete-text-properties (copy-sequence string) props))
;;; Emacs Compatibility
(static-if (fboundp 'member-if) ; Emacs 31.1
(defalias 'magit--any 'member-if)
(defalias 'magit--any 'cl-member-if))
;;; Kludges for Emacs Bugs ;;; Kludges for Emacs Bugs
(defun magit-which-function () (defun magit-which-function ()
@@ -1187,6 +1205,16 @@ Like `message', except that `message-log-max' is bound to nil."
(push char quoted)) (push char quoted))
(concat (nreverse quoted)))) (concat (nreverse quoted))))
(defun magit--find-buffer (&rest plist)
"Like `find-buffer' but take multiple VARIABLE-VALUE pairs."
(seq-find (lambda (buf)
(while (and plist
(equal (buffer-local-value (car plist) buf)
(cadr plist)))
(setq plist (cddr plist)))
(not plist))
(buffer-list)))
;;; _ ;;; _
(provide 'magit-base) (provide 'magit-base)
;; Local Variables: ;; Local Variables:
@@ -1195,6 +1223,7 @@ Like `message', except that `message-log-max' is bound to nil."
;; ("and>" . "cond-let--and>") ;; ("and>" . "cond-let--and>")
;; ("and-let" . "cond-let--and-let") ;; ("and-let" . "cond-let--and-let")
;; ("if-let" . "cond-let--if-let") ;; ("if-let" . "cond-let--if-let")
;; ("when$" . "cond-let--when$")
;; ("when-let" . "cond-let--when-let") ;; ("when-let" . "cond-let--when-let")
;; ("while-let" . "cond-let--while-let") ;; ("while-let" . "cond-let--while-let")
;; ("match-string" . "match-string") ;; ("match-string" . "match-string")
+2 -1
View File
@@ -1,6 +1,6 @@
;;; magit-bisect.el --- Bisect support for Magit -*- lexical-binding:t -*- ;;; magit-bisect.el --- Bisect support for Magit -*- lexical-binding:t -*-
;; Copyright (C) 2008-2025 The Magit Project Contributors ;; Copyright (C) 2008-2026 The Magit Project Contributors
;; Author: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev> ;; Author: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
;; Maintainer: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev> ;; Maintainer: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
@@ -321,6 +321,7 @@ bisect run'."
;; ("and>" . "cond-let--and>") ;; ("and>" . "cond-let--and>")
;; ("and-let" . "cond-let--and-let") ;; ("and-let" . "cond-let--and-let")
;; ("if-let" . "cond-let--if-let") ;; ("if-let" . "cond-let--if-let")
;; ("when$" . "cond-let--when$")
;; ("when-let" . "cond-let--when-let") ;; ("when-let" . "cond-let--when-let")
;; ("while-let" . "cond-let--while-let") ;; ("while-let" . "cond-let--while-let")
;; ("match-string" . "match-string") ;; ("match-string" . "match-string")
+5 -4
View File
@@ -1,6 +1,6 @@
;;; magit-blame.el --- Blame support for Magit -*- lexical-binding:t -*- ;;; magit-blame.el --- Blame support for Magit -*- lexical-binding:t -*-
;; Copyright (C) 2008-2025 The Magit Project Contributors ;; Copyright (C) 2008-2026 The Magit Project Contributors
;; Author: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev> ;; Author: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
;; Maintainer: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev> ;; Maintainer: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
@@ -261,7 +261,7 @@ Also see option `magit-blame-styles'."
(or (and (not (and type (not (eq type magit-blame-type)))) (or (and (not (and type (not (eq type magit-blame-type))))
(magit-blame-chunk-at (point))) (magit-blame-chunk-at (point)))
(and type (and type
(let ((rev (or magit-buffer-refname magit-buffer-revision)) (let ((rev magit-buffer-revision)
(file (and (not (derived-mode-p 'dired-mode)) (file (and (not (derived-mode-p 'dired-mode))
(magit-file-relative-name (magit-file-relative-name
nil (not magit-buffer-file-name)))) nil (not magit-buffer-file-name))))
@@ -418,8 +418,8 @@ modes is toggled, then this mode also gets toggled automatically.
(magit-blame-mode 1)) (magit-blame-mode 1))
(message "Blaming...") (message "Blaming...")
(magit-blame-run-process (magit-blame-run-process
(and$ (or magit-buffer-refname magit-buffer-revision) (and (not (equal magit-buffer-revision "{index}"))
(and (not (equal $ "{index}")) $)) magit-buffer-revision)
(magit-file-relative-name nil (not magit-buffer-file-name)) (magit-file-relative-name nil (not magit-buffer-file-name))
(if (memq magit-blame-type '(final removal)) (if (memq magit-blame-type '(final removal))
(cons "--reverse" args) (cons "--reverse" args)
@@ -1006,6 +1006,7 @@ instead of the hash, like `kill-ring-save' would."
;; ("and>" . "cond-let--and>") ;; ("and>" . "cond-let--and>")
;; ("and-let" . "cond-let--and-let") ;; ("and-let" . "cond-let--and-let")
;; ("if-let" . "cond-let--if-let") ;; ("if-let" . "cond-let--if-let")
;; ("when$" . "cond-let--when$")
;; ("when-let" . "cond-let--when-let") ;; ("when-let" . "cond-let--when-let")
;; ("while-let" . "cond-let--while-let") ;; ("while-let" . "cond-let--while-let")
;; ("match-string" . "match-string") ;; ("match-string" . "match-string")
+16 -14
View File
@@ -1,6 +1,6 @@
;;; magit-bookmark.el --- Bookmarks for Magit buffers -*- lexical-binding:t -*- ;;; magit-bookmark.el --- Bookmarks for Magit buffers -*- lexical-binding:t -*-
;; Copyright (C) 2008-2025 The Magit Project Contributors ;; Copyright (C) 2008-2026 The Magit Project Contributors
;; Inspired by an earlier implementation by Yuri Khan. ;; Inspired by an earlier implementation by Yuri Khan.
@@ -56,8 +56,8 @@
;;;; Diff ;;;; Diff
(put 'magit-diff-mode 'magit-bookmark-variables (put 'magit-diff-mode 'magit-bookmark-variables
'(magit-buffer-range-hashed '(magit-buffer-diff-range-oids
magit-buffer-typearg magit-buffer-diff-typearg
magit-buffer-diff-args magit-buffer-diff-args
magit-buffer-diff-files)) magit-buffer-diff-files))
@@ -66,9 +66,10 @@
(pcase (magit-diff-type) (pcase (magit-diff-type)
('staged "staged") ('staged "staged")
('unstaged "unstaged") ('unstaged "unstaged")
('committed magit-buffer-range) ('committed magit-buffer-diff-range)
('undefined ('undefined
(delq nil (list magit-buffer-typearg magit-buffer-range-hashed)))) (delq nil
(list magit-buffer-diff-typearg magit-buffer-diff-range-oids))))
(if magit-buffer-diff-files (if magit-buffer-diff-files
(concat " -- " (string-join magit-buffer-diff-files " ")) (concat " -- " (string-join magit-buffer-diff-files " "))
""))) "")))
@@ -76,7 +77,7 @@
;;;; Revision ;;;; Revision
(put 'magit-revision-mode 'magit-bookmark-variables (put 'magit-revision-mode 'magit-bookmark-variables
'(magit-buffer-revision-hash '(magit-buffer-revision-oid
magit-buffer-diff-args magit-buffer-diff-args
magit-buffer-diff-files)) magit-buffer-diff-files))
@@ -90,7 +91,7 @@
;;;; Stash ;;;; Stash
(put 'magit-stash-mode 'magit-bookmark-variables (put 'magit-stash-mode 'magit-bookmark-variables
'(magit-buffer-revision-hash '(magit-buffer-revision-oid
magit-buffer-diff-args magit-buffer-diff-args
magit-buffer-diff-files)) magit-buffer-diff-files))
@@ -104,20 +105,20 @@
(cl-defmethod magit-bookmark--get-child-value (cl-defmethod magit-bookmark--get-child-value
(section &context (major-mode magit-stash-mode)) (section &context (major-mode magit-stash-mode))
(string-replace magit-buffer-revision (string-replace magit-buffer-revision
magit-buffer-revision-hash magit-buffer-revision-oid
(oref section value))) (oref section value)))
;;; Log ;;; Log
;;;; Log ;;;; Log
(put 'magit-log-mode 'magit-bookmark-variables (put 'magit-log-mode 'magit-bookmark-variables
'(magit-buffer-revisions '(magit-buffer-log-revisions
magit-buffer-log-args magit-buffer-log-args
magit-buffer-log-files)) magit-buffer-log-files))
(cl-defmethod magit-bookmark-name (&context (major-mode magit-log-mode)) (cl-defmethod magit-bookmark-name (&context (major-mode magit-log-mode))
(format "magit-log(%s%s)" (format "magit-log(%s%s)"
(string-join magit-buffer-revisions " ") (string-join magit-buffer-log-revisions " ")
(if magit-buffer-log-files (if magit-buffer-log-files
(concat " -- " (string-join magit-buffer-log-files " ")) (concat " -- " (string-join magit-buffer-log-files " "))
""))) "")))
@@ -126,12 +127,12 @@
(put 'magit-cherry-mode 'magit-bookmark-variables (put 'magit-cherry-mode 'magit-bookmark-variables
'(magit-buffer-refname '(magit-buffer-refname
magit-buffer-upstream)) magit-buffer-cherry-upstream))
(cl-defmethod magit-bookmark-name (&context (major-mode magit-cherry-mode)) (cl-defmethod magit-bookmark-name (&context (major-mode magit-cherry-mode))
(format "magit-cherry(%s > %s)" (format "magit-cherry(%s > %s)"
magit-buffer-refname magit-buffer-refname
magit-buffer-upstream)) magit-buffer-cherry-upstream))
;;;; Reflog ;;;; Reflog
@@ -146,8 +147,8 @@
(put 'magit-status-mode 'magit-bookmark-variables nil) (put 'magit-status-mode 'magit-bookmark-variables nil)
(put 'magit-refs-mode 'magit-bookmark-variables (put 'magit-refs-mode 'magit-bookmark-variables
'(magit-buffer-upstream '(magit-buffer-refs-upstream
magit-buffer-arguments)) magit-buffer-refs-args))
(put 'magit-stashes-mode 'magit-bookmark-variables nil) (put 'magit-stashes-mode 'magit-bookmark-variables nil)
@@ -162,6 +163,7 @@
;; ("and>" . "cond-let--and>") ;; ("and>" . "cond-let--and>")
;; ("and-let" . "cond-let--and-let") ;; ("and-let" . "cond-let--and-let")
;; ("if-let" . "cond-let--if-let") ;; ("if-let" . "cond-let--if-let")
;; ("when$" . "cond-let--when$")
;; ("when-let" . "cond-let--when-let") ;; ("when-let" . "cond-let--when-let")
;; ("while-let" . "cond-let--while-let") ;; ("while-let" . "cond-let--while-let")
;; ("match-string" . "match-string") ;; ("match-string" . "match-string")
+13 -12
View File
@@ -1,6 +1,6 @@
;;; magit-branch.el --- Branch support -*- lexical-binding:t -*- ;;; magit-branch.el --- Branch support -*- lexical-binding:t -*-
;; Copyright (C) 2008-2025 The Magit Project Contributors ;; Copyright (C) 2008-2026 The Magit Project Contributors
;; Author: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev> ;; Author: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
;; Maintainer: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev> ;; Maintainer: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
@@ -153,11 +153,11 @@ to set `magit-branch-prefer-remote-upstream' to a non-nil value.
However, I recommend that you use local branches as UPSTREAM." However, I recommend that you use local branches as UPSTREAM."
:package-version '(magit . "2.9.0") :package-version '(magit . "2.9.0")
:group 'magit-commands :group 'magit-commands
:type '(repeat (cons (string :tag "Use upstream") :type '(alist :key-type (string :tag "Use upstream")
(choice :tag "For branches" ;??? :value-type (choice :tag "For branches" ;???
(regexp :tag "Matching") (regexp :tag "Matching")
(repeat :tag "Except" (repeat :tag "Except"
(string :tag "Branch")))))) (string :tag "Branch")))))
(defcustom magit-branch-rename-push-target t (defcustom magit-branch-rename-push-target t
"Whether the push-remote setup is preserved when renaming a branch. "Whether the push-remote setup is preserved when renaming a branch.
@@ -511,8 +511,8 @@ from the source branch's upstream, then an error is raised."
(if checkout (if checkout
(magit-call-git "checkout" "-b" branch current) (magit-call-git "checkout" "-b" branch current)
(magit-call-git "branch" branch current))) (magit-call-git "branch" branch current)))
(when-let ((upstream (magit-get-indirect-upstream-branch current))) (when$ (magit-get-indirect-upstream-branch current)
(magit-call-git "branch" "--set-upstream-to" upstream branch)) (magit-call-git "branch" "--set-upstream-to" $ branch))
(when (and tracked (when (and tracked
(setq base (setq base
(if from (if from
@@ -560,8 +560,7 @@ that is being reset."
(magit-reset-hard to)) (magit-reset-hard to))
(magit-call-git "update-ref" (magit-call-git "update-ref"
"-m" (format "reset: moving to %s" to) "-m" (format "reset: moving to %s" to)
(magit-git-string "rev-parse" "--symbolic-full-name" (magit-ref-fullname branch)
branch)
to)) to))
(when (and set-upstream (magit-branch-p to)) (when (and set-upstream (magit-branch-p to))
(magit-set-upstream-branch branch to) (magit-set-upstream-branch branch to)
@@ -639,10 +638,10 @@ prompt is confusing."
(magit-rev-parse "--short" ref))) (magit-rev-parse "--short" ref)))
;; Assume the branches actually still exist on the remote. ;; Assume the branches actually still exist on the remote.
(magit-run-git-async (magit-run-git-async
"push" "push" "--delete"
(and (or force magit-branch-delete-never-verify) "--no-verify") (and (or force magit-branch-delete-never-verify) "--no-verify")
remote remote
(mapcar (##concat ":" (substring % offset)) branches)) (mapcar (##concat "refs/heads/" (substring % offset)) branches))
;; If that is not the case, then this deletes the tracking branches. ;; If that is not the case, then this deletes the tracking branches.
(set-process-sentinel (set-process-sentinel
magit-this-process magit-this-process
@@ -891,7 +890,8 @@ Also rename the respective reflog file."
(magit-run-git-with-editor "branch" "--edit-description" branch)) (magit-run-git-with-editor "branch" "--edit-description" branch))
(defclass magit--git-branch:upstream (magit--git-variable) (defclass magit--git-branch:upstream (magit--git-variable)
((format :initform " %k %m %M\n %r %R"))) ((format :initform " %k %m %M\n %r %R")
(accessible-format :initform "%k %m is %M and %r is %R")))
(transient-define-infix magit-branch.<branch>.merge/remote () (transient-define-infix magit-branch.<branch>.merge/remote ()
:class 'magit--git-branch:upstream) :class 'magit--git-branch:upstream)
@@ -919,7 +919,7 @@ Also rename the respective reflog file."
(cl-defmethod transient-format ((obj magit--git-branch:upstream)) (cl-defmethod transient-format ((obj magit--git-branch:upstream))
(let ((branch (transient-scope))) (let ((branch (transient-scope)))
(format-spec (format-spec
(oref obj format) (transient--get-format obj)
`((?k . ,(transient-format-key obj)) `((?k . ,(transient-format-key obj))
(?r . ,(format "branch.%s.remote" branch)) (?r . ,(format "branch.%s.remote" branch))
(?m . ,(format "branch.%s.merge" branch)) (?m . ,(format "branch.%s.merge" branch))
@@ -977,6 +977,7 @@ Also rename the respective reflog file."
;; ("and>" . "cond-let--and>") ;; ("and>" . "cond-let--and>")
;; ("and-let" . "cond-let--and-let") ;; ("and-let" . "cond-let--and-let")
;; ("if-let" . "cond-let--if-let") ;; ("if-let" . "cond-let--if-let")
;; ("when$" . "cond-let--when$")
;; ("when-let" . "cond-let--when-let") ;; ("when-let" . "cond-let--when-let")
;; ("while-let" . "cond-let--while-let") ;; ("while-let" . "cond-let--while-let")
;; ("match-string" . "match-string") ;; ("match-string" . "match-string")
+2 -1
View File
@@ -1,6 +1,6 @@
;;; magit-bundle.el --- Bundle support for Magit -*- lexical-binding:t -*- ;;; magit-bundle.el --- Bundle support for Magit -*- lexical-binding:t -*-
;; Copyright (C) 2008-2025 The Magit Project Contributors ;; Copyright (C) 2008-2026 The Magit Project Contributors
;; Author: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev> ;; Author: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
;; Maintainer: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev> ;; Maintainer: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
@@ -142,6 +142,7 @@
;; ("and>" . "cond-let--and>") ;; ("and>" . "cond-let--and>")
;; ("and-let" . "cond-let--and-let") ;; ("and-let" . "cond-let--and-let")
;; ("if-let" . "cond-let--if-let") ;; ("if-let" . "cond-let--if-let")
;; ("when$" . "cond-let--when$")
;; ("when-let" . "cond-let--when-let") ;; ("when-let" . "cond-let--when-let")
;; ("while-let" . "cond-let--while-let") ;; ("while-let" . "cond-let--while-let")
;; ("match-string" . "match-string") ;; ("match-string" . "match-string")
+2 -1
View File
@@ -1,6 +1,6 @@
;;; magit-clone.el --- Clone a repository -*- lexical-binding:t -*- ;;; magit-clone.el --- Clone a repository -*- lexical-binding:t -*-
;; Copyright (C) 2008-2025 The Magit Project Contributors ;; Copyright (C) 2008-2026 The Magit Project Contributors
;; Author: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev> ;; Author: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
;; Maintainer: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev> ;; Maintainer: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
@@ -354,6 +354,7 @@ Then show the status buffer for the new repository."
;; ("and>" . "cond-let--and>") ;; ("and>" . "cond-let--and>")
;; ("and-let" . "cond-let--and-let") ;; ("and-let" . "cond-let--and-let")
;; ("if-let" . "cond-let--if-let") ;; ("if-let" . "cond-let--if-let")
;; ("when$" . "cond-let--when$")
;; ("when-let" . "cond-let--when-let") ;; ("when-let" . "cond-let--when-let")
;; ("while-let" . "cond-let--while-let") ;; ("while-let" . "cond-let--while-let")
;; ("match-string" . "match-string") ;; ("match-string" . "match-string")
+33 -19
View File
@@ -1,6 +1,6 @@
;;; magit-commit.el --- Create Git commits -*- lexical-binding:t -*- ;;; magit-commit.el --- Create Git commits -*- lexical-binding:t -*-
;; Copyright (C) 2008-2025 The Magit Project Contributors ;; Copyright (C) 2008-2026 The Magit Project Contributors
;; Author: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev> ;; Author: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
;; Maintainer: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev> ;; Maintainer: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
@@ -144,6 +144,7 @@ This hook is still experimental.")
"Create a new commit or replace an existing commit." "Create a new commit or replace an existing commit."
:info-manual "(magit)Initiating a Commit" :info-manual "(magit)Initiating a Commit"
:man-page "git-commit" :man-page "git-commit"
:value '("--verbose")
["Arguments" ["Arguments"
("-a" "Stage all modified and deleted files" ("-a" "--all")) ("-a" "Stage all modified and deleted files" ("-a" "--all"))
("-e" "Allow empty commit" "--allow-empty") ("-e" "Allow empty commit" "--allow-empty")
@@ -548,8 +549,7 @@ is updated:
(user-error "There are no modified modules that could be absorbed")) (user-error "There are no modified modules that could be absorbed"))
(when commit (when commit
(setq commit (magit-rebase-interactive-assert commit t))) (setq commit (magit-rebase-interactive-assert commit t)))
(if (and commit (eq phase 'run)) (cond ((and commit (eq phase 'run))
(progn
(dolist (module modules) (dolist (module modules)
(when-let ((msg (magit-git-string (when-let ((msg (magit-git-string
"log" "-1" "--format=%s" "log" "-1" "--format=%s"
@@ -558,10 +558,10 @@ is updated:
"--only" "--" module))) "--only" "--" module)))
(magit-refresh) (magit-refresh)
t) t)
(magit-log-select ((magit-log-select
(lambda (commit) (lambda (commit)
(magit-commit-absorb-modules 'run commit)) (magit-commit-absorb-modules 'run commit))
nil nil nil nil commit)))) nil nil nil nil commit)))))
;;;###autoload(autoload 'magit-commit-absorb "magit-commit" nil t) ;;;###autoload(autoload 'magit-commit-absorb "magit-commit" nil t)
(transient-define-prefix magit-commit-absorb (phase commit args) (transient-define-prefix magit-commit-absorb (phase commit args)
@@ -669,18 +669,25 @@ an alternative implementation."
'magit-commit--rebase 'magit-commit--rebase
last-command)) last-command))
(when (and git-commit-mode magit-commit-show-diff) (when (and git-commit-mode magit-commit-show-diff)
(when-let ((diff-buffer (magit-get-mode-buffer 'magit-diff-mode))) (when-let ((diff-buffer
;; This window just started displaying the commit message ;; This signals an error if not inside a Git repository,
;; buffer. Without this that buffer would immediately be ;; but the user may be visiting COMMIT_EDITMSG using a
;; replaced with the diff buffer. See #2632. ;; tool other than git, which can be used outside a Git
;; repository. See #5527.
(ignore-error magit-outside-git-repo
(magit-get-mode-buffer 'magit-diff-mode))))
;; This window just started displaying the commit message buffer.
;; Without unrecording that buffer would immediately be replaced
;; with the diff buffer. See #2632.
(unrecord-window-buffer nil diff-buffer)) (unrecord-window-buffer nil diff-buffer))
(message "Diffing changes to be committed (C-g to abort diffing)") (message "Diffing changes to be committed (C-g to abort diffing)")
(let ((inhibit-quit nil)) (let ((inhibit-quit nil))
(condition-case nil (condition-case nil
(magit-commit-diff-1) (with-demoted-errors "Error showing commit diff: %S"
(magit-commit-diff--show))
(quit))))) (quit)))))
(defun magit-commit-diff-1 () (defun magit-commit-diff--args ()
(let ((rev nil) (let ((rev nil)
(arg "--cached") (arg "--cached")
(command (magit-repository-local-get 'this-commit-command)) (command (magit-repository-local-get 'this-commit-command))
@@ -695,6 +702,9 @@ an alternative implementation."
(and (file-exists-p f) (length (magit-file-lines f))))) (and (file-exists-p f) (length (magit-file-lines f)))))
(noalt nil)) (noalt nil))
(pcase (list staged unstaged command) (pcase (list staged unstaged command)
((guard (not (magit-commit-p "HEAD^")))
(setq rev "HEAD")
(setq arg nil))
((and `(,_ ,_ magit-commit--rebase) ((and `(,_ ,_ magit-commit--rebase)
(guard (integerp squash))) (guard (integerp squash)))
(setq rev (format "HEAD~%s" squash))) (setq rev (format "HEAD~%s" squash)))
@@ -716,20 +726,23 @@ an alternative implementation."
(setq arg nil))) (setq arg nil)))
(cond (cond
((not ((not
(and (eq this-command 'magit-diff-while-committing) (and-let*
(and-let ((buf (magit-get-mode-buffer ((_(eq this-command 'magit-diff-while-committing))
'magit-diff-mode nil 'selected))) (buf (magit-get-mode-buffer 'magit-diff-mode nil 'selected))
(and (equal rev (buffer-local-value 'magit-buffer-range buf)) (_(equal rev (buffer-local-value 'magit-buffer-diff-range buf)))
(equal arg (buffer-local-value 'magit-buffer-typearg buf))))))) (_(equal arg (buffer-local-value 'magit-buffer-diff-typearg buf)))))))
((eq command 'magit-commit-amend) ((eq command 'magit-commit-amend)
(setq rev nil)) (setq rev nil))
((or squash ((or squash
(file-exists-p (expand-file-name "rebase-merge/amend" (magit-gitdir)))) (file-exists-p (expand-file-name "rebase-merge/amend" (magit-gitdir))))
(setq rev "HEAD^")) (setq rev "HEAD^"))
(t ((setq noalt t)))
(list rev arg noalt)))
(defun magit-commit-diff--show ()
(pcase-let ((`(,rev ,arg ,noalt) (magit-commit-diff--args)))
(if noalt
(message "No alternative diff while committing") (message "No alternative diff while committing")
(setq noalt t)))
(unless noalt
(let ((magit-inhibit-save-previous-winconf 'unset) (let ((magit-inhibit-save-previous-winconf 'unset)
(magit-display-buffer-noselect t) (magit-display-buffer-noselect t)
(display-buffer-overriding-action (display-buffer-overriding-action
@@ -858,6 +871,7 @@ Also see `git-commit-post-finish-hook'."
;; ("and>" . "cond-let--and>") ;; ("and>" . "cond-let--and>")
;; ("and-let" . "cond-let--and-let") ;; ("and-let" . "cond-let--and-let")
;; ("if-let" . "cond-let--if-let") ;; ("if-let" . "cond-let--if-let")
;; ("when$" . "cond-let--when$")
;; ("when-let" . "cond-let--when-let") ;; ("when-let" . "cond-let--when-let")
;; ("while-let" . "cond-let--while-let") ;; ("while-let" . "cond-let--while-let")
;; ("match-string" . "match-string") ;; ("match-string" . "match-string")
+2 -1
View File
@@ -1,6 +1,6 @@
;;; magit-core.el --- Core functionality -*- lexical-binding:t -*- ;;; magit-core.el --- Core functionality -*- lexical-binding:t -*-
;; Copyright (C) 2008-2025 The Magit Project Contributors ;; Copyright (C) 2008-2026 The Magit Project Contributors
;; Author: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev> ;; Author: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
;; Maintainer: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev> ;; Maintainer: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
@@ -126,6 +126,7 @@ Each of these options falls into one or more of these categories:
;; ("and>" . "cond-let--and>") ;; ("and>" . "cond-let--and>")
;; ("and-let" . "cond-let--and-let") ;; ("and-let" . "cond-let--and-let")
;; ("if-let" . "cond-let--if-let") ;; ("if-let" . "cond-let--if-let")
;; ("when$" . "cond-let--when$")
;; ("when-let" . "cond-let--when-let") ;; ("when-let" . "cond-let--when-let")
;; ("while-let" . "cond-let--while-let") ;; ("while-let" . "cond-let--while-let")
;; ("match-string" . "match-string") ;; ("match-string" . "match-string")
+538 -209
View File
File diff suppressed because it is too large Load Diff
+2 -1
View File
@@ -1,6 +1,6 @@
;;; magit-dired.el --- Dired support for Magit -*- lexical-binding:t -*- ;;; magit-dired.el --- Dired support for Magit -*- lexical-binding:t -*-
;; Copyright (C) 2008-2025 The Magit Project Contributors ;; Copyright (C) 2008-2026 The Magit Project Contributors
;; Author: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev> ;; Author: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
;; Maintainer: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev> ;; Maintainer: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
@@ -116,6 +116,7 @@ Interactively, open the file at point."
;; ("and>" . "cond-let--and>") ;; ("and>" . "cond-let--and>")
;; ("and-let" . "cond-let--and-let") ;; ("and-let" . "cond-let--and-let")
;; ("if-let" . "cond-let--if-let") ;; ("if-let" . "cond-let--if-let")
;; ("when$" . "cond-let--when$")
;; ("when-let" . "cond-let--when-let") ;; ("when-let" . "cond-let--when-let")
;; ("while-let" . "cond-let--while-let") ;; ("while-let" . "cond-let--while-let")
;; ("match-string" . "match-string") ;; ("match-string" . "match-string")
+126 -167
View File
@@ -1,6 +1,6 @@
;;; magit-ediff.el --- Ediff extension for Magit -*- lexical-binding:t -*- ;;; magit-ediff.el --- Ediff extension for Magit -*- lexical-binding:t -*-
;; Copyright (C) 2008-2025 The Magit Project Contributors ;; Copyright (C) 2008-2026 The Magit Project Contributors
;; Author: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev> ;; Author: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
;; Maintainer: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev> ;; Maintainer: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
@@ -42,19 +42,17 @@
:group 'magit-extensions) :group 'magit-extensions)
(defcustom magit-ediff-quit-hook (defcustom magit-ediff-quit-hook
(list #'magit-ediff-cleanup-auxiliary-buffers (list #'magit-ediff-restore-previous-winconf)
#'magit-ediff-restore-previous-winconf)
"Hooks to run after finishing Ediff, when that was invoked using Magit. "Hooks to run after finishing Ediff, when that was invoked using Magit.
The hooks are run in the Ediff control buffer. This is similar The hooks are run in the Ediff control buffer. This is similar
to `ediff-quit-hook' but takes the needs of Magit into account. to `ediff-quit-hook' but takes the needs of Magit into account.
The `ediff-quit-hook' is ignored by Ediff sessions which were The `ediff-quit-hook' is ignored by Ediff sessions which were
invoked using Magit." invoked using Magit."
:package-version '(magit . "2.2.0") :package-version '(magit . "4.6.0")
:group 'magit-ediff :group 'magit-ediff
:type 'hook :type 'hook
:get #'magit-hook-custom-get :get #'magit-hook-custom-get
:options (list #'magit-ediff-cleanup-auxiliary-buffers :options (list #'magit-ediff-restore-previous-winconf))
#'magit-ediff-restore-previous-winconf))
(defcustom magit-ediff-dwim-resolve-function #'magit-ediff-resolve-rest (defcustom magit-ediff-dwim-resolve-function #'magit-ediff-resolve-rest
"The function `magit-ediff-dwim' uses to resolve conflicts." "The function `magit-ediff-dwim' uses to resolve conflicts."
@@ -115,7 +113,7 @@ recommend you do not further complicate that by enabling this.")
(defvar magit-ediff-previous-winconf nil) (defvar magit-ediff-previous-winconf nil)
;;;###autoload(autoload 'magit-ediff "magit-ediff" nil) ;;;###autoload(autoload 'magit-ediff "magit-ediff" nil t)
(transient-define-prefix magit-ediff () (transient-define-prefix magit-ediff ()
"Show differences using the Ediff package." "Show differences using the Ediff package."
:info-manual "(ediff)" :info-manual "(ediff)"
@@ -132,86 +130,8 @@ recommend you do not further complicate that by enabling this.")
("r" "Show range" magit-ediff-compare) ("r" "Show range" magit-ediff-compare)
("z" "Show stash" magit-ediff-show-stash)]]) ("z" "Show stash" magit-ediff-show-stash)]])
(defmacro magit-ediff-buffers (a b &optional c setup quit file) ;;;###autoload(autoload 'magit-ediff-resolve-all "magit-ediff" nil t)
"Run Ediff on two or three buffers. (transient-define-suffix magit-ediff-resolve-all (file)
This is a wrapper around `ediff-buffers-internal'.
A, B and C have the form (GET-BUFFER CREATE-BUFFER). If
GET-BUFFER returns a non-nil value, then that buffer is used and
it is not killed when exiting Ediff. Otherwise CREATE-BUFFER
must return a buffer and that is killed when exiting Ediff.
If non-nil, SETUP must be a function. It is called without
arguments after Ediff is done setting up buffers.
If non-nil, QUIT must be a function. It is added to
`ediff-quit-hook' and is called without arguments.
If FILE is non-nil, then perform a merge. The merge result
is put in FILE."
(let (get make kill (char ?A))
(dolist (spec (list a b c))
(if (not spec)
(push nil make)
(pcase-let ((`(,g ,m) spec))
(let ((b (intern (format "buf%c" char))))
(push `(,b ,g) get)
;; This is an unfortunate complication that I have added for
;; the benefit of one user. Pretend we used this instead:
;; (push `(or ,b ,m) make)
(push `(if ,b
(if magit-ediff-use-indirect-buffers
(prog1 (make-indirect-buffer
,b
(generate-new-buffer-name (buffer-name ,b))
t)
(setq ,b nil))
,b)
,m)
make)
(push `(unless ,b
;; For merge jobs Ediff switches buffer names around.
;; See (if ediff-merge-job ...) in `ediff-setup'.
(let ((var ,(if (and file (= char ?C))
'ediff-ancestor-buffer
(intern (format "ediff-buffer-%c" char)))))
(ediff-kill-buffer-carefully var)))
kill))
(cl-incf char))))
(setq get (nreverse get))
(setq make (nreverse make))
(setq kill (nreverse kill))
(let ((mconf (gensym "conf"))
(mfile (gensym "file")))
`(magit-with-toplevel
(let ((,mconf (current-window-configuration))
(,mfile ,file)
,@get)
(ediff-buffers-internal
,@make
(list ,@(and setup (list setup))
(lambda ()
;; We do not want to kill buffers that existed before
;; Ediff was invoked, so we cannot use Ediff's default
;; quit functions. Ediff splits quitting across two
;; hooks for merge jobs but we only ever use one.
(setq-local ediff-quit-merge-hook nil)
(setq-local ediff-quit-hook
(list
,@(and quit (list quit))
(lambda ()
,@kill
(let ((magit-ediff-previous-winconf ,mconf))
(run-hooks 'magit-ediff-quit-hook)))))))
(pcase (list ,(and c t) (and ,mfile t))
('(nil nil) 'ediff-buffers)
('(nil t) 'ediff-merge-buffers)
('(t nil) 'ediff-buffers3)
('(t t) 'ediff-merge-buffers-with-ancestor))
,mfile))))))
;;;###autoload
(defun magit-ediff-resolve-all (file)
"Resolve all conflicts in the FILE at point using Ediff. "Resolve all conflicts in the FILE at point using Ediff.
If there is no file at point or if it doesn't have any unmerged If there is no file at point or if it doesn't have any unmerged
@@ -219,16 +139,17 @@ changes, then prompt for a file.
See info node `(magit) Ediffing' for more information about this See info node `(magit) Ediffing' for more information about this
and alternative commands." and alternative commands."
:inapt-if-not #'magit-anything-unmerged-p
(interactive (list (magit-read-unmerged-file))) (interactive (list (magit-read-unmerged-file)))
(magit-with-toplevel (magit-with-toplevel
(let* ((dir (magit-gitdir)) (let* ((dir (magit-gitdir))
(revA (or (magit-name-branch "HEAD") (revA (or (magit-name-branch "HEAD")
(magit-commit-p "HEAD"))) (magit-commit-oid "HEAD")))
(revB (cl-find-if (##file-exists-p (expand-file-name % dir)) (revB (cl-find-if (##file-exists-p (expand-file-name % dir))
'("MERGE_HEAD" "CHERRY_PICK_HEAD" "REVERT_HEAD"))) '("MERGE_HEAD" "CHERRY_PICK_HEAD" "REVERT_HEAD")))
(revB (or (magit-name-branch revB) (revB (or (magit-name-branch revB)
(magit-commit-p revB))) (magit-commit-oid revB)))
(revC (magit-commit-p (magit-git-string "merge-base" revA revB))) (revC (magit-commit-oid (magit-git-string "merge-base" revA revB)))
(fileA (magit--rev-file-name file revA revB)) (fileA (magit--rev-file-name file revA revB))
(fileB (magit--rev-file-name file revB revA)) (fileB (magit--rev-file-name file revB revA))
(fileC (or (magit--rev-file-name file revC revA) (fileC (or (magit--rev-file-name file revC revA)
@@ -256,7 +177,7 @@ and alternative commands."
,(format ">>>>>>> %s" revB))))) ,(format ">>>>>>> %s" revB)))))
(quit (lambda () (quit (lambda ()
;; For merge jobs Ediff switches buffer names around. ;; For merge jobs Ediff switches buffer names around.
;; At this point `ediff-buffer-C' no longer refer to ;; At this point `ediff-buffer-C' no longer refers to
;; the ancestor buffer but to the merge result buffer. ;; the ancestor buffer but to the merge result buffer.
;; See (if ediff-merge-job ...) in `ediff-setup'. ;; See (if ediff-merge-job ...) in `ediff-setup'.
(when (buffer-live-p ediff-buffer-C) (when (buffer-live-p ediff-buffer-C)
@@ -266,24 +187,14 @@ and alternative commands."
(goto-char (point-min)) (goto-char (point-min))
(unless (re-search-forward "^<<<<<<< " nil t) (unless (re-search-forward "^<<<<<<< " nil t)
(magit-stage-files (list file))))))))) (magit-stage-files (list file)))))))))
(cond (fileC
(magit-ediff-buffers (magit-ediff-buffers
((magit-get-revision-buffer revA fileA) (magit-ediff--find-file revA fileA)
(magit-find-file-noselect revA fileA)) (magit-ediff--find-file revB fileB)
((magit-get-revision-buffer revB fileB) (and fileC (magit-ediff--find-file revC fileC))
(magit-find-file-noselect revB fileB)) setup quit file)))))
((magit-get-revision-buffer revC fileC)
(magit-find-file-noselect revC fileC))
setup quit file))
((magit-ediff-buffers
((magit-get-revision-buffer revA fileA)
(magit-find-file-noselect revA fileA))
((magit-get-revision-buffer revB fileB)
(magit-find-file-noselect revB fileB))
nil setup quit file)))))))
;;;###autoload ;;;###autoload(autoload 'magit-ediff-resolve-rest "magit-ediff" nil t)
(defun magit-ediff-resolve-rest (file) (transient-define-suffix magit-ediff-resolve-rest (file)
"Resolve outstanding conflicts in the FILE at point using Ediff. "Resolve outstanding conflicts in the FILE at point using Ediff.
If there is no file at point or if it doesn't have any unmerged If there is no file at point or if it doesn't have any unmerged
@@ -291,6 +202,7 @@ changes, then prompt for a file.
See info node `(magit) Ediffing' for more information about this See info node `(magit) Ediffing' for more information about this
and alternative commands." and alternative commands."
:inapt-if-not #'magit-anything-unmerged-p
(interactive (list (magit-read-unmerged-file))) (interactive (list (magit-read-unmerged-file)))
(magit-with-toplevel (magit-with-toplevel
(with-current-buffer (find-file-noselect file) (with-current-buffer (find-file-noselect file)
@@ -314,32 +226,27 @@ and alternative commands."
(let ((magit-ediff-previous-winconf smerge-ediff-windows)) (let ((magit-ediff-previous-winconf smerge-ediff-windows))
(run-hooks 'magit-ediff-quit-hook))))))) (run-hooks 'magit-ediff-quit-hook)))))))
;;;###autoload ;;;###autoload(autoload 'magit-ediff-stage "magit-ediff" nil t)
(defun magit-ediff-stage (file) (transient-define-suffix magit-ediff-stage (file)
"Stage and unstage changes to FILE using Ediff. "Stage and unstage changes to FILE using Ediff.
FILE has to be relative to the top directory of the repository." FILE has to be relative to the top directory of the repository."
:inapt-if-not #'magit-anything-modified-p
(interactive (interactive
(let ((files (magit-tracked-files))) (let ((files (magit-tracked-files)))
(list (magit-completing-read "Selectively stage file" files nil t nil nil (list (magit-completing-read "Selectively stage file" files nil t nil nil
(car (member (magit-current-file) files)))))) (car (member (magit-current-file) files))))))
(magit-with-toplevel (magit-with-toplevel
(let* ((bufA (magit-get-revision-buffer "HEAD" file)) (let* ((bufC (magit-ediff--find-file "{worktree}" file))
(bufB (magit-get-revision-buffer "{index}" file))
(lockB (and bufB (buffer-local-value 'buffer-read-only bufB)))
(bufC (get-file-buffer file))
;; Use the same encoding for all three buffers or we ;; Use the same encoding for all three buffers or we
;; may end up changing the file in an unintended way. ;; may end up changing the file in an unintended way.
(bufC* (or bufC (find-file-noselect file)))
(coding-system-for-read (coding-system-for-read
(buffer-local-value 'buffer-file-coding-system bufC*)) (buffer-local-value 'buffer-file-coding-system bufC))
(bufA* (magit-find-file-noselect "HEAD" file t)) (bufA (magit-ediff--find-file "HEAD" file))
(bufB* (magit-find-file-index-noselect file t))) (bufB (magit-ediff--find-file "{index}" file))
(with-current-buffer bufB* (setq buffer-read-only nil)) (lockB (buffer-local-value 'buffer-read-only bufB)))
(with-current-buffer bufB (setq buffer-read-only nil))
(magit-ediff-buffers (magit-ediff-buffers
(bufA bufA*) bufA bufB bufC nil
(bufB bufB*)
(bufC bufC*)
nil
(lambda () (lambda ()
(when (buffer-live-p ediff-buffer-B) (when (buffer-live-p ediff-buffer-B)
(when lockB (when lockB
@@ -353,13 +260,12 @@ FILE has to be relative to the top directory of the repository."
(when (y-or-n-p (format "Save file %s? " buffer-file-name)) (when (y-or-n-p (format "Save file %s? " buffer-file-name))
(save-buffer))))))))) (save-buffer)))))))))
;;;###autoload ;;;###autoload(autoload 'magit-ediff-compare "magit-ediff" nil t)
(defun magit-ediff-compare (revA revB fileA fileB) (transient-define-suffix magit-ediff-compare (revA revB fileA fileB)
"Compare REVA:FILEA with REVB:FILEB using Ediff. "Compare REVA:FILEA with REVB:FILEB using Ediff.
FILEA and FILEB have to be relative to the top directory of the FILEA and FILEB have to be relative to the top directory of the
repository. If REVA or REVB is nil, then this stands for the repository.
working tree state.
If the region is active, use the revisions on the first and last If the region is active, use the revisions on the first and last
line of the region. With a prefix argument, instead of diffing line of the region. With a prefix argument, instead of diffing
@@ -372,10 +278,8 @@ range)."
(nconc (list revA revB) (nconc (list revA revB)
(magit-ediff-read-files revA revB)))) (magit-ediff-read-files revA revB))))
(magit-ediff-buffers (magit-ediff-buffers
((if revA (magit-get-revision-buffer revA fileA) (get-file-buffer fileA)) (magit-ediff--find-file revA fileA)
(if revA (magit-find-file-noselect revA fileA) (find-file-noselect fileA))) (magit-ediff--find-file revB fileB)))
((if revB (magit-get-revision-buffer revB fileB) (get-file-buffer fileB))
(if revB (magit-find-file-noselect revB fileB) (find-file-noselect fileB)))))
(defun magit-ediff-compare--read-revisions (&optional arg mbase) (defun magit-ediff-compare--read-revisions (&optional arg mbase)
(let ((input (or arg (magit-diff-read-range-or-commit (let ((input (or arg (magit-diff-read-range-or-commit
@@ -383,12 +287,14 @@ range)."
nil mbase)))) nil mbase))))
(if-let ((range (magit-split-range input))) (if-let ((range (magit-split-range input)))
(list (car range) (cdr range)) (list (car range) (cdr range))
(list input nil)))) (list input "{worktree}"))))
(defun magit-ediff-read-files (revA revB &optional fileB) (defun magit-ediff-read-files (revA revB &optional fileB)
"Read file in REVB, return it and the corresponding file in REVA. "Read file in REVB, return it and the corresponding file in REVA.
When FILEB is non-nil, use this as REVB's file instead of When FILEB is non-nil, use this as REVB's file instead of
prompting for it." prompting for it."
(when (equal revA "{worktree}") (setq revA nil))
(when (equal revB "{worktree}") (setq revB nil))
(unless (and fileB (member fileB (magit-revision-files revB))) (unless (and fileB (member fileB (magit-revision-files revB)))
(setq fileB (setq fileB
(or (and fileB (or (and fileB
@@ -416,8 +322,8 @@ prompting for it."
revA revB))) revA revB)))
fileB)) fileB))
;;;###autoload ;;;###autoload(autoload 'magit-ediff-dwim "magit-ediff" nil t)
(defun magit-ediff-dwim () (transient-define-suffix magit-ediff-dwim ()
"Compare, stage, or resolve using Ediff. "Compare, stage, or resolve using Ediff.
This command tries to guess what file, and what commit or range This command tries to guess what file, and what commit or range
the user wants to compare, stage, or resolve using Ediff. It the user wants to compare, stage, or resolve using Ediff. It
@@ -459,7 +365,7 @@ mind at all, then it asks the user for a command to run."
(pcase (magit-diff-type) (pcase (magit-diff-type)
('committed (pcase-let ((`(,a ,b) ('committed (pcase-let ((`(,a ,b)
(magit-ediff-compare--read-revisions (magit-ediff-compare--read-revisions
magit-buffer-range))) magit-buffer-diff-range)))
(setq revA a) (setq revA a)
(setq revB b))) (setq revB b)))
((guard (not magit-ediff-dwim-show-on-hunks)) ((guard (not magit-ediff-dwim-show-on-hunks))
@@ -490,55 +396,52 @@ mind at all, then it asks the user for a command to run."
(funcall command file)) (funcall command file))
((call-interactively command))))))) ((call-interactively command)))))))
;;;###autoload ;;;###autoload(autoload 'magit-ediff-show-staged "magit-ediff" nil t)
(defun magit-ediff-show-staged (file) (transient-define-suffix magit-ediff-show-staged (file)
"Show staged changes using Ediff. "Show staged changes using Ediff.
This only allows looking at the changes; to stage, unstage, This only allows looking at the changes; to stage, unstage,
and discard changes using Ediff, use `magit-ediff-stage'. and discard changes using Ediff, use `magit-ediff-stage'.
FILE must be relative to the top directory of the repository." FILE must be relative to the top directory of the repository."
:inapt-if-not #'magit-anything-staged-p
(interactive (interactive
(list (magit-read-file-choice "Show staged changes for file" (list (magit-read-file-choice "Show staged changes for file"
(magit-staged-files) (magit-staged-files)
"No staged files"))) "No staged files")))
(magit-ediff-buffers ((magit-get-revision-buffer "HEAD" file) (magit-ediff-buffers (magit-ediff--find-file "HEAD" file)
(magit-find-file-noselect "HEAD" file)) (magit-ediff--find-file "{index}" file)))
((get-buffer (concat file ".~{index}~"))
(magit-find-file-index-noselect file t))))
;;;###autoload ;;;###autoload(autoload 'magit-ediff-show-unstaged "magit-ediff" nil t)
(defun magit-ediff-show-unstaged (file) (transient-define-suffix magit-ediff-show-unstaged (file)
"Show unstaged changes using Ediff. "Show unstaged changes using Ediff.
This only allows looking at the changes; to stage, unstage, This only allows looking at the changes; to stage, unstage,
and discard changes using Ediff, use `magit-ediff-stage'. and discard changes using Ediff, use `magit-ediff-stage'.
FILE must be relative to the top directory of the repository." FILE must be relative to the top directory of the repository."
:inapt-if-not #'magit-anything-unstaged-p
(interactive (interactive
(list (magit-read-file-choice "Show unstaged changes for file" (list (magit-read-file-choice "Show unstaged changes for file"
(magit-unstaged-files) (magit-unstaged-files)
"No unstaged files"))) "No unstaged files")))
(magit-ediff-buffers ((get-buffer (concat file ".~{index}~")) (magit-ediff-buffers (magit-ediff--find-file "{index}" file)
(magit-find-file-index-noselect file t)) (magit-ediff--find-file "{worktree}" file)))
((get-file-buffer file)
(find-file-noselect file))))
;;;###autoload ;;;###autoload(autoload 'magit-ediff-show-working-tree "magit-ediff" nil t)
(defun magit-ediff-show-working-tree (file) (transient-define-suffix magit-ediff-show-working-tree (file)
"Show changes between `HEAD' and working tree using Ediff. "Show changes between `HEAD' and working tree using Ediff.
FILE must be relative to the top directory of the repository." FILE must be relative to the top directory of the repository."
:inapt-if-not #'magit-anything-modified-p
(interactive (interactive
(list (magit-read-file-choice "Show changes in file" (list (magit-read-file-choice "Show changes in file"
(magit-changed-files "HEAD") (magit-modified-files)
"No changed files"))) "No changed files")))
(magit-ediff-buffers ((magit-get-revision-buffer "HEAD" file) (magit-ediff-buffers (magit-ediff--find-file "HEAD" file)
(magit-find-file-noselect "HEAD" file)) (magit-ediff--find-file "{worktree}" file)))
((get-file-buffer file)
(find-file-noselect file))))
;;;###autoload ;;;###autoload(autoload 'magit-ediff-show-commit "magit-ediff" nil t)
(defun magit-ediff-show-commit (commit) (transient-define-suffix magit-ediff-show-commit (commit)
"Show changes introduced by COMMIT using Ediff." "Show changes introduced by COMMIT using Ediff."
(interactive (list (magit-read-branch-or-commit "Revision"))) (interactive (list (magit-read-branch-or-commit "Revision")))
(let ((revA (concat commit "^")) (let ((revA (concat commit "^"))
@@ -547,12 +450,13 @@ FILE must be relative to the top directory of the repository."
revA revB revA revB
(magit-ediff-read-files revA revB (magit-current-file))))) (magit-ediff-read-files revA revB (magit-current-file)))))
;;;###autoload ;;;###autoload(autoload 'magit-ediff-show-stash "magit-ediff" nil t)
(defun magit-ediff-show-stash (stash) (transient-define-suffix magit-ediff-show-stash (stash)
"Show changes introduced by STASH using Ediff. "Show changes introduced by STASH using Ediff.
`magit-ediff-show-stash-with-index' controls whether a `magit-ediff-show-stash-with-index' controls whether a three-buffer
three-buffer Ediff is used in order to distinguish changes in the Ediff is used in order to distinguish changes in the stash that were
stash that were staged." staged."
:inapt-if-not #'magit-list-stashes
(interactive (list (magit-read-stash "Stash"))) (interactive (list (magit-read-stash "Stash")))
(pcase-let* ((revA (concat stash "^1")) (pcase-let* ((revA (concat stash "^1"))
(revB (concat stash "^2")) (revB (concat stash "^2"))
@@ -562,15 +466,64 @@ stash that were staged."
(if (and magit-ediff-show-stash-with-index (if (and magit-ediff-show-stash-with-index
(member fileA (magit-changed-files revB revA))) (member fileA (magit-changed-files revB revA)))
(magit-ediff-buffers (magit-ediff-buffers
((magit-get-revision-buffer revA fileA) (magit-ediff--find-file revA fileA)
(magit-find-file-noselect revA fileA)) (magit-ediff--find-file revB fileB)
((magit-get-revision-buffer revB fileB) (magit-ediff--find-file revC fileC))
(magit-find-file-noselect revB fileB))
((magit-get-revision-buffer revC fileC)
(magit-find-file-noselect revC fileC)))
(magit-ediff-compare revA revC fileA fileC)))) (magit-ediff-compare revA revC fileA fileC))))
(defun magit-ediff-cleanup-auxiliary-buffers () ;;; Setup
(defun magit-ediff-buffers (a b &optional c setup quit file)
"Run Ediff on two or three buffers A, B and C.
If optional FILE is non-nil, then perform a merge. The merge result
is put in FILE.
Neutralize the hooks `ediff-quit-hook' and `ediff-quit-merge-hook'
because they usually feature functions that do not work for Magit.
Instead run optional QUIT (if non-nil), `magit-ediff--cleanup-buffers'
and `magit-ediff-quit-hook', with no arguments.
Optional SETUP, if non-nil, is called with no arguments after Ediff
is done setting up buffers."
(magit-with-toplevel
(ediff-buffers-internal
a b c
(let ((winconf (current-window-configuration)))
(list (lambda ()
(when setup
(funcall setup))
(setq-local ediff-quit-merge-hook nil)
(setq-local ediff-quit-hook nil)
(when quit
(add-hook 'ediff-quit-hook quit nil t))
(add-hook 'ediff-quit-hook #'magit-ediff--cleanup-buffers t t)
(add-hook 'ediff-quit-hook
(lambda ()
(let ((magit-ediff-previous-winconf winconf))
(run-hooks 'magit-ediff-quit-hook)))
t t))))
(pcase (list (and c t) (and file t))
('(nil nil) 'ediff-buffers)
('(nil t) 'ediff-merge-buffers)
('(t nil) 'ediff-buffers3)
('(t t) 'ediff-merge-buffers-with-ancestor))
file)))
(defun magit-ediff--find-file (rev file)
(let ((buffer (magit-find-file-noselect rev file t 'ediff)))
(when magit-ediff-use-indirect-buffers
(setq buffer (make-indirect-buffer
buffer (generate-new-buffer-name (buffer-name buffer)) t)))
buffer))
;;; Quit
(defun magit-ediff--cleanup-buffers ()
(magit-ediff--bury-buffer ediff-buffer-A)
(magit-ediff--bury-buffer ediff-buffer-B)
(magit-ediff--bury-buffer ediff-buffer-C)
(magit-ediff--bury-buffer ediff-ancestor-buffer)
(let* ((ctl-buf ediff-control-buffer) (let* ((ctl-buf ediff-control-buffer)
(ctl-win (ediff-get-visible-buffer-window ctl-buf)) (ctl-win (ediff-get-visible-buffer-window ctl-buf))
(ctl-frm ediff-control-frame) (ctl-frm ediff-control-frame)
@@ -596,6 +549,11 @@ stash that were staged."
(when (frame-live-p main-frame) (when (frame-live-p main-frame)
(select-frame main-frame)))) (select-frame main-frame))))
(defun magit-ediff--bury-buffer (buffer)
(when (and (ediff-buffer-live-p buffer)
(eq (buffer-local-value 'magit-buffer--volatile buffer) 'ediff))
(kill-buffer (get-buffer buffer))))
(defun magit-ediff-restore-previous-winconf () (defun magit-ediff-restore-previous-winconf ()
(set-window-configuration magit-ediff-previous-winconf)) (set-window-configuration magit-ediff-previous-winconf))
@@ -607,6 +565,7 @@ stash that were staged."
;; ("and>" . "cond-let--and>") ;; ("and>" . "cond-let--and>")
;; ("and-let" . "cond-let--and-let") ;; ("and-let" . "cond-let--and-let")
;; ("if-let" . "cond-let--if-let") ;; ("if-let" . "cond-let--if-let")
;; ("when$" . "cond-let--when$")
;; ("when-let" . "cond-let--when-let") ;; ("when-let" . "cond-let--when-let")
;; ("while-let" . "cond-let--while-let") ;; ("while-let" . "cond-let--while-let")
;; ("match-string" . "match-string") ;; ("match-string" . "match-string")
+5 -4
View File
@@ -1,6 +1,6 @@
;;; magit-extras.el --- Additional functionality for Magit -*- lexical-binding:t -*- ;;; magit-extras.el --- Additional functionality for Magit -*- lexical-binding:t -*-
;; Copyright (C) 2008-2025 The Magit Project Contributors ;; Copyright (C) 2008-2026 The Magit Project Contributors
;; Author: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev> ;; Author: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
;; Maintainer: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev> ;; Maintainer: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
@@ -737,9 +737,9 @@ abbreviated revision to the `kill-ring' and the
(cl-case major-mode (cl-case major-mode
(magit-diff-mode (magit-diff-mode
(if (string-match "\\.\\.\\.?\\(.+\\)" (if (string-match "\\.\\.\\.?\\(.+\\)"
magit-buffer-range) magit-buffer-diff-range)
(match-str 1 magit-buffer-range) (match-str 1 magit-buffer-diff-range)
magit-buffer-range)) magit-buffer-diff-range))
(magit-status-mode "HEAD")))] (magit-status-mode "HEAD")))]
[_(magit-commit-p rev)] [_(magit-commit-p rev)]
(setq rev (magit-rev-parse (setq rev (magit-rev-parse
@@ -833,6 +833,7 @@ In Magit diffs, also skip over - and + at the beginning of the line."
;; ("and>" . "cond-let--and>") ;; ("and>" . "cond-let--and>")
;; ("and-let" . "cond-let--and-let") ;; ("and-let" . "cond-let--and-let")
;; ("if-let" . "cond-let--if-let") ;; ("if-let" . "cond-let--if-let")
;; ("when$" . "cond-let--when$")
;; ("when-let" . "cond-let--when-let") ;; ("when-let" . "cond-let--when-let")
;; ("while-let" . "cond-let--while-let") ;; ("while-let" . "cond-let--while-let")
;; ("match-string" . "match-string") ;; ("match-string" . "match-string")
+2 -1
View File
@@ -1,6 +1,6 @@
;;; magit-fetch.el --- Download objects and refs -*- lexical-binding:t -*- ;;; magit-fetch.el --- Download objects and refs -*- lexical-binding:t -*-
;; Copyright (C) 2008-2025 The Magit Project Contributors ;; Copyright (C) 2008-2026 The Magit Project Contributors
;; Author: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev> ;; Author: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
;; Maintainer: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev> ;; Maintainer: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
@@ -188,6 +188,7 @@ with a prefix argument."
;; ("and>" . "cond-let--and>") ;; ("and>" . "cond-let--and>")
;; ("and-let" . "cond-let--and-let") ;; ("and-let" . "cond-let--and-let")
;; ("if-let" . "cond-let--if-let") ;; ("if-let" . "cond-let--if-let")
;; ("when$" . "cond-let--when$")
;; ("when-let" . "cond-let--when-let") ;; ("when-let" . "cond-let--when-let")
;; ("while-let" . "cond-let--while-let") ;; ("while-let" . "cond-let--while-let")
;; ("match-string" . "match-string") ;; ("match-string" . "match-string")
+269 -115
View File
@@ -1,6 +1,6 @@
;;; magit-files.el --- Finding files -*- lexical-binding:t -*- ;;; magit-files.el --- Finding files -*- lexical-binding:t -*-
;; Copyright (C) 2008-2025 The Magit Project Contributors ;; Copyright (C) 2008-2026 The Magit Project Contributors
;; Author: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev> ;; Author: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
;; Maintainer: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev> ;; Maintainer: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
@@ -31,10 +31,21 @@
(require 'magit) (require 'magit)
(declare-function ediff-quit "ediff-util" (reverse-default-keep-variants))
;;; Find Blob ;;; Find Blob
(defvar magit-find-file-hook nil) (define-obsolete-variable-alias 'magit-find-file-hook
(add-hook 'magit-find-file-hook #'magit-blob-mode) 'magit-find-blob-hook "Magit 4.6.0")
(define-obsolete-variable-alias 'magit-find-index-hook
'magit-find-blob-hook "Magit 4.6.0")
(defvar magit-find-blob-hook (list #'magit-blob-mode))
(defvar-local magit-buffer-blob-oid--init nil)
(defvar-local magit-buffer--volatile nil)
(put 'magit-buffer--volatile 'permanent-local t)
;;;###autoload ;;;###autoload
(defun magit-find-file (rev file) (defun magit-find-file (rev file)
@@ -44,7 +55,7 @@ already exists. If prior to calling this command the current
buffer and/or cursor position is about the same file, then go buffer and/or cursor position is about the same file, then go
to the line and column corresponding to that location." to the line and column corresponding to that location."
(interactive (magit-find-file-read-args "Find file")) (interactive (magit-find-file-read-args "Find file"))
(magit-find-file--internal rev file #'pop-to-buffer-same-window)) (pop-to-buffer-same-window (magit-find-file-noselect rev file)))
;;;###autoload ;;;###autoload
(defun magit-find-file-other-window (rev file) (defun magit-find-file-other-window (rev file)
@@ -54,7 +65,7 @@ already exists. If prior to calling this command the current
buffer and/or cursor position is about the same file, then go to buffer and/or cursor position is about the same file, then go to
the line and column corresponding to that location." the line and column corresponding to that location."
(interactive (magit-find-file-read-args "Find file in other window")) (interactive (magit-find-file-read-args "Find file in other window"))
(magit-find-file--internal rev file #'switch-to-buffer-other-window)) (switch-to-buffer-other-window (magit-find-file-noselect rev file)))
;;;###autoload ;;;###autoload
(defun magit-find-file-other-frame (rev file) (defun magit-find-file-other-frame (rev file)
@@ -64,11 +75,11 @@ already exists. If prior to calling this command the current
buffer and/or cursor position is about the same file, then go to buffer and/or cursor position is about the same file, then go to
the line and column corresponding to that location." the line and column corresponding to that location."
(interactive (magit-find-file-read-args "Find file in other frame")) (interactive (magit-find-file-read-args "Find file in other frame"))
(magit-find-file--internal rev file #'switch-to-buffer-other-frame)) (switch-to-buffer-other-frame (magit-find-file-noselect rev file)))
(defun magit-find-file-read-args (prompt) (defun magit-find-file-read-args (prompt)
(let ((pseudo-revs '("{worktree}" "{index}"))) (let* ((pseudo-revs '("{worktree}" "{index}"))
(let ((rev (magit-completing-read "Find file from revision" (rev (magit-completing-read "Find file from revision"
(append pseudo-revs (append pseudo-revs
(magit-list-refnames nil t)) (magit-list-refnames nil t))
nil 'any nil 'magit-revision-history nil 'any nil 'magit-revision-history
@@ -76,128 +87,244 @@ the line and column corresponding to that location."
(magit-get-current-branch))))) (magit-get-current-branch)))))
(list rev (list rev
(magit-read-file-from-rev (if (member rev pseudo-revs) "HEAD" rev) (magit-read-file-from-rev (if (member rev pseudo-revs) "HEAD" rev)
prompt))))) prompt))))
(defun magit-find-file--internal (rev file fn) (defun magit-find-file-noselect (rev file &optional no-restore-position volatile)
(let ((buf (magit-find-file-noselect rev file))
line col)
(when-let ((visited-file (magit-file-relative-name)))
(setq line (line-number-at-pos))
(setq col (current-column))
(cond
((not (equal visited-file file)))
((equal magit-buffer-revision rev))
((equal rev "{worktree}")
(setq line (magit-diff-visit--offset file magit-buffer-revision line)))
((equal rev "{index}")
(setq line (magit-diff-visit--offset file nil line)))
(magit-buffer-revision
(setq line (magit-diff-visit--offset
file (concat magit-buffer-revision ".." rev) line)))
((setq line (magit-diff-visit--offset file (list "-R" rev) line)))))
(funcall fn buf)
(when line
(with-current-buffer buf
(widen)
(goto-char (point-min))
(forward-line (1- line))
(move-to-column col)))
buf))
(defun magit-find-file-noselect (rev file &optional revert)
"Read FILE from REV into a buffer and return the buffer. "Read FILE from REV into a buffer and return the buffer.
REV is a revision or one of \"{worktree}\" or \"{index}\". FILE must REV is a revision or one of \"{worktree}\" or \"{index}\".
be relative to the top directory of the repository. Non-nil REVERT Non-interactively REV can also be a blob object."
means to revert the buffer. If `ask-revert', then only after asking. (let* ((rev (pcase rev
A non-nil value for REVERT is ignored if REV is \"{worktree}\"." ('nil "{worktree}")
(let* ((topdir (magit-toplevel)) ((and "{index}"
(absolute (file-name-absolute-p file)) (guard (length> (magit--file-index-stages file) 1)))
(file-abs (if absolute file (expand-file-name file topdir))) "{worktree}")
(file-rel (if absolute (file-relative-name file topdir) file)) (rev rev)))
(defdir (file-name-directory file-abs)) (topdir (magit-toplevel))
(rev (magit--abbrev-if-hash rev))) (file (expand-file-name file topdir))
(if (equal rev "{worktree}") (file-relative (file-relative-name file topdir))
(buffer
(cond-let
((equal rev "{worktree}")
(let ((revert-without-query (let ((revert-without-query
(if (and$ (find-buffer-visiting file-abs) (if (and$ (find-buffer-visiting file)
(buffer-local-value 'auto-revert-mode $)) (buffer-local-value 'auto-revert-mode $))
(cons "." revert-without-query) (cons "." revert-without-query)
revert-without-query))) revert-without-query)))
(find-file-noselect file-abs)) (find-file-noselect file volatile)))
(with-current-buffer (magit-get-revision-buffer-create rev file-rel) ((not topdir)
(when (or (not magit-buffer-file-name) (error "%s is not inside a Git repository" file))
(if (eq revert 'ask-revert) ([defdir (file-name-directory file)]
(y-or-n-p (format "%s already exists; revert it? " [rev (magit--abbrev-if-oid rev)]
(buffer-name)))) (unless (file-in-directory-p file topdir)
revert) (error "%s is not inside Git repository %s" file topdir))
(setq magit-buffer-revision rev) (with-current-buffer
(setq magit-buffer-refname rev) (magit--get-blob-buffer rev file-relative volatile)
(setq magit-buffer-file-name file-abs) (if (magit-blob-p rev)
(setq default-directory (if (file-exists-p defdir) defdir topdir)) (setq magit-buffer-blob-oid--init (magit-rev-parse rev))
(setq-local revert-buffer-function #'magit-revert-rev-file-buffer) (setq magit-buffer-revision rev))
(revert-buffer t t) (setq magit-buffer-file-name file)
(run-hooks (if (equal rev "{index}") (setq default-directory
'magit-find-index-hook (if (file-exists-p defdir) defdir topdir))
'magit-find-file-hook))) (setq-local revert-buffer-function #'magit--revert-blob-buffer)
(current-buffer))))) (magit--refresh-blob-buffer)
(current-buffer)))
((error "Unexpected error")))))
(when (and (not no-restore-position)
(equal (magit-file-relative-name) file-relative))
(let ((pos (magit-find-file--position)))
(with-current-buffer buffer
(apply #'magit-find-file--restore-position pos))))
buffer))
(defun magit-get-revision-buffer-create (rev file) (defun magit--get-blob-buffer (obj file &optional volatile)
(magit-get-revision-buffer rev file t)) ;; If OBJ is a commit, is assummed to be abbreviated.
;; FILE is assumed to be relative to the top-level.
(cond-let
([buf (if (magit-blob-p obj)
(magit--find-buffer 'magit-buffer-blob-oid (magit-rev-parse obj)
'magit-buffer-file-name file)
(magit--find-buffer 'magit-buffer-revision obj
'magit-buffer-file-name file))]
(with-current-buffer buf
(when (and (not volatile) magit-buffer--volatile)
(setq magit-buffer--volatile nil)
(rename-buffer (magit--blob-buffer-name obj file))
(magit--blob-cache-remove buf)))
buf)
([buf (get-buffer-create (magit--blob-buffer-name obj file volatile))]
(with-current-buffer buf
(setq magit-buffer--volatile volatile)
(magit--blob-cache-put buf))
(buffer-enable-undo buf)
buf)))
(defun magit-get-revision-buffer (rev file &optional create) (defun magit--blob-buffer-name (obj file &optional volatile)
(funcall (if create #'get-buffer-create #'get-buffer) (format "%s%s.~%s~"
(format "%s.~%s~" file (subst-char-in-string ?/ ?_ rev)))) (if volatile " " "")
(or file (and (magit-blob-p obj) "{blob}"))
(subst-char-in-string ?/ ?_ obj)))
(defun magit-revert-rev-file-buffer (_ignore-auto noconfirm) (defun magit--revert-blob-buffer (_ignore-auto _noconfirm)
(when (or noconfirm (let ((pos (magit-find-file--position)))
(and (not (buffer-modified-p)) (magit--refresh-blob-buffer t)
(catch 'found (apply #'magit-find-file--restore-position pos)))
(dolist (regexp revert-without-query)
(when (string-match regexp magit-buffer-file-name) (defun magit--refresh-blob-buffer (&optional force)
(throw 'found t))))) (let ((old-blob-oid magit-buffer-blob-oid))
(yes-or-no-p (format "Revert buffer from Git %s? " (cond
(if (equal magit-buffer-refname "{index}") (magit-buffer-revision
"index" (setq magit-buffer-revision-oid
(concat "revision " magit-buffer-refname))))) (magit-commit-oid magit-buffer-revision t))
(let* ((inhibit-read-only t) (setq magit-buffer-blob-oid
(default-directory (magit-toplevel)) (magit-blob-oid magit-buffer-revision magit-buffer-file-name)))
(file (file-relative-name magit-buffer-file-name)) (magit-buffer-blob-oid--init
(coding-system-for-read (or coding-system-for-read 'undecided))) (setq magit-buffer-blob-oid magit-buffer-blob-oid--init)
(setq magit-buffer-blob-oid--init nil)))
(when (or force (not (equal old-blob-oid magit-buffer-blob-oid)))
(let ((inhibit-read-only t))
(erase-buffer) (erase-buffer)
(magit-git-insert "cat-file" "-p" (save-excursion
(if (equal magit-buffer-refname "{index}") (magit--insert-blob-contents magit-buffer-revision
(concat ":" file) (magit-file-relative-name))))
(concat magit-buffer-refname ":" file))) (magit--blob-normal-mode))))
(setq buffer-file-coding-system last-coding-system-used))
(defun magit--blob-normal-mode ()
(let ((buffer-file-name magit-buffer-file-name) (let ((buffer-file-name magit-buffer-file-name)
(after-change-major-mode-hook (after-change-major-mode-hook
;; Inhibit diff-hl and eglot; see bb8a65269d and 234a787b8c.
(seq-difference after-change-major-mode-hook (seq-difference after-change-major-mode-hook
'(global-diff-hl-mode-enable-in-buffer ; Emacs >= 30 '(global-diff-hl-mode-enable-in-buffer ; Emacs >= 30
global-diff-hl-mode-enable-in-buffers ; Emacs < 30 global-diff-hl-mode-enable-in-buffers ; Emacs < 30
eglot--maybe-activate-editing-mode) eglot--maybe-activate-editing-mode)
#'eq))) #'eq))
(buffer-name (buffer-name)))
;; `font-lock-mode' contains a hardcoded condition that prevents it
;; from being enabled in hidden buffers. Use a fake `buffer-name'
;; to trick it into believing the buffer is not hidden.
(if (eq (aref buffer-name 0) ?\s)
(letrec ((adv (lambda (fn &optional buffer)
(let ((name (funcall fn buffer)))
(if (equal name buffer-name)
(substring name 1)
name)))))
(advice-add 'buffer-name :around adv)
(unwind-protect
(normal-mode (not enable-local-variables))
(advice-remove 'buffer-name adv)))
;; We want `normal-mode' to respect nil `enable-local-variables'. ;; We want `normal-mode' to respect nil `enable-local-variables'.
;; The FIND-FILE argument wasn't designed for our use case, so we ;; The FIND-FILE argument wasn't designed for our use case,
;; have to use this strange invocation to achieve that. ;; so we have to use this strange invocation to achieve that.
(normal-mode (not enable-local-variables))) (normal-mode (not enable-local-variables)))
(setq buffer-read-only t) (setq buffer-read-only t)
(set-buffer-modified-p nil) (set-buffer-modified-p nil)
(goto-char (point-min)))) (run-hooks 'magit-find-blob-hook)))
(defun magit-find-file--position ()
(list (or magit-buffer-revision-oid magit-buffer-revision "{worktree}")
magit-buffer-blob-oid
(line-number-at-pos)
(current-column)))
(defun magit-find-file--restore-position (before blob line col)
(let ((file (magit-file-relative-name))
(rev (or magit-buffer-revision-oid magit-buffer-revision "{worktree}")))
(goto-char (point-min))
(forward-line
(1-
(pcase (list before rev)
((guard (equal magit-buffer-blob-oid blob)) line)
('("{worktree}" "{worktree}") line)
('("{worktree}" "{index}")
(magit-diff-visit--offset line file "-R"))
(`("{worktree}" ,_)
(magit-diff-visit--offset line file "-R" rev))
('("{index}" "{worktree}")
(magit-diff-visit--offset line file))
('("{index}" "{index}")
(magit-diff-visit--offset line (list blob magit-buffer-blob-oid file)))
(`("{index}" ,_)
(magit-diff-visit--offset line file "-R" "--cached"))
(`(,_ "{worktree}")
(magit-diff-visit--offset line file before))
(`(,_ "{index}")
(magit-diff-visit--offset line file "--cached"))
(_
(magit-diff-visit--offset line file before rev)))))
(move-to-column col)))
(defvar magit--blob-cache-limit 100
"Limit number of volatile blob buffers to be kept alive.
If nil, only use `magit--blob-cache-timeout'.")
(defvar magit--blob-cache-timeout 1800
"Limit age, since last access, of volatile blob buffers to be kept alive.
Age is tracked in seconds. If nil, only use `magit--blob-cache-limit'.")
(defvar magit--blob-cache-interval 600
"Seconds between volatile blob buffer pruning runs.")
(defvar magit--blob-cache-timer nil)
(defvar magit--blob-cache nil)
(defun magit--blob-cache-put (buffer)
(if-let ((elt (assq buffer magit--blob-cache)))
(setcdr elt (current-time))
(push (cons buffer (current-time)) magit--blob-cache))
(magit--blob-cache-start))
(defun magit--blob-cache-remove (buffer)
(and$ (assq buffer magit--blob-cache)
(delq $ magit--blob-cache)))
(defun magit--blob-cache-start ()
(when (and magit--blob-cache-interval
(not magit--blob-cache-timer))
(setq magit--blob-cache-timer
(run-with-timer magit--blob-cache-interval nil
#'magit--blob-cache-prune))))
(defun magit--blob-cache-prune ()
(when magit--blob-cache-timer
(cancel-timer magit--blob-cache-timer))
(pcase-let
((`(,active ,rest)
(magit--separate
(pcase-lambda (`(,buffer))
(or (get-buffer-window buffer t)
(not (eq (buffer-local-value 'magit-buffer--volatile buffer) t))))
magit--blob-cache)))
(when magit--blob-cache-timeout
(setq rest
(seq-filter (pcase-lambda (`(,buffer . ,time))
(cond
((not (buffer-live-p buffer)) nil)
((time-less-p (time-subtract (current-time) time)
magit--blob-cache-timeout)
buffer)
(t (kill-buffer buffer) nil)))
rest)))
(when-let* ((_ magit--blob-cache-limit)
(ceiling (- magit--blob-cache-limit (length active)))
(_ (length> rest ceiling)))
(let ((sorted (static-if (>= emacs-major-version 30)
(sort rest :key (##float-time (cdr %))
:lessp #'< :reverse t)
(cl-sort rest #'> :key (##float-time (cdr %))))))
(dolist (kill (nthcdr ceiling sorted))
(kill-buffer (car kill)))
(setq rest (ntake ceiling sorted))))
(setq magit--blob-cache (nconc active rest)))
(magit--blob-cache-start))
(defun magit--blob-cache-zap ()
(pcase-dolist (`(,buffer) magit--blob-cache)
(kill-buffer buffer))
(setq magit--blob-cache nil))
(define-advice lsp (:around (fn &rest args) magit-find-file) (define-advice lsp (:around (fn &rest args) magit-find-file)
"Do nothing when visiting blob using `magit-find-file' and similar. "Do nothing when visiting blob using `magit-find-file' and similar.
See also https://github.com/doomemacs/doomemacs/pull/6309." See also https://github.com/doomemacs/doomemacs/pull/6309."
(unless magit-buffer-revision (unless magit-buffer-blob-oid
(apply fn args))) (apply fn args)))
;;; Find Index ;;; Update Index
(defvar magit-find-index-hook nil)
(add-hook 'magit-find-index-hook #'magit-blob-mode)
(defun magit-find-file-index-noselect (file &optional revert)
"Read FILE from the index into a buffer and return the buffer.
FILE must to be relative to the top directory of the repository."
(magit-find-file-noselect "{index}" file (or revert 'ask-revert)))
(defun magit-update-index () (defun magit-update-index ()
"Update the index with the contents of the current buffer. "Update the index with the contents of the current buffer.
@@ -205,7 +332,7 @@ The current buffer has to be visiting a file in the index, which
is done using `magit-find-index-noselect'." is done using `magit-find-index-noselect'."
(interactive) (interactive)
(let ((file (magit-file-relative-name))) (let ((file (magit-file-relative-name)))
(unless (equal magit-buffer-refname "{index}") (unless (equal magit-buffer-revision "{index}")
(user-error "%s isn't visiting the index" file)) (user-error "%s isn't visiting the index" file))
(if (y-or-n-p (format "Update index with contents of %s?" (buffer-name))) (if (y-or-n-p (format "Update index with contents of %s?" (buffer-name)))
(let ((index (make-temp-name (let ((index (make-temp-name
@@ -230,8 +357,8 @@ is done using `magit-find-index-noselect'."
(set-buffer-modified-p nil) (set-buffer-modified-p nil)
(magit-run-after-apply-functions file "un-/stage")) (magit-run-after-apply-functions file "un-/stage"))
(message "Abort"))) (message "Abort")))
(when-let ((buffer (magit-get-mode-buffer 'magit-status-mode))) (when$ (magit-get-mode-buffer 'magit-status-mode)
(with-current-buffer buffer (with-current-buffer $
(magit-refresh))) (magit-refresh)))
t) t)
@@ -345,6 +472,7 @@ to `magit-dispatch'."
(defvar-keymap magit-blob-mode-map (defvar-keymap magit-blob-mode-map
:doc "Keymap for `magit-blob-mode'." :doc "Keymap for `magit-blob-mode'."
"g" #'revert-buffer
"p" #'magit-blob-previous "p" #'magit-blob-previous
"n" #'magit-blob-next "n" #'magit-blob-next
"b" #'magit-blame-addition "b" #'magit-blame-addition
@@ -360,18 +488,32 @@ Currently this only adds the following key bindings.
:package-version '(magit . "2.3.0")) :package-version '(magit . "2.3.0"))
(defun magit-bury-buffer (&optional kill-buffer) (defun magit-bury-buffer (&optional kill-buffer)
"Bury the current buffer, or with a prefix argument kill it." "Bury the current buffer, or with a prefix argument kill it.
If the buffer is used by an Ediff session, refuse to kill or bury just
that buffer. That former would break the session and the latter makes
little sense in this context. Instead offer to quit the whole session."
(interactive "P") (interactive "P")
(if kill-buffer (kill-buffer) (bury-buffer))) (cond ((bound-and-true-p ediff-this-buffer-ediff-sessions)
(ediff-quit nil))
(kill-buffer (kill-buffer))
((bury-buffer))))
(defun magit-bury-or-kill-buffer (&optional bury-buffer) (defun magit-bury-or-kill-buffer (&optional bury-buffer)
"Bury the current buffer if displayed in multiple windows, else kill it. "Bury the current buffer if displayed in multiple windows, else kill it.
With a prefix argument only bury the buffer even if it is only displayed
in a single window." With a prefix argument only bury the buffer even if it is only
displayed in a single window.
If the buffer is used by an Ediff session, refuse to kill or bury just
that buffer. That former would break the session and the latter makes
little sense in this context. Instead offer to quit the whole session."
(interactive "P") (interactive "P")
(if (or bury-buffer (cdr (get-buffer-window-list nil nil t))) (cond ((bound-and-true-p ediff-this-buffer-ediff-sessions)
(bury-buffer) (ediff-quit nil))
(kill-buffer))) ((or bury-buffer (cdr (get-buffer-window-list nil nil t)))
(bury-buffer))
((kill-buffer))))
(defun magit-kill-this-buffer () (defun magit-kill-this-buffer ()
"Kill the current buffer." "Kill the current buffer."
@@ -412,7 +554,7 @@ When visiting a blob or the version from the index, then go to
the same location in the respective file in the working tree." the same location in the respective file in the working tree."
(interactive) (interactive)
(if-let ((file (magit-file-relative-name))) (if-let ((file (magit-file-relative-name)))
(magit-find-file--internal "{worktree}" file #'pop-to-buffer-same-window) (pop-to-buffer-same-window (magit-find-file-noselect "{worktree}" file))
(user-error "Not visiting a blob"))) (user-error "Not visiting a blob")))
(defun magit-blob-visit (rev file) (defun magit-blob-visit (rev file)
@@ -624,6 +766,17 @@ If DEFAULT is non-nil, use this as the default value instead of
(define-obsolete-function-alias 'magit-find-file-noselect-1 (define-obsolete-function-alias 'magit-find-file-noselect-1
'magit-find-file-noselect "Magit 4.4.0") 'magit-find-file-noselect "Magit 4.4.0")
(defun magit-find-file--internal (rev file display)
(declare (obsolete magit-find-file-noselect "Magit 4.6.0"))
(let ((buf (magit-find-file-noselect rev file)))
(funcall display buf)
buf))
(defun magit-find-file-index-noselect (file)
"Read FILE from the index into a buffer and return the buffer."
(declare (obsolete magit-find-file-noselect "Magit 4.6.0"))
(magit-find-file-noselect "{index}" file t))
(provide 'magit-files) (provide 'magit-files)
;; Local Variables: ;; Local Variables:
;; read-symbol-shorthands: ( ;; read-symbol-shorthands: (
@@ -631,6 +784,7 @@ If DEFAULT is non-nil, use this as the default value instead of
;; ("and>" . "cond-let--and>") ;; ("and>" . "cond-let--and>")
;; ("and-let" . "cond-let--and-let") ;; ("and-let" . "cond-let--and-let")
;; ("if-let" . "cond-let--if-let") ;; ("if-let" . "cond-let--if-let")
;; ("when$" . "cond-let--when$")
;; ("when-let" . "cond-let--when-let") ;; ("when-let" . "cond-let--when-let")
;; ("while-let" . "cond-let--while-let") ;; ("while-let" . "cond-let--while-let")
;; ("match-string" . "match-string") ;; ("match-string" . "match-string")
+153 -86
View File
@@ -1,6 +1,6 @@
;;; magit-git.el --- Git functionality -*- lexical-binding:t -*- ;;; magit-git.el --- Git functionality -*- lexical-binding:t -*-
;; Copyright (C) 2008-2025 The Magit Project Contributors ;; Copyright (C) 2008-2026 The Magit Project Contributors
;; Author: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev> ;; Author: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
;; Maintainer: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev> ;; Maintainer: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
@@ -48,7 +48,6 @@
(defvar magit-buffer-file-name) (defvar magit-buffer-file-name)
(defvar magit-buffer-log-args) (defvar magit-buffer-log-args)
(defvar magit-buffer-log-files) (defvar magit-buffer-log-files)
(defvar magit-buffer-refname)
(defvar magit-buffer-revision) (defvar magit-buffer-revision)
;; From `magit-process'. ;; From `magit-process'.
@@ -72,6 +71,8 @@
(cl-pushnew 'orig-rev eieio--known-slot-names) (cl-pushnew 'orig-rev eieio--known-slot-names)
(cl-pushnew 'number eieio--known-slot-names)) (cl-pushnew 'number eieio--known-slot-names))
(defvar crm-prompt) ; Emacs 31.1
;;; Options ;;; Options
;; For now this is shared between `magit-process' and `magit-git'. ;; For now this is shared between `magit-process' and `magit-git'.
@@ -393,7 +394,7 @@ to do the following.
* Prepend `magit-git-global-arguments' to ARGS. * Prepend `magit-git-global-arguments' to ARGS.
* If ASYNC is non-nil and `magit-overriding-githook-directory' is non-nil * If ASYNC is non-nil and `magit-overriding-githook-directory' is non-nil
and valid, set `core.hooksPath' by adding additional aguments to ARGS. and valid, set `core.hooksPath' by adding additional arguments to ARGS.
* Flatten ARGS, removing nil arguments. * Flatten ARGS, removing nil arguments.
* If `system-type' is `windows-nt', encode ARGS to `w32-ansi-code-page'." * If `system-type' is `windows-nt', encode ARGS to `w32-ansi-code-page'."
(cond ((not async)) (cond ((not async))
@@ -434,22 +435,6 @@ to do the following.
"Execute Git with ARGS, returning t if its exit code is 1." "Execute Git with ARGS, returning t if its exit code is 1."
(= (magit-git-exit-code args) 1)) (= (magit-git-exit-code args) 1))
(defun magit-git-string-p (&rest args)
"Execute Git with ARGS, returning the first line of its output.
If the exit code isn't zero or if there is no output, then return
nil. Neither of these results is considered an error; if that is
what you want, then use `magit-git-string-ng' instead.
This is an experimental replacement for `magit-git-string', and
still subject to major changes."
(magit--with-refresh-cache (cons default-directory args)
(magit--with-temp-process-buffer
(and (zerop (magit-process-git t args))
(not (bobp))
(progn
(goto-char (point-min))
(buffer-substring-no-properties (point) (line-end-position)))))))
(defun magit-git-string-ng (&rest args) (defun magit-git-string-ng (&rest args)
"Execute Git with ARGS, returning the first line of its output. "Execute Git with ARGS, returning the first line of its output.
If the exit code isn't zero or if there is no output, then that If the exit code isn't zero or if there is no output, then that
@@ -459,7 +444,7 @@ buffer (creating it if necessary) and the error message is shown
in the status buffer (provided it exists). in the status buffer (provided it exists).
This is an experimental replacement for `magit-git-string', and This is an experimental replacement for `magit-git-string', and
still subject to major changes. Also see `magit-git-string-p'." still subject to major changes."
(magit--with-refresh-cache (magit--with-refresh-cache
(list default-directory 'magit-git-string-ng args) (list default-directory 'magit-git-string-ng args)
(magit--with-temp-process-buffer (magit--with-temp-process-buffer
@@ -526,9 +511,9 @@ signal `magit-invalid-git-boolean'."
(defun magit-git-config-p (variable &optional default) (defun magit-git-config-p (variable &optional default)
"Return the boolean value of the Git variable VARIABLE. "Return the boolean value of the Git variable VARIABLE.
VARIABLE has to be specified as a string. Return DEFAULT (which VARIABLE has to be specified as a string. If VARIABLE is unset,
defaults to nil) if VARIABLE is unset. If VARIABLE's value isn't return nil by default, unless DEFAULT is non-nil, in which case
a boolean, then raise an error." return t. Signal an error if VARIABLE is set but not a boolean."
(let ((args (list "config" "--bool" "--default" (if default "true" "false") (let ((args (list "config" "--bool" "--default" (if default "true" "false")
variable))) variable)))
(magit--with-refresh-cache (cons default-directory args) (magit--with-refresh-cache (cons default-directory args)
@@ -577,10 +562,12 @@ insert the run command and stderr into the process buffer."
exit log 'magit-section-secondary-heading) exit log 'magit-section-secondary-heading)
exit))))) exit)))))
(cond ((not magit-git-debug)) (cond ((not magit-git-debug))
(errmsg (message "%s" errmsg)) (errmsg (message "magit--git-insert: %S" errmsg))
((zerop exit)) ((zerop exit))
((message "Git returned with exit-code %s" exit)))) ((message "magit--git-insert: %s %s"
(or errmsg exit)) "Git returned with exit-code" exit))))
(or (and return-error errmsg)
exit))
(ignore-errors (delete-file log)))) (ignore-errors (delete-file log))))
(magit-process-git (list t nil) args))) (magit-process-git (list t nil) args)))
@@ -591,16 +578,18 @@ insert the run command and stderr into the process buffer."
(match-str 1))) (match-str 1)))
(defun magit-git-string (&rest args) (defun magit-git-string (&rest args)
"Execute Git with ARGS, returning the first line of its output. "Execute Git with ARGS, returning the first line of its output (stdout).
If there is no output, return nil. If the output begins with a If the exit code isn't zero or if there is no output, then return nil.
newline, return an empty string." Neither of these results is considered an error; if that is what you
want, then use `magit-git-string-ng' instead."
(setq args (flatten-tree args)) (setq args (flatten-tree args))
(magit--with-refresh-cache (cons default-directory args) (magit--with-refresh-cache (cons default-directory args)
(magit--with-temp-process-buffer (magit--with-temp-process-buffer
(apply #'magit-git-insert args) (and (zerop (apply #'magit-git-insert args))
(unless (bobp) (not (bobp))
(progn
(goto-char (point-min)) (goto-char (point-min))
(buffer-substring-no-properties (point) (line-end-position)))))) (buffer-substring-no-properties (point) (line-end-position)))))))
(defun magit-git-lines (&rest args) (defun magit-git-lines (&rest args)
"Execute Git with ARGS, returning its output as a list of lines. "Execute Git with ARGS, returning its output as a list of lines.
@@ -1019,9 +1008,7 @@ returning the truename."
(define-error 'magit-outside-git-repo "Not inside Git repository") (define-error 'magit-outside-git-repo "Not inside Git repository")
(define-error 'magit-corrupt-git-config "Corrupt Git configuration") (define-error 'magit-corrupt-git-config "Corrupt Git configuration")
(define-error 'magit-git-executable-not-found (define-error 'magit-git-executable-not-found "Git executable cannot be found")
(concat "Git executable cannot be found "
"(see https://magit.vc/goto/e6a78ed2)"))
(defun magit--assert-usable-git () (defun magit--assert-usable-git ()
(if (not (executable-find (magit-git-executable) t)) (if (not (executable-find (magit-git-executable) t))
@@ -1121,7 +1108,7 @@ tracked file."
(file-relative-name file dir)))) (file-relative-name file dir))))
(defun magit-file-ignored-p (file) (defun magit-file-ignored-p (file)
(magit-git-string-p "ls-files" "--others" "--ignored" "--exclude-standard" (magit-git-string "ls-files" "--others" "--ignored" "--exclude-standard"
"--" (magit-convert-filename-for-git file))) "--" (magit-convert-filename-for-git file)))
(defun magit-file-tracked-p (file) (defun magit-file-tracked-p (file)
@@ -1145,6 +1132,16 @@ issue."
(and (not all) "--exclude-standard") (and (not all) "--exclude-standard")
"--" files)) "--" files))
(defun magit--untracked-files (&optional directory all)
(magit-with-toplevel
(seq-keep (##and (eq (aref % 0) ??)
(substring % 3))
(magit-git-items "status" "-z" "--porcelain"
(if all
"--untracked-files=all"
"--untracked-files=normal")
"--" directory))))
(defun magit-list-untracked-files (&optional files) (defun magit-list-untracked-files (&optional files)
"Return a list of untracked files. "Return a list of untracked files.
@@ -1258,13 +1255,12 @@ or if no rename is detected."
(y (char-after (1+ pos))) (y (char-after (1+ pos)))
(file (buffer-substring (+ pos 3) (point)))) (file (buffer-substring (+ pos 3) (point))))
(forward-char) (forward-char)
(if (memq x '(?R ?C)) (cond ((memq x '(?R ?C))
(progn
(setq pos (point)) (setq pos (point))
(skip-chars-forward "[:print:]") (skip-chars-forward "[:print:]")
(push (list file (buffer-substring pos (point)) x y) status) (push (list file (buffer-substring pos (point)) x y) status)
(forward-char)) (forward-char))
(push (list file nil x y) status))) ((push (list file nil x y) status))))
(setq pos (point))) (setq pos (point)))
status))) status)))
@@ -1279,11 +1275,10 @@ or if no rename is detected."
"Failed to parse Cygwin mount: %S" mount))) "Failed to parse Cygwin mount: %S" mount)))
;; If --exec-path is not a native Windows path, ;; If --exec-path is not a native Windows path,
;; then we probably have a cygwin git. ;; then we probably have a cygwin git.
(and (not (string-match-p (and-let ((dirs (magit--early-process-lines
"\\`[a-zA-Z]:" magit-git-executable "--exec-path")))
(car (magit--early-process-lines (and (not (string-match-p "\\`[a-zA-Z]:" (car dirs)))
magit-git-executable "--exec-path")))) (magit--early-process-lines "mount"))))
(magit--early-process-lines "mount")))
#'> :key (pcase-lambda (`(,cyg . ,_win)) (length cyg)))) #'> :key (pcase-lambda (`(,cyg . ,_win)) (length cyg))))
"Alist of (CYGWIN . WIN32) directory names. "Alist of (CYGWIN . WIN32) directory names.
Sorted from longest to shortest CYGWIN name." Sorted from longest to shortest CYGWIN name."
@@ -1344,6 +1339,36 @@ Sorted from longest to shortest CYGWIN name."
(and (derived-mode-p 'magit-log-mode) (and (derived-mode-p 'magit-log-mode)
(car magit-buffer-log-files)))) (car magit-buffer-log-files))))
;;; Blobs
(defun magit-blob-p (obj)
(equal (magit-object-type obj) "blob"))
(defun magit-blob-oid (rev file)
(cond-let
((equal rev "{index}")
(cadr (car (magit--file-index-stages file))))
;; --object-only and --format were only added in Git v2.36.0.
([out (magit-git-string "ls-tree" "--full-tree" rev "--"
(magit-convert-filename-for-git file))]
(nth 2 (split-string out "[\s\t]")))))
(defun magit--file-index-stages (file)
(mapcar (##split-string % " ")
(magit-git-lines "ls-files" "--stage" "--"
(magit-convert-filename-for-git file))))
(defun magit--insert-blob-contents (obj file)
(let ((coding-system-for-read (or coding-system-for-read 'undecided)))
(if (magit-blob-p obj)
(magit-git-insert "cat-file" "blob" obj)
(magit-git-insert "cat-file" "-p"
(if (equal obj "{index}")
(concat ":" file)
(concat obj ":" file))))
(setq buffer-file-coding-system last-coding-system-used)
nil))
;;; Predicates ;;; Predicates
(defun magit-no-commit-p () (defun magit-no-commit-p ()
@@ -1441,21 +1466,29 @@ string \"true\", otherwise return nil."
(equal (magit-git-str "rev-parse" args) "true")) (equal (magit-git-str "rev-parse" args) "true"))
(defun magit-rev-verify (rev) (defun magit-rev-verify (rev)
(magit-git-string-p "rev-parse" "--verify" rev)) (magit-git-string "rev-parse" "--verify" rev))
(defun magit-commit-p (rev) (defun magit-commit-p (rev)
"Return full hash for REV if it names an existing commit." "Return non-nil if REV can be dereferences as a commit.
Otherwise return nil. Use `magit-commit-oid' if you actually need
the oid; eventually this function will return t instead of the oid,
as it currently does for backward compatibility."
;; TODO Return t instead of the oid.
(magit-rev-verify (magit--rev-dereference rev))) (magit-rev-verify (magit--rev-dereference rev)))
(defalias 'magit-rev-verify-commit #'magit-commit-p) (defun magit-commit-oid (rev &optional noerror)
"Return commit oid for REV if it can be dereferences as a commit.
(defalias 'magit-rev-hash #'magit-commit-p) Otherwise signal an error, or return nil, if optional NOERROR is non-nil."
(cond ((magit-rev-verify (magit--rev-dereference rev)))
(noerror nil)
((error "%s cannot be dereferenced as a commit" rev))))
(defun magit--rev-dereference (rev) (defun magit--rev-dereference (rev)
"Return a rev that forces Git to interpret REV as a commit. "Return a rev that forces Git to interpret REV as a commit.
If REV is nil or has the form \":/TEXT\", return REV itself." Do so by appending \"^{commit}\"; see \"--verify\" in git-rev-parse(1).
However, if REV is nil or has the form \":/TEXT\", return REV itself."
(cond ((not rev) nil) (cond ((not rev) nil)
((string-match-p "^:/" rev) rev) ((string-prefix-p ":/" rev) rev)
((concat rev "^{commit}")))) ((concat rev "^{commit}"))))
(defun magit-rev-equal (a b) (defun magit-rev-equal (a b)
@@ -1464,20 +1497,18 @@ If REV is nil or has the form \":/TEXT\", return REV itself."
(defun magit-rev-eq (a b) (defun magit-rev-eq (a b)
"Return t if A and B refer to the same commit." "Return t if A and B refer to the same commit."
(let ((a (magit-commit-p a)) (and-let ((a (magit-commit-oid a t))
(b (magit-commit-p b))) (b (magit-commit-oid b t)))
(and a b (equal a b)))) (equal a b)))
(defun magit-rev-ancestor-p (a b) (defun magit-rev-ancestor-p (a b)
"Return non-nil if commit A is an ancestor of commit B." "Return non-nil if commit A is an ancestor of commit B."
(magit-git-success "merge-base" "--is-ancestor" a b)) (magit-git-success "merge-base" "--is-ancestor" a b))
(defun magit-rev-head-p (rev) (defun magit-rev-head-p (rev)
"Return t if REV can be dereferences as the `HEAD' commit."
(or (equal rev "HEAD") (or (equal rev "HEAD")
(and rev (magit-rev-eq rev "HEAD")))
(not (string-search ".." rev))
(equal (magit-rev-parse rev)
(magit-rev-parse "HEAD")))))
(defun magit-rev-author-p (rev) (defun magit-rev-author-p (rev)
"Return t if the user is the author of REV. "Return t if the user is the author of REV.
@@ -1584,9 +1615,9 @@ nil, then use \"heads/\"."
A symbolic-ref pointing to some ref, is `equal' to that ref, A symbolic-ref pointing to some ref, is `equal' to that ref,
as are two symbolic-refs pointing to the same ref. Refnames as are two symbolic-refs pointing to the same ref. Refnames
may be abbreviated." may be abbreviated."
(let ((a (magit-ref-fullname a)) (and-let ((a (magit-ref-fullname a))
(b (magit-ref-fullname b))) (b (magit-ref-fullname b)))
(and a b (equal a b)))) (equal a b)))
(defun magit-ref-eq (a b) (defun magit-ref-eq (a b)
"Return t if the refnames A and B are `eq'. "Return t if the refnames A and B are `eq'.
@@ -1682,7 +1713,7 @@ to, or to some other symbolic-ref that points to the same ref."
(magit-current-blame-chunk)))) (magit-current-blame-chunk))))
(oref chunk orig-rev)) (oref chunk orig-rev))
(and magit-buffer-file-name (and magit-buffer-file-name
magit-buffer-refname) magit-buffer-revision)
(and (derived-mode-p 'magit-stash-mode (and (derived-mode-p 'magit-stash-mode
'magit-merge-preview-mode 'magit-merge-preview-mode
'magit-revision-mode) 'magit-revision-mode)
@@ -1874,7 +1905,8 @@ according to the branch type."
(defun magit-get-push-branch (&optional branch verify) (defun magit-get-push-branch (&optional branch verify)
(magit--with-refresh-cache (magit--with-refresh-cache
(list default-directory 'magit-get-push-branch branch verify) (list default-directory 'magit-get-push-branch branch verify)
(and-let* ((branch (or branch (setq branch (magit-get-current-branch)))) (and-let*
((branch (magit-ref-abbrev (or branch (magit-get-current-branch))))
(remote (magit-get-push-remote branch)) (remote (magit-get-push-remote branch))
(target (concat remote "/" branch))) (target (concat remote "/" branch)))
(and (or (not verify) (and (or (not verify)
@@ -1882,11 +1914,9 @@ according to the branch type."
(magit--propertize-face target 'magit-branch-remote))))) (magit--propertize-face target 'magit-branch-remote)))))
(defun magit-get-@{push}-branch (&optional branch) (defun magit-get-@{push}-branch (&optional branch)
(let ((ref (magit-rev-parse "--symbolic-full-name" (and-let* ((branch (magit-ref-abbrev (or branch (magit-get-current-branch))))
(concat branch "@{push}")))) (target (magit-ref-fullname (concat branch "@{push}"))))
(and ref (magit-ref-abbrev target)))
(string-prefix-p "refs/remotes/" ref)
(substring ref 13))))
(defun magit-get-remote (&optional branch) (defun magit-get-remote (&optional branch)
(and (or branch (setq branch (magit-get-current-branch))) (and (or branch (setq branch (magit-get-current-branch)))
@@ -2232,11 +2262,11 @@ specified using `core.worktree'."
(let* ((default-directory (car worktree)) (let* ((default-directory (car worktree))
(wt (and (not (magit-get-boolean "core.bare")) (wt (and (not (magit-get-boolean "core.bare"))
(magit-get "core.worktree")))) (magit-get "core.worktree"))))
(if (and wt (file-exists-p (expand-file-name wt))) (cond ((and wt (file-exists-p (expand-file-name wt)))
(progn (setf (nth 0 worktree) (expand-file-name wt)) (setf (nth 0 worktree) (expand-file-name wt))
(setf (nth 2 worktree) (magit-rev-parse "HEAD")) (setf (nth 2 worktree) (magit-rev-parse "HEAD"))
(setf (nth 3 worktree) (magit-get-current-branch))) (setf (nth 3 worktree) (magit-get-current-branch)))
(setf (nth 3 worktree) t)))) ((setf (nth 3 worktree) t)))))
((string-equal line "detached") ((string-equal line "detached")
(setf (nth 4 worktree) t)) (setf (nth 4 worktree) t))
((string-prefix-p line "locked") ((string-prefix-p line "locked")
@@ -2271,8 +2301,8 @@ specified using `core.worktree'."
'magit-branch-local 'magit-branch-local
'magit-branch-remote))) 'magit-branch-remote)))
(defun magit-tag-p (rev) (defun magit-tag-p (obj)
(car (member rev (magit-list-tags)))) (equal (magit-object-type obj) "tag"))
(defun magit-remote-p (string) (defun magit-remote-p (string)
(car (member string (magit-list-remotes)))) (car (member string (magit-list-remotes))))
@@ -2342,10 +2372,10 @@ If `first-parent' is set, traverse only first parents."
(defun magit-rev-abbrev (rev) (defun magit-rev-abbrev (rev)
(magit-rev-parse (magit-abbrev-arg "short") rev)) (magit-rev-parse (magit-abbrev-arg "short") rev))
(defun magit--abbrev-if-hash (rev) (defun magit--abbrev-if-oid (obj)
(cond ((or (magit-ref-p rev) (member rev '("{index}" "{worktree}"))) rev) (cond ((or (magit-ref-p obj) (member obj '("{index}" "{worktree}"))) obj)
((magit-rev-parse (magit-abbrev-arg "short") rev)) ((magit-rev-parse (magit-abbrev-arg "short") obj))
(rev))) (obj)))
(defun magit-commit-children (rev &optional args) (defun magit-commit-children (rev &optional args)
(seq-keep (lambda (line) (seq-keep (lambda (line)
@@ -2568,8 +2598,8 @@ and this option only controls what face is used.")
(beg (or beg "HEAD")) (beg (or beg "HEAD"))
(end (or end "HEAD"))) (end (or end "HEAD")))
(when abbrev (when abbrev
(setq beg (magit--abbrev-if-hash beg)) (setq beg (magit--abbrev-if-oid beg))
(setq end (magit--abbrev-if-hash end))) (setq end (magit--abbrev-if-oid end)))
(pcase sep (pcase sep
(".." (cons beg end)) (".." (cons beg end))
("..." (and$ (magit-git-string "merge-base" beg end) ("..." (and$ (magit-git-string "merge-base" beg end)
@@ -2583,15 +2613,18 @@ and this option only controls what face is used.")
(list beg end sep))))) (list beg end sep)))))
(defun magit-hash-range (range) (defun magit-hash-range (range)
"Return a string with the revisions in RANGE replaced with commit oids.
Either side of RANGE may be omitted, and RANGE may be just a revision.
If either revision cannot be dereferenced as a commit, signal an error."
(if (string-match magit-range-re range) (if (string-match magit-range-re range)
(magit-bind-match-strings (beg sep end) range (magit-bind-match-strings (beg sep end) range
(and (or beg end) (and (or beg end)
(let ((beg-hash (and beg (magit-rev-hash beg))) (let ((beg-oid (and beg (magit-commit-oid beg)))
(end-hash (and end (magit-rev-hash end)))) (end-oid (and end (magit-commit-oid end))))
(and (or (not beg) beg-hash) (and (or (not beg) beg-oid)
(or (not end) end-hash) (or (not end) end-oid)
(concat beg-hash sep end-hash))))) (concat beg-oid sep end-oid)))))
(magit-rev-hash range))) (magit-commit-oid range)))
(defvar magit-revision-faces (defvar magit-revision-faces
'(magit-hash '(magit-hash
@@ -2645,7 +2678,7 @@ and this option only controls what face is used.")
(and (not (equal string "@")) (and (not (equal string "@"))
(or (and (>= (length string) 7) (or (and (>= (length string) 7)
(string-match-p "[a-z]" string) (string-match-p "[a-z]" string)
(magit-commit-p string)) (magit-commit-oid string t))
(and (magit-ref-p string) (and (magit-ref-p string)
(member (get-text-property (point) 'face) (member (get-text-property (point) 'face)
magit-revision-faces))) magit-revision-faces)))
@@ -2729,10 +2762,11 @@ and this option only controls what face is used.")
(lambda () (lambda ()
(magit--minibuf-default-add-commit) (magit--minibuf-default-add-commit)
(setq-local crm-separator "\\.\\.\\.?")) (setq-local crm-separator "\\.\\.\\.?"))
(let ((crm-prompt "%p"))
(magit-completing-read-multiple (magit-completing-read-multiple
(concat prompt ": ") (concat prompt ": ")
(magit-list-refnames) (magit-list-refnames)
nil 'any nil 'magit-revision-history default nil t))) nil 'any nil 'magit-revision-history default nil t))))
(defun magit-read-remote-branch (defun magit-read-remote-branch
(prompt &optional remote default local-branch require-match) (prompt &optional remote default local-branch require-match)
@@ -2812,6 +2846,23 @@ and this option only controls what face is used.")
(magit-completing-read prompt (delete exclude (magit-list-refnames)) (magit-completing-read prompt (delete exclude (magit-list-refnames))
nil 'any nil 'magit-revision-history default)))) nil 'any nil 'magit-revision-history default))))
(defun magit-read-other-branches-or-commits
(prompt &optional exclude secondary-default)
(let* ((current (magit-get-current-branch))
(atpoint (magit-branch-or-commit-at-point))
(exclude (or exclude current))
(default (or (and (not (equal atpoint exclude))
(not (and (not current)
(magit-rev-equal atpoint "HEAD")))
atpoint)
(and (not (equal current exclude)) current)
secondary-default
(magit-get-previous-branch))))
(minibuffer-with-setup-hook #'magit--minibuf-default-add-commit
(magit-completing-read-multiple
prompt (delete exclude (magit-list-refnames))
nil 'any nil 'magit-revision-history default))))
(defun magit-read-other-local-branch (defun magit-read-other-local-branch
(prompt &optional exclude secondary-default) (prompt &optional exclude secondary-default)
(let* ((current (magit-get-current-branch)) (let* ((current (magit-get-current-branch))
@@ -2993,6 +3044,21 @@ out. Only existing branches can be selected."
(server-send-string client msg)))) (server-send-string client msg))))
;;; _ ;;; _
(define-obsolete-function-alias 'magit-git-string-p
#'magit-git-string "Magit 4.6.0")
(define-obsolete-function-alias 'magit-rev-verify-commit
#'magit-commit-p "Magit 4.6.0")
(define-obsolete-function-alias 'magit-rev-hash
#'magit-commit-p "Magit 4.6.0"
"Return oid for REV if it names an existing commit, nil otherwise.
Instead use `magit-commit-p' or `magit-commit-oid'.")
(define-obsolete-function-alias 'magit--abbrev-if-hash
#'magit--abbrev-if-oid "Magit 4.6.0")
(provide 'magit-git) (provide 'magit-git)
;; Local Variables: ;; Local Variables:
;; read-symbol-shorthands: ( ;; read-symbol-shorthands: (
@@ -3000,6 +3066,7 @@ out. Only existing branches can be selected."
;; ("and>" . "cond-let--and>") ;; ("and>" . "cond-let--and>")
;; ("and-let" . "cond-let--and-let") ;; ("and-let" . "cond-let--and-let")
;; ("if-let" . "cond-let--if-let") ;; ("if-let" . "cond-let--if-let")
;; ("when$" . "cond-let--when$")
;; ("when-let" . "cond-let--when-let") ;; ("when-let" . "cond-let--when-let")
;; ("while-let" . "cond-let--while-let") ;; ("while-let" . "cond-let--while-let")
;; ("match-string" . "match-string") ;; ("match-string" . "match-string")
+71 -59
View File
@@ -1,6 +1,6 @@
;;; magit-gitignore.el --- Intentionally untracked files -*- lexical-binding:t -*- ;;; magit-gitignore.el --- Intentionally untracked files -*- lexical-binding:t -*-
;; Copyright (C) 2008-2025 The Magit Project Contributors ;; Copyright (C) 2008-2026 The Magit Project Contributors
;; Author: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev> ;; Author: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
;; Maintainer: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev> ;; Maintainer: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
@@ -35,16 +35,10 @@
"Instruct Git to ignore a file or pattern." "Instruct Git to ignore a file or pattern."
:man-page "gitignore" :man-page "gitignore"
["Gitignore" ["Gitignore"
("t" "shared at toplevel (.gitignore)" ("t" magit-gitignore-in-topdir)
magit-gitignore-in-topdir) ("s" magit-gitignore-in-subdir)
("s" "shared in subdirectory (path/to/.gitignore)" ("p" magit-gitignore-in-gitdir)
magit-gitignore-in-subdir) ("g" magit-gitignore-on-system)]
("p" "privately (.git/info/exclude)"
magit-gitignore-in-gitdir)
("g" magit-gitignore-on-system
:if (##magit-get "core.excludesfile")
:description (##format "privately for all repositories (%s)"
(magit-get "core.excludesfile")))]
["Skip worktree" ["Skip worktree"
(7 "w" "do skip worktree" magit-skip-worktree) (7 "w" "do skip worktree" magit-skip-worktree)
(7 "W" "do not skip worktree" magit-no-skip-worktree)] (7 "W" "do not skip worktree" magit-no-skip-worktree)]
@@ -54,51 +48,56 @@
;;; Gitignore Commands ;;; Gitignore Commands
;;;###autoload ;;;###autoload(autoload 'magit-gitignore-in-topdir "magit-gitignore" nil t)
(defun magit-gitignore-in-topdir (rule) (transient-define-suffix magit-gitignore-in-topdir (rule)
"Add the Git ignore RULE to the top-level \".gitignore\" file. "Add the Git ignore RULE to the top-level \".gitignore\" file.
Since this file is tracked, it is shared with other clones of the Since this file is tracked, it is shared with other clones of the
repository. Also stage the file." repository. Also stage the file."
:description "shared at toplevel (.gitignore)"
(interactive (list (magit-gitignore-read-pattern))) (interactive (list (magit-gitignore-read-pattern)))
(magit-with-toplevel (magit--gitignore rule (expand-file-name ".gitignore" (magit-toplevel)) t))
(magit--gitignore rule ".gitignore")
(magit-run-git "add" ".gitignore")))
;;;###autoload ;;;###autoload(autoload 'magit-gitignore-in-subdir "magit-gitignore" nil t)
(defun magit-gitignore-in-subdir (rule directory) (transient-define-suffix magit-gitignore-in-subdir (rule directory)
"Add the Git ignore RULE to a \".gitignore\" file in DIRECTORY. "Add the Git ignore RULE to a \".gitignore\" file in DIRECTORY.
Prompt the user for a directory and add the rule to the Prompt the user for a directory and add the rule to the
\".gitignore\" file in that directory. Since such files are \".gitignore\" file in that directory. Since such files are
tracked, they are shared with other clones of the repository. tracked, they are shared with other clones of the repository.
Also stage the file." Also stage the file."
(interactive (list (magit-gitignore-read-pattern) :description "shared in subdirectory (path/to/.gitignore)"
(read-directory-name "Limit rule to files in: "))) (interactive (let ((dir (expand-file-name
(magit-with-toplevel (read-directory-name
(let ((file (expand-file-name ".gitignore" directory))) "Limit rule to files in: "
(magit--gitignore rule file) (and$ (magit-current-file)
(magit-run-git "add" (magit-convert-filename-for-git file))))) (file-name-directory
(expand-file-name $ (magit-toplevel))))))))
(list (magit-gitignore-read-pattern dir) dir)))
(magit--gitignore rule (expand-file-name ".gitignore" directory) t))
;;;###autoload ;;;###autoload(autoload 'magit-gitignore-in-gitdir "magit-gitignore" nil t)
(defun magit-gitignore-in-gitdir (rule) (transient-define-suffix magit-gitignore-in-gitdir (rule)
"Add the Git ignore RULE to \"$GIT_DIR/info/exclude\". "Add the Git ignore RULE to \"$GIT_DIR/info/exclude\".
Rules in that file only affects this clone of the repository." Rules in that file only affects this clone of the repository."
:description "privately (.git/info/exclude)"
(interactive (list (magit-gitignore-read-pattern))) (interactive (list (magit-gitignore-read-pattern)))
(magit--gitignore rule (expand-file-name "info/exclude" (magit-gitdir))) (magit--gitignore rule (expand-file-name "info/exclude" (magit-gitdir))))
(magit-refresh))
;;;###autoload ;;;###autoload(autoload 'magit-gitignore-on-system "magit-gitignore" nil t)
(defun magit-gitignore-on-system (rule) (transient-define-suffix magit-gitignore-on-system (rule)
"Add the Git ignore RULE to the file specified by `core.excludesFile'. "Add the Git ignore RULE to the file specified by `core.excludesFile'.
Rules that are defined in that file affect all local repositories." Rules that are defined in that file affect all local repositories."
:inapt-if-not (##magit-get "core.excludesfile")
:description (##format "privately for all repositories (%s)"
(or (magit-get "core.excludesfile")
"core.excludesfile is not set"))
(interactive (list (magit-gitignore-read-pattern))) (interactive (list (magit-gitignore-read-pattern)))
(magit--gitignore rule (if-let ((file (magit-get "core.excludesFile")))
(or (magit-get "core.excludesFile") (magit--gitignore rule file)
(error "Variable `core.excludesFile' isn't set"))) (error "Variable `core.excludesFile' isn't set")))
(magit-refresh))
(defun magit--gitignore (rule file) (defun magit--gitignore (rule file &optional stage)
(when-let ((directory (file-name-directory file))) (when$ (file-name-directory file)
(make-directory directory t)) (make-directory $ t))
(with-temp-buffer (with-temp-buffer
(when (file-exists-p file) (when (file-exists-p file)
(insert-file-contents file)) (insert-file-contents file))
@@ -107,31 +106,21 @@ Rules that are defined in that file affect all local repositories."
(insert "\n")) (insert "\n"))
(insert (replace-regexp-in-string "\\(\\\\*\\)" "\\1\\1" rule)) (insert (replace-regexp-in-string "\\(\\\\*\\)" "\\1\\1" rule))
(insert "\n") (insert "\n")
(write-region nil nil file))) (write-region nil nil file))
(if stage
(magit-with-toplevel
(magit-run-git "add" (magit-convert-filename-for-git file)))
(magit-refresh)))
(defun magit-gitignore-read-pattern () (defun magit-gitignore-read-pattern (&optional directory)
(let* ((default (magit-current-file)) (let ((choices (magit--gitignore-patterns directory))
(base (car magit-buffer-diff-files)) (default (magit-current-file)))
(base (and base (file-directory-p base) base))
(choices
(delete-dups
(mapcan
(lambda (file)
(cons (concat "/" file)
(and$ (file-name-extension file)
(list (concat "/" (file-name-directory file) "*." $)
(concat "*." $)))))
(sort (nconc
(magit-untracked-files nil base)
;; The untracked section of the status buffer lists
;; directories containing only untracked files.
;; Add those as candidates.
(seq-filter #'directory-name-p
(magit-list-files
"--other" "--exclude-standard" "--directory"
"--no-empty-directory" "--" base)))
#'string-lessp)))))
(when default (when default
(when directory
(setq default
(substring default
(length
(file-relative-name directory (magit-toplevel))))))
(setq default (concat "/" default)) (setq default (concat "/" default))
(unless (member default choices) (unless (member default choices)
(setq default (concat "*." (file-name-extension default))) (setq default (concat "*." (file-name-extension default)))
@@ -140,6 +129,28 @@ Rules that are defined in that file affect all local repositories."
(magit-completing-read "File or pattern to ignore" (magit-completing-read "File or pattern to ignore"
choices nil 'any nil nil default))) choices nil 'any nil nil default)))
(defun magit--gitignore-patterns (&optional directory)
(let* ((topdir (magit-toplevel))
(default-directory (or directory topdir))
(files (magit--untracked-files directory t))
;; Include directories that contain only untracked files.
(dirs (seq-filter (##equal (substring % -1) "/")
(magit--untracked-files directory)))
(globs nil)
(dirglobs nil))
(when directory
(let ((beg (length (file-relative-name directory topdir))))
(setq files (mapcar (##substring % beg) files))
(setq dirs (mapcar (##substring % beg) dirs))))
(dolist (file files)
(when-let ((ext (file-name-extension file)))
(cl-pushnew (concat "*." ext) globs :test #'equal)
(when-let ((dir (file-name-directory file)))
(cl-pushnew (concat dir "*." ext) dirglobs :test #'equal))))
(sort (nconc globs
(mapcar (##concat "/" %) (nconc files dirs dirglobs)))
#'string<)))
;;; Skip Worktree Commands ;;; Skip Worktree Commands
;;;###autoload ;;;###autoload
@@ -198,6 +209,7 @@ Rules that are defined in that file affect all local repositories."
;; ("and>" . "cond-let--and>") ;; ("and>" . "cond-let--and>")
;; ("and-let" . "cond-let--and-let") ;; ("and-let" . "cond-let--and-let")
;; ("if-let" . "cond-let--if-let") ;; ("if-let" . "cond-let--if-let")
;; ("when$" . "cond-let--when$")
;; ("when-let" . "cond-let--when-let") ;; ("when-let" . "cond-let--when-let")
;; ("while-let" . "cond-let--while-let") ;; ("while-let" . "cond-let--while-let")
;; ("match-string" . "match-string") ;; ("match-string" . "match-string")
+33 -22
View File
@@ -1,6 +1,6 @@
;;; magit-log.el --- Inspect Git history -*- lexical-binding:t; coding:utf-8 -*- ;;; magit-log.el --- Inspect Git history -*- lexical-binding:t; coding:utf-8 -*-
;; Copyright (C) 2008-2025 The Magit Project Contributors ;; Copyright (C) 2008-2026 The Magit Project Contributors
;; Author: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev> ;; Author: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
;; Maintainer: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev> ;; Maintainer: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
@@ -374,6 +374,12 @@ commits before and half after."
:group 'magit-log :group 'magit-log
:type 'integer) :type 'integer)
;;; Variables
(defvar-local magit-buffer-log-revisions nil)
(defvar-local magit-buffer-log-args nil)
(defvar-local magit-buffer-log-files nil)
;;; Arguments ;;; Arguments
;;;; Prefix Classes ;;;; Prefix Classes
@@ -779,7 +785,7 @@ restrict the log to the lines that the region touches."
(require 'magit) (require 'magit)
(if-let ((file (magit-file-relative-name))) (if-let ((file (magit-file-relative-name)))
(magit-log-setup-buffer (magit-log-setup-buffer
(list (or magit-buffer-refname (list (or magit-buffer-revision
(magit-get-current-branch) (magit-get-current-branch)
"HEAD")) "HEAD"))
(let ((args (car (magit-log-arguments)))) (let ((args (car (magit-log-arguments))))
@@ -802,7 +808,7 @@ restrict the log to the lines that the region touches."
(user-error "Buffer isn't visiting a file")) (user-error "Buffer isn't visiting a file"))
(or (funcall magit-log-trace-definition-function) (or (funcall magit-log-trace-definition-function)
(user-error "No function at point found")) (user-error "No function at point found"))
(or magit-buffer-refname (or magit-buffer-revision
(magit-get-current-branch) (magit-get-current-branch)
"HEAD"))) "HEAD")))
(require 'magit) (require 'magit)
@@ -872,7 +878,7 @@ https://github.com/mhagger/git-when-merged."
(to (if (<= to 0) (to (if (<= to 0)
branch branch
(format "%s~%s" branch to)))) (format "%s~%s" branch to))))
(unless (magit-rev-verify-commit from) (unless (magit-commit-p from)
(setq from (magit-git-string "rev-list" "--max-parents=0" (setq from (magit-git-string "rev-list" "--max-parents=0"
commit))) commit)))
(magit-log-setup-buffer (list (concat from ".." to)) (magit-log-setup-buffer (list (concat from ".." to))
@@ -1131,7 +1137,7 @@ Type \\[magit-reset] to reset `HEAD' to the commit at point.
(require 'magit) (require 'magit)
(with-current-buffer (with-current-buffer
(magit-setup-buffer #'magit-log-mode locked (magit-setup-buffer #'magit-log-mode locked
(magit-buffer-revisions revs) (magit-buffer-log-revisions revs)
(magit-buffer-log-args args) (magit-buffer-log-args args)
(magit-buffer-log-files files)) (magit-buffer-log-files files))
(when (if focus (when (if focus
@@ -1141,7 +1147,7 @@ Type \\[magit-reset] to reset `HEAD' to the commit at point.
(current-buffer))) (current-buffer)))
(defun magit-log-refresh-buffer () (defun magit-log-refresh-buffer ()
(let ((revs magit-buffer-revisions) (let ((revs magit-buffer-log-revisions)
(args magit-buffer-log-args) (args magit-buffer-log-args)
(files magit-buffer-log-files) (files magit-buffer-log-files)
(limit (magit-log-get-commit-limit))) (limit (magit-log-get-commit-limit)))
@@ -1181,8 +1187,9 @@ Type \\[magit-reset] to reset `HEAD' to the commit at point.
(defvar-local magit-log--color-graph nil) (defvar-local magit-log--color-graph nil)
(defun magit-log--maybe-drop-color-graph (args limit) (defun magit-log--maybe-drop-color-graph (args limit)
(if (member "--color" args) (cond ((not (member "--color" args))
(if (cond ((not (member "--graph" args))) (setq magit-log--color-graph nil))
((cond ((not (member "--graph" args)) t)
((not magit-log-color-graph-limit) nil) ((not magit-log-color-graph-limit) nil)
((not limit) ((not limit)
(message "Dropping --color because -n isn't set (see %s)" (message "Dropping --color because -n isn't set (see %s)"
@@ -1190,15 +1197,14 @@ Type \\[magit-reset] to reset `HEAD' to the commit at point.
((> limit magit-log-color-graph-limit) ((> limit magit-log-color-graph-limit)
(message "Dropping --color because -n is larger than %s" (message "Dropping --color because -n is larger than %s"
'magit-log-color-graph-limit))) 'magit-log-color-graph-limit)))
(progn (setq args (remove "--color" args)) (setq args (remove "--color" args))
(setq magit-log--color-graph nil))
(setq magit-log--color-graph t))
(setq magit-log--color-graph nil)) (setq magit-log--color-graph nil))
((setq magit-log--color-graph t)))
args) args)
(cl-defmethod magit-buffer-value (&context (major-mode magit-log-mode)) (cl-defmethod magit-buffer-value (&context (major-mode magit-log-mode))
(append magit-buffer-revisions (append magit-buffer-log-revisions
(if (and magit-buffer-revisions magit-buffer-log-files) (if (and magit-buffer-log-revisions magit-buffer-log-files)
(cons "--" magit-buffer-log-files) (cons "--" magit-buffer-log-files)
magit-buffer-log-files))) magit-buffer-log-files)))
@@ -1779,20 +1785,20 @@ Type \\[magit-log-select-quit] to abort without selecting a commit."
(defun magit-log-select-setup-buffer (revs args) (defun magit-log-select-setup-buffer (revs args)
(magit-setup-buffer #'magit-log-select-mode nil (magit-setup-buffer #'magit-log-select-mode nil
(magit-buffer-revisions revs) (magit-buffer-log-revisions revs)
(magit-buffer-log-args args))) (magit-buffer-log-args args)))
(defun magit-log-select-refresh-buffer () (defun magit-log-select-refresh-buffer ()
(setq magit-section-inhibit-markers t) (setq magit-section-inhibit-markers t)
(setq magit-section-insert-in-reverse t) (setq magit-section-insert-in-reverse t)
(magit-insert-section (logbuf) (magit-insert-section (logbuf)
(magit--insert-log t magit-buffer-revisions (magit--insert-log t magit-buffer-log-revisions
(magit-log--maybe-drop-color-graph (magit-log--maybe-drop-color-graph
magit-buffer-log-args magit-buffer-log-args
(magit-log-get-commit-limit))))) (magit-log-get-commit-limit)))))
(cl-defmethod magit-buffer-value (&context (major-mode magit-log-select-mode)) (cl-defmethod magit-buffer-value (&context (major-mode magit-log-select-mode))
magit-buffer-revisions) magit-buffer-log-revisions)
(defvar-local magit-log-select-pick-function nil) (defvar-local magit-log-select-pick-function nil)
(defvar-local magit-log-select-quit-function nil) (defvar-local magit-log-select-quit-function nil)
@@ -1881,11 +1887,14 @@ Type \\[magit-cherry-pick] to apply the commit at point.
(magit-hack-dir-local-variables) (magit-hack-dir-local-variables)
(setq magit--imenu-group-types 'cherries)) (setq magit--imenu-group-types 'cherries))
(defvar-local magit-buffer-cherry-upstream nil)
(defvar-local magit-buffer-cherry-range nil)
(defun magit-cherry-setup-buffer (head upstream) (defun magit-cherry-setup-buffer (head upstream)
(magit-setup-buffer #'magit-cherry-mode nil (magit-setup-buffer #'magit-cherry-mode nil
(magit-buffer-refname head) (magit-buffer-refname head)
(magit-buffer-upstream upstream) (magit-buffer-cherry-upstream upstream)
(magit-buffer-range (concat upstream ".." head)))) (magit-buffer-cherry-range (concat upstream ".." head))))
(defun magit-cherry-refresh-buffer () (defun magit-cherry-refresh-buffer ()
(setq magit-section-insert-in-reverse t) (setq magit-section-insert-in-reverse t)
@@ -1893,7 +1902,7 @@ Type \\[magit-cherry-pick] to apply the commit at point.
(magit-run-section-hook 'magit-cherry-sections-hook))) (magit-run-section-hook 'magit-cherry-sections-hook)))
(cl-defmethod magit-buffer-value (&context (major-mode magit-cherry-mode)) (cl-defmethod magit-buffer-value (&context (major-mode magit-cherry-mode))
magit-buffer-range) magit-buffer-cherry-range)
;;;###autoload ;;;###autoload
(defun magit-cherry (head upstream) (defun magit-cherry (head upstream)
@@ -1909,8 +1918,9 @@ Type \\[magit-cherry-pick] to apply the commit at point.
"Insert headers appropriate for `magit-cherry-mode' buffers." "Insert headers appropriate for `magit-cherry-mode' buffers."
(let ((branch (propertize magit-buffer-refname (let ((branch (propertize magit-buffer-refname
'font-lock-face 'magit-branch-local)) 'font-lock-face 'magit-branch-local))
(upstream (propertize magit-buffer-upstream 'font-lock-face (upstream (propertize
(if (magit-local-branch-p magit-buffer-upstream) magit-buffer-cherry-upstream 'font-lock-face
(if (magit-local-branch-p magit-buffer-cherry-upstream)
'magit-branch-local 'magit-branch-local
'magit-branch-remote)))) 'magit-branch-remote))))
(magit-insert-head-branch-header branch) (magit-insert-head-branch-header branch)
@@ -1923,7 +1933,7 @@ Type \\[magit-cherry-pick] to apply the commit at point.
(magit-insert-heading t "Cherry commits") (magit-insert-heading t "Cherry commits")
(magit-git-wash (apply-partially #'magit-log-wash-log 'cherry) (magit-git-wash (apply-partially #'magit-log-wash-log 'cherry)
"cherry" "-v" "--abbrev" "cherry" "-v" "--abbrev"
magit-buffer-upstream magit-buffer-cherry-upstream
magit-buffer-refname))) magit-buffer-refname)))
;;; Log Sections ;;; Log Sections
@@ -2114,6 +2124,7 @@ all others with \"-\"."
;; ("and>" . "cond-let--and>") ;; ("and>" . "cond-let--and>")
;; ("and-let" . "cond-let--and-let") ;; ("and-let" . "cond-let--and-let")
;; ("if-let" . "cond-let--if-let") ;; ("if-let" . "cond-let--if-let")
;; ("when$" . "cond-let--when$")
;; ("when-let" . "cond-let--when-let") ;; ("when-let" . "cond-let--when-let")
;; ("while-let" . "cond-let--while-let") ;; ("while-let" . "cond-let--while-let")
;; ("match-string" . "match-string") ;; ("match-string" . "match-string")
+2 -1
View File
@@ -1,6 +1,6 @@
;;; magit-margin.el --- Margins in Magit buffers -*- lexical-binding:t -*- ;;; magit-margin.el --- Margins in Magit buffers -*- lexical-binding:t -*-
;; Copyright (C) 2008-2025 The Magit Project Contributors ;; Copyright (C) 2008-2026 The Magit Project Contributors
;; Author: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev> ;; Author: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
;; Maintainer: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev> ;; Maintainer: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
@@ -263,6 +263,7 @@ English.")
;; ("and>" . "cond-let--and>") ;; ("and>" . "cond-let--and>")
;; ("and-let" . "cond-let--and-let") ;; ("and-let" . "cond-let--and-let")
;; ("if-let" . "cond-let--if-let") ;; ("if-let" . "cond-let--if-let")
;; ("when$" . "cond-let--when$")
;; ("when-let" . "cond-let--when-let") ;; ("when-let" . "cond-let--when-let")
;; ("while-let" . "cond-let--while-let") ;; ("while-let" . "cond-let--while-let")
;; ("match-string" . "match-string") ;; ("match-string" . "match-string")
+18 -9
View File
@@ -1,6 +1,6 @@
;;; magit-merge.el --- Merge functionality -*- lexical-binding:t -*- ;;; magit-merge.el --- Merge functionality -*- lexical-binding:t -*-
;; Copyright (C) 2008-2025 The Magit Project Contributors ;; Copyright (C) 2008-2026 The Magit Project Contributors
;; Author: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev> ;; Author: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
;; Maintainer: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev> ;; Maintainer: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
@@ -95,8 +95,10 @@ the user inspect the result. With a prefix argument pretend the
merge failed to give the user the opportunity to inspect the merge failed to give the user the opportunity to inspect the
merge. merge.
To create an octopus-merge, separate branches with commas.
\(git merge --no-edit|--no-commit [ARGS] REV)" \(git merge --no-edit|--no-commit [ARGS] REV)"
(interactive (list (magit-read-other-branch-or-commit "Merge") (interactive (list (magit-read-other-branches-or-commits "Merge")
(magit-merge-arguments) (magit-merge-arguments)
current-prefix-arg)) current-prefix-arg))
(magit-merge-assert) (magit-merge-assert)
@@ -105,24 +107,30 @@ merge.
;;;###autoload ;;;###autoload
(defun magit-merge-editmsg (rev &optional args) (defun magit-merge-editmsg (rev &optional args)
"Merge commit REV into the current branch; and edit message. "Merge commit REV into the current branch; and edit message.
Perform the merge and prepare a commit message but let the user Perform the merge and prepare a commit message but let the user
edit it. edit it.
\n(git merge --edit --no-ff [ARGS] REV)"
(interactive (list (magit-read-other-branch-or-commit "Merge") To create an octopus-merge, separate branches with commas.
\(git merge --edit --no-ff [ARGS] REV)"
(interactive (list (magit-read-other-branches-or-commits "Merge")
(magit-merge-arguments))) (magit-merge-arguments)))
(magit-merge-assert) (magit-merge-assert)
(cl-pushnew "--no-ff" args :test #'equal) (cl-pushnew "--no-ff" args :test #'equal)
(apply #'magit-run-git-with-editor "merge" "--edit" (magit-run-git-with-editor "merge" "--edit" (delete "--ff-only" args) rev))
(append (delete "--ff-only" args)
(list rev))))
;;;###autoload ;;;###autoload
(defun magit-merge-nocommit (rev &optional args) (defun magit-merge-nocommit (rev &optional args)
"Merge commit REV into the current branch; pretending it failed. "Merge commit REV into the current branch; pretending it failed.
Pretend the merge failed to give the user the opportunity to Pretend the merge failed to give the user the opportunity to
inspect the merge and change the commit message. inspect the merge and change the commit message.
\n(git merge --no-commit --no-ff [ARGS] REV)"
(interactive (list (magit-read-other-branch-or-commit "Merge") To create an octopus-merge, separate branches with commas.
\(git merge --no-commit --no-ff [ARGS] REV)"
(interactive (list (magit-read-other-branches-or-commits "Merge")
(magit-merge-arguments))) (magit-merge-arguments)))
(magit-merge-assert) (magit-merge-assert)
(cl-pushnew "--no-ff" args :test #'equal) (cl-pushnew "--no-ff" args :test #'equal)
@@ -317,6 +325,7 @@ If no merge is in progress, do nothing."
;; ("and>" . "cond-let--and>") ;; ("and>" . "cond-let--and>")
;; ("and-let" . "cond-let--and-let") ;; ("and-let" . "cond-let--and-let")
;; ("if-let" . "cond-let--if-let") ;; ("if-let" . "cond-let--if-let")
;; ("when$" . "cond-let--when$")
;; ("when-let" . "cond-let--when-let") ;; ("when-let" . "cond-let--when-let")
;; ("while-let" . "cond-let--while-let") ;; ("while-let" . "cond-let--while-let")
;; ("match-string" . "match-string") ;; ("match-string" . "match-string")
+56 -31
View File
@@ -1,6 +1,6 @@
;;; magit-mode.el --- Create and refresh Magit buffers -*- lexical-binding:t -*- ;;; magit-mode.el --- Create and refresh Magit buffers -*- lexical-binding:t -*-
;; Copyright (C) 2008-2025 The Magit Project Contributors ;; Copyright (C) 2008-2026 The Magit Project Contributors
;; Author: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev> ;; Author: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
;; Maintainer: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev> ;; Maintainer: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
@@ -51,6 +51,8 @@
(declare-function magit-wip-get-ref "magit-wip" ()) (declare-function magit-wip-get-ref "magit-wip" ())
(declare-function magit-wip-commit-worktree "magit-wip" (ref files msg)) (declare-function magit-wip-commit-worktree "magit-wip" (ref files msg))
(declare-function magit--blob-cache-zap "magit-files" ())
;;; Options ;;; Options
(defcustom magit-mode-hook nil (defcustom magit-mode-hook nil
@@ -578,35 +580,41 @@ Magit is documented in info node `(magit)'."
;;; Local Variables ;;; Local Variables
(defvar-local magit-buffer-arguments nil) (defvaralias 'magit-buffer-refname 'magit-buffer-revision)
(defvar-local magit-buffer-diff-type nil)
(defvar-local magit-buffer-diff-args nil)
(defvar-local magit-buffer-diff-files nil)
(defvar-local magit-buffer-diff-files-suspended nil)
(defvar-local magit-buffer-file-name nil)
(defvar-local magit-buffer-files nil)
(defvar-local magit-buffer-log-args nil)
(defvar-local magit-buffer-log-files nil)
(defvar-local magit-buffer-range nil)
(defvar-local magit-buffer-range-hashed nil)
(defvar-local magit-buffer-refname nil)
(defvar-local magit-buffer-revision nil) (defvar-local magit-buffer-revision nil)
(defvar-local magit-buffer-revision-hash nil) (defvar-local magit-buffer-revision-oid nil)
(defvar-local magit-buffer-revisions nil) (defvar-local magit-buffer-blob-oid nil)
(defvar-local magit-buffer-typearg nil) (defvar-local magit-buffer-file-name nil)
(defvar-local magit-buffer-upstream nil)
;; These variables are also used in file-visiting buffers. ;; Preserve when major-mode is changed in file-visiting buffers.
;; Because the user may change the major-mode, they have
;; to be permanent buffer-local.
(put 'magit-buffer-file-name 'permanent-local t)
(put 'magit-buffer-refname 'permanent-local t)
(put 'magit-buffer-revision 'permanent-local t) (put 'magit-buffer-revision 'permanent-local t)
(put 'magit-buffer-revision-hash 'permanent-local t) (put 'magit-buffer-revision-oid 'permanent-local t)
(put 'magit-buffer-blob-oid 'permanent-local t)
(put 'magit-buffer-file-name 'permanent-local t)
;; `magit-status' re-enables mode function but its refresher (eval-and-compile
;; function does not reinstate this. (defvar magit-define-aliases-for:magit-buffer-* t)
(put 'magit-buffer-diff-files-suspended 'permanent-local t) (when magit-define-aliases-for:magit-buffer-*
;; Unfortunately defvar-local can only be used at top-level,
;; so instead we have to use make-variable-buffer-local below.
(defvar magit-buffer-arguments nil)
(make-obsolete-variable 'magit-buffer-arguments
"use a mode- or package-specific `magit-buffer-{*}-args' instead"
"magit 4.6.0")
(defvar magit-buffer-upstream nil)
(make-obsolete-variable 'magit-buffer-upstream
"use a mode- or package-specific `magit-buffer-{*}-upstream' instead"
"magit 4.6.0")
(define-obsolete-variable-alias 'magit-buffer-range-hashed
'magit-buffer-diff-range-oids "magit 4.6.0")
(define-obsolete-variable-alias 'magit-buffer-revisions
'magit-buffer-log-revisions "magit 4.6.0")
(define-obsolete-variable-alias 'magit-buffer-revision-hash
'magit-buffer-revision-oid "magit 4.6.0")
(define-obsolete-variable-alias 'magit-buffer-typearg
'magit-buffer-diff-typearg "magit 4.6.0")))
(make-variable-buffer-local 'magit-buffer-arguments)
(make-variable-buffer-local 'magit-buffer-upstream)
(defun magit-buffer-file-name () (defun magit-buffer-file-name ()
"Return `magit-buffer-file-name' or if that is nil `buffer-file-name'. "Return `magit-buffer-file-name' or if that is nil `buffer-file-name'.
@@ -617,6 +625,7 @@ In an indirect buffer get the value for its base buffer."
(defun magit-buffer-revision () (defun magit-buffer-revision ()
"Return `magit-buffer-revision' or if that is nil \"{worktree}\". "Return `magit-buffer-revision' or if that is nil \"{worktree}\".
If not visiting a blob or file, or the file isn't being tracked, If not visiting a blob or file, or the file isn't being tracked,
return nil. If visiting a blob but `magit-buffer-revision' is nil,
return nil." return nil."
(or magit-buffer-revision (or magit-buffer-revision
(and buffer-file-name (and buffer-file-name
@@ -1179,7 +1188,21 @@ The arguments are for internal use."
;; for the wrong buffer. Originally reported in #4196 and ;; for the wrong buffer. Originally reported in #4196 and
;; fixed with 482c25a3204468a4f6c2fe12ff061666b61f5f4d. ;; fixed with 482c25a3204468a4f6c2fe12ff061666b61f5f4d.
(let ((magit-section-movement-hook nil)) (let ((magit-section-movement-hook nil))
(magit-section-goto-successor section line char))))) (magit-section-goto-successor section line char)
;; To store the point value for the selected window, it isn't
;; enough for it to be current, the window has to "display" it.
;; The effect of `goto-char', used by the above function, is not
;; preserved, and using just `set-window-point' would affect the
;; wrong buffer.
(unless (eq (window-dedicated-p) t)
(let ((restore (window-buffer))
(window-scroll-functions nil)
(window-configuration-change-hook nil))
(unwind-protect
(progn
(set-window-buffer nil (current-buffer) t)
(set-window-point nil (point)))
(set-window-buffer nil restore t))))))))
(defun magit-revert-buffer (_ignore-auto _noconfirm) (defun magit-revert-buffer (_ignore-auto _noconfirm)
"Wrapper around `magit-refresh-buffer' suitable as `revert-buffer-function'." "Wrapper around `magit-refresh-buffer' suitable as `revert-buffer-function'."
@@ -1539,13 +1562,14 @@ repositories."
"Zap caches for the current repository. "Zap caches for the current repository.
Remove the repository's entry from `magit-repository-local-cache', Remove the repository's entry from `magit-repository-local-cache',
remove the host's entry from `magit--host-git-version-cache', and remove the host's entry from `magit--host-git-version-cache', set
set `magit-section-visibility-cache' to nil for all Magit buffers `magit-section-visibility-cache' to nil for all Magit buffers of
of the repository. the repository, and empty the `magit--blob-cache'.
With a prefix argument or if optional ALL is non-nil, discard the With a prefix argument or if optional ALL is non-nil, discard the
mentioned caches completely." mentioned caches completely."
(interactive) (interactive)
(magit--blob-cache-zap)
(cond (all (cond (all
(setq magit-repository-local-cache nil) (setq magit-repository-local-cache nil)
(setq magit--host-git-version-cache nil) (setq magit--host-git-version-cache nil)
@@ -1594,7 +1618,7 @@ The additional output can be found in the *Messages* buffer."
(defun magit-file-region-line-numbers () (defun magit-file-region-line-numbers ()
"Return the bounds of the region as line numbers. "Return the bounds of the region as line numbers.
The returned value has the form (BEGINNING-LINE END-LINE). If The returned value has the form (BEGINNING-LINE END-LINE). If
the region end at the beginning of a line, do not include that the region ends at the beginning of a line, do not include that
line. Avoid including the line after the end of the file." line. Avoid including the line after the end of the file."
(and (magit-buffer-file-name) (and (magit-buffer-file-name)
(region-active-p) (region-active-p)
@@ -1615,6 +1639,7 @@ line. Avoid including the line after the end of the file."
;; ("and>" . "cond-let--and>") ;; ("and>" . "cond-let--and>")
;; ("and-let" . "cond-let--and-let") ;; ("and-let" . "cond-let--and-let")
;; ("if-let" . "cond-let--if-let") ;; ("if-let" . "cond-let--if-let")
;; ("when$" . "cond-let--when$")
;; ("when-let" . "cond-let--when-let") ;; ("when-let" . "cond-let--when-let")
;; ("while-let" . "cond-let--while-let") ;; ("while-let" . "cond-let--while-let")
;; ("match-string" . "match-string") ;; ("match-string" . "match-string")
+2 -1
View File
@@ -1,6 +1,6 @@
;;; magit-notes.el --- Notes support -*- lexical-binding:t -*- ;;; magit-notes.el --- Notes support -*- lexical-binding:t -*-
;; Copyright (C) 2008-2025 The Magit Project Contributors ;; Copyright (C) 2008-2026 The Magit Project Contributors
;; Author: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev> ;; Author: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
;; Maintainer: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev> ;; Maintainer: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
@@ -204,6 +204,7 @@ Also see `magit-notes-merge'."
;; ("and>" . "cond-let--and>") ;; ("and>" . "cond-let--and>")
;; ("and-let" . "cond-let--and-let") ;; ("and-let" . "cond-let--and-let")
;; ("if-let" . "cond-let--if-let") ;; ("if-let" . "cond-let--if-let")
;; ("when$" . "cond-let--when$")
;; ("when-let" . "cond-let--when-let") ;; ("when-let" . "cond-let--when-let")
;; ("while-let" . "cond-let--while-let") ;; ("while-let" . "cond-let--while-let")
;; ("match-string" . "match-string") ;; ("match-string" . "match-string")

Some files were not shown because too many files have changed in this diff Show More