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 -*-
(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>
;; 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
;; it under the terms of the GNU General Public License as published by
@@ -17,7 +18,7 @@
;; 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/>.
;; along with this program. If not, see <https://www.gnu.org/licenses/>.
;;; Commentary:
@@ -26,6 +27,12 @@
;; 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.
;;; News:
;; Since version 0.8:
;; - Use `lexical-binding'.
;;; Code:
(defcustom adaptive-wrap-extra-indent 0
@@ -104,7 +111,8 @@ extra indent = 2
""))))
(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
;; `fill-context-prefix' ignores prefixes that look like 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."
'((emacs "24.4")
(s "0"))
:url "http://github.com/DarwinAwardWinner/amx/"
:url "https://github.com/DarwinAwardWinner/amx/"
:commit "1c2428d21e9d2ee8bee944b572a39ca8c91ca13b"
:revdesc "1c2428d21e9d"
:keywords '("convenience" "usability" "completion")
+3 -3
View File
@@ -1,10 +1,10 @@
;; -*- no-byte-compile: t; lexical-binding: nil -*-
(define-package "async" "20251005.634"
(define-package "async" "20260318.1803"
"Asynchronous processing in Emacs."
'((emacs "24.4"))
:url "https://github.com/jwiegley/emacs-async"
:commit "31cb2fea8f4bc7a593acd76187a89075d8075500"
:revdesc "31cb2fea8f4b"
:commit "5faab28916603bb324d9faba057021ce028ca847"
:revdesc "5faab2891660"
:keywords '("async")
:authors '(("John Wiegley" . "jwiegley@gmail.com"))
:maintainers '(("Thierry Volpiatto" . "thievol@posteo.net")))
+11 -13
View File
@@ -6,12 +6,12 @@
;; Maintainer: Thierry Volpiatto <thievol@posteo.net>
;; Created: 18 Jun 2012
;; Package-Version: 20251005.634
;; Package-Revision: 31cb2fea8f4b
;; Package-Version: 20260318.1803
;; Package-Revision: 5faab2891660
;; Package-Requires: ((emacs "24.4"))
;; 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
;; 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)))))))
(defun async--receive-sexp (&optional stream)
;; FIXME: Why use `utf-8-auto' instead of `utf-8-unix'? This is
;; a communication channel over which we have complete control,
;; so we get to choose exactly which encoding and EOL we use, isn't
;; it?
;; UPDATE: We use now `utf-8-emacs-unix' instead of `utf-8-auto' as
;; recommended in bug#165.
;; We use `utf-8-emacs-unix' for the communication channel between
;; parent and child Emacs processes. This encoding can represent any
;; character that Emacs is capable of processing and gives us full
;; control over the EOL format. (See bug#165)
(let ((sexp (decode-coding-string (base64-decode-string (read stream))
'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))
(if async-debug
(message "Received sexp {{{%s}}}" (pp-to-string sexp)))
@@ -324,8 +322,8 @@ is used."
(defun async-batch-invoke ()
"Called from the child Emacs process' command line."
;; Make sure 'message' and 'prin1' encode stuff in UTF-8, as parent
;; process expects.
;; Make sure 'message' and 'prin1' encode stuff in utf-8-emacs-unix,
;; as parent process expects.
(let ((coding-system-for-write 'utf-8-emacs-unix)
(args-left command-line-args-left))
(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
`async-ready' or `async-wait'."
(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))
(setq async--procvar
(apply 'async-start-process
+1 -1
View File
@@ -237,7 +237,7 @@ CSL tests."
"<span style=\"text-decoration:underline;\">" x "</span>")))
(vertical-align-sub . ,(lambda (x) (concat "<sub>" x "</sub>")))
(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\">"
x "</div>")))
(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 -*-
(define-package "citeproc" "20251103.716"
(define-package "citeproc" "20260113.1047"
"A CSL 1.0.2 Citation Processor."
'((emacs "26")
(dash "2.13.0")
@@ -11,8 +11,8 @@
(parsebib "2.4")
(compat "28.1"))
:url "https://github.com/andras-simonyi/citeproc-el"
:commit "a3d62ab8e40a75fcfc6e4c0c107e3137b4db6db8"
:revdesc "a3d62ab8e40a"
:commit "4bde999a41803fe519ea80eab8b813d53503eebd"
:revdesc "4bde999a4180"
:keywords '("bib")
:authors '(("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
;; 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-Version: 20251103.716
;; Package-Revision: a3d62ab8e40a
;; Package-Version: 20260113.1047
;; Package-Revision: 4bde999a4180
;; 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
+3 -3
View File
@@ -1,6 +1,6 @@
;;; 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
@@ -153,8 +153,8 @@ comments or strings."
(pcase company-dabbrev-code-other-buffers
(`t (list major-mode))
(`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)))
:expire t
:check-tag
+3 -3
View File
@@ -1,9 +1,9 @@
;; -*- no-byte-compile: t; lexical-binding: nil -*-
(define-package "company" "20251021.2211"
(define-package "company" "20260331.245"
"Modular text completion framework."
'((emacs "26.1"))
:url "http://company-mode.github.io/"
:commit "4ff89f7369227fbb89fe721d1db707f1af74cd0f"
:revdesc "4ff89f736922"
:commit "59626254bbac187fc2b8d7a189aca90976ab36a8"
:revdesc "59626254bbac"
:keywords '("abbrev" "convenience" "matching")
:maintainers '(("Dmitry Gutov" . "dmitry@gutov.dev")))
+11 -9
View File
@@ -5,8 +5,8 @@
;; Author: Nikolaj Schumacher
;; Maintainer: Dmitry Gutov <dmitry@gutov.dev>
;; URL: http://company-mode.github.io/
;; Package-Version: 20251021.2211
;; Package-Revision: 4ff89f736922
;; Package-Version: 20260331.245
;; Package-Revision: 59626254bbac
;; Keywords: abbrev, convenience, matching
;; Package-Requires: ((emacs "26.1"))
@@ -80,7 +80,7 @@
(defface company-tooltip
'((((class color) (min-colors 88) (background light))
(:foreground "black" :background "cornsilk"))
(:foreground "black" :background "ghostwhite"))
(((class color) (min-colors 88) (background dark))
(:background "gray26"))
(t (:foreground "black" :background "yellow")))
@@ -88,7 +88,7 @@
(defface company-tooltip-selection
'((((class color) (min-colors 88) (background light))
(:background "light blue"))
(:background "lavender"))
(((class color) (min-colors 88) (background dark))
(:background "gray31"))
(t (:background "green")))
@@ -149,7 +149,7 @@
(defface company-tooltip-scrollbar-thumb
'((((background light))
:background "indian red")
:background "lightpink3")
(((background dark))
:background "gray33"))
"Face used for the tooltip scrollbar thumb (bar).")
@@ -161,7 +161,7 @@
(defface company-tooltip-scrollbar-track
'((((background light))
:background "wheat")
:background "thistle")
(((background dark))
:background "gray28"))
"Face used for the tooltip scrollbar track (trough).")
@@ -4163,7 +4163,7 @@ but adjust the expected values appropriately."
left
right)
(when scrollbar-bounds
(company--scrollbar i scrollbar-bounds)))
(company--scrollbar i scrollbar-bounds selected)))
new)))
(when remainder
@@ -4180,7 +4180,7 @@ but adjust the expected values appropriately."
(upper (+ lower size -1)))
(cons lower upper))))
(defun company--scrollbar (i bounds)
(defun company--scrollbar (i bounds selected)
(let* ((scroll-width (ceiling (* (default-font-width)
company-tooltip-scrollbar-width))))
(propertize " "
@@ -4188,7 +4188,9 @@ but adjust the expected values appropriately."
'face
(if (and (>= i (car bounds)) (<= i (cdr bounds)))
'company-tooltip-scrollbar-thumb
'company-tooltip-scrollbar-track))))
(if selected
'company-tooltip-selection
'company-tooltip)))))
(defun company--right-margin (limit length)
(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.
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
This is one of the values (together with company-idle-delay),
based on which Company auto-stars looking up completion candidates.
This option configures how many characters have to be typed in by a
user before candidates start to be collected and displayed. An
often choice nowadays is to configure this option to a lower number
than the default value of 3.
based on which Company auto-starts looking up completion
candidates. This option configures how many characters have to be
typed in by a user before candidates start to be collected and
displayed. An often choice nowadays is to configure this option to
a lower number than the default value of 3.
-- User Option: company-idle-delay
This is the second of the options that configure Company's
@@ -1786,32 +1786,32 @@ Ref: Commands-Footnote-110079
Node: Customization10246
Node: Customization Interface10718
Node: Configuration File11251
Ref: company-selection-wrap-around13563
Node: Frontends16052
Node: Tooltip Frontends17021
Ref: Tooltip Frontends-Footnote-127717
Node: Preview Frontends27954
Ref: Preview Frontends-Footnote-129212
Node: Echo Frontends29339
Node: Candidates Search30868
Node: Filter Candidates32200
Node: Quick Access a Candidate32980
Node: Backends34598
Node: Backends Usage Basics35628
Ref: Backends Usage Basics-Footnote-137060
Node: Grouped Backends37144
Node: Package Backends38655
Node: Code Completion39582
Node: Text Completion45099
Node: File Name Completion49523
Node: Template Expansion51069
Node: Candidates Post-Processing51788
Node: Troubleshooting54365
Node: Index56036
Node: Key Index56199
Node: Variable Index57698
Node: Function Index62551
Node: Concept Index67251
Ref: company-selection-wrap-around13565
Node: Frontends16054
Node: Tooltip Frontends17023
Ref: Tooltip Frontends-Footnote-127719
Node: Preview Frontends27956
Ref: Preview Frontends-Footnote-129214
Node: Echo Frontends29341
Node: Candidates Search30870
Node: Filter Candidates32202
Node: Quick Access a Candidate32982
Node: Backends34600
Node: Backends Usage Basics35630
Ref: Backends Usage Basics-Footnote-137062
Node: Grouped Backends37146
Node: Package Backends38657
Node: Code Completion39584
Node: Text Completion45101
Node: File Name Completion49525
Node: Template Expansion51071
Node: Candidates Post-Processing51790
Node: Troubleshooting54367
Node: Index56038
Node: Key Index56201
Node: Variable Index57700
Node: Function Index62553
Node: Concept Index67253

End Tag Table
+3 -3
View File
@@ -1,8 +1,8 @@
;; -*- no-byte-compile: t; lexical-binding: nil -*-
(define-package "cond-let" "20251101.1942"
(define-package "cond-let" "20260201.1500"
"Additional and improved binding conditionals."
'((emacs "28.1"))
:url "https://github.com/tarsius/cond-let"
:commit "288b7d36563223ebaf64cb220a3b270bdffb63f1"
:revdesc "288b7d365632"
:commit "8bf87d45e169ebc091103b2aae325aece3aa804d"
:revdesc "8bf87d45e169"
:keywords '("extensions"))
+12 -9
View File
@@ -1,6 +1,6 @@
;;; 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
;; Copyright (C) 1985-2025 Free Software Foundation, Inc.
@@ -9,8 +9,8 @@
;; Homepage: https://github.com/tarsius/cond-let
;; Keywords: extensions
;; Package-Version: 20251101.1942
;; Package-Revision: 288b7d365632
;; Package-Version: 20260201.1500
;; Package-Revision: 8bf87d45e169
;; Package-Requires: ((emacs "28.1"))
;; SPDX-License-Identifier: GPL-3.0-or-later
@@ -30,14 +30,16 @@
;;; Commentary:
;; This is an ALPHA release!
;; Breaking changes are possible!
;; This is a BETA release!
;; Breaking changes are unlikely but still possible!
;; See https://github.com/tarsius/cond-let/wiki.
;; Emacs provides the binding conditionals `if-let', `if-let*',
;; `when-let', `when-let*', `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
;; implementations of the binding conditionals already provided by
@@ -61,6 +63,7 @@
;; ("and>" . "cond-let--and>")
;; ("and-let" . "cond-let--and-let")
;; ("if-let" . "cond-let--if-let")
;; ("when$" . "cond-let--when$")
;; ("when-let" . "cond-let--when-let")
;; ("while-let" . "cond-let--while-let"))
;; End:
@@ -73,8 +76,8 @@
;; Due to limitations of the shorthand implementation this has to be
;; 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
;; configuration:
;; If you use `when$', `and$' and `and>', you might want to add this
;; to your configuration:
;; (with-eval-after-load 'cond-let
;; (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.
\(fn VARLIST BODY...)"
(declare (debug (form form)))
(declare (indent 1) (debug (form form)))
`(let (($ ,varform))
(when $
,bodyform ,@body)))
+3 -3
View File
@@ -1,12 +1,12 @@
;; -*- no-byte-compile: t; lexical-binding: nil -*-
(define-package "counsel" "20250329.1401"
(define-package "counsel" "20260214.1004"
"Various completion functions using Ivy."
'((emacs "24.5")
(ivy "0.15.1")
(swiper "0.15.1"))
:url "https://github.com/abo-abo/swiper"
:commit "e33b028ed4b1258a211c87fd5fe801bed25de429"
:revdesc "e33b028ed4b1"
:commit "ee79f68215ae7e2b8a38ba6bf7f82b3fe57dc16c"
:revdesc "ee79f68215ae"
:keywords '("convenience" "matching" "tools")
:authors '(("Oleh Krehel" . "ohwoeowho@gmail.com"))
: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 -*-
;; Copyright (C) 2015-2025 Free Software Foundation, Inc.
;; Copyright (C) 2015-2026 Free Software Foundation, Inc.
;; Author: Oleh Krehel <ohwoeowho@gmail.com>
;; Maintainer: Basil L. Contovounesios <basil@contovou.net>
;; URL: https://github.com/abo-abo/swiper
;; Package-Version: 20250329.1401
;; Package-Revision: e33b028ed4b1
;; Package-Version: 20260214.1004
;; Package-Revision: ee79f68215ae
;; Package-Requires: ((emacs "24.5") (ivy "0.15.1") (swiper "0.15.1"))
;; Keywords: convenience, matching, tools
@@ -42,6 +42,7 @@
;;; Code:
(require 'cl-lib)
(require 'ivy)
(require 'swiper)
@@ -424,11 +425,10 @@ Update the minibuffer with the amount of lines collected every
(defun counsel-irony ()
"Inline C/C++ completion using Irony."
(interactive)
(irony-completion-candidates-async 'counsel-irony-callback))
(irony-completion-candidates-async #'counsel-irony-callback))
(defun counsel-irony-callback (candidates)
"Callback function for Irony to search among CANDIDATES."
(interactive)
(let* ((symbol-bounds (irony-completion-symbol-bounds))
(beg (car 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)))
(define-key map (kbd "C-.") #'counsel-find-symbol)
(define-key map (kbd "C-,") #'counsel--info-lookup-symbol)
map))
map)
"Keymap for Counsel commands that describe symbols.")
(ivy-set-actions
'counsel-describe-variable
@@ -472,12 +473,15 @@ Used by commands `counsel-describe-symbol',
"Jump to the definition of the current symbol."
(interactive)
(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 ()
"Lookup the current symbol in the info docs."
(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)
"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)))))
(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
(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
(find-library full-name)
(let ((sym (read x)))
@@ -532,7 +537,7 @@ Used by commands `counsel-describe-symbol',
(defun counsel-describe-variable-transformer (var)
"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)
var))
@@ -551,7 +556,8 @@ Variables declared using `defcustom' are highlighted according to
:keymap counsel-describe-map
:preselect (ivy-thing-at-point)
: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)))
(ivy-configure 'counsel-describe-variable
@@ -571,7 +577,7 @@ Variables declared using `defcustom' are highlighted according to
(defun counsel-describe-function-transformer (function-name)
"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)
function-name))
@@ -585,9 +591,15 @@ Variables declared using `defcustom' are highlighted according to
(function-item ivy-thing-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)
"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
(defun counsel-describe-function ()
@@ -600,7 +612,7 @@ to `ivy-highlight-face'."
(ivy-read "Describe function: " obarray
:predicate (lambda (sym)
(or (fboundp sym)
(get sym 'function-documentation)))
(function-get sym 'function-documentation)))
:require-match t
:history 'counsel-describe-symbol-history
:keymap counsel-describe-map
@@ -637,7 +649,8 @@ to `ivy-highlight-face'."
:keymap counsel-describe-map
:preselect (ivy-thing-at-point)
: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)))
(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'
(defface counsel-key-binding
;; Default Emacs 28 `help-key-binding' doesn't look great in parentheses.
'((t :inherit font-lock-keyword-face))
"Face used by `counsel-M-x' for key bindings."
:group 'ivy-faces)
@@ -874,7 +888,7 @@ With prefix arg MODE a query for the symbol help mode is offered."
(concat cmd
(when (and (symbolp alias) counsel-alias-expand)
(format " (%s)" alias))
(when key
(when (and key suggest-key-bindings)
;; Prefer `<f2>' over `C-x 6' where applicable
(let ((i (cl-search [?\C-x ?6] key)))
(when i
@@ -884,114 +898,149 @@ With prefix arg MODE a query for the symbol help mode is offered."
(lookup-key map dup))
(setq key dup)))))
(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)))))
(defvar amx-initialized)
(defvar amx-cache)
(declare-function amx-initialize "ext:amx")
(declare-function amx-detect-new-commands "ext:amx")
(declare-function amx-update "ext:amx")
(declare-function amx-rank "ext:amx")
(defvar smex-initialized-p)
(defvar smex-ido-cache)
(declare-function smex-initialize "ext:smex")
(declare-function smex-detect-new-commands "ext:smex")
(declare-function smex-update "ext:smex")
(declare-function smex-rank "ext:smex")
(defcustom counsel-M-x-collection 'auto
"Where to source `counsel-M-x' completion candidates from.
`obarray' - Use the default M-x collection built into Emacs.
`amx' - Source candidates from the external `amx' package.
`smex' - Source candidates from the external `smex' package.
`auto' - Automatically detect one of the previous options,
falling back to `obarray'. This is the default.
The value can alternatively be a function of no arguments
that returns a completion table suitable for `ivy-read'."
:package-version '(counsel . "0.16.0")
:type '(choice (const :tag "Built-in" obarray)
(const :tag "Amx package" amx)
(const :tag "Smex package" smex)
(const :tag "Auto-detect" auto)
(function :tag "Custom function")))
(defun counsel--M-x-externs ()
"Return `counsel-M-x' candidates from external packages.
The return value is a list of strings. The currently supported
packages are, in order of precedence, `amx' and `smex'."
(cond ((require 'amx nil t)
(defun counsel--M-x-collection ()
"Return a completion table obeying `counsel-M-x-collection'."
(let ((src counsel-M-x-collection))
(cond ((eq src 'obarray) obarray)
((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
(amx-initialize))
(when (amx-detect-new-commands)
(amx-update))
(mapcar (lambda (entry)
(symbol-name (car entry)))
amx-cache))
((require 'smex nil t)
amx-cache)
(defun counsel--smex-collection ()
"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
(smex-initialize))
(when (smex-detect-new-commands)
(smex-update))
smex-ido-cache)))
smex-ido-cache)
(defun counsel--M-x-externs-predicate (cand)
"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 ()
(defun counsel--M-x-predicate ()
"Return a predicate for `counsel-M-x' in the current buffer."
(defvar read-extended-command-predicate)
(let ((buf (current-buffer)))
(lambda (sym)
(and (commandp sym)
(not (get sym 'byte-obsolete-info))
(not (get sym 'no-counsel-M-x))
(cond ((not (bound-and-true-p read-extended-command-predicate)))
((functionp read-extended-command-predicate)
;; Should work with all completion table types.
(lambda (key &optional _val)
(when (consp key) (setq key (car key)))
(when (stringp key) (setq key (intern key)))
(and (commandp key)
(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
(funcall read-extended-command-predicate sym buf)
(funcall pred key buf)
(error (message "read-extended-command-predicate: %s: %s"
sym (error-message-string err))))))))))
key (error-message-string err))))))))))
(defun counsel--M-x-prompt ()
"String for `M-x' plus the string representation of `current-prefix-arg'."
(concat (cond ((null current-prefix-arg)
nil)
((eq current-prefix-arg '-)
"- ")
((integerp current-prefix-arg)
(format "%d " current-prefix-arg))
((= (car current-prefix-arg) 4)
"C-u ")
(t
(format "%d " (car current-prefix-arg))))
(defun counsel--M-x-prompt (arg)
"Prompt for `counsel-M-x' preceded by a printed form of prefix ARG."
(concat (cond ((null arg) ())
((eq (car-safe arg) 4) "C-u ")
((or (eq arg '-)
(integerp (or (car-safe arg) arg)))
(format "%s " (or (car-safe arg) arg))))
"M-x "))
(defvar counsel-M-x-history nil
"History for `counsel-M-x'.")
(defun counsel-M-x-action (cmd)
"Execute CMD."
(setq cmd (intern
(subst-char-in-string ?\s ?- (string-remove-prefix "^" cmd))))
(cond ((bound-and-true-p amx-initialized)
(amx-rank cmd))
((bound-and-true-p smex-initialized-p)
(smex-rank cmd)))
(setq prefix-arg current-prefix-arg)
"Execute CMD from `counsel-M-x'."
;; Currently CMD is a string either following `ivy-immediate-done',
;; or for all collection types but alist, where CMD is the original
;; cons. There is no harm in allowing other atoms through.
(setq cmd (cond ((stringp cmd)
(or (intern-soft cmd)
;; For the benefit of `ivy-immediate-done'.
(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 real-this-command cmd)
(command-execute cmd 'record))
(let ((prefix-arg (or ivy-current-prefix-arg current-prefix-arg)))
(command-execute cmd 'record)))
;;;###autoload
(defun counsel-M-x (&optional initial-input)
"Ivy version of `execute-extended-command'.
Optional INITIAL-INPUT is the initial input in the minibuffer.
This function integrates with either the `amx' or `smex' package
when available, in that order of precedence."
This function integrates with either the `amx' or `smex' package when
available, in that order of precedence; see `counsel-M-x-collection'."
(interactive)
;; When `counsel-M-x' returns, `last-command' would be set to
;; `counsel-M-x' because :action hasn't been invoked yet.
;; Instead, preserve the old value of `this-command'.
(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))
(ivy-read (counsel--M-x-prompt current-prefix-arg)
(counsel--M-x-collection)
:predicate (counsel--M-x-predicate)
:require-match t
:history 'counsel-M-x-history
:action #'counsel-M-x-action
:keymap counsel-describe-map
:initial-input initial-input
:caller 'counsel-M-x)))
:caller 'counsel-M-x))
(ivy-configure 'counsel-M-x
:initial-input "^"
@@ -1208,13 +1257,13 @@ See `execute-extended-command' for further information."
"Find symbol definition of candidate X.
See `counsel--find-symbol' for further information."
(let ((cmd (cddr x)))
(counsel--find-symbol (symbol-name cmd))))
(counsel--find-symbol cmd)))
(defun counsel-descbinds-action-info (x)
"Display symbol definition of candidate X, as found in the relevant manual.
See `info-lookup-symbol' for further information."
(let ((cmd (cddr x)))
(counsel-info-lookup-symbol (symbol-name cmd))))
(counsel-info-lookup-symbol cmd)))
;;;###autoload
(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)
(setq ivy--all-candidates
(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)
;; Prepend ./ if necessary:
@@ -1809,6 +1859,7 @@ When CMD is non-nil, prompt for a specific \"git grep\" command."
(find-file file-name)
(goto-char (point-min)))
(perform-replace from to t t nil))))))))))
(ivy--no-M-x #'counsel-git-grep-query-replace #'ivy--minibuffer-p)
;;;; `counsel-git-stash'
@@ -1974,20 +2025,12 @@ currently checked out."
;;; 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 ()
"Switch to `counsel-file-jump' from `counsel-find-file'."
(interactive)
(ivy-quit-and-run
(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")
(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)))))
(ivy-set-actions
'counsel-find-file
'(("j" find-file-other-window "other window")
("f" find-file-other-frame "other frame")
("b" counsel-find-file-cd-bookmark-action "cd bookmark")
("x" counsel-find-file-extern "open externally")
("r" counsel-find-file-as-root "open as root")
("R" find-file-read-only "read only")
("l" find-file-literally "open literally")
("k" counsel-find-file-delete "delete")
("c" counsel-find-file-copy "copy file")
("m" counsel-find-file-move "move or rename")
("d" counsel-find-file-mkdir-action "mkdir")))
#'counsel-find-file
`(("j" ,#'find-file-other-window "other window")
("f" ,#'find-file-other-frame "other frame")
("b" ,#'counsel-find-file-cd-bookmark-action "cd bookmark")
("x" ,#'counsel-find-file-extern "open externally")
("r" ,#'counsel-find-file-as-root "open as root")
("R" ,#'find-file-read-only "read only")
("l" ,#'find-file-literally "open literally")
("k" ,#'counsel-find-file-delete "delete")
("c" ,#'counsel-find-file-copy "copy file")
("m" ,#'counsel-find-file-move "move or rename")
("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
"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))
(if (= 0 (length regex))
"cat"
(let ((filter-cmd (cl-find-if
(lambda (x)
(let ((filter-cmd (cl-assoc-if
(lambda (cmd)
(executable-find
(car (split-string (car x)))))
(car (split-string cmd))))
counsel-file-name-filter-alist))
cmd)
(when (and use-ignore ivy-use-ignore
@@ -2339,11 +2393,13 @@ See variable `counsel-up-directory-level'."
(ivy--cd up-dir)
(setf (ivy-state-preselect ivy-last)
(file-name-as-directory (file-name-nondirectory cur-dir)))))))
(ivy--no-M-x #'counsel-up-directory #'ivy--minibuffer-p)
(defun counsel-down-directory ()
"Descend into the current directory."
(interactive)
(ivy--directory-enter))
(ivy--no-M-x #'counsel-down-directory #'ivy--minibuffer-p)
(defun counsel-find-file-undo ()
(interactive)
@@ -2354,6 +2410,7 @@ See variable `counsel-up-directory-level'."
(when dir
(ivy--cd dir)))
(undo)))
(ivy--no-M-x #'counsel-find-file-undo #'ivy--minibuffer-p)
(defun counsel-at-git-issue-p ()
"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'."
(recentf-mode)
(let ((buffers (delq nil (mapcar #'buffer-file-name (buffer-list)))))
(nconc
buffers
(cl-remove-if (lambda (f) (member f buffers))
(counsel-recentf-candidates)))))
(nconc buffers (cl-set-difference (counsel-recentf-candidates)
buffers :test #'equal))))
;;;###autoload
(defun counsel-buffer-or-recentf ()
@@ -2648,24 +2703,24 @@ By default `counsel-bookmark' opens a dired buffer for directories."
;;;; `counsel-bookmarked-directory'
(defun counsel-bookmarked-directory--candidates ()
"Get a list of bookmarked directories sorted by file path."
(defun counsel--bookmarked-dirs ()
"Return a list of bookmarked directories sorted by file name."
(bookmark-maybe-load-default-file)
(sort (cl-delete-if-not
#'ivy--dirname-p
(delq nil (mapcar #'bookmark-get-filename bookmark-alist)))
(sort (cl-mapcan (lambda (bm)
(let ((dir (bookmark-get-filename bm)))
(and dir (ivy--dirname-p dir) (list dir))))
bookmark-alist)
#'string<))
;;;###autoload
(defun counsel-bookmarked-directory ()
"Ivy interface for bookmarked directories.
With a prefix argument, this command creates a new bookmark which points to the
current value of `default-directory'."
With a prefix argument, this command creates a new bookmark which points
to the current value of `default-directory'."
(interactive)
(require 'bookmark)
(ivy-read "Bookmarked directory: "
(counsel-bookmarked-directory--candidates)
(ivy-read "Bookmarked directory: " (counsel--bookmarked-dirs)
:caller 'counsel-bookmarked-directory
:action #'dired))
@@ -2829,17 +2884,19 @@ library, which see."
"Location where to put the locatedb in case your home folder is encrypted."
:type 'file)
(defun counsel-file-stale-p (fname seconds)
"Return non-nil if FNAME was modified more than SECONDS ago."
(> (float-time (time-since (nth 5 (file-attributes fname))))
seconds))
(defun counsel-file-stale-p (file seconds)
"Return non-nil if FILE was modified more than SECONDS ago.
Also return non-nil if FILE does not exist."
(let ((mtime (nth 5 (file-attributes file))))
(or (not mtime)
(> (float-time (time-since mtime))
seconds))))
(defun counsel--locate-updatedb ()
(when (file-exists-p "~/.Private")
(let ((db-fname (expand-file-name counsel-locate-db-path)))
(setenv "LOCATE_PATH" db-fname)
(when (or (not (file-exists-p db-fname))
(counsel-file-stale-p db-fname 60))
(when (counsel-file-stale-p db-fname 60)
(message "Updating %s..." db-fname)
(counsel--command
"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)
(ivy-quit-and-run
(counsel-find-file ivy-text (ivy-state-directory ivy-last))))
(ivy--no-M-x #'counsel-find-file-from-jump #'ivy--minibuffer-p)
;;;###autoload
(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)))
(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 "C-'") #'swiper-avy)
(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")
"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)))
(ivy-quit-and-run
(funcall (ivy-state-caller ivy-last) input new-dir))))
(ivy--no-M-x #'counsel-cd #'ivy--minibuffer-p)
(defun counsel--grep-smart-case-flag ()
(if (ivy--case-fold-p ivy-text)
@@ -3457,8 +3516,8 @@ Example input with inclusion and exclusion file patterns:
(let ((map (make-sparse-keymap)))
(define-key map (kbd "C-l") #'ivy-call-and-recenter)
(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"
"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'."
(unless package--initialized
(package-initialize t))
(if (or (not package-archive-contents)
(cl-find-if (lambda (package-archive)
(let ((fname
(format
"%s/archives/%s/archive-contents"
package-user-dir (car package-archive))))
(or (not (file-exists-p fname))
(counsel-file-stale-p fname (* 4 60 60)))))
(when (or (null package-archive-contents)
(cl-some (lambda (archive)
(let* ((fname (format "archives/%s/archive-contents"
(car archive)))
(fname (expand-file-name fname package-user-dir)))
(counsel-file-stale-p fname (* 4 60 60))))
package-archives))
(package-refresh-contents))
(sort (mapcar (lambda (entry)
@@ -5099,6 +5156,7 @@ An extra action allows to switch to the process buffer."
(delete-minibuffer-contents)
(insert (substring-no-properties (car x))))
:caller 'counsel-minibuffer-history)))
(ivy--no-M-x #'counsel-minibuffer-history '(minibuffer-mode) t)
;;;; `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)
map))
;; Avoid (declare (modes ...)) warnings in Emacs < 28.
(function-put #'counsel-kmacro-kill 'command-modes '(minibuffer-mode))
(defun counsel-kmacro-kill ()
"Kill the line, or delete the currently selected keyboard macro."
(interactive)
@@ -5877,6 +5933,7 @@ You can insert or kill the name of the selected font."
(ivy-state-current ivy-last)
(ivy-state-collection ivy-last)))
(ivy--kill-current-candidate)))
(ivy--no-M-x #'counsel-kmacro-kill #'ivy--minibuffer-p)
(defvar kmacro-counter)
(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
counsel--linux-apps-cache-format-function)
(equal new-files counsel--linux-apps-cached-files)
(null (cl-find-if
(lambda (file)
(cl-notany (lambda (file)
(time-less-p
counsel--linux-apps-cache-timestamp
(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-format-function counsel-linux-app-format-function)
(setq counsel--linux-apps-cache-timestamp (current-time))
@@ -7010,15 +7066,16 @@ handling for the `counsel-compile' metadata."
(insert (substring-no-properties
cmd 0 (and (get-text-property 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.
(defvar counsel-compile-map
(let ((map (make-sparse-keymap)))
(define-key map `[remap ,#'ivy-insert-current]
#'counsel-compile-edit-command)
map)
"Additional ivy keybindings during command selection.")
"Additional Ivy keybindings during command selection.")
;;;###autoload
(defun counsel-compile (&optional dir)
+3 -3
View File
@@ -1,10 +1,10 @@
;; -*- no-byte-compile: t; lexical-binding: nil -*-
(define-package "dash" "20250312.1307"
(define-package "dash" "20260221.1346"
"A modern list library for Emacs."
'((emacs "24"))
:url "https://github.com/magnars/dash.el"
:commit "fcb5d831fc08a43f984242c7509870f30983c27c"
:revdesc "fcb5d831fc08"
:commit "d3a84021dbe48dba63b52ef7665651e0cf02e915"
:revdesc "d3a84021dbe4"
:keywords '("extensions" "lisp")
:authors '(("Magnar Sveen" . "magnars@gmail.com"))
: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 -*-
;; Copyright (C) 2012-2025 Free Software Foundation, Inc.
;; Copyright (C) 2012-2026 Free Software Foundation, Inc.
;; Author: Magnar Sveen <magnars@gmail.com>
;; Maintainer: Basil L. Contovounesios <basil@contovou.net>
;; Package-Version: 20250312.1307
;; Package-Revision: fcb5d831fc08
;; Package-Version: 20260221.1346
;; Package-Revision: d3a84021dbe4
;; Package-Requires: ((emacs "24"))
;; Keywords: extensions, lisp
;; URL: https://github.com/magnars/dash.el
@@ -27,7 +27,19 @@
;; 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:
@@ -1882,7 +1894,7 @@ LISTS, it is generally recommended to use `-unzip-lists' instead."
"Return an infinite circular copy of LIST.
The returned list cycles through the elements of LIST and repeats
from the beginning."
(declare (pure t) (side-effect-free t))
(declare (side-effect-free t))
;; Also works with sequences that aren't lists.
(let ((newlist (append list ())))
(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.
Copyright © 2012-2025 Free Software Foundation, Inc.
Copyright © 2012-2026 Free Software Foundation, Inc.
Permission is granted to copy, distribute and/or modify this
document under the terms of the GNU Free Documentation License,
@@ -24,7 +24,7 @@ Dash
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
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 -*-
(define-package "dashboard" "20250708.57"
(define-package "dashboard" "20260402.436"
"A startup screen extracted from Spacemacs."
'((emacs "27.1"))
:url "https://github.com/emacs-dashboard/emacs-dashboard"
:commit "8c2cf0cfde4f5dac8c477f755380fffef6824108"
:revdesc "8c2cf0cfde4f"
:url "https://github.com/emacs-dashboard/dashboard"
:commit "176d641a55543bda1f0c7506fb954702350c1857"
:revdesc "176d641a5554"
:keywords '("startup" "screen" "tools" "dashboard")
:authors '(("Rakan Al-Hneiti" . "rakan.alhneiti@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 -*-
;; Copyright (c) 2016-2025 emacs-dashboard maintainers
;; Copyright (c) 2016-2026 emacs-dashboard maintainers
;; 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-fileicon "ext:data-fileicons.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-file "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-all-names "ext:bookmark.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-load-known-projects "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-today "ext:org.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-agenda-new-buffers)
(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")
"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
(concat dashboard-banners-directory "logo.png")
"Emacs banner image.")
@@ -261,7 +278,7 @@ nerd-icons or (all-the-icons-faicon \"newspaper-o\") using all-the-icons."
:group 'dashboard)
(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'."
:type 'string
:group 'dashboard)
@@ -409,6 +426,29 @@ It can be a string or a string list for display random icons."
Value can be
- \\='official displays the official 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.
- a string that specifies the path of an custom banner
supported files types are gif/image/text/xbm.
@@ -419,6 +459,9 @@ Value can be
:type '(choice (const :tag "official" official)
(const :tag "logo" logo)
(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")
(string :tag "path to an image or text banner")
(cons :tag "image and text banner"
@@ -429,6 +472,9 @@ Value can be
(const :tag "official" official)
(const :tag "logo" logo)
(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"))))
:group 'dashboard)
@@ -589,7 +635,7 @@ Set to nil for unbounded."
;; TODO: Use function `string-pixel-width' after 29.1
(defun dashboard-string-pixel-width (str)
"Return the width of STR in pixels."
(if (fboundp #'string-pixel-width)
(if (fboundp 'string-pixel-width)
(string-pixel-width str)
(require 'shr)
(shr-string-pixel-width str)))
@@ -623,9 +669,7 @@ Set to nil for unbounded."
search-label
&optional no-next-line)
"Insert a shortcut SHORTCUT-CHAR for a given SEARCH-LABEL.
SHORTCUT-ID is the section identifier.
Optionally, provide NO-NEXT-LINE to move the cursor forward a line."
(let* (;; Ensure punctuation and upper case in search string is not
;; used to construct the `defun'
@@ -633,7 +677,6 @@ Optionally, provide NO-NEXT-LINE to move the cursor forward a line."
;; remove symbol quote
(sym (intern (replace-regexp-in-string "'" "" (format "dashboard-jump-to-%s" shortcut-id)))))
`(progn
(eval-when-compile (defvar dashboard-mode-map))
(defun ,sym nil
,(concat "Jump to " name ".
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)))
(back-to-indentation))
(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)
"Append MSG to dashboard buffer.
@@ -735,7 +787,17 @@ When called with TIMES return a function that insert TIMES number of newlines."
('logo
(append (when (image-type-available-p '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
(append (list :text dashboard-banner-ascii)))
((pred integerp)
@@ -809,6 +871,10 @@ Argument IMAGE-PATH path to the image."
(if (file-exists-p txt)
(insert-file-contents 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)
(setq text-width (dashboard--find-max-width start (point-max)))
(goto-char (point-max)))
@@ -955,33 +1021,39 @@ Return a space if icon is not found."
;;; Section list
(defmacro dashboard-insert-section-list (section-name list action &rest rest)
"Insert into SECTION-NAME a LIST of items, expanding ACTION and passing REST
to widget creation."
"Insert into SECTION-NAME a LIST of items, expanding ACTION.
REST is for widget creation."
`(when (car ,list)
(mapc
(lambda (el)
(let ((tag ,@rest))
(let* ((tag ,@rest)
(item tag))
(insert "\n")
(insert (spaces-string (or standard-indent tab-width 4)))
(when (and (dashboard-display-icons-p)
dashboard-set-file-icons)
(let* ((path (car (last (split-string ,@rest " - "))))
(icon (if (and (not (file-remote-p path))
(file-directory-p path))
(dashboard-icon-for-dir path
:height dashboard-icon-file-height
:v-adjust dashboard-icon-file-v-adjust)
(cond
(let* ((path (get-text-property 0 'dashboard-path item))
(icon (cond
((or (string-equal ,section-name "Agenda for today:")
(string-equal ,section-name "Agenda for the coming week:"))
dashboard-agenda-item-icon)
((file-remote-p path)
((and (stringp path)
(file-remote-p path))
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
:v-adjust dashboard-icon-file-v-adjust))))))
(setq tag (concat icon " " ,@rest))))
:v-adjust dashboard-icon-file-v-adjust))
((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
:tag tag
@@ -992,7 +1064,6 @@ to widget creation."
:button-suffix ""
:format "%[%t%]")))
,list)))
;;
;;; Footer
@@ -1198,6 +1269,26 @@ to widget creation."
(defvar dashboard--recentf-cache-item-format nil
"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)
"Add the list of LIST-SIZE items from recently edited files."
(setq dashboard--recentf-cache-item-format nil)
@@ -1212,20 +1303,9 @@ to widget creation."
'recents
(dashboard-get-shortcut 'recents)
`(lambda (&rest _)
(find-file-existing (dashboard-expand-path-alist ,el dashboard-recentf-alist)))
(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)))
(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))))))
(find-file-existing
(dashboard-expand-path-alist ,el dashboard-recentf-alist)))
(dashboard-recentf--propertize-item el)))
;;
;;; Bookmarks
@@ -1246,6 +1326,31 @@ to widget creation."
(defvar dashboard--bookmarks-cache-item-format nil
"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)
"Add the list of LIST-SIZE items of bookmarks."
(require 'bookmark)
@@ -1256,20 +1361,7 @@ to widget creation."
'bookmarks
(dashboard-get-shortcut 'bookmarks)
`(lambda (&rest _) (bookmark-jump ,el))
(if-let* ((filename 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)))
(dashboard-bookmarks--propertize-name-and-path el)))
;;
;;; 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))
(filename (dashboard-f-base file))
(path (dashboard-extract-key-path-alist el dashboard-projects-alist)))
(let ((display
(cl-case dashboard-projects-show-base
(`align
(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
dashboard-projects-item-format len-align)))
(setq dashboard--projects-cache-item-format new-fmt)))
(format dashboard--projects-cache-item-format filename 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 ()
"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
(dashboard-mute-apply
(ignore-errors
(dashboard-funcall-fboundp #'project-forget-zombie-projects))))
(project-known-project-roots))
(dashboard-funcall-fboundp 'project-forget-zombie-projects))))
(dashboard-funcall-fboundp 'project-known-project-roots))
(t
(display-warning '(dashboard)
"Invalid value for `dashboard-projects-backend'"
@@ -1358,11 +1455,7 @@ over custom backends."
(or dashboard-projects-switch-function
(cl-case dashboard-projects-backend
(`projectile 'projectile-switch-project-by-name)
(`project-el
(lambda (project)
"This function is used to switch to `PROJECT'."
(let ((default-directory project))
(project-find-file))))
(`project-el 'project-switch-project)
(t
(display-warning '(dashboard)
"Invalid value for `dashboard-projects-backend'"
@@ -1419,13 +1512,21 @@ each agenda entry."
(defcustom dashboard-agenda-tags-format 'identity
"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
(const :tag "Show tags" identity)
(const :tag "Hide tags" ignore)
(function :tag "Custom function"))
: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 ()
"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)))
(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
(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 ()
"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 -*-
;; Copyright (c) 2016-2025 emacs-dashboard maintainers
;; Copyright (c) 2016-2026 emacs-dashboard maintainers
;;
;; Author : Rakan Al-Hneiti <rakan.alhneiti@gmail.com>
;; Maintainer : Shen, Jen-Chieh <jcs090218@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.
;;
;;; License: GPLv3
;;
;; Created: October 05, 2016
;; Package-Version: 20250708.57
;; Package-Revision: 8c2cf0cfde4f
;; Package-Version: 20260402.436
;; Package-Revision: 176d641a5554
;; Keywords: startup, screen, tools, dashboard
;; Package-Requires: ((emacs "27.1"))
@@ -32,8 +32,9 @@
;;
;;; Externals
(declare-function bookmark-get-filename "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--files "ext:dashboard-ls.el")
(declare-function page-break-lines-mode "ext:page-break-lines.el")
@@ -50,7 +51,6 @@
"Extensible startup screen."
:group 'applications)
;; Custom splash screen
(defvar dashboard-mode-map
(let ((map (make-sparse-keymap)))
(define-key map (kbd "C-p") #'dashboard-previous-line)
@@ -273,32 +273,46 @@ example:
(defun dashboard-cycle-section-forward (&optional section)
"Cycle forward through the entries in SECTION.
If SECTION is nil, cycle in the current section."
(let ((target-section (or section (dashboard--current-section))))
(if target-section
(condition-case nil
(progn
(if section
(lambda () "Cycle section forwards"
(interactive)
(widget-forward 1)
(unless (eq target-section (dashboard--current-section))
(dashboard--goto-section target-section)))
(widget-forward 1))
(widget-forward 1))))
(unless (eq section (ignore-errors (dashboard--current-section)))
(dashboard--goto-section section)))
(lambda ()
(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)
"Cycle backward through the entries in SECTION.
If SECTION is nil, cycle in the current section."
(let ((target-section (or section (dashboard--current-section))))
(if target-section
(condition-case nil
(progn
(if section
(lambda () "Cycle section backwards"
(interactive)
(widget-backward 1)
(unless (eq target-section (dashboard--current-section))
(progn
(dashboard--goto-section target-section)
(while (eq target-section (dashboard--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-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-backward 1))))
(widget-backward 1))
(widget-backward 1))))
(widget-backward 1)))))
(defun dashboard-section-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 ()
"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 ()
"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."
(interactive)
(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)
(dashboard-num-recents (or (cdr (assoc 'recents dashboard-items)) 0)))
(when recentf-is-on
+3 -3
View File
@@ -1,11 +1,11 @@
;; -*- no-byte-compile: t; lexical-binding: nil -*-
(define-package "diff-hl" "20251216.242"
(define-package "diff-hl" "20260328.1925"
"Highlight uncommitted changes using VC."
'((cl-lib "0.2")
(emacs "26.1"))
:url "https://github.com/dgutov/diff-hl"
:commit "e79aa49ad3cbbe85379cf6646db3aaacd3b04708"
:revdesc "e79aa49ad3cb"
:commit "b965e19e6e7f9933199e421849a49229207c1c9f"
:revdesc "b965e19e6e7f"
:keywords '("vc" "diff")
:authors '(("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>
;; URL: https://github.com/dgutov/diff-hl
;; Keywords: vc, diff
;; Package-Version: 20251216.242
;; Package-Revision: e79aa49ad3cb
;; Package-Version: 20260328.1925
;; Package-Revision: b965e19e6e7f
;; Package-Requires: ((cl-lib "0.2") (emacs "26.1"))
;; This file is part of GNU Emacs.
@@ -143,6 +143,11 @@ enclosed in a `progn' form. ELSE-FORMS may be empty."
:group 'diff-hl
: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
"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)
1))
(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))
(if (floatp spacing)
(truncate (* (frame-char-height) spacing))
spacing)))
(if (floatp total-spacing)
(truncate (* (frame-char-height) total-spacing))
total-spacing)))
(w (min (frame-parameter nil (intern (format "%s-fringe" diff-hl-side)))
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))))
(when 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
;; prohibiting the async process call inside.
;; That still makes it partially async.
(diff-hl-update-async (and (not (eq window-system 'ns))
;; That still makes it partially async on macOS.
;; 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))))
(cond
((and
@@ -581,11 +591,6 @@ contents as they are (or would be) after applying the changes in NEW."
(setq old (cdr old)))
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)
(with-current-buffer buf
(let (res)
@@ -765,8 +770,9 @@ Return a list of line overlays used."
((eq (process-status proc) 'signal))
;; If a process is running, set the sentinel.
((eq (process-status proc) 'run)
(set-process-sentinel
proc
(add-function
:after
(process-sentinel proc)
(lambda (proc _status)
;; Delegate to the parent cond for decision logic.
(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."
(interactive)
(let ((overlay (diff-hl-search-next-hunk backward)))
(if overlay
(unless overlay
(user-error "No further hunks found"))
(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 ()
"Go to the beginning of the previous hunk in the current buffer."
@@ -1120,7 +1128,8 @@ its end position."
(diff-hl-next-hunk t))
(defun diff-hl-find-current-hunk ()
(let (o)
(let ((o)
(diff-hl-next-previous-hunk-auto-recenter nil))
(cond
((diff-hl-hunk-overlay-at (point)))
((setq o (diff-hl-search-next-hunk t))
+3 -3
View File
@@ -1,9 +1,9 @@
;; -*- no-byte-compile: t; lexical-binding: nil -*-
(define-package "emacsql" "20251130.1841"
(define-package "emacsql" "20260401.1220"
"High-level SQL database front-end."
'((emacs "26.1"))
:url "https://github.com/magit/emacsql"
:commit "f177a41e93b92a4b1139a553eed5415ca33f439c"
:revdesc "f177a41e93b9"
:commit "2fe6d4562b32a170a750d5e80514fbb6b6694803"
:revdesc "2fe6d4562b32"
:authors '(("Christopher Wellons" . "wellons@nullprogram.com"))
:maintainers '(("Jonas Bernoulli" . "emacs.emacsql@jonas.bernoulli.dev")))
+3 -3
View File
@@ -6,8 +6,8 @@
;; Maintainer: Jonas Bernoulli <emacs.emacsql@jonas.bernoulli.dev>
;; Homepage: https://github.com/magit/emacsql
;; Package-Version: 20251130.1841
;; Package-Revision: f177a41e93b9
;; Package-Version: 20260401.1220
;; Package-Revision: 2fe6d4562b32
;; Package-Requires: ((emacs "26.1"))
;; SPDX-License-Identifier: Unlicense
@@ -38,7 +38,7 @@
"The EmacSQL SQL database front-end."
:group 'comm)
(defconst emacsql-version "4.3.3")
(defconst emacsql-version "4.3.6")
(defvar emacsql-global-timeout 30
"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"
"Emacs Package Library."
'((cl-lib "0.3"))
:url "http://github.com/cask/epl"
:url "https://github.com/cask/epl"
:commit "78ab7a85c08222cd15582a298a364774e3282ce6"
:revdesc "78ab7a85c082"
:keywords '("convenience")
+1 -1
View File
@@ -16,4 +16,4 @@ File: dir, Node: Top This is the top of the INFO tree
Emacs
* 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\\)\\>"
font-lock-keyword-face)
(cons (concat "\\<d\\(bern\\|beta\\|bin\\|cat\\|chisq\\|"
"dexp\\|dirch\\|exp\\|\\(gen[.]\\)?gamma\\|hyper\\|"
"interval\\|lnorm\\|logis\\|mnorm\\|mt\\|multi\\|"
"negbin\\|norm\\(mix\\)?\\|par\\|pois\\|sum\\|t\\|"
"unif\\|weib\\|wish\\)[ \t\n]*(")
(cons (concat "\\<d\\(bern\\|beta\\|bin\\|binom\\|"
"cat\\|chisq\\|chisqr\\|CRP\\|"
"dexp\\|dirch\\|dirich\\|"
"exp\\|\\(gen[.]\\|inv\\)?gamma\\|hyper\\|"
"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)
(cons (concat "\\<\\(abs\\|cos\\|C\\|dim\\|\\(i\\)?cloglog\\|equals\\|"
"exp\\|for\\|inprod\\|interp[.]line\\|inverse\\|length\\|"
"\\(i\\)?logit\\|logdet\\|logfact\\|loggam\\|max\\|mean\\|"
"mexp\\|min\\|phi\\|pow\\|probit\\|prod\\|rank\\|round\\|"
"sd\\|sin\\|sort\\|sqrt\\|step\\|sum\\|t\\|trunc\\|T\\)[ \t\n]*(")
(cons (concat "\\<\\(abs\\|acos\\|acosh\\|asin\\|asinh\\|atan\\|atanh\\|"
"asCol\\|asRow\\|backsolve\\|besselK\\|ceiling\\|chol\\|"
"cos\\|C\\|dim\\|\\(i\\)?cloglog\\|cube\\|"
"equals\\|exp\\|expm\\|expAv\\|expit\\|"
"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)
;; .bmd files
+20 -19
View File
@@ -29,14 +29,14 @@
(require 'ess-utils)
(defvar ess-bugs-command)
(defvar ess-bugs-chains)
(defvar ess-jags-command)
(defvar ess-jags-chains)
;;(defvar ess-jags-command)
;;(defvar ess-jags-chains)
(defvar ess-bugs-default-bins)
(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-jags-na-jmd "ess-jags-d")
;;(declare-function ess-jags-na-jmd "ess-jags-d")
(defgroup ess-bugs nil
"ESS: BUGS."
@@ -140,8 +140,9 @@ Users whose default is not \\='sh, but are accessing a remote machine with
(defvar ess-bugs-mode-map
(let ((map (make-sparse-keymap)))
(define-key map (quote [f2]) #'ess-revert-wisely)
(define-key map "\C-c\C-c" #'ess-bugs-next-action)
(define-key map "=" #'ess-bugs-hot-arrow)
;;(define-key map "\C-c\C-c" #'ess-bugs-next-action)
(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)
map)
"ESS[BUGS]: Keymap for mode.")
@@ -191,20 +192,20 @@ and `ess-bugs-file-dir'."
(interactive)
(insert " <- "))
(defun ess-bugs-next-action ()
"ESS[BUGS/JAGS]: Perform the appropriate next action."
(interactive)
(ess-bugs-file)
;; (defun ess-bugs-next-action ()
;; "ESS[BUGS/JAGS]: Perform the appropriate next action."
;; (interactive)
;; (ess-bugs-file)
(cond ((equal ".bug" ess-bugs-file-suffix) (ess-bugs-na-bug))
((equal ".jag" ess-bugs-file-suffix) (ess-jags-na-bug))
((equal ".bmd" ess-bugs-file-suffix)
(ess-save-and-set-local-variables)
(ess-bugs-na-bmd ess-bugs-command ess-bugs-chains))
((equal ".jmd" ess-bugs-file-suffix)
(ess-save-and-set-local-variables)
(ess-jags-na-jmd ess-jags-command ess-jags-chains)))
)
;; (cond ((equal ".bug" ess-bugs-file-suffix) (ess-bugs-na-bug))
;; ((equal ".jag" ess-bugs-file-suffix) (ess-jags-na-bug))
;; ((equal ".bmd" ess-bugs-file-suffix)
;; (ess-save-and-set-local-variables)
;; (ess-bugs-na-bmd ess-bugs-command ess-bugs-chains))
;; ((equal ".jmd" ess-bugs-file-suffix)
;; (ess-save-and-set-local-variables)
;; (ess-jags-na-jmd ess-jags-command ess-jags-chains)))
;; )
(defun ess-bugs-sci-to-round-4-dp ()
"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; -*-
;; Copyright (C) 1997-2025 Free Software Foundation, Inc.
;; Copyright (C) 1997-2026 Free Software Foundation, Inc.
;; Author: Rodney Sparapani
;; Maintainer: ESS-help <ess-help@r-project.org>
@@ -1571,11 +1571,21 @@ by `ess-function-template'."
:group 'ess
:type 'regexp)
(defcustom ess-r-outline-regexp
"^[ \t]*#+ +.*\\(?:----\\|====\\|####\\)\\s-*$"
"Regexp used to detect the beginning of R headings."
(defcustom ess-r-outline-style 'none
"Outline convention used by `ess-r-mode'.
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
: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.
+3 -3
View File
@@ -1,10 +1,10 @@
;; -*- no-byte-compile: t; lexical-binding: nil -*-
(define-package "ess" "20251212.937"
(define-package "ess" "20260322.1703"
"Emacs Speaks Statistics."
'((emacs "25.1"))
:url "https://ess.r-project.org/"
:commit "e39ca8fa7fce703aa2851e83987a412737d575f0"
:revdesc "e39ca8fa7fce"
:commit "4e112590d1c13cfe464ca7de77837f1b956e4a9f"
:revdesc "4e112590d1c1"
:authors '(("David Smith" . "dsmith@stats.adelaide.edu.au")
("A.J. Rossini" . "blindglobe@gmail.com")
("Richard M. Heiberger" . "rmh@temple.edu")
+103 -5
View File
@@ -1,6 +1,6 @@
;;; 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
;; Created: 12 Jun 1997
;; 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
namespace.")
(defun ess-r-outline-level ()
"R mode `outline-level` function."
(defconst ess-r--outline-rstudio-regexp
"^[ \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
(beginning-of-line)
(if (looking-at "^[ \t]*\\(#+\\)\\s-")
(length (match-string 1))
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
;; lambdas. Inside strings it should be treated as an escape
;; character which we ensure here.
@@ -843,6 +940,8 @@ top level functions only."
(setq-local electric-layout-rules '((?{ . after)))
;; indentation
(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
(ess--setup-eldoc #'ess-r-eldoc-function)
;; auto-complete
@@ -864,8 +963,7 @@ top level functions only."
(when ess-imenu-use-S
(imenu-add-to-menubar "Imenu-R"))
;; outline
(setq-local outline-level #'ess-r-outline-level)
(setq-local outline-regexp ess-r-outline-regexp)
(ess-r-set-outline-style)
(setq-local beginning-of-defun-function #'ess-r-beginning-of-defun)
(setq-local end-of-defun-function #'ess-r-end-of-defun)
(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"
"href"
"ifelse" "if"
"item" "kbd" "ldots" "linkS4class" "link" "method"
"item" "kbd" "ldots" "linkS4class" "linkS4methods" "link" "method"
"manual"
"newcommand" "option" "out"
"pkg" "sQuote" "renewcommand"
+2 -2
View File
@@ -17,8 +17,8 @@
;;
;; Maintainer: ESS Core Team <ESS-core@r-project.org>
;; Created: 7 Jan 1994
;; Package-Version: 20251212.937
;; Package-Revision: e39ca8fa7fce
;; Package-Version: 20260322.1703
;; Package-Revision: 4e112590d1c1
;; URL: https://ess.r-project.org/
;; Package-Requires: ((emacs "25.1"))
;; ESSR-Version: 1.8
+166 -286
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
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
ESS -- Emacs Speaks Statistics
@@ -14,7 +14,7 @@ File: ess.info, Node: Top, Next: Introduction, Up: (dir)
ESS: Emacs Speaks Statistics
****************************
ESS version 25.01.0
ESS version 26.01.0
by A.J. Rossini,
R.M. Heiberger,
@@ -30,7 +30,7 @@ ESS version 25.01.0
Emacs Speaks Statistics (ESS) provides an intelligent, consistent
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
Windows. ESS is itself a package within the Emacs text editor and
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 SAS::
* ESS for BUGS::
* ESS for JAGS::
* Mailing lists/bug reports:: How to get assistance with ESS
* Customization:: Customizing ESS
* 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
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.
Throughout this manual, _Emacs_ refers to _GNU Emacs_ by the Free
@@ -249,7 +248,14 @@ File: ess.info, Node: New features, Next: Credits, Prev: Features, Up: Intro
1.2 New features in ESS
=======================
Changes and New Features in 25.01.0:
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:
• polymode: In our transition from literate libraries (such as noweb
documented below with respect to 19.04), we now recommend the
@@ -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
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
outline-level and installs ess-r-outline-regexp so that comment
headings drive folding. 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.
outline-level and configures outline-regexp according to
ess-r-outline-style so that comment headings drive folding. By
default, outline support is disabled (none), but you can enable it by
setting ess-r-outline-style to RStudio or Org-like. With the
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 ----
## Data ----
### Models ====
#### Helpers ####
The number of leading # characters sets the outline depth. 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:
The number of leading # characters sets the outline depth. When
using the RStudio outline style, ess-indent-with-fancy-comments is
automatically set to nil locally in the buffer to prevent single-hash
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)
-- User Option: ess-r-outline-regexp
Regular expression used by ESS to recognise outline headings in R
buffers. The default matches the RStudio-style sections shown
above, but you can customise it if you prefer a different comment
convention.
-- User Option: ess-r-outline-style
Select which outline convention ess-r-mode should use. The
default none disables outline support to preserve backward
compatibility. Set to RStudio to recognise the comment rulers
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
@@ -3662,48 +3687,6 @@ polymode <https://github.com/polymode/poly-R/>,
<https://polymode.github.io/>, or markdown-mode with edit-indirect
<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
@@ -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.

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
***************
ESS[BUGS] provides 5 features. First, BUGS syntax is described to allow
for proper fontification of statements, distributions, functions,
commands and comments in BUGS model files, command files and log files.
Second, ESS creates templates for the command file from the model file
so that a BUGS batch process can be defined by a single file. Third,
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.
ESS[BUGS] NIMBLE has re-vitalized the BUGS language. All previous
instances of BUGS such as OpenBUGS and JAGS are now deprecated.
Therefore, ESS suppors BUGS syntax to allow for proper fontification of
statements, distributions, functions, commands and comments in
BUGS/NIMBLE model files.
14.1 ESS[BUGS]-Model files
==========================
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
***************
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
15 Bugs and Bug Reporting, Mailing Lists
****************************************
* 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
16.1 Bugs
15.1 Bugs
=========
• 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
16.2 Reporting Bugs
15.2 Reporting Bugs
===================
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
16.3 Mailing Lists
15.3 Mailing Lists
==================
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
16.4 Help with Emacs
15.4 Help with Emacs
====================
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-?: Object names. (line 33)
* 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)
* RET: Command-line editing. (line 10)
* RET <1>: Resubmit. (line 18)
@@ -4770,7 +4656,7 @@ Function and program index
* dump(): Edit buffer. (line 35)
* ess-change-directory: Package listing. (line 29)
* 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-describe-help-mode: Help. (line 21)
* 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 <1>: Error Checking. (line 9)
* 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-outline-level: Outline. (line 6)
* 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-switch-to-end-of-ESS: Help. (line 117)
* 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-transcript-clean-region: Clean. (line 10)
* ess-transcript-copy-command: Resubmit. (line 13)
@@ -4913,14 +4795,13 @@ Variable index
* ess-r-flymake-linters: ESS Flymake. (line 16)
* ess-r-flymake-lintr-cache: ESS Flymake. (line 23)
* ess-R-font-lock-keywords: Highlighting. (line 19)
* ess-r-outline-regexp: Outline. (line 6)
* ess-r-outline-regexp <1>: Outline. (line 27)
* ess-r-outline-style: Outline. (line 6)
* ess-r-outline-style <1>: Outline. (line 37)
* ess-search-list: Source Directories. (line 62)
* ess-source-directory: Source Directories. (line 22)
* ess-style: Styles. (line 21)
* ess-style-alist: Styles. (line 28)
* 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-flymake: ESS Flymake. (line 12)
* iESS program arguments: Customizing startup. (line 48)
@@ -5091,111 +4972,110 @@ Concept Index

Tag Table:
Node: Top268
Node: Introduction2906
Node: Features5692
Node: Current Features6518
Node: New features10065
Node: Credits37885
Node: Manual41544
Node: Installation44254
Node: Installing from a third-party repository45191
Node: Installing from source46138
Node: Activating and Loading ESS47762
Node: Check Installation48844
Node: Interactive ESS49068
Node: Starting up49913
Node: Multiple ESS processes50673
Node: ESS processes on Remote Computers51786
Node: Customizing startup56013
Node: Controlling buffer display58995
Node: Entering commands61632
Node: Command-line editing62794
Node: Transcript64059
Node: Last command65856
Node: Process buffer motion67314
Node: Transcript resubmit68857
Node: Saving transcripts70854
Node: Command History72688
Node: Saving History76189
Node: History expansion76970
Node: Hot keys80361
Node: Statistical Process running in ESS?84531
Node: Emacsclient85878
Node: Other86698
Node: Evaluating code87741
Node: Transcript Mode91673
Node: Resubmit92846
Node: Clean93921
Node: Editing objects94921
Node: Edit buffer96039
Node: Loading98129
Node: Error Checking99184
Node: Indenting100257
Node: Styles103409
Node: Other edit buffer commands105911
Node: Source Files107623
Node: Source Directories112339
Node: Help115548
Node: Completion120250
Node: Object names120465
Node: Function arguments123179
Node: Minibuffer completion124158
Node: Company124656
Node: Icicles125055
Node: Developing with ESS126431
Node: ESS tracebug126877
Node: Getting started with tracebug129934
Node: Editing documentation132220
Node: R documentation files132772
Node: roxygen2136587
Node: Namespaced Evaluation141110
Node: Extras143124
Node: ESS ElDoc144216
Node: ESS Flymake145796
Node: Handy commands146926
Node: Highlighting148203
Node: Parens149254
Node: Graphics149730
Node: printer150401
Node: X11151173
Node: winjava151512
Node: Imenu151924
Node: Outline152779
Node: Toolbar154091
Node: Xref154501
Node: Rdired154831
Node: Package listing155910
Node: Org157358
Node: Sweave and AUCTeX158312
Node: ESS for R160944
Node: ESS(R)--Editing files161244
Node: iESS(R)--Inferior ESS processes161749
Node: Philosophies for using ESS(R)164468
Node: Example ESS usage165395
Node: ESS for SAS166799
Node: ESS(SAS)--Design philosophy167526
Node: ESS(SAS)--Editing files168463
Node: ESS(SAS)--TAB key170407
Node: ESS(SAS)--Batch SAS processes171821
Node: ESS(SAS)--Function keys for batch processing177041
Node: iESS(SAS)--Interactive SAS processes186948
Node: iESS(SAS)--Common problems190890
Node: ESS(SAS)--Graphics192504
Node: ESS(SAS)--Windows193303
Node: ESS for BUGS193887
Node: ESS for JAGS195699
Node: Mailing lists/bug reports199195
Node: Bugs199459
Node: Reporting Bugs201135
Node: Mailing Lists202054
Node: Help with Emacs202792
Node: Customization203328
Node: Indices204106
Node: Key index204281
Node: Function and program index209413
Node: Variable index218979
Node: Concept index222686
Node: Top270
Node: Introduction2893
Node: Features5681
Node: Current Features6507
Node: New features10054
Node: Credits38231
Node: Manual41890
Node: Installation44600
Node: Installing from a third-party repository45537
Node: Installing from source46484
Node: Activating and Loading ESS48108
Node: Check Installation49190
Node: Interactive ESS49414
Node: Starting up50259
Node: Multiple ESS processes51019
Node: ESS processes on Remote Computers52132
Node: Customizing startup56359
Node: Controlling buffer display59341
Node: Entering commands61978
Node: Command-line editing63140
Node: Transcript64405
Node: Last command66202
Node: Process buffer motion67660
Node: Transcript resubmit69203
Node: Saving transcripts71200
Node: Command History73034
Node: Saving History76535
Node: History expansion77316
Node: Hot keys80707
Node: Statistical Process running in ESS?84877
Node: Emacsclient86224
Node: Other87044
Node: Evaluating code88087
Node: Transcript Mode92019
Node: Resubmit93192
Node: Clean94267
Node: Editing objects95267
Node: Edit buffer96385
Node: Loading98475
Node: Error Checking99530
Node: Indenting100603
Node: Styles103755
Node: Other edit buffer commands106257
Node: Source Files107969
Node: Source Directories112685
Node: Help115894
Node: Completion120596
Node: Object names120811
Node: Function arguments123525
Node: Minibuffer completion124504
Node: Company125002
Node: Icicles125401
Node: Developing with ESS126777
Node: ESS tracebug127223
Node: Getting started with tracebug130280
Node: Editing documentation132566
Node: R documentation files133118
Node: roxygen2136933
Node: Namespaced Evaluation141456
Node: Extras143470
Node: ESS ElDoc144562
Node: ESS Flymake146142
Node: Handy commands147272
Node: Highlighting148549
Node: Parens149600
Node: Graphics150076
Node: printer150747
Node: X11151519
Node: winjava151858
Node: Imenu152270
Node: Outline153125
Node: Toolbar155358
Node: Xref155768
Node: Rdired156098
Node: Package listing157177
Node: Org158625
Node: Sweave and AUCTeX159579
Node: ESS for R160176
Node: ESS(R)--Editing files160476
Node: iESS(R)--Inferior ESS processes160981
Node: Philosophies for using ESS(R)163700
Node: Example ESS usage164627
Node: ESS for SAS166031
Node: ESS(SAS)--Design philosophy166758
Node: ESS(SAS)--Editing files167695
Node: ESS(SAS)--TAB key169639
Node: ESS(SAS)--Batch SAS processes171053
Node: ESS(SAS)--Function keys for batch processing176273
Node: iESS(SAS)--Interactive SAS processes186180
Node: iESS(SAS)--Common problems190122
Node: ESS(SAS)--Graphics191736
Node: ESS(SAS)--Windows192535
Node: ESS for BUGS193119
Node: Mailing lists/bug reports193675
Node: Bugs193939
Node: Reporting Bugs195615
Node: Mailing Lists196534
Node: Help with Emacs197272
Node: Customization197808
Node: Indices198586
Node: Key index198761
Node: Function and program index203674
Node: Variable index212948
Node: Concept index216582

End Tag Table
+1 -1
View File
@@ -4,7 +4,7 @@
'((emacs "24.1")
(s "1.7.0")
(dash "2.2.0"))
:url "http://github.com/rejeep/f.el"
:url "https://github.com/rejeep/f.el"
:commit "931b6d0667fe03e7bf1c6c282d6d8d7006143c52"
:revdesc "931b6d0667fe"
: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)
(function-put 'flycheck-def-config-file-var 'lisp-indent-function 3)
(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
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
(register-definition-prefixes "flycheck-buttercup" '("flycheck-buttercup-format-error-list"))
;;; Generated autoloads from flycheck-ert.el
(register-definition-prefixes "flycheck-ert" '("flycheck-er"))
(register-definition-prefixes "flycheck-buttercup" '("flycheck-buttercup-"))
;;; End of scraped data
+434 -5
View File
@@ -42,6 +42,8 @@
(require 'buttercup)
(require 'flycheck)
(require 'seq)
(require 'cl-lib)
(require 'macroexp)
;;; Buttercup helpers
@@ -55,12 +57,14 @@
;;; Data matchers
(buttercup-define-matcher :to-be-empty-string (s)
"Match that S is an empty string."
(let ((s (funcall 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)))))
(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))
(s (funcall s))
(index (funcall index))
@@ -81,6 +85,7 @@
;;; Emacs feature matchers
(buttercup-define-matcher :to-be-live (buffer)
"Match that BUFFER is a live buffer."
(let ((buffer (get-buffer (funcall buffer))))
(if (buffer-live-p buffer)
(cons t (format "Expected %S not to be a live buffer, but it is"
@@ -89,6 +94,7 @@
buffer)))))
(buttercup-define-matcher :to-be-visible (buffer)
"Match that BUFFER is displayed in a window."
(let ((buffer (get-buffer (funcall buffer))))
(cond
((and buffer (get-buffer-window buffer))
@@ -104,6 +110,7 @@
buffer))))))
(buttercup-define-matcher :to-be-local (symbol)
"Match that SYMBOL is a buffer-local variable in the current buffer."
(let ((symbol (funcall symbol)))
(if (local-variable-p symbol)
(cons t (format "Expected %S not to be a local variable, but it is"
@@ -112,6 +119,7 @@
symbol)))))
(buttercup-define-matcher :to-contain-match (buffer re)
"Match that BUFFER contains text matching regexp RE."
(let ((buffer (funcall buffer))
(re (funcall re)))
(if (not (get-buffer buffer))
@@ -121,15 +129,16 @@ but is not a buffer" buffer re))
(save-excursion
(goto-char (point-min))
(if (re-search-forward re nil 'noerror)
(cons t (format "Expected %S to contain a match \
for %s, but it did not" buffer re))
(cons nil (format "Expected %S not to contain a match for \
%s but it did not." buffer re))))))))
(cons t (format "Expected %S not to contain a match \
for %s, but it did" buffer re))
(cons nil (format "Expected %S to contain a match for \
%s, but it did not." buffer re))))))))
;;; Flycheck matchers
(buttercup-define-matcher :to-be-equal-flycheck-errors (a b)
"Match that flycheck error lists A and B are equal."
(let* ((a (funcall a))
(b (funcall b))
(a-formatted (flycheck-buttercup-format-error-list a))
@@ -144,6 +153,426 @@ not to be equal to
to be equal to
%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)
;; 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 -*-
(define-package "flycheck" "20251128.1706"
(define-package "flycheck" "20260320.1715"
"On-the-fly syntax checking."
'((emacs "27.1")
(seq "2.24"))
:url "https://www.flycheck.org"
:commit "62570fafbedb8fa3f7d75a50a9364feca3b294ef"
:revdesc "62570fafbedb"
:url "https://github.com/flycheck/flycheck"
:commit "0e5eb8300d32fd562724216c19eaf199ee1451ab"
:revdesc "0e5eb8300d32"
:keywords '("convenience" "languages" "tools")
:authors '(("Sebastian Wiesner" . "swiesner@lunaryorn.com"))
:maintainers '(("Clément Pit-Claudel" . "clement.pitclaudel@live.com")
+626 -1033
View File
File diff suppressed because it is too large Load Diff
@@ -1,11 +1,11 @@
;; -*- 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."
'((flyspell-correct "0.6.1")
'((flyspell-correct "1.0.0")
(ivy "0.8.0")
(emacs "24.4"))
(emacs "29.1"))
:url "https://github.com/d12frosted/flyspell-correct"
:commit "7d7b6b01188bd28e20a13736ac9f36c3367bd16e"
:revdesc "7d7b6b01188b"
:commit "a5a41c0f3a7881bd3eba07bee424ecb7c7d5061e"
:revdesc "a5a41c0f3a78"
:authors '(("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; -*-
;;
;; Copyright (c) 2016-2022 Boris Buliga
;; Copyright (c) 2016-2026 Boris Buliga
;;
;; Author: Boris Buliga <boris@d12frosted.io>
;; URL: https://github.com/d12frosted/flyspell-correct
;; Package-Version: 20220520.630
;; Package-Revision: 7d7b6b01188b
;; Package-Requires: ((flyspell-correct "0.6.1") (ivy "0.8.0") (emacs "24.4"))
;; Package-Version: 20260106.955
;; Package-Revision: a5a41c0f3a78
;; Package-Requires: ((flyspell-correct "1.0.0") (ivy "0.8.0") (emacs "29.1"))
;;
;; 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; -*-
;;
;; Copyright (c) 2016-2022 Boris Buliga
;; Copyright (c) 2016-2026 Boris Buliga
;;
;; Author: Boris Buliga <boris@d12frosted.io>
;; 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.
;;
@@ -1,9 +1,9 @@
;; -*- 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."
'((emacs "24"))
'((emacs "29.1"))
:url "https://github.com/d12frosted/flyspell-correct"
:commit "7d7b6b01188bd28e20a13736ac9f36c3367bd16e"
:revdesc "7d7b6b01188b"
:commit "a5a41c0f3a7881bd3eba07bee424ecb7c7d5061e"
:revdesc "a5a41c0f3a78"
:authors '(("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; -*-
;;
;; Copyright (c) 2016-2022 Boris Buliga
;; Copyright (c) 2016-2026 Boris Buliga
;;
;; Author: Boris Buliga <boris@d12frosted.io>
;; URL: https://github.com/d12frosted/flyspell-correct
;; Package-Version: 20220520.630
;; Package-Revision: 7d7b6b01188b
;; Package-Requires: ((emacs "24"))
;; Package-Version: 20260106.955
;; Package-Revision: a5a41c0f3a78
;; Package-Requires: ((emacs "29.1"))
;;
;; This file is not part of GNU Emacs.
;;
@@ -63,31 +63,22 @@
(defcustom flyspell-correct-interface #'flyspell-correct-completing-read
"Interface for `flyspell-correct-at-point'.
`flyspell-correct-interface' is a function accepting two arguments:
- candidates for correction (list of strings)
- misspelled word (string)
Result must be either a string (replacement word) or a cons of a
command and a string (replacement word), where the command is one
of the following:
- skip - do nothing to misspelled word, in rapid mode used for
jumping to the next (or previous) misspelled word
- break - do nothing to misspelled word, break from rapid mode
- stop - do nothing to misspelled word, break from rapid
mode (if enabled) and leave the point at the misspelled word
- save - replace misspelled word with replacement word and save
it to the personal dictionary
- session - replace misspelled word with replacement word and
save it to the session dictionary (correction will be
discarded upon quitting Emacs)
- buffer - replace misspelled word with replacement word and
save it to the buffer dictionary (added to the bottom of
buffer)"
@@ -96,12 +87,27 @@ of the following:
(defcustom flyspell-correct-highlight t
"When non-nil highlight the word while correcting.
The face `flyspell-correct-highlight-face' is used for
highlighting."
:group 'flyspell-correct
: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
'((t (:inherit isearch)))
"Face used for highlighting the word while correcting."
@@ -125,7 +131,6 @@ highlighting."
(defun flyspell-correct--cr-index (n)
"Generate a short unique index string for N.
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
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)
"Run `completing-read' for the given CANDIDATES.
List of CANDIDATES is given by flyspell for the WORD.
Return a selected word to use as a replacement or a tuple
of (command, word) to be used by `flyspell-do-correct'."
(let* ((idx 0)
@@ -212,7 +215,7 @@ of (command, word) to be used by `flyspell-do-correct'."
(define-obsolete-function-alias
'flyspell-correct-dummy
'flyspell-correct-completing-read
"0.6.1")
"1.0.0")
;;; On point word correction
;;
@@ -225,7 +228,9 @@ Adapted from `flyspell-correct-word-before-point'."
(unless flyspell-correct-interface
(error "Could not correct word because `flyspell-correct-interface' is not set"))
(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-correct--highlight-add)
(unwind-protect
@@ -293,10 +298,9 @@ Adapted from `flyspell-correct-word-before-point'."
(defun flyspell-correct-previous (position)
"Correct the first misspelled word that occurs before POSITION.
But don't look beyond what's visible on the screen.
Uses `flyspell-correct-at-point' function for correction.
With a prefix argument, automatically continues to all prior misspelled words in the buffer."
With a prefix argument, automatically continues to all prior
misspelled words in the buffer."
(interactive "d")
(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
(defun flyspell-correct-next (position)
"Correct the first misspelled word that occurs after POSITION.
Uses `flyspell-correct-at-point' function for correction.
With a prefix argument, automatically continues to all further
misspelled words in the buffer."
(interactive "d")
@@ -320,48 +322,84 @@ misspelled words in the buffer."
;;;###autoload
(defun flyspell-correct-wrapper ()
"Correct spelling error in a dwim fashion based on universal argument.
- One \\[universal-argument] enables rapid mode.
- Two \\[universal-argument]'s changes direction of spelling
errors search.
- 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)
(let ((forward-direction nil)
(let ((forward-direction (eq flyspell-correct-default-direction 'forward))
(rapid nil))
(cond
((equal current-prefix-arg '(4)) ; C-u = rapid
(setq rapid t))
((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
(setq rapid t)
(setq forward-direction t)))
(setq forward-direction (not forward-direction))))
(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
(defun flyspell-correct-move (position &optional forward rapid)
"Correct the first misspelled word that occurs before POSITION.
Uses `flyspell-correct-at-point' function for correction.
With FORWARD set non-nil, check forward instead of backward.
With RAPID set non-nil, automatically continues in direction
until all errors in buffer have been addressed."
;; NOTE: The way I may be pushing the mark may possibly be more
;; idiomatically done using the opoint arg of
;; `flyspell-correct-word-before-point'.
(interactive "d")
;; push mark when starting
(when (or (not (mark t))
(/= (mark t) (point)))
(push-mark (point) t))
(let ((original-pos (point))
(target-pos (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
(save-excursion
(let ((incorrect-word-pos))
@@ -403,13 +441,19 @@ until all errors in buffer have been addressed."
(<= original-pos (overlay-end overlay))))
;; 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
;; stop at misspelled word
(when (eq (car-safe res) 'stop)
(setq target-pos incorrect-word-pos
hard-move-point t
mark-opos t))
(setq target-pos incorrect-word-pos)
(setq hard-move-point t)
(setq preserve-mark t))
;; break from rapid mode
(when (or
@@ -420,23 +464,15 @@ until all errors in buffer have been addressed."
;; explicit rapid mode disablers
(eq (car-safe res) 'break)
(eq (car-safe res) 'stop))
(setq overlay nil))
(setq overlay nil)))))))))
(when (and
;; don't push mark if there is no change
(not (memq (car-safe res) '(stop break skip)))
(/= (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))
(if hard-move-point
(goto-char target-pos)
(goto-char (mark t)))
;; 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.
(when (= (mark t) (point)) (pop-mark)))))
(unless preserve-mark
(setq mark-ring original-mark-ring)))))
;;; Overlays
@@ -461,7 +497,6 @@ until all errors in buffer have been addressed."
(defun flyspell-correct--overlay-loc ()
"Return `cons' with start and end of `flyspell' overlay at point.
Returns nil if no overlay is found."
(let ((ovs (overlays-at (point)))
ov)
@@ -488,12 +523,11 @@ Use floating point numbers to express fractions of seconds."
"Interface to use in `flyspell-correct-auto-mode'.
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'.")
(make-variable-buffer-local 'flyspell-correct--auto-timer)
(defvar flyspell-correct--auto-active-p nil)
(make-variable-buffer-local 'flyspell-correct--auto-active-p)
(defvar-local flyspell-correct--auto-active-p nil
"Non-nil when auto-correction is active.")
(defun flyspell-correct-auto-cancel-timer ()
"Cancel auto correct timer."
@@ -527,12 +561,10 @@ When set to nil `flyspell-correct-interface' is used.")
;;;###autoload
(define-minor-mode flyspell-correct-auto-mode
"Minor mode for automatically correcting word at point.
Take my advice and don't use this functionality unless you find
`flyspell-correct-previous' function useless for your purposes.
Seriously, just try named function for completion. You can find
more info in comment[1].
[1]:
https://github.com/syl20bnr/spacemacs/issues/6209#issuecomment-274320376"
:group 'flyspell
+1 -1
View File
@@ -3,7 +3,7 @@
"Dim the font color of text in surrounding sections."
'((emacs "24.3")
(cl-lib "0.5"))
:url "http://github.com/larstvei/Focus"
:url "https://github.com/larstvei/Focus"
:commit "29b412b209c3542a7932c201f0166e48c9fd7fee"
:revdesc "29b412b209c3"
:authors '(("Lars Tveito" . "larstvei@ifi.uio.no"))
+8 -10
View File
@@ -4,8 +4,6 @@
;; 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
;; it under the terms of the GNU General Public License as published by
;; 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
(let* ((pat1 (cadr pat))
(pat2 (cl-caddr pat))
(pat2 (caddr pat))
(pat1-c (gnuplot-context--compile-pattern pat1))
(pat2-c (gnuplot-context--compile-pattern pat2))
(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
((delimited-list)
(let* ((item (cadr pat))
(sep (cl-caddr pat)))
(sep (caddr pat)))
(gnuplot-context--compile-pattern
`(sequence ,item (many (sequence ,sep ,item))))))
@@ -1799,7 +1797,7 @@ there."
;; (literal LITERAL NO-COMPLETE)
((literal)
(let ((expect (cadr inst))
(no-complete (cl-caddr inst)))
(no-complete (caddr inst)))
(cond (end-of-tokens
(unless no-complete
(gnuplot-context--trace "\tpushing \"%s\" to completions\n" expect)
@@ -1824,7 +1822,7 @@ there."
;; regexp-matches REGEXP, use NAME for completions
((keyword)
(let ((regexp (cadr inst))
(name (cl-caddr inst)))
(name (caddr inst)))
(cond (end-of-tokens
(gnuplot-context--trace "\tpushing \"%s\" to completions\n" name)
(push name gnuplot-context--completions)
@@ -1901,7 +1899,7 @@ there."
;; onto the stack
((push)
(let* ((type (cadr inst))
(value (cl-caddr inst)))
(value (caddr inst)))
(push `(,type ,value ,tokens) stack)))
;; (pop TYPE): pop something off the stack
@@ -1925,7 +1923,7 @@ there."
(record (assoc name gnuplot-context--captures)))
(if (not record)
(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)))))
;; (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)))
(let* ((item (car stack))
(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))
(not (eq position tokens)))
(cl-case type
@@ -2013,7 +2011,7 @@ there."
(let ((record (assoc name gnuplot-context--captures)))
(if (not record) nil
(let ((begin (cadr record))
(end (cl-caddr record))
(end (caddr record))
(accum '()))
(while (and begin (not (eq begin end)))
(push (pop begin) accum))
+23 -27
View File
@@ -4,8 +4,6 @@
;; 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
;; it under the terms of the GNU General Public License as published by
;; 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)))
(when (or
(and (equal gnuplot-gui-plot-splot-fit-style 'complete)
(cl-member word '("plot" "splot" "fit")
:test 'equal))
(member word '("plot" "splot" "fit")))
(equal word "test"))
(gnuplot-gui-set-frame-param 'height 32)
(gnuplot-gui-set-frame-param 'top 50))
(gnuplot-gui-prompt-for-frame word)
(when (or
(and (equal gnuplot-gui-plot-splot-fit-style 'complete)
(cl-member word '("plot" "splot" "fit")
:test 'equal))
(member word '("plot" "splot" "fit")))
(equal word "test"))
(gnuplot-gui-set-frame-param 'height old-height)
(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
used in `gnuplot-gui-all-types'."
(let (fixed-list quote quoted) ; remove blanks
(setq list (cl-remove "\\s-+" list :test 'string-match)
list (cl-remove "" list :test 'equal))
(setq list (cl-remove "\\s-+" list :test #'string-match)
list (remove "" list))
(while list ; concatinate parts of quoted string
(if (not (string-match "^\\([\]\[()'\"]\\)" (car list)))
(setq fixed-list (append fixed-list (list (car list))))
@@ -998,15 +994,15 @@ arguments."
(while temp-list
(cond
;; ---------------------------- list
((cl-member symbol '(list list*) :test 'equal)
((memq symbol '(list list*))
(let* ((case-fold-search nil)
(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
(not (equal " " (car match-cons))))
(setq this-cons (cons tag (car match-cons))
arg-list (cl-remove (car temp-list) arg-list
:test 'equal :count 1)
:test #'equal :count 1)
temp-list nil)
(setq temp-list (cdr temp-list)))))
;; ---------------------------- tag (first number in list)
@@ -1027,16 +1023,16 @@ arguments."
(string-match "^[-0-9.]+$" (cadr temp-list)))
(setq this-cons (cons tag (cadr temp-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
:test 'equal :count 1)
:test #'equal :count 1)
temp-list nil))
;; --------------------- number without prefix
((and (not prefix)
(string-match "^[-0-9.]+$" (car temp-list)))
(setq this-cons (cons tag (car temp-list))
arg-list (cl-remove (car temp-list) arg-list
:test 'equal :count 1)
:test #'equal :count 1)
temp-list nil))
(t
(setq temp-list (cdr temp-list)))))
@@ -1045,8 +1041,8 @@ arguments."
(if (and (equal prefix (car temp-list))
(string-match "^[-0-9.]+$" (cadr temp-list)))
(let ((this-car (cadr temp-list))
(this-cdr (if (string-match "^[-0-9.]+$" (cl-caddr temp-list))
(cl-caddr temp-list) "")))
(this-cdr (if (string-match "^[-0-9.]+$" (caddr temp-list))
(caddr temp-list) "")))
(setq this-cons (cons tag (cons this-car this-cdr))
temp-list nil))
(setq temp-list (cdr temp-list))))
@@ -1062,7 +1058,7 @@ arguments."
(cons tag (cons (match-string 1 (car temp-list))
(match-string 2 (car temp-list))))
arg-list (cl-remove (car temp-list) arg-list
:test 'equal :count 1)
:test #'equal :count 1)
temp-list nil)
(setq temp-list (cdr temp-list)) ))
;; ---------------------------- labels
@@ -1072,7 +1068,7 @@ arguments."
")") ; closing paren
(car temp-list))
(let* ((list (split-string (car temp-list) "[ \t(),]+"))
(list (cl-remove "" list :test 'equal))
(list (remove "" list))
(return ()))
(while list
(if (string-match "['\"]\\([^'\"]*\\)['\"]" (car list))
@@ -1084,18 +1080,18 @@ arguments."
(setq list (cdr list)) )
(setq this-cons (cons tag return)
arg-list (cl-remove (car temp-list) arg-list
:test 'equal :count 1)
:test #'equal :count 1)
temp-list nil))
(setq temp-list (cdr temp-list))) )
;; ---------------------------- string, file, format
((cl-member symbol '(string file format) :test 'equal)
((memq symbol '(string file format))
(if (string-match (concat "['\"]" ; opening quote
"\\([^'\"]*\\)" ; string
"['\"]") ; closing quote
(car temp-list))
(setq this-cons (cons tag (match-string 0 (car temp-list)))
arg-list (cl-remove (car temp-list) arg-list
:test 'equal :count 1)
:test #'equal :count 1)
temp-list nil)
(setq temp-list (cdr temp-list)) ))
;; ---------------------------- string*
@@ -1103,9 +1099,9 @@ arguments."
(if (equal prefix (car temp-list))
(setq this-cons (cons tag (cadr temp-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
:test 'equal :count 1)
:test #'equal :count 1)
temp-list nil)
(setq temp-list (cdr temp-list)) ) )
;; ---------------------------- 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
(cond
;;------------------------------ list, list* ------------
((cl-member (eval wtype) '(list list*) :test 'equal)
((memq (eval wtype) '(list list*))
(let ((starred (if (equal (eval wtype) 'list*) t nil)))
(gnuplot-gui-menu-choice tag default list starred)))
;;------------------------------ number, tag, fontsize --
((cl-member (eval wtype) '(number tag fontsize) :test 'equal)
((memq (eval wtype) '(number tag fontsize))
(gnuplot-gui-number tag default prefix))
;;------------------------------ position ---------------
;;------------------------------ range, pair ------------
((cl-member (eval wtype) '(range pair) :test 'equal)
((memq (eval wtype) '(range pair))
(let ((is-range (equal (eval wtype) 'range)))
(gnuplot-gui-range tag default prefix is-range)))
;;------------------------------ string, string* --------
((cl-member (eval wtype) '(string string*) :test 'equal)
((memq (eval wtype) '(string string*))
(let ((starred (if (equal (eval wtype) 'string) nil t)))
(gnuplot-gui-string tag default prefix starred)))
;;------------------------------ format -----------------
+3 -3
View File
@@ -1,11 +1,11 @@
;; -*- no-byte-compile: t; lexical-binding: nil -*-
(define-package "gnuplot" "20250724.1531"
(define-package "gnuplot" "20260322.20"
"Major-mode and interactive frontend for gnuplot."
'((emacs "28.1")
(compat "30"))
:url "https://github.com/emacs-gnuplot/gnuplot"
:commit "43e9674b869475b1c2a32f045c167673eb2faae0"
:revdesc "43e9674b8694"
:commit "39ba1dec5e8e227ba093a30ca07b20d8eb038f29"
:revdesc "39ba1dec5e8e"
:keywords '("data" "gnuplot" "plotting")
:maintainers '(("Maxime Tréca" . "maxime@gmail.com")
("Daniel Mendler" . "mail@daniel-mendler.de")))
+2 -4
View File
@@ -5,14 +5,12 @@
;; Author: Jon Oddie, Bruce Ravel, Phil Type
;; Maintainer: Maxime Tréca <maxime@gmail.com>, Daniel Mendler <mail@daniel-mendler.de>
;; Created: 1998
;; Package-Version: 20250724.1531
;; Package-Revision: 43e9674b8694
;; Package-Version: 20260322.20
;; Package-Revision: 39ba1dec5e8e
;; Keywords: data gnuplot plotting
;; URL: https://github.com/emacs-gnuplot/gnuplot
;; 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
;; it under the terms of the GNU General Public License as published by
;; 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.
INFO-DIR-SECTION Math
@@ -23499,7 +23499,7 @@ Concept Index
* ? <3>: gamma. (line 9)
* ? <4>: inverf. (line 7)
* ? <5>: imag. (line 7)
* ? <6>: invnorm. (line 10)
* ? <6>: invnorm. (line 9)
* ? <7>: invnorm. (line 9)
* ? <8>: real. (line 6)
* ? <9>: sqrt. (line 8)
@@ -23519,13 +23519,13 @@ Concept Index
* ? <23>: words. (line 33)
* ? <24>: words. (line 35)
* ? <25>: words. (line 38)
* ? <26>: words. (line 40)
* ? <27>: words. (line 40)
* ? <28>: words. (line 40)
* ? <26>: words. (line 39)
* ? <27>: words. (line 39)
* ? <28>: words. (line 39)
* ? <29>: words. (line 39)
* ? <30>: hsv2rgb. (line 7)
* ? <31>: rgbcolor. (line 11)
* ? <32>: rgbcolor. (line 13)
* ? <32>: rgbcolor. (line 12)
* ? <33>: rgbcolor. (line 12)
* .gnuplot: Start-up_(initialization).
(line 6)
+3 -3
View File
@@ -1,7 +1,7 @@
;; -*- 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."
()
:url "http://hins11.yu-yake.com/"
:commit "d388c3387781a370ca13233ff445d03f3c5cf12f"
:revdesc "d388c3387781")
:commit "f3455c6c798b568a6ea1013b7eea1153d2e092be"
:revdesc "f3455c6c798b")
+59 -21
View File
@@ -18,8 +18,8 @@
;; Author: zk_phi
;; URL: http://hins11.yu-yake.com/
;; Package-Version: 20210115.400
;; Package-Revision: d388c3387781
;; Package-Version: 20260211.1005
;; Package-Revision: f3455c6c798b
;;; Commentary:
@@ -76,7 +76,7 @@
(require 'cl-lib)
(defconst indent-guide-version "2.3.1")
(defconst indent-guide-version "2.4")
;; * customs
@@ -85,7 +85,17 @@
:group 'environment)
(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
: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)
(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
(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)"
(let (diff string ov prop)
(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)))
(concat str
(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)
(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
ov (make-overlay (point) (point)))))
((< diff 0) ; the column is inside a tab
@@ -226,19 +252,22 @@ the point. When no such points are found, just return nil."
str)
prop 'display)
(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))
prop 'display
ov (make-overlay (point) (1- (point))))))
((looking-at "\t") ; okay but looking at tab
;; <-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))
prop 'display
ov (make-overlay (point) (1+ (point)))))
(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
ov (make-overlay (point) (1+ (point))))))
(when ov
@@ -247,8 +276,10 @@ the point. When no such points are found, just return nil."
(defun indent-guide-show ()
(interactive)
(unless (or (indent-guide--active-overlays)
(active-minibuffer-window))
;;; NOTE(arka): redraw only when needed
(unless (active-minibuffer-window)
(indent-guide-remove)
(let ((win-start (window-start))
(win-end (window-end nil t))
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)))))
;; draw line
(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)))))
(defun indent-guide-remove ()
@@ -298,10 +329,16 @@ the point. When no such points are found, just return nil."
(indent-guide-show)
(setq indent-guide--timer-object nil)))))))
(defun indent-guide-pre-command-hook ()
;; some commands' behavior may affected by indent-guide overlays, so
;; remove all overlays in pre-command-hook.
(indent-guide-remove))
;;; NOTE(arka): root cause of flickering effect. we don't actually need
;;; pre-hook to redraw guides on each command.
;; (defun indent-guide-pre-command-hook ()
;; ;; 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
(define-minor-mode indent-guide-mode
@@ -311,10 +348,11 @@ the point. When no such points are found, just return nil."
:global nil
(if indent-guide-mode
(progn
(add-hook 'pre-command-hook 'indent-guide-pre-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)
(remove-hook 'post-command-hook 'indent-guide-post-command-hook 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 'window-scroll-functions 'indent-guide--window-scroll-hook nil t))
(remove-hook 'post-command-hook 'indent-guide-post-command-hook t)
(remove-hook 'window-scroll-functions 'indent-guide--window-scroll-hook t)))
;;;###autoload
(define-globalized-minor-mode indent-guide-global-mode
+1 -1
View File
@@ -1,6 +1,6 @@
;;; 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>
+1 -1
View File
@@ -1,6 +1,6 @@
;;; 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>
;; Keywords: convenience
+1 -1
View File
@@ -1,6 +1,6 @@
;;; 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>
;; Keywords: convenience
+3 -3
View File
@@ -1,10 +1,10 @@
;; -*- no-byte-compile: t; lexical-binding: nil -*-
(define-package "ivy" "20251123.1023"
(define-package "ivy" "20260318.1355"
"Incremental Vertical completYon."
'((emacs "24.5"))
:url "https://github.com/abo-abo/swiper"
:commit "ec9421340c88ebe08f05680e22308ed57ed68a3d"
:revdesc "ec9421340c88"
:commit "1005bff8a700b92dc464f770aff8a0db5b4a1c0b"
:revdesc "1005bff8a700"
:keywords '("matching")
:authors '(("Oleh Krehel" . "ohwoeowho@gmail.com"))
: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
@@ -11,7 +11,7 @@ available choices while previewing in the minibuffer. Selecting the
final candidate is either through simple keyboard character inputs or
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
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.
Copyright © 2013, Craig Earls. All rights reserved.
+2
View File
@@ -1,5 +1,7 @@
((nil
(indent-tabs-mode . nil))
(emacs-lisp-mode
(lisp-indent-local-overrides . ((cond . 0) (interactive . 0))))
(makefile-mode
(indent-tabs-mode . t))
(git-commit-mode
+3 -3
View File
@@ -1,9 +1,9 @@
;; -*- no-byte-compile: t; lexical-binding: nil -*-
(define-package "llama" "20251101.2002"
(define-package "llama" "20260301.1253"
"Compact syntax for short lambda."
'((emacs "26.1")
(compat "30.1"))
:url "https://github.com/tarsius/llama"
:commit "e4803de8ab85991b6a944430bb4f543ea338636d"
:revdesc "e4803de8ab85"
:commit "d430d48e0b5afd2a34b5531f103dcb110c3539c4"
:revdesc "d430d48e0b5a"
:keywords '("extensions"))
+5 -4
View File
@@ -1,13 +1,13 @@
;;; 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>
;; Homepage: https://github.com/tarsius/llama
;; Keywords: extensions
;; Package-Version: 20251101.2002
;; Package-Revision: e4803de8ab85
;; Package-Version: 20260301.1253
;; Package-Revision: d430d48e0b5a
;; Package-Requires: (
;; (emacs "26.1")
;; (compat "30.1"))
@@ -355,7 +355,8 @@ expansion, and the looks of this face should hint at that.")
(prog1 t
(save-excursion
(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
(read-positioning-symbols (current-buffer)))))
(put-text-property (match-beginning 0) (point)
+4 -4
View File
@@ -1,14 +1,14 @@
;; -*- no-byte-compile: t; lexical-binding: nil -*-
(define-package "magit-section" "20251220.917"
(define-package "magit-section" "20260330.1102"
"Sections for read-only buffers."
'((emacs "28.1")
(compat "30.1")
(cond-let "0.1")
(cond-let "0.2")
(llama "1.0")
(seq "2.24"))
:url "https://github.com/magit/magit"
:commit "649b4c972151c0ee495876c0d4c8c13787614886"
:revdesc "649b4c972151"
:commit "89a51310bd8f8087c44f7ac5c902cc82dddbbe2a"
:revdesc "89a51310bd8f"
:keywords '("tools")
:authors '(("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 -*-
;; Copyright (C) 2008-2025 The Magit Project Contributors
;; Copyright (C) 2008-2026 The Magit Project Contributors
;; Author: 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
;; Keywords: tools
;; Package-Version: 20251220.917
;; Package-Revision: 649b4c972151
;; Package-Version: 20260330.1102
;; Package-Revision: 89a51310bd8f
;; Package-Requires: (
;; (emacs "28.1")
;; (compat "30.1")
;; (cond-let "0.1")
;; (cond-let "0.2")
;; (llama "1.0")
;; (seq "2.24"))
@@ -106,7 +106,8 @@ similar defect.")
'magit-section-keep-region-overlay "Magit-Section 4.0.0")
(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
@@ -885,10 +886,10 @@ If there is no previous sibling section, then move to the parent."
(defun magit-section-goto (arg)
"Run `magit-section-movement-hook'.
See info node `(magit)Section Movement'."
(if (integerp arg)
(progn (forward-line arg)
(cond ((integerp arg)
(forward-line arg)
(setq arg (magit-current-section)))
(goto-char (oref arg start)))
((goto-char (oref arg start))))
(run-hook-with-args 'magit-section-movement-hook arg))
(defun magit-section-set-window-start (section)
@@ -936,8 +937,8 @@ With a prefix argument also expand it." heading)
(oset section hidden nil)
(magit-section--opportunistic-wash section)
(magit-section--opportunistic-paint section)
(when-let ((beg (oref section content)))
(remove-overlays beg (oref section end) 'invisible t))
(when$ (oref section content)
(remove-overlays $ (oref section end) 'invisible t))
(magit-section-maybe-update-visibility-indicator section)
(magit-section-maybe-cache-visibility section)
(dolist (child (oref section children))
@@ -2677,6 +2678,7 @@ with the variables' values as arguments, which were recorded by
;; ("and>" . "cond-let--and>")
;; ("and-let" . "cond-let--and-let")
;; ("if-let" . "cond-let--if-let")
;; ("when$" . "cond-let--when$")
;; ("when-let" . "cond-let--when-let")
;; ("while-let" . "cond-let--while-let")
;; ("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.
Copyright (C) 2015-2025 Jonas Bernoulli
Copyright (C) 2015-2026 Jonas Bernoulli
<emacs.magit@jonas.bernoulli.dev>
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
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>
You can redistribute this document and/or modify it under the terms
+5 -4
View File
@@ -1,11 +1,12 @@
((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
(indent-tabs-mode . t)
(outline-regexp . "#\\(#+\\)")
(mode . outline-minor))
(emacs-lisp-mode
(checkdoc-allow-quoting-nil-and-t . t))
(mode . outline-minor)
(outline-regexp . "#\\(#+\\)"))
(git-commit-mode
(git-commit-major-mode . git-commit-elisp-text-mode))
(".github/PULL_REQUEST_TEMPLATE"
+2
View File
@@ -49,6 +49,7 @@ All Contributors
- Alex Kreisher
- Alex Ott
- Allen Li
- Andrea Alberti
- Andreas Fuchs
- Andreas Liljeqvist
- Andreas Rottmann
@@ -230,6 +231,7 @@ All Contributors
- Lele Gaifax
- Lénaïc Huard
- Leo Liu
- Leonard Lausen
- Leonardo Etcheverry
- Leo Vivier
- Li Chen
+187 -58
View File
@@ -1,6 +1,6 @@
;;; 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>
;; Sebastian Wiesner <lunaryorn@gmail.com>
@@ -110,6 +110,7 @@
(require 'transient)
(require 'with-editor)
(defvar dabbrev--abbrev-char-regexp)
(defvar diff-default-read-only)
(defvar flyspell-generic-check-word-predicate)
(defvar font-lock-beg)
@@ -118,6 +119,12 @@
(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
'git-commit-known-pseudo-headers
'git-commit-trailers
@@ -132,42 +139,6 @@
:link '(info-link "(magit)Editing Commit Messages")
: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
"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
(list #'git-commit-ensure-comment-gap
#'git-commit-save-message
#'git-commit-setup-capf
#'git-commit-setup-changelog-support
#'git-commit-turn-on-auto-fill
#'git-commit-setup-auto-fill
#'git-commit-propertize-diff
#'git-commit-collapse-diff
#'bug-reference-mode)
"Hook run at the end of `git-commit-setup'."
: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
:options '(git-commit-ensure-comment-gap
git-commit-save-message
git-commit-setup-capf
git-commit-setup-changelog-support
magit-generate-changelog
git-commit-turn-on-auto-fill
git-commit-turn-on-orglink
git-commit-turn-on-flyspell
git-commit-setup-auto-fill
git-commit-setup-orglink
git-commit-setup-flyspell
git-commit-propertize-diff
git-commit-collapse-diff
bug-reference-mode))
(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."
: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
'((t :inherit git-commit-trailer-value))
"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]
["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 "/\\(\
\\(\\(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))
(git-commit-setup)))
(defvar git-commit-mode)
(defun git-commit-file-not-found ()
;; cygwin git will pass a cygwin path (/cygdrive/c/foo/.git/...),
;; 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)
(add-hook 'find-file-not-found-functions #'git-commit-file-not-found))
;;; Local Mode
(defvar git-commit-mode)
(defconst git-commit-default-usage-message "\
Type \\[with-editor-finish] to finish, \
\\[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")
(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)
(cd (and git-commit-cd-to-toplevel
(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"
(run-hooks 'git-commit-setup-hook))
(set-buffer-modified-p nil)
(when-let ((format git-commit-header-line-format))
(when$ git-commit-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
(setq with-editor-usage-message git-commit-usage-message))
(with-editor-usage-message))
@@ -585,6 +609,8 @@ used."
(put 'git-commit-mode 'permanent-local t)
;;; Setup
(defun git-commit-ensure-comment-gap ()
"Separate initial empty line from initial comment.
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))
(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 ()
"Treat ChangeLog entries as unindented paragraphs."
(setq-local fill-paragraph-function #'log-edit-fill-entry)
(setq-local fill-indent-according-to-mode t)
(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.
Ensure auto filling happens everywhere, except in the summary line."
(auto-fill-mode 1)
(setq-local comment-auto-fill-only-comments nil)
(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)
(do-auto-fill)))
(defun git-commit-turn-on-orglink ()
(defun git-commit-setup-orglink ()
"Turn on Orglink mode if it is available.
If `git-commit-major-mode' is `org-mode', then silently forgo
turning on `orglink-mode'."
@@ -623,15 +660,14 @@ turning on `orglink-mode'."
(setq-local orglink-match-anywhere t)
(orglink-mode 1)))
(defun git-commit-turn-on-flyspell ()
(defun git-commit-setup-flyspell ()
"Unconditionally turn on Flyspell mode.
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
comment and anything below the cut line (\"--- >8 ---\")."
(require 'flyspell)
(flyspell-mode 1)
(setq flyspell-generic-check-word-predicate
#'git-commit-flyspell-verify)
(setq flyspell-generic-check-word-predicate #'git-commit--flyspell-verify)
(let ((end nil)
;; The "cut line" is defined in "git/wt-status.c". It appears
;; 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)))
(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))
(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)
(run-hook-with-args-until-failure
'git-commit-finish-query-functions force))
@@ -784,6 +847,55 @@ Save current message first."
(setq str (replace-match "\n" t t 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
(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
serves as a good introduction."
[[:description (##cond (prefix-arg
"Insert ... by someone ")
("Insert ... by yourself"))
"Insert trailer ... by someone ")
("Insert trailer ... by yourself"))
("a" "Ack" git-commit-ack)
("m" "Modified" git-commit-modified)
("r" "Reviewed" git-commit-review)
("s" "Signed-off" git-commit-signoff)
("t" "Tested" git-commit-test)]
["Insert ... by someone"
["Insert trailer ... by someone"
("C-c" "Cc" git-commit-cc)
("C-r" "Reported" git-commit-reported)
("C-i" "Suggested" git-commit-suggested)
("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)
"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 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)
;; Local Variables:
;; read-symbol-shorthands: (
@@ -1232,6 +1360,7 @@ commit, then the hook is not run at all."
;; ("and>" . "cond-let--and>")
;; ("and-let" . "cond-let--and-let")
;; ("if-let" . "cond-let--if-let")
;; ("when$" . "cond-let--when$")
;; ("when-let" . "cond-let--when-let")
;; ("while-let" . "cond-let--while-let")
;; ("match-string" . "match-string")
+2 -1
View File
@@ -1,6 +1,6 @@
;;; 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>
;; 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-let" . "cond-let--and-let")
;; ("if-let" . "cond-let--if-let")
;; ("when$" . "cond-let--when$")
;; ("when-let" . "cond-let--when-let")
;; ("while-let" . "cond-let--while-let")
;; ("match-string" . "match-string")
+29 -28
View File
@@ -1,6 +1,6 @@
;;; 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>
;; 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
so causes the change to be applied to the index as well."
(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))
(`(,(or 'unstaged 'staged) ,_)
(user-error "Change is already in the working tree"))
(`(untracked ,(or 'file 'files))
(call-interactively #'magit-am))
(`(,_ region) (magit-apply-region s args))
(`(,_ hunk) (magit-apply-hunk s args))
(`(,_ hunks) (magit-apply-hunks s args))
(`(,_ region) (magit-apply-region $ args))
(`(,_ hunk) (magit-apply-hunk $ args))
(`(,_ hunks) (magit-apply-hunks $ args))
(`(rebase-sequence file)
(call-interactively #'magit-patch-apply))
(`(,_ file) (magit-apply-diff s args))
(`(,_ files) (magit-apply-diffs s args)))))
(`(,_ file) (magit-apply-diff $ args))
(`(,_ files) (magit-apply-diffs $ args)))))
(defun magit-apply--section-content (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
of a side, then keep that side without prompting."
(interactive)
(when-let ((s (magit-apply--get-selection)))
(when$ (magit-apply--get-selection)
(pcase (list (magit-diff-type) (magit-diff-scope))
(`(committed ,_) (user-error "Cannot discard committed changes"))
(`(undefined ,_) (user-error "Cannot discard this change"))
(`(untracked list) (magit-discard-untracked))
(`(,_ region) (magit-discard-region s))
(`(,_ hunk) (magit-discard-hunk s))
(`(,_ hunks) (magit-discard-hunks s))
(`(,_ file) (magit-discard-file s))
(`(,_ files) (magit-discard-files s))
(`(,_ list) (magit-discard-files s)))))
(`(,_ region) (magit-discard-region $))
(`(,_ hunk) (magit-discard-hunk $))
(`(,_ hunks) (magit-discard-hunks $))
(`(,_ file) (magit-discard-file $))
(`(,_ files) (magit-discard-files $))
(`(,_ list) (magit-discard-files $)))))
(defun magit-discard-untracked ()
(magit-discard-files--delete
@@ -642,13 +642,13 @@ of a side, then keep that side without prompting."
files))
(dolist (file files)
(let ((orig (cadr (assoc file status))))
(if (file-exists-p file)
(progn
(when-let ((path (file-name-directory orig)))
(make-directory path t))
(cond ((file-exists-p file)
(when$ (file-name-directory orig)
(make-directory $ t))
(magit-call-git "mv" file orig))
(t
(magit-call-git "rm" "--cached" "--" file)
(magit-call-git "reset" "--" orig)))))
(magit-call-git "reset" "--" orig))))))
(defun magit-discard-files--discard (sections new-files)
(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
so causes the change to be applied to the index as well."
(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))
(`(untracked ,_) (user-error "Cannot reverse untracked changes"))
(`(unstaged ,_) (user-error "Cannot reverse unstaged changes"))
(`(,_ region) (magit-reverse-region s args))
(`(,_ hunk) (magit-reverse-hunk s args))
(`(,_ hunks) (magit-reverse-hunks s args))
(`(,_ file) (magit-reverse-file s args))
(`(,_ files) (magit-reverse-files s args))
(`(,_ list) (magit-reverse-files s args)))))
(`(,_ region) (magit-reverse-region $ args))
(`(,_ hunk) (magit-reverse-hunk $ args))
(`(,_ hunks) (magit-reverse-hunks $ args))
(`(,_ file) (magit-reverse-file $ args))
(`(,_ files) (magit-reverse-files $ args))
(`(,_ list) (magit-reverse-files $ args)))))
(defun magit-reverse-region (section args)
(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)
(let ((bs (magit-binary-files
(cond ((derived-mode-p 'magit-revision-mode)
magit-buffer-range)
magit-buffer-diff-range)
((derived-mode-p 'magit-diff-mode)
magit-buffer-range)
magit-buffer-diff-range)
("--cached")))))
(magit--separate (##member (oref % value) bs)
sections))))
@@ -822,6 +822,7 @@ a separate commit. A typical workflow would be:
;; ("and>" . "cond-let--and>")
;; ("and-let" . "cond-let--and-let")
;; ("if-let" . "cond-let--if-let")
;; ("when$" . "cond-let--when$")
;; ("when-let" . "cond-let--when-let")
;; ("while-let" . "cond-let--while-let")
;; ("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 -*-
;; Copyright (C) 2008-2025 The Magit Project Contributors
;; Copyright (C) 2008-2026 The Magit Project Contributors
;; Author: 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 -*-
;; Copyright (C) 2008-2025 The Magit Project Contributors
;; Copyright (C) 2008-2026 The Magit Project Contributors
;; Author: 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)
((keymap :initform 'magit-hunk-section-map)
(painted :initform nil)
(fontified :initform nil) ;TODO
(fontified :initform nil)
(refined :initform nil)
(combined :initform nil :initarg :combined)
(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 (eq magit-no-confirm t)
(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)
(memq action sub)
(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."
(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
(defun magit-which-function ()
@@ -1187,6 +1205,16 @@ Like `message', except that `message-log-max' is bound to nil."
(push char 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)
;; Local Variables:
@@ -1195,6 +1223,7 @@ Like `message', except that `message-log-max' is bound to nil."
;; ("and>" . "cond-let--and>")
;; ("and-let" . "cond-let--and-let")
;; ("if-let" . "cond-let--if-let")
;; ("when$" . "cond-let--when$")
;; ("when-let" . "cond-let--when-let")
;; ("while-let" . "cond-let--while-let")
;; ("match-string" . "match-string")
+2 -1
View File
@@ -1,6 +1,6 @@
;;; 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>
;; Maintainer: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
@@ -321,6 +321,7 @@ bisect run'."
;; ("and>" . "cond-let--and>")
;; ("and-let" . "cond-let--and-let")
;; ("if-let" . "cond-let--if-let")
;; ("when$" . "cond-let--when$")
;; ("when-let" . "cond-let--when-let")
;; ("while-let" . "cond-let--while-let")
;; ("match-string" . "match-string")
+5 -4
View File
@@ -1,6 +1,6 @@
;;; 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>
;; 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))))
(magit-blame-chunk-at (point)))
(and type
(let ((rev (or magit-buffer-refname magit-buffer-revision))
(let ((rev magit-buffer-revision)
(file (and (not (derived-mode-p 'dired-mode))
(magit-file-relative-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))
(message "Blaming...")
(magit-blame-run-process
(and$ (or magit-buffer-refname magit-buffer-revision)
(and (not (equal $ "{index}")) $))
(and (not (equal magit-buffer-revision "{index}"))
magit-buffer-revision)
(magit-file-relative-name nil (not magit-buffer-file-name))
(if (memq magit-blame-type '(final removal))
(cons "--reverse" args)
@@ -1006,6 +1006,7 @@ instead of the hash, like `kill-ring-save' would."
;; ("and>" . "cond-let--and>")
;; ("and-let" . "cond-let--and-let")
;; ("if-let" . "cond-let--if-let")
;; ("when$" . "cond-let--when$")
;; ("when-let" . "cond-let--when-let")
;; ("while-let" . "cond-let--while-let")
;; ("match-string" . "match-string")
+16 -14
View File
@@ -1,6 +1,6 @@
;;; 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.
@@ -56,8 +56,8 @@
;;;; Diff
(put 'magit-diff-mode 'magit-bookmark-variables
'(magit-buffer-range-hashed
magit-buffer-typearg
'(magit-buffer-diff-range-oids
magit-buffer-diff-typearg
magit-buffer-diff-args
magit-buffer-diff-files))
@@ -66,9 +66,10 @@
(pcase (magit-diff-type)
('staged "staged")
('unstaged "unstaged")
('committed magit-buffer-range)
('committed magit-buffer-diff-range)
('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
(concat " -- " (string-join magit-buffer-diff-files " "))
"")))
@@ -76,7 +77,7 @@
;;;; Revision
(put 'magit-revision-mode 'magit-bookmark-variables
'(magit-buffer-revision-hash
'(magit-buffer-revision-oid
magit-buffer-diff-args
magit-buffer-diff-files))
@@ -90,7 +91,7 @@
;;;; Stash
(put 'magit-stash-mode 'magit-bookmark-variables
'(magit-buffer-revision-hash
'(magit-buffer-revision-oid
magit-buffer-diff-args
magit-buffer-diff-files))
@@ -104,20 +105,20 @@
(cl-defmethod magit-bookmark--get-child-value
(section &context (major-mode magit-stash-mode))
(string-replace magit-buffer-revision
magit-buffer-revision-hash
magit-buffer-revision-oid
(oref section value)))
;;; Log
;;;; Log
(put 'magit-log-mode 'magit-bookmark-variables
'(magit-buffer-revisions
'(magit-buffer-log-revisions
magit-buffer-log-args
magit-buffer-log-files))
(cl-defmethod magit-bookmark-name (&context (major-mode magit-log-mode))
(format "magit-log(%s%s)"
(string-join magit-buffer-revisions " ")
(string-join magit-buffer-log-revisions " ")
(if magit-buffer-log-files
(concat " -- " (string-join magit-buffer-log-files " "))
"")))
@@ -126,12 +127,12 @@
(put 'magit-cherry-mode 'magit-bookmark-variables
'(magit-buffer-refname
magit-buffer-upstream))
magit-buffer-cherry-upstream))
(cl-defmethod magit-bookmark-name (&context (major-mode magit-cherry-mode))
(format "magit-cherry(%s > %s)"
magit-buffer-refname
magit-buffer-upstream))
magit-buffer-cherry-upstream))
;;;; Reflog
@@ -146,8 +147,8 @@
(put 'magit-status-mode 'magit-bookmark-variables nil)
(put 'magit-refs-mode 'magit-bookmark-variables
'(magit-buffer-upstream
magit-buffer-arguments))
'(magit-buffer-refs-upstream
magit-buffer-refs-args))
(put 'magit-stashes-mode 'magit-bookmark-variables nil)
@@ -162,6 +163,7 @@
;; ("and>" . "cond-let--and>")
;; ("and-let" . "cond-let--and-let")
;; ("if-let" . "cond-let--if-let")
;; ("when$" . "cond-let--when$")
;; ("when-let" . "cond-let--when-let")
;; ("while-let" . "cond-let--while-let")
;; ("match-string" . "match-string")
+13 -12
View File
@@ -1,6 +1,6 @@
;;; 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>
;; 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."
:package-version '(magit . "2.9.0")
:group 'magit-commands
:type '(repeat (cons (string :tag "Use upstream")
(choice :tag "For branches" ;???
:type '(alist :key-type (string :tag "Use upstream")
:value-type (choice :tag "For branches" ;???
(regexp :tag "Matching")
(repeat :tag "Except"
(string :tag "Branch"))))))
(string :tag "Branch")))))
(defcustom magit-branch-rename-push-target t
"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
(magit-call-git "checkout" "-b" branch current)
(magit-call-git "branch" branch current)))
(when-let ((upstream (magit-get-indirect-upstream-branch current)))
(magit-call-git "branch" "--set-upstream-to" upstream branch))
(when$ (magit-get-indirect-upstream-branch current)
(magit-call-git "branch" "--set-upstream-to" $ branch))
(when (and tracked
(setq base
(if from
@@ -560,8 +560,7 @@ that is being reset."
(magit-reset-hard to))
(magit-call-git "update-ref"
"-m" (format "reset: moving to %s" to)
(magit-git-string "rev-parse" "--symbolic-full-name"
branch)
(magit-ref-fullname branch)
to))
(when (and set-upstream (magit-branch-p to))
(magit-set-upstream-branch branch to)
@@ -639,10 +638,10 @@ prompt is confusing."
(magit-rev-parse "--short" ref)))
;; Assume the branches actually still exist on the remote.
(magit-run-git-async
"push"
"push" "--delete"
(and (or force magit-branch-delete-never-verify) "--no-verify")
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.
(set-process-sentinel
magit-this-process
@@ -891,7 +890,8 @@ Also rename the respective reflog file."
(magit-run-git-with-editor "branch" "--edit-description" branch))
(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 ()
:class 'magit--git-branch:upstream)
@@ -919,7 +919,7 @@ Also rename the respective reflog file."
(cl-defmethod transient-format ((obj magit--git-branch:upstream))
(let ((branch (transient-scope)))
(format-spec
(oref obj format)
(transient--get-format obj)
`((?k . ,(transient-format-key obj))
(?r . ,(format "branch.%s.remote" branch))
(?m . ,(format "branch.%s.merge" branch))
@@ -977,6 +977,7 @@ Also rename the respective reflog file."
;; ("and>" . "cond-let--and>")
;; ("and-let" . "cond-let--and-let")
;; ("if-let" . "cond-let--if-let")
;; ("when$" . "cond-let--when$")
;; ("when-let" . "cond-let--when-let")
;; ("while-let" . "cond-let--while-let")
;; ("match-string" . "match-string")
+2 -1
View File
@@ -1,6 +1,6 @@
;;; 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>
;; Maintainer: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
@@ -142,6 +142,7 @@
;; ("and>" . "cond-let--and>")
;; ("and-let" . "cond-let--and-let")
;; ("if-let" . "cond-let--if-let")
;; ("when$" . "cond-let--when$")
;; ("when-let" . "cond-let--when-let")
;; ("while-let" . "cond-let--while-let")
;; ("match-string" . "match-string")
+2 -1
View File
@@ -1,6 +1,6 @@
;;; 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>
;; 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-let" . "cond-let--and-let")
;; ("if-let" . "cond-let--if-let")
;; ("when$" . "cond-let--when$")
;; ("when-let" . "cond-let--when-let")
;; ("while-let" . "cond-let--while-let")
;; ("match-string" . "match-string")
+33 -19
View File
@@ -1,6 +1,6 @@
;;; 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>
;; 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."
:info-manual "(magit)Initiating a Commit"
:man-page "git-commit"
:value '("--verbose")
["Arguments"
("-a" "Stage all modified and deleted files" ("-a" "--all"))
("-e" "Allow empty commit" "--allow-empty")
@@ -548,8 +549,7 @@ is updated:
(user-error "There are no modified modules that could be absorbed"))
(when commit
(setq commit (magit-rebase-interactive-assert commit t)))
(if (and commit (eq phase 'run))
(progn
(cond ((and commit (eq phase 'run))
(dolist (module modules)
(when-let ((msg (magit-git-string
"log" "-1" "--format=%s"
@@ -558,10 +558,10 @@ is updated:
"--only" "--" module)))
(magit-refresh)
t)
(magit-log-select
((magit-log-select
(lambda (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)
(transient-define-prefix magit-commit-absorb (phase commit args)
@@ -669,18 +669,25 @@ an alternative implementation."
'magit-commit--rebase
last-command))
(when (and git-commit-mode magit-commit-show-diff)
(when-let ((diff-buffer (magit-get-mode-buffer 'magit-diff-mode)))
;; This window just started displaying the commit message
;; buffer. Without this that buffer would immediately be
;; replaced with the diff buffer. See #2632.
(when-let ((diff-buffer
;; This signals an error if not inside a Git repository,
;; but the user may be visiting COMMIT_EDITMSG using a
;; 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))
(message "Diffing changes to be committed (C-g to abort diffing)")
(let ((inhibit-quit nil))
(condition-case nil
(magit-commit-diff-1)
(with-demoted-errors "Error showing commit diff: %S"
(magit-commit-diff--show))
(quit)))))
(defun magit-commit-diff-1 ()
(defun magit-commit-diff--args ()
(let ((rev nil)
(arg "--cached")
(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)))))
(noalt nil))
(pcase (list staged unstaged command)
((guard (not (magit-commit-p "HEAD^")))
(setq rev "HEAD")
(setq arg nil))
((and `(,_ ,_ magit-commit--rebase)
(guard (integerp squash)))
(setq rev (format "HEAD~%s" squash)))
@@ -716,20 +726,23 @@ an alternative implementation."
(setq arg nil)))
(cond
((not
(and (eq this-command 'magit-diff-while-committing)
(and-let ((buf (magit-get-mode-buffer
'magit-diff-mode nil 'selected)))
(and (equal rev (buffer-local-value 'magit-buffer-range buf))
(equal arg (buffer-local-value 'magit-buffer-typearg buf)))))))
(and-let*
((_(eq this-command 'magit-diff-while-committing))
(buf (magit-get-mode-buffer 'magit-diff-mode nil 'selected))
(_(equal rev (buffer-local-value 'magit-buffer-diff-range buf)))
(_(equal arg (buffer-local-value 'magit-buffer-diff-typearg buf)))))))
((eq command 'magit-commit-amend)
(setq rev nil))
((or squash
(file-exists-p (expand-file-name "rebase-merge/amend" (magit-gitdir))))
(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")
(setq noalt t)))
(unless noalt
(let ((magit-inhibit-save-previous-winconf 'unset)
(magit-display-buffer-noselect t)
(display-buffer-overriding-action
@@ -858,6 +871,7 @@ Also see `git-commit-post-finish-hook'."
;; ("and>" . "cond-let--and>")
;; ("and-let" . "cond-let--and-let")
;; ("if-let" . "cond-let--if-let")
;; ("when$" . "cond-let--when$")
;; ("when-let" . "cond-let--when-let")
;; ("while-let" . "cond-let--while-let")
;; ("match-string" . "match-string")
+2 -1
View File
@@ -1,6 +1,6 @@
;;; 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>
;; 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-let" . "cond-let--and-let")
;; ("if-let" . "cond-let--if-let")
;; ("when$" . "cond-let--when$")
;; ("when-let" . "cond-let--when-let")
;; ("while-let" . "cond-let--while-let")
;; ("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 -*-
;; Copyright (C) 2008-2025 The Magit Project Contributors
;; Copyright (C) 2008-2026 The Magit Project Contributors
;; Author: 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-let" . "cond-let--and-let")
;; ("if-let" . "cond-let--if-let")
;; ("when$" . "cond-let--when$")
;; ("when-let" . "cond-let--when-let")
;; ("while-let" . "cond-let--while-let")
;; ("match-string" . "match-string")
+126 -167
View File
@@ -1,6 +1,6 @@
;;; 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>
;; Maintainer: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
@@ -42,19 +42,17 @@
:group 'magit-extensions)
(defcustom magit-ediff-quit-hook
(list #'magit-ediff-cleanup-auxiliary-buffers
#'magit-ediff-restore-previous-winconf)
(list #'magit-ediff-restore-previous-winconf)
"Hooks to run after finishing Ediff, when that was invoked using Magit.
The hooks are run in the Ediff control buffer. This is similar
to `ediff-quit-hook' but takes the needs of Magit into account.
The `ediff-quit-hook' is ignored by Ediff sessions which were
invoked using Magit."
:package-version '(magit . "2.2.0")
:package-version '(magit . "4.6.0")
:group 'magit-ediff
:type 'hook
:get #'magit-hook-custom-get
:options (list #'magit-ediff-cleanup-auxiliary-buffers
#'magit-ediff-restore-previous-winconf))
:options (list #'magit-ediff-restore-previous-winconf))
(defcustom magit-ediff-dwim-resolve-function #'magit-ediff-resolve-rest
"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)
;;;###autoload(autoload 'magit-ediff "magit-ediff" nil)
;;;###autoload(autoload 'magit-ediff "magit-ediff" nil t)
(transient-define-prefix magit-ediff ()
"Show differences using the Ediff package."
:info-manual "(ediff)"
@@ -132,86 +130,8 @@ recommend you do not further complicate that by enabling this.")
("r" "Show range" magit-ediff-compare)
("z" "Show stash" magit-ediff-show-stash)]])
(defmacro magit-ediff-buffers (a b &optional c setup quit file)
"Run Ediff on two or three buffers.
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)
;;;###autoload(autoload 'magit-ediff-resolve-all "magit-ediff" nil t)
(transient-define-suffix magit-ediff-resolve-all (file)
"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
@@ -219,16 +139,17 @@ changes, then prompt for a file.
See info node `(magit) Ediffing' for more information about this
and alternative commands."
:inapt-if-not #'magit-anything-unmerged-p
(interactive (list (magit-read-unmerged-file)))
(magit-with-toplevel
(let* ((dir (magit-gitdir))
(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))
'("MERGE_HEAD" "CHERRY_PICK_HEAD" "REVERT_HEAD")))
(revB (or (magit-name-branch revB)
(magit-commit-p revB)))
(revC (magit-commit-p (magit-git-string "merge-base" revA revB)))
(magit-commit-oid revB)))
(revC (magit-commit-oid (magit-git-string "merge-base" revA revB)))
(fileA (magit--rev-file-name file revA revB))
(fileB (magit--rev-file-name file revB revA))
(fileC (or (magit--rev-file-name file revC revA)
@@ -256,7 +177,7 @@ and alternative commands."
,(format ">>>>>>> %s" revB)))))
(quit (lambda ()
;; 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.
;; See (if ediff-merge-job ...) in `ediff-setup'.
(when (buffer-live-p ediff-buffer-C)
@@ -266,24 +187,14 @@ and alternative commands."
(goto-char (point-min))
(unless (re-search-forward "^<<<<<<< " nil t)
(magit-stage-files (list file)))))))))
(cond (fileC
(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))
((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)))))))
(magit-ediff--find-file revA fileA)
(magit-ediff--find-file revB fileB)
(and fileC (magit-ediff--find-file revC fileC))
setup quit file)))))
;;;###autoload
(defun magit-ediff-resolve-rest (file)
;;;###autoload(autoload 'magit-ediff-resolve-rest "magit-ediff" nil t)
(transient-define-suffix magit-ediff-resolve-rest (file)
"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
@@ -291,6 +202,7 @@ changes, then prompt for a file.
See info node `(magit) Ediffing' for more information about this
and alternative commands."
:inapt-if-not #'magit-anything-unmerged-p
(interactive (list (magit-read-unmerged-file)))
(magit-with-toplevel
(with-current-buffer (find-file-noselect file)
@@ -314,32 +226,27 @@ and alternative commands."
(let ((magit-ediff-previous-winconf smerge-ediff-windows))
(run-hooks 'magit-ediff-quit-hook)))))))
;;;###autoload
(defun magit-ediff-stage (file)
;;;###autoload(autoload 'magit-ediff-stage "magit-ediff" nil t)
(transient-define-suffix magit-ediff-stage (file)
"Stage and unstage changes to FILE using Ediff.
FILE has to be relative to the top directory of the repository."
:inapt-if-not #'magit-anything-modified-p
(interactive
(let ((files (magit-tracked-files)))
(list (magit-completing-read "Selectively stage file" files nil t nil nil
(car (member (magit-current-file) files))))))
(magit-with-toplevel
(let* ((bufA (magit-get-revision-buffer "HEAD" file))
(bufB (magit-get-revision-buffer "{index}" file))
(lockB (and bufB (buffer-local-value 'buffer-read-only bufB)))
(bufC (get-file-buffer file))
(let* ((bufC (magit-ediff--find-file "{worktree}" file))
;; Use the same encoding for all three buffers or we
;; may end up changing the file in an unintended way.
(bufC* (or bufC (find-file-noselect file)))
(coding-system-for-read
(buffer-local-value 'buffer-file-coding-system bufC*))
(bufA* (magit-find-file-noselect "HEAD" file t))
(bufB* (magit-find-file-index-noselect file t)))
(with-current-buffer bufB* (setq buffer-read-only nil))
(buffer-local-value 'buffer-file-coding-system bufC))
(bufA (magit-ediff--find-file "HEAD" file))
(bufB (magit-ediff--find-file "{index}" file))
(lockB (buffer-local-value 'buffer-read-only bufB)))
(with-current-buffer bufB (setq buffer-read-only nil))
(magit-ediff-buffers
(bufA bufA*)
(bufB bufB*)
(bufC bufC*)
nil
bufA bufB bufC nil
(lambda ()
(when (buffer-live-p ediff-buffer-B)
(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))
(save-buffer)))))))))
;;;###autoload
(defun magit-ediff-compare (revA revB fileA fileB)
;;;###autoload(autoload 'magit-ediff-compare "magit-ediff" nil t)
(transient-define-suffix magit-ediff-compare (revA revB fileA fileB)
"Compare REVA:FILEA with REVB:FILEB using Ediff.
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
working tree state.
repository.
If the region is active, use the revisions on the first and last
line of the region. With a prefix argument, instead of diffing
@@ -372,10 +278,8 @@ range)."
(nconc (list revA revB)
(magit-ediff-read-files revA revB))))
(magit-ediff-buffers
((if revA (magit-get-revision-buffer revA fileA) (get-file-buffer fileA))
(if revA (magit-find-file-noselect revA fileA) (find-file-noselect fileA)))
((if revB (magit-get-revision-buffer revB fileB) (get-file-buffer fileB))
(if revB (magit-find-file-noselect revB fileB) (find-file-noselect fileB)))))
(magit-ediff--find-file revA fileA)
(magit-ediff--find-file revB fileB)))
(defun magit-ediff-compare--read-revisions (&optional arg mbase)
(let ((input (or arg (magit-diff-read-range-or-commit
@@ -383,12 +287,14 @@ range)."
nil mbase))))
(if-let ((range (magit-split-range input)))
(list (car range) (cdr range))
(list input nil))))
(list input "{worktree}"))))
(defun magit-ediff-read-files (revA revB &optional fileB)
"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
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)))
(setq fileB
(or (and fileB
@@ -416,8 +322,8 @@ prompting for it."
revA revB)))
fileB))
;;;###autoload
(defun magit-ediff-dwim ()
;;;###autoload(autoload 'magit-ediff-dwim "magit-ediff" nil t)
(transient-define-suffix magit-ediff-dwim ()
"Compare, stage, or resolve using Ediff.
This command tries to guess what file, and what commit or range
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)
('committed (pcase-let ((`(,a ,b)
(magit-ediff-compare--read-revisions
magit-buffer-range)))
magit-buffer-diff-range)))
(setq revA a)
(setq revB b)))
((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))
((call-interactively command)))))))
;;;###autoload
(defun magit-ediff-show-staged (file)
;;;###autoload(autoload 'magit-ediff-show-staged "magit-ediff" nil t)
(transient-define-suffix magit-ediff-show-staged (file)
"Show staged changes using Ediff.
This only allows looking at the changes; to stage, unstage,
and discard changes using Ediff, use `magit-ediff-stage'.
FILE must be relative to the top directory of the repository."
:inapt-if-not #'magit-anything-staged-p
(interactive
(list (magit-read-file-choice "Show staged changes for file"
(magit-staged-files)
"No staged files")))
(magit-ediff-buffers ((magit-get-revision-buffer "HEAD" file)
(magit-find-file-noselect "HEAD" file))
((get-buffer (concat file ".~{index}~"))
(magit-find-file-index-noselect file t))))
(magit-ediff-buffers (magit-ediff--find-file "HEAD" file)
(magit-ediff--find-file "{index}" file)))
;;;###autoload
(defun magit-ediff-show-unstaged (file)
;;;###autoload(autoload 'magit-ediff-show-unstaged "magit-ediff" nil t)
(transient-define-suffix magit-ediff-show-unstaged (file)
"Show unstaged changes using Ediff.
This only allows looking at the changes; to stage, unstage,
and discard changes using Ediff, use `magit-ediff-stage'.
FILE must be relative to the top directory of the repository."
:inapt-if-not #'magit-anything-unstaged-p
(interactive
(list (magit-read-file-choice "Show unstaged changes for file"
(magit-unstaged-files)
"No unstaged files")))
(magit-ediff-buffers ((get-buffer (concat file ".~{index}~"))
(magit-find-file-index-noselect file t))
((get-file-buffer file)
(find-file-noselect file))))
(magit-ediff-buffers (magit-ediff--find-file "{index}" file)
(magit-ediff--find-file "{worktree}" file)))
;;;###autoload
(defun magit-ediff-show-working-tree (file)
;;;###autoload(autoload 'magit-ediff-show-working-tree "magit-ediff" nil t)
(transient-define-suffix magit-ediff-show-working-tree (file)
"Show changes between `HEAD' and working tree using Ediff.
FILE must be relative to the top directory of the repository."
:inapt-if-not #'magit-anything-modified-p
(interactive
(list (magit-read-file-choice "Show changes in file"
(magit-changed-files "HEAD")
(magit-modified-files)
"No changed files")))
(magit-ediff-buffers ((magit-get-revision-buffer "HEAD" file)
(magit-find-file-noselect "HEAD" file))
((get-file-buffer file)
(find-file-noselect file))))
(magit-ediff-buffers (magit-ediff--find-file "HEAD" file)
(magit-ediff--find-file "{worktree}" file)))
;;;###autoload
(defun magit-ediff-show-commit (commit)
;;;###autoload(autoload 'magit-ediff-show-commit "magit-ediff" nil t)
(transient-define-suffix magit-ediff-show-commit (commit)
"Show changes introduced by COMMIT using Ediff."
(interactive (list (magit-read-branch-or-commit "Revision")))
(let ((revA (concat commit "^"))
@@ -547,12 +450,13 @@ FILE must be relative to the top directory of the repository."
revA revB
(magit-ediff-read-files revA revB (magit-current-file)))))
;;;###autoload
(defun magit-ediff-show-stash (stash)
;;;###autoload(autoload 'magit-ediff-show-stash "magit-ediff" nil t)
(transient-define-suffix magit-ediff-show-stash (stash)
"Show changes introduced by STASH using Ediff.
`magit-ediff-show-stash-with-index' controls whether a
three-buffer Ediff is used in order to distinguish changes in the
stash that were staged."
`magit-ediff-show-stash-with-index' controls whether a three-buffer
Ediff is used in order to distinguish changes in the stash that were
staged."
:inapt-if-not #'magit-list-stashes
(interactive (list (magit-read-stash "Stash")))
(pcase-let* ((revA (concat stash "^1"))
(revB (concat stash "^2"))
@@ -562,15 +466,64 @@ stash that were staged."
(if (and magit-ediff-show-stash-with-index
(member fileA (magit-changed-files revB revA)))
(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))
((magit-get-revision-buffer revC fileC)
(magit-find-file-noselect revC fileC)))
(magit-ediff--find-file revA fileA)
(magit-ediff--find-file revB fileB)
(magit-ediff--find-file revC 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)
(ctl-win (ediff-get-visible-buffer-window ctl-buf))
(ctl-frm ediff-control-frame)
@@ -596,6 +549,11 @@ stash that were staged."
(when (frame-live-p 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 ()
(set-window-configuration magit-ediff-previous-winconf))
@@ -607,6 +565,7 @@ stash that were staged."
;; ("and>" . "cond-let--and>")
;; ("and-let" . "cond-let--and-let")
;; ("if-let" . "cond-let--if-let")
;; ("when$" . "cond-let--when$")
;; ("when-let" . "cond-let--when-let")
;; ("while-let" . "cond-let--while-let")
;; ("match-string" . "match-string")
+5 -4
View File
@@ -1,6 +1,6 @@
;;; 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>
;; Maintainer: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
@@ -737,9 +737,9 @@ abbreviated revision to the `kill-ring' and the
(cl-case major-mode
(magit-diff-mode
(if (string-match "\\.\\.\\.?\\(.+\\)"
magit-buffer-range)
(match-str 1 magit-buffer-range)
magit-buffer-range))
magit-buffer-diff-range)
(match-str 1 magit-buffer-diff-range)
magit-buffer-diff-range))
(magit-status-mode "HEAD")))]
[_(magit-commit-p rev)]
(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-let" . "cond-let--and-let")
;; ("if-let" . "cond-let--if-let")
;; ("when$" . "cond-let--when$")
;; ("when-let" . "cond-let--when-let")
;; ("while-let" . "cond-let--while-let")
;; ("match-string" . "match-string")
+2 -1
View File
@@ -1,6 +1,6 @@
;;; 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>
;; Maintainer: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
@@ -188,6 +188,7 @@ with a prefix argument."
;; ("and>" . "cond-let--and>")
;; ("and-let" . "cond-let--and-let")
;; ("if-let" . "cond-let--if-let")
;; ("when$" . "cond-let--when$")
;; ("when-let" . "cond-let--when-let")
;; ("while-let" . "cond-let--while-let")
;; ("match-string" . "match-string")
+269 -115
View File
@@ -1,6 +1,6 @@
;;; 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>
;; Maintainer: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
@@ -31,10 +31,21 @@
(require 'magit)
(declare-function ediff-quit "ediff-util" (reverse-default-keep-variants))
;;; Find Blob
(defvar magit-find-file-hook nil)
(add-hook 'magit-find-file-hook #'magit-blob-mode)
(define-obsolete-variable-alias 'magit-find-file-hook
'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
(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
to the line and column corresponding to that location."
(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
(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
the line and column corresponding to that location."
(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
(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
the line and column corresponding to that location."
(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)
(let ((pseudo-revs '("{worktree}" "{index}")))
(let ((rev (magit-completing-read "Find file from revision"
(let* ((pseudo-revs '("{worktree}" "{index}"))
(rev (magit-completing-read "Find file from revision"
(append pseudo-revs
(magit-list-refnames nil t))
nil 'any nil 'magit-revision-history
@@ -76,128 +87,244 @@ the line and column corresponding to that location."
(magit-get-current-branch)))))
(list rev
(magit-read-file-from-rev (if (member rev pseudo-revs) "HEAD" rev)
prompt)))))
prompt))))
(defun magit-find-file--internal (rev file fn)
(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)
(defun magit-find-file-noselect (rev file &optional no-restore-position volatile)
"Read FILE from REV into a buffer and return the buffer.
REV is a revision or one of \"{worktree}\" or \"{index}\". FILE must
be relative to the top directory of the repository. Non-nil REVERT
means to revert the buffer. If `ask-revert', then only after asking.
A non-nil value for REVERT is ignored if REV is \"{worktree}\"."
(let* ((topdir (magit-toplevel))
(absolute (file-name-absolute-p file))
(file-abs (if absolute file (expand-file-name file topdir)))
(file-rel (if absolute (file-relative-name file topdir) file))
(defdir (file-name-directory file-abs))
(rev (magit--abbrev-if-hash rev)))
(if (equal rev "{worktree}")
REV is a revision or one of \"{worktree}\" or \"{index}\".
Non-interactively REV can also be a blob object."
(let* ((rev (pcase rev
('nil "{worktree}")
((and "{index}"
(guard (length> (magit--file-index-stages file) 1)))
"{worktree}")
(rev rev)))
(topdir (magit-toplevel))
(file (expand-file-name file topdir))
(file-relative (file-relative-name file topdir))
(buffer
(cond-let
((equal rev "{worktree}")
(let ((revert-without-query
(if (and$ (find-buffer-visiting file-abs)
(if (and$ (find-buffer-visiting file)
(buffer-local-value 'auto-revert-mode $))
(cons "." revert-without-query)
revert-without-query)))
(find-file-noselect file-abs))
(with-current-buffer (magit-get-revision-buffer-create rev file-rel)
(when (or (not magit-buffer-file-name)
(if (eq revert 'ask-revert)
(y-or-n-p (format "%s already exists; revert it? "
(buffer-name))))
revert)
(setq magit-buffer-revision rev)
(setq magit-buffer-refname rev)
(setq magit-buffer-file-name file-abs)
(setq default-directory (if (file-exists-p defdir) defdir topdir))
(setq-local revert-buffer-function #'magit-revert-rev-file-buffer)
(revert-buffer t t)
(run-hooks (if (equal rev "{index}")
'magit-find-index-hook
'magit-find-file-hook)))
(current-buffer)))))
(find-file-noselect file volatile)))
((not topdir)
(error "%s is not inside a Git repository" file))
([defdir (file-name-directory file)]
[rev (magit--abbrev-if-oid rev)]
(unless (file-in-directory-p file topdir)
(error "%s is not inside Git repository %s" file topdir))
(with-current-buffer
(magit--get-blob-buffer rev file-relative volatile)
(if (magit-blob-p rev)
(setq magit-buffer-blob-oid--init (magit-rev-parse rev))
(setq magit-buffer-revision rev))
(setq magit-buffer-file-name file)
(setq default-directory
(if (file-exists-p defdir) defdir topdir))
(setq-local revert-buffer-function #'magit--revert-blob-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)
(magit-get-revision-buffer rev file t))
(defun magit--get-blob-buffer (obj file &optional volatile)
;; 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)
(funcall (if create #'get-buffer-create #'get-buffer)
(format "%s.~%s~" file (subst-char-in-string ?/ ?_ rev))))
(defun magit--blob-buffer-name (obj file &optional volatile)
(format "%s%s.~%s~"
(if volatile " " "")
(or file (and (magit-blob-p obj) "{blob}"))
(subst-char-in-string ?/ ?_ obj)))
(defun magit-revert-rev-file-buffer (_ignore-auto noconfirm)
(when (or noconfirm
(and (not (buffer-modified-p))
(catch 'found
(dolist (regexp revert-without-query)
(when (string-match regexp magit-buffer-file-name)
(throw 'found t)))))
(yes-or-no-p (format "Revert buffer from Git %s? "
(if (equal magit-buffer-refname "{index}")
"index"
(concat "revision " magit-buffer-refname)))))
(let* ((inhibit-read-only t)
(default-directory (magit-toplevel))
(file (file-relative-name magit-buffer-file-name))
(coding-system-for-read (or coding-system-for-read 'undecided)))
(defun magit--revert-blob-buffer (_ignore-auto _noconfirm)
(let ((pos (magit-find-file--position)))
(magit--refresh-blob-buffer t)
(apply #'magit-find-file--restore-position pos)))
(defun magit--refresh-blob-buffer (&optional force)
(let ((old-blob-oid magit-buffer-blob-oid))
(cond
(magit-buffer-revision
(setq magit-buffer-revision-oid
(magit-commit-oid magit-buffer-revision t))
(setq magit-buffer-blob-oid
(magit-blob-oid magit-buffer-revision magit-buffer-file-name)))
(magit-buffer-blob-oid--init
(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)
(magit-git-insert "cat-file" "-p"
(if (equal magit-buffer-refname "{index}")
(concat ":" file)
(concat magit-buffer-refname ":" file)))
(setq buffer-file-coding-system last-coding-system-used))
(save-excursion
(magit--insert-blob-contents magit-buffer-revision
(magit-file-relative-name))))
(magit--blob-normal-mode))))
(defun magit--blob-normal-mode ()
(let ((buffer-file-name magit-buffer-file-name)
(after-change-major-mode-hook
;; Inhibit diff-hl and eglot; see bb8a65269d and 234a787b8c.
(seq-difference after-change-major-mode-hook
'(global-diff-hl-mode-enable-in-buffer ; Emacs >= 30
global-diff-hl-mode-enable-in-buffers ; Emacs < 30
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'.
;; The FIND-FILE argument wasn't designed for our use case, so we
;; have to use this strange invocation to achieve that.
;; The FIND-FILE argument wasn't designed for our use case,
;; so we have to use this strange invocation to achieve that.
(normal-mode (not enable-local-variables)))
(setq buffer-read-only t)
(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)
"Do nothing when visiting blob using `magit-find-file' and similar.
See also https://github.com/doomemacs/doomemacs/pull/6309."
(unless magit-buffer-revision
(unless magit-buffer-blob-oid
(apply fn args)))
;;; Find 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)))
;;; Update Index
(defun magit-update-index ()
"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'."
(interactive)
(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))
(if (y-or-n-p (format "Update index with contents of %s?" (buffer-name)))
(let ((index (make-temp-name
@@ -230,8 +357,8 @@ is done using `magit-find-index-noselect'."
(set-buffer-modified-p nil)
(magit-run-after-apply-functions file "un-/stage"))
(message "Abort")))
(when-let ((buffer (magit-get-mode-buffer 'magit-status-mode)))
(with-current-buffer buffer
(when$ (magit-get-mode-buffer 'magit-status-mode)
(with-current-buffer $
(magit-refresh)))
t)
@@ -345,6 +472,7 @@ to `magit-dispatch'."
(defvar-keymap magit-blob-mode-map
:doc "Keymap for `magit-blob-mode'."
"g" #'revert-buffer
"p" #'magit-blob-previous
"n" #'magit-blob-next
"b" #'magit-blame-addition
@@ -360,18 +488,32 @@ Currently this only adds the following key bindings.
:package-version '(magit . "2.3.0"))
(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")
(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)
"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")
(if (or bury-buffer (cdr (get-buffer-window-list nil nil t)))
(bury-buffer)
(kill-buffer)))
(cond ((bound-and-true-p ediff-this-buffer-ediff-sessions)
(ediff-quit nil))
((or bury-buffer (cdr (get-buffer-window-list nil nil t)))
(bury-buffer))
((kill-buffer))))
(defun magit-kill-this-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."
(interactive)
(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")))
(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
'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)
;; Local Variables:
;; 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-let" . "cond-let--and-let")
;; ("if-let" . "cond-let--if-let")
;; ("when$" . "cond-let--when$")
;; ("when-let" . "cond-let--when-let")
;; ("while-let" . "cond-let--while-let")
;; ("match-string" . "match-string")
+153 -86
View File
@@ -1,6 +1,6 @@
;;; 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>
;; Maintainer: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
@@ -48,7 +48,6 @@
(defvar magit-buffer-file-name)
(defvar magit-buffer-log-args)
(defvar magit-buffer-log-files)
(defvar magit-buffer-refname)
(defvar magit-buffer-revision)
;; From `magit-process'.
@@ -72,6 +71,8 @@
(cl-pushnew 'orig-rev eieio--known-slot-names)
(cl-pushnew 'number eieio--known-slot-names))
(defvar crm-prompt) ; Emacs 31.1
;;; Options
;; 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.
* 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.
* If `system-type' is `windows-nt', encode ARGS to `w32-ansi-code-page'."
(cond ((not async))
@@ -434,22 +435,6 @@ to do the following.
"Execute Git with ARGS, returning t if its exit code is 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)
"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
@@ -459,7 +444,7 @@ buffer (creating it if necessary) and the error message is shown
in the status buffer (provided it exists).
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
(list default-directory 'magit-git-string-ng args)
(magit--with-temp-process-buffer
@@ -526,9 +511,9 @@ signal `magit-invalid-git-boolean'."
(defun magit-git-config-p (variable &optional default)
"Return the boolean value of the Git variable VARIABLE.
VARIABLE has to be specified as a string. Return DEFAULT (which
defaults to nil) if VARIABLE is unset. If VARIABLE's value isn't
a boolean, then raise an error."
VARIABLE has to be specified as a string. If VARIABLE is unset,
return nil by default, unless DEFAULT is non-nil, in which case
return t. Signal an error if VARIABLE is set but not a boolean."
(let ((args (list "config" "--bool" "--default" (if default "true" "false")
variable)))
(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)))))
(cond ((not magit-git-debug))
(errmsg (message "%s" errmsg))
(errmsg (message "magit--git-insert: %S" errmsg))
((zerop exit))
((message "Git returned with exit-code %s" exit))))
(or errmsg exit))
((message "magit--git-insert: %s %s"
"Git returned with exit-code" exit))))
(or (and return-error errmsg)
exit))
(ignore-errors (delete-file log))))
(magit-process-git (list t nil) args)))
@@ -591,16 +578,18 @@ insert the run command and stderr into the process buffer."
(match-str 1)))
(defun magit-git-string (&rest args)
"Execute Git with ARGS, returning the first line of its output.
If there is no output, return nil. If the output begins with a
newline, return an empty string."
"Execute Git with ARGS, returning the first line of its output (stdout).
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."
(setq args (flatten-tree args))
(magit--with-refresh-cache (cons default-directory args)
(magit--with-temp-process-buffer
(apply #'magit-git-insert args)
(unless (bobp)
(and (zerop (apply #'magit-git-insert args))
(not (bobp))
(progn
(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)
"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-corrupt-git-config "Corrupt Git configuration")
(define-error 'magit-git-executable-not-found
(concat "Git executable cannot be found "
"(see https://magit.vc/goto/e6a78ed2)"))
(define-error 'magit-git-executable-not-found "Git executable cannot be found")
(defun magit--assert-usable-git ()
(if (not (executable-find (magit-git-executable) t))
@@ -1121,7 +1108,7 @@ tracked file."
(file-relative-name file dir))))
(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)))
(defun magit-file-tracked-p (file)
@@ -1145,6 +1132,16 @@ issue."
(and (not all) "--exclude-standard")
"--" 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)
"Return a list of untracked files.
@@ -1258,13 +1255,12 @@ or if no rename is detected."
(y (char-after (1+ pos)))
(file (buffer-substring (+ pos 3) (point))))
(forward-char)
(if (memq x '(?R ?C))
(progn
(cond ((memq x '(?R ?C))
(setq pos (point))
(skip-chars-forward "[:print:]")
(push (list file (buffer-substring pos (point)) x y) status)
(forward-char))
(push (list file nil x y) status)))
((push (list file nil x y) status))))
(setq pos (point)))
status)))
@@ -1279,11 +1275,10 @@ or if no rename is detected."
"Failed to parse Cygwin mount: %S" mount)))
;; If --exec-path is not a native Windows path,
;; then we probably have a cygwin git.
(and (not (string-match-p
"\\`[a-zA-Z]:"
(car (magit--early-process-lines
magit-git-executable "--exec-path"))))
(magit--early-process-lines "mount")))
(and-let ((dirs (magit--early-process-lines
magit-git-executable "--exec-path")))
(and (not (string-match-p "\\`[a-zA-Z]:" (car dirs)))
(magit--early-process-lines "mount"))))
#'> :key (pcase-lambda (`(,cyg . ,_win)) (length cyg))))
"Alist of (CYGWIN . WIN32) directory names.
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)
(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
(defun magit-no-commit-p ()
@@ -1441,21 +1466,29 @@ string \"true\", otherwise return nil."
(equal (magit-git-str "rev-parse" args) "true"))
(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)
"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)))
(defalias 'magit-rev-verify-commit #'magit-commit-p)
(defalias 'magit-rev-hash #'magit-commit-p)
(defun magit-commit-oid (rev &optional noerror)
"Return commit oid for REV if it can be dereferences as a commit.
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)
"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)
((string-match-p "^:/" rev) rev)
((string-prefix-p ":/" rev) rev)
((concat rev "^{commit}"))))
(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)
"Return t if A and B refer to the same commit."
(let ((a (magit-commit-p a))
(b (magit-commit-p b)))
(and a b (equal a b))))
(and-let ((a (magit-commit-oid a t))
(b (magit-commit-oid b t)))
(equal a b)))
(defun magit-rev-ancestor-p (a b)
"Return non-nil if commit A is an ancestor of commit B."
(magit-git-success "merge-base" "--is-ancestor" a b))
(defun magit-rev-head-p (rev)
"Return t if REV can be dereferences as the `HEAD' commit."
(or (equal rev "HEAD")
(and rev
(not (string-search ".." rev))
(equal (magit-rev-parse rev)
(magit-rev-parse "HEAD")))))
(magit-rev-eq rev "HEAD")))
(defun magit-rev-author-p (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,
as are two symbolic-refs pointing to the same ref. Refnames
may be abbreviated."
(let ((a (magit-ref-fullname a))
(and-let ((a (magit-ref-fullname a))
(b (magit-ref-fullname b)))
(and a b (equal a b))))
(equal a b)))
(defun magit-ref-eq (a b)
"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))))
(oref chunk orig-rev))
(and magit-buffer-file-name
magit-buffer-refname)
magit-buffer-revision)
(and (derived-mode-p 'magit-stash-mode
'magit-merge-preview-mode
'magit-revision-mode)
@@ -1874,7 +1905,8 @@ according to the branch type."
(defun magit-get-push-branch (&optional branch verify)
(magit--with-refresh-cache
(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))
(target (concat remote "/" branch)))
(and (or (not verify)
@@ -1882,11 +1914,9 @@ according to the branch type."
(magit--propertize-face target 'magit-branch-remote)))))
(defun magit-get-@{push}-branch (&optional branch)
(let ((ref (magit-rev-parse "--symbolic-full-name"
(concat branch "@{push}"))))
(and ref
(string-prefix-p "refs/remotes/" ref)
(substring ref 13))))
(and-let* ((branch (magit-ref-abbrev (or branch (magit-get-current-branch))))
(target (magit-ref-fullname (concat branch "@{push}"))))
(magit-ref-abbrev target)))
(defun magit-get-remote (&optional branch)
(and (or branch (setq branch (magit-get-current-branch)))
@@ -2232,11 +2262,11 @@ specified using `core.worktree'."
(let* ((default-directory (car worktree))
(wt (and (not (magit-get-boolean "core.bare"))
(magit-get "core.worktree"))))
(if (and wt (file-exists-p (expand-file-name wt)))
(progn (setf (nth 0 worktree) (expand-file-name wt))
(cond ((and wt (file-exists-p (expand-file-name wt)))
(setf (nth 0 worktree) (expand-file-name wt))
(setf (nth 2 worktree) (magit-rev-parse "HEAD"))
(setf (nth 3 worktree) (magit-get-current-branch)))
(setf (nth 3 worktree) t))))
((setf (nth 3 worktree) t)))))
((string-equal line "detached")
(setf (nth 4 worktree) t))
((string-prefix-p line "locked")
@@ -2271,8 +2301,8 @@ specified using `core.worktree'."
'magit-branch-local
'magit-branch-remote)))
(defun magit-tag-p (rev)
(car (member rev (magit-list-tags))))
(defun magit-tag-p (obj)
(equal (magit-object-type obj) "tag"))
(defun magit-remote-p (string)
(car (member string (magit-list-remotes))))
@@ -2342,10 +2372,10 @@ If `first-parent' is set, traverse only first parents."
(defun magit-rev-abbrev (rev)
(magit-rev-parse (magit-abbrev-arg "short") rev))
(defun magit--abbrev-if-hash (rev)
(cond ((or (magit-ref-p rev) (member rev '("{index}" "{worktree}"))) rev)
((magit-rev-parse (magit-abbrev-arg "short") rev))
(rev)))
(defun magit--abbrev-if-oid (obj)
(cond ((or (magit-ref-p obj) (member obj '("{index}" "{worktree}"))) obj)
((magit-rev-parse (magit-abbrev-arg "short") obj))
(obj)))
(defun magit-commit-children (rev &optional args)
(seq-keep (lambda (line)
@@ -2568,8 +2598,8 @@ and this option only controls what face is used.")
(beg (or beg "HEAD"))
(end (or end "HEAD")))
(when abbrev
(setq beg (magit--abbrev-if-hash beg))
(setq end (magit--abbrev-if-hash end)))
(setq beg (magit--abbrev-if-oid beg))
(setq end (magit--abbrev-if-oid end)))
(pcase sep
(".." (cons 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)))))
(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)
(magit-bind-match-strings (beg sep end) range
(and (or beg end)
(let ((beg-hash (and beg (magit-rev-hash beg)))
(end-hash (and end (magit-rev-hash end))))
(and (or (not beg) beg-hash)
(or (not end) end-hash)
(concat beg-hash sep end-hash)))))
(magit-rev-hash range)))
(let ((beg-oid (and beg (magit-commit-oid beg)))
(end-oid (and end (magit-commit-oid end))))
(and (or (not beg) beg-oid)
(or (not end) end-oid)
(concat beg-oid sep end-oid)))))
(magit-commit-oid range)))
(defvar magit-revision-faces
'(magit-hash
@@ -2645,7 +2678,7 @@ and this option only controls what face is used.")
(and (not (equal string "@"))
(or (and (>= (length string) 7)
(string-match-p "[a-z]" string)
(magit-commit-p string))
(magit-commit-oid string t))
(and (magit-ref-p string)
(member (get-text-property (point) 'face)
magit-revision-faces)))
@@ -2729,10 +2762,11 @@ and this option only controls what face is used.")
(lambda ()
(magit--minibuf-default-add-commit)
(setq-local crm-separator "\\.\\.\\.?"))
(let ((crm-prompt "%p"))
(magit-completing-read-multiple
(concat prompt ": ")
(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
(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))
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
(prompt &optional exclude secondary-default)
(let* ((current (magit-get-current-branch))
@@ -2993,6 +3044,21 @@ out. Only existing branches can be selected."
(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)
;; Local Variables:
;; read-symbol-shorthands: (
@@ -3000,6 +3066,7 @@ out. Only existing branches can be selected."
;; ("and>" . "cond-let--and>")
;; ("and-let" . "cond-let--and-let")
;; ("if-let" . "cond-let--if-let")
;; ("when$" . "cond-let--when$")
;; ("when-let" . "cond-let--when-let")
;; ("while-let" . "cond-let--while-let")
;; ("match-string" . "match-string")
+71 -59
View File
@@ -1,6 +1,6 @@
;;; 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>
;; Maintainer: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
@@ -35,16 +35,10 @@
"Instruct Git to ignore a file or pattern."
:man-page "gitignore"
["Gitignore"
("t" "shared at toplevel (.gitignore)"
magit-gitignore-in-topdir)
("s" "shared in subdirectory (path/to/.gitignore)"
magit-gitignore-in-subdir)
("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")))]
("t" magit-gitignore-in-topdir)
("s" magit-gitignore-in-subdir)
("p" magit-gitignore-in-gitdir)
("g" magit-gitignore-on-system)]
["Skip worktree"
(7 "w" "do skip worktree" magit-skip-worktree)
(7 "W" "do not skip worktree" magit-no-skip-worktree)]
@@ -54,51 +48,56 @@
;;; Gitignore Commands
;;;###autoload
(defun magit-gitignore-in-topdir (rule)
;;;###autoload(autoload 'magit-gitignore-in-topdir "magit-gitignore" nil t)
(transient-define-suffix magit-gitignore-in-topdir (rule)
"Add the Git ignore RULE to the top-level \".gitignore\" file.
Since this file is tracked, it is shared with other clones of the
repository. Also stage the file."
:description "shared at toplevel (.gitignore)"
(interactive (list (magit-gitignore-read-pattern)))
(magit-with-toplevel
(magit--gitignore rule ".gitignore")
(magit-run-git "add" ".gitignore")))
(magit--gitignore rule (expand-file-name ".gitignore" (magit-toplevel)) t))
;;;###autoload
(defun magit-gitignore-in-subdir (rule directory)
;;;###autoload(autoload 'magit-gitignore-in-subdir "magit-gitignore" nil t)
(transient-define-suffix magit-gitignore-in-subdir (rule directory)
"Add the Git ignore RULE to a \".gitignore\" file in DIRECTORY.
Prompt the user for a directory and add the rule to the
\".gitignore\" file in that directory. Since such files are
tracked, they are shared with other clones of the repository.
Also stage the file."
(interactive (list (magit-gitignore-read-pattern)
(read-directory-name "Limit rule to files in: ")))
(magit-with-toplevel
(let ((file (expand-file-name ".gitignore" directory)))
(magit--gitignore rule file)
(magit-run-git "add" (magit-convert-filename-for-git file)))))
:description "shared in subdirectory (path/to/.gitignore)"
(interactive (let ((dir (expand-file-name
(read-directory-name
"Limit rule to files in: "
(and$ (magit-current-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
(defun magit-gitignore-in-gitdir (rule)
;;;###autoload(autoload 'magit-gitignore-in-gitdir "magit-gitignore" nil t)
(transient-define-suffix magit-gitignore-in-gitdir (rule)
"Add the Git ignore RULE to \"$GIT_DIR/info/exclude\".
Rules in that file only affects this clone of the repository."
:description "privately (.git/info/exclude)"
(interactive (list (magit-gitignore-read-pattern)))
(magit--gitignore rule (expand-file-name "info/exclude" (magit-gitdir)))
(magit-refresh))
(magit--gitignore rule (expand-file-name "info/exclude" (magit-gitdir))))
;;;###autoload
(defun magit-gitignore-on-system (rule)
;;;###autoload(autoload 'magit-gitignore-on-system "magit-gitignore" nil t)
(transient-define-suffix magit-gitignore-on-system (rule)
"Add the Git ignore RULE to the file specified by `core.excludesFile'.
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)))
(magit--gitignore rule
(or (magit-get "core.excludesFile")
(if-let ((file (magit-get "core.excludesFile")))
(magit--gitignore rule file)
(error "Variable `core.excludesFile' isn't set")))
(magit-refresh))
(defun magit--gitignore (rule file)
(when-let ((directory (file-name-directory file)))
(make-directory directory t))
(defun magit--gitignore (rule file &optional stage)
(when$ (file-name-directory file)
(make-directory $ t))
(with-temp-buffer
(when (file-exists-p file)
(insert-file-contents file))
@@ -107,31 +106,21 @@ Rules that are defined in that file affect all local repositories."
(insert "\n"))
(insert (replace-regexp-in-string "\\(\\\\*\\)" "\\1\\1" rule))
(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 ()
(let* ((default (magit-current-file))
(base (car magit-buffer-diff-files))
(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)))))
(defun magit-gitignore-read-pattern (&optional directory)
(let ((choices (magit--gitignore-patterns directory))
(default (magit-current-file)))
(when default
(when directory
(setq default
(substring default
(length
(file-relative-name directory (magit-toplevel))))))
(setq default (concat "/" default))
(unless (member default choices)
(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"
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
;;;###autoload
@@ -198,6 +209,7 @@ Rules that are defined in that file affect all local repositories."
;; ("and>" . "cond-let--and>")
;; ("and-let" . "cond-let--and-let")
;; ("if-let" . "cond-let--if-let")
;; ("when$" . "cond-let--when$")
;; ("when-let" . "cond-let--when-let")
;; ("while-let" . "cond-let--while-let")
;; ("match-string" . "match-string")
+33 -22
View File
@@ -1,6 +1,6 @@
;;; 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>
;; Maintainer: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
@@ -374,6 +374,12 @@ commits before and half after."
:group 'magit-log
: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
;;;; Prefix Classes
@@ -779,7 +785,7 @@ restrict the log to the lines that the region touches."
(require 'magit)
(if-let ((file (magit-file-relative-name)))
(magit-log-setup-buffer
(list (or magit-buffer-refname
(list (or magit-buffer-revision
(magit-get-current-branch)
"HEAD"))
(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"))
(or (funcall magit-log-trace-definition-function)
(user-error "No function at point found"))
(or magit-buffer-refname
(or magit-buffer-revision
(magit-get-current-branch)
"HEAD")))
(require 'magit)
@@ -872,7 +878,7 @@ https://github.com/mhagger/git-when-merged."
(to (if (<= to 0)
branch
(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"
commit)))
(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)
(with-current-buffer
(magit-setup-buffer #'magit-log-mode locked
(magit-buffer-revisions revs)
(magit-buffer-log-revisions revs)
(magit-buffer-log-args args)
(magit-buffer-log-files files))
(when (if focus
@@ -1141,7 +1147,7 @@ Type \\[magit-reset] to reset `HEAD' to the commit at point.
(current-buffer)))
(defun magit-log-refresh-buffer ()
(let ((revs magit-buffer-revisions)
(let ((revs magit-buffer-log-revisions)
(args magit-buffer-log-args)
(files magit-buffer-log-files)
(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)
(defun magit-log--maybe-drop-color-graph (args limit)
(if (member "--color" args)
(if (cond ((not (member "--graph" args)))
(cond ((not (member "--color" args))
(setq magit-log--color-graph nil))
((cond ((not (member "--graph" args)) t)
((not magit-log-color-graph-limit) nil)
((not limit)
(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)
(message "Dropping --color because -n is larger than %s"
'magit-log-color-graph-limit)))
(progn (setq args (remove "--color" args))
(setq magit-log--color-graph nil))
(setq magit-log--color-graph t))
(setq args (remove "--color" args))
(setq magit-log--color-graph nil))
((setq magit-log--color-graph t)))
args)
(cl-defmethod magit-buffer-value (&context (major-mode magit-log-mode))
(append magit-buffer-revisions
(if (and magit-buffer-revisions magit-buffer-log-files)
(append magit-buffer-log-revisions
(if (and magit-buffer-log-revisions magit-buffer-log-files)
(cons "--" 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)
(magit-setup-buffer #'magit-log-select-mode nil
(magit-buffer-revisions revs)
(magit-buffer-log-revisions revs)
(magit-buffer-log-args args)))
(defun magit-log-select-refresh-buffer ()
(setq magit-section-inhibit-markers t)
(setq magit-section-insert-in-reverse t)
(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-buffer-log-args
(magit-log-get-commit-limit)))))
(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-quit-function nil)
@@ -1881,11 +1887,14 @@ Type \\[magit-cherry-pick] to apply the commit at point.
(magit-hack-dir-local-variables)
(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)
(magit-setup-buffer #'magit-cherry-mode nil
(magit-buffer-refname head)
(magit-buffer-upstream upstream)
(magit-buffer-range (concat upstream ".." head))))
(magit-buffer-cherry-upstream upstream)
(magit-buffer-cherry-range (concat upstream ".." head))))
(defun magit-cherry-refresh-buffer ()
(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)))
(cl-defmethod magit-buffer-value (&context (major-mode magit-cherry-mode))
magit-buffer-range)
magit-buffer-cherry-range)
;;;###autoload
(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."
(let ((branch (propertize magit-buffer-refname
'font-lock-face 'magit-branch-local))
(upstream (propertize magit-buffer-upstream 'font-lock-face
(if (magit-local-branch-p magit-buffer-upstream)
(upstream (propertize
magit-buffer-cherry-upstream 'font-lock-face
(if (magit-local-branch-p magit-buffer-cherry-upstream)
'magit-branch-local
'magit-branch-remote))))
(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-git-wash (apply-partially #'magit-log-wash-log 'cherry)
"cherry" "-v" "--abbrev"
magit-buffer-upstream
magit-buffer-cherry-upstream
magit-buffer-refname)))
;;; Log Sections
@@ -2114,6 +2124,7 @@ all others with \"-\"."
;; ("and>" . "cond-let--and>")
;; ("and-let" . "cond-let--and-let")
;; ("if-let" . "cond-let--if-let")
;; ("when$" . "cond-let--when$")
;; ("when-let" . "cond-let--when-let")
;; ("while-let" . "cond-let--while-let")
;; ("match-string" . "match-string")
+2 -1
View File
@@ -1,6 +1,6 @@
;;; 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>
;; Maintainer: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
@@ -263,6 +263,7 @@ English.")
;; ("and>" . "cond-let--and>")
;; ("and-let" . "cond-let--and-let")
;; ("if-let" . "cond-let--if-let")
;; ("when$" . "cond-let--when$")
;; ("when-let" . "cond-let--when-let")
;; ("while-let" . "cond-let--while-let")
;; ("match-string" . "match-string")
+18 -9
View File
@@ -1,6 +1,6 @@
;;; 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>
;; 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.
To create an octopus-merge, separate branches with commas.
\(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)
current-prefix-arg))
(magit-merge-assert)
@@ -105,24 +107,30 @@ merge.
;;;###autoload
(defun magit-merge-editmsg (rev &optional args)
"Merge commit REV into the current branch; and edit message.
Perform the merge and prepare a commit message but let the user
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-assert)
(cl-pushnew "--no-ff" args :test #'equal)
(apply #'magit-run-git-with-editor "merge" "--edit"
(append (delete "--ff-only" args)
(list rev))))
(magit-run-git-with-editor "merge" "--edit" (delete "--ff-only" args) rev))
;;;###autoload
(defun magit-merge-nocommit (rev &optional args)
"Merge commit REV into the current branch; pretending it failed.
Pretend the merge failed to give the user the opportunity to
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-assert)
(cl-pushnew "--no-ff" args :test #'equal)
@@ -317,6 +325,7 @@ If no merge is in progress, do nothing."
;; ("and>" . "cond-let--and>")
;; ("and-let" . "cond-let--and-let")
;; ("if-let" . "cond-let--if-let")
;; ("when$" . "cond-let--when$")
;; ("when-let" . "cond-let--when-let")
;; ("while-let" . "cond-let--while-let")
;; ("match-string" . "match-string")
+56 -31
View File
@@ -1,6 +1,6 @@
;;; 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>
;; Maintainer: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
@@ -51,6 +51,8 @@
(declare-function magit-wip-get-ref "magit-wip" ())
(declare-function magit-wip-commit-worktree "magit-wip" (ref files msg))
(declare-function magit--blob-cache-zap "magit-files" ())
;;; Options
(defcustom magit-mode-hook nil
@@ -578,35 +580,41 @@ Magit is documented in info node `(magit)'."
;;; Local Variables
(defvar-local magit-buffer-arguments nil)
(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)
(defvaralias 'magit-buffer-refname 'magit-buffer-revision)
(defvar-local magit-buffer-revision nil)
(defvar-local magit-buffer-revision-hash nil)
(defvar-local magit-buffer-revisions nil)
(defvar-local magit-buffer-typearg nil)
(defvar-local magit-buffer-upstream nil)
(defvar-local magit-buffer-revision-oid nil)
(defvar-local magit-buffer-blob-oid nil)
(defvar-local magit-buffer-file-name nil)
;; These variables are also used 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)
;; Preserve when major-mode is changed in file-visiting buffers.
(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
;; function does not reinstate this.
(put 'magit-buffer-diff-files-suspended 'permanent-local t)
(eval-and-compile
(defvar magit-define-aliases-for:magit-buffer-* 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 ()
"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 ()
"Return `magit-buffer-revision' or if that is nil \"{worktree}\".
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."
(or magit-buffer-revision
(and buffer-file-name
@@ -1179,7 +1188,21 @@ The arguments are for internal use."
;; for the wrong buffer. Originally reported in #4196 and
;; fixed with 482c25a3204468a4f6c2fe12ff061666b61f5f4d.
(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)
"Wrapper around `magit-refresh-buffer' suitable as `revert-buffer-function'."
@@ -1539,13 +1562,14 @@ repositories."
"Zap caches for the current repository.
Remove the repository's entry from `magit-repository-local-cache',
remove the host's entry from `magit--host-git-version-cache', and
set `magit-section-visibility-cache' to nil for all Magit buffers
of the repository.
remove the host's entry from `magit--host-git-version-cache', set
`magit-section-visibility-cache' to nil for all Magit buffers of
the repository, and empty the `magit--blob-cache'.
With a prefix argument or if optional ALL is non-nil, discard the
mentioned caches completely."
(interactive)
(magit--blob-cache-zap)
(cond (all
(setq magit-repository-local-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 ()
"Return the bounds of the region as line numbers.
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."
(and (magit-buffer-file-name)
(region-active-p)
@@ -1615,6 +1639,7 @@ line. Avoid including the line after the end of the file."
;; ("and>" . "cond-let--and>")
;; ("and-let" . "cond-let--and-let")
;; ("if-let" . "cond-let--if-let")
;; ("when$" . "cond-let--when$")
;; ("when-let" . "cond-let--when-let")
;; ("while-let" . "cond-let--while-let")
;; ("match-string" . "match-string")
+2 -1
View File
@@ -1,6 +1,6 @@
;;; 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>
;; Maintainer: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
@@ -204,6 +204,7 @@ Also see `magit-notes-merge'."
;; ("and>" . "cond-let--and>")
;; ("and-let" . "cond-let--and-let")
;; ("if-let" . "cond-let--if-let")
;; ("when$" . "cond-let--when$")
;; ("when-let" . "cond-let--when-let")
;; ("while-let" . "cond-let--while-let")
;; ("match-string" . "match-string")

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