diff options
Diffstat (limited to 'lisp')
93 files changed, 2179 insertions, 1866 deletions
diff --git a/lisp/calc/calc-embed.el b/lisp/calc/calc-embed.el index ea79bfa69a0..fda0b4bbedb 100644 --- a/lisp/calc/calc-embed.el +++ b/lisp/calc/calc-embed.el @@ -651,6 +651,8 @@ The command \\[yank] can retrieve it from there." (defvar calc-embed-prev-modes) (defun calc-embedded-set-modes (gmodes modes local-modes &optional temp) + (defvar the-language) + (defvar the-display-just) (let ((the-language (calc-embedded-language)) (the-display-just (calc-embedded-justify)) (v gmodes) diff --git a/lisp/calc/calc-lang.el b/lisp/calc/calc-lang.el index b4b2d4cc4f4..0117f449dd5 100644 --- a/lisp/calc/calc-lang.el +++ b/lisp/calc/calc-lang.el @@ -2181,7 +2181,7 @@ order to Calc's." v math-read-big-baseline)) ;; Small radical sign. - ((and (= other-char ?V) + ((and (memq other-char '(?V ?√)) (= (math-read-big-char (1+ math-rb-h1) (1- v)) ?\_)) (setq h (1+ math-rb-h1)) (math-read-big-emptyp math-rb-h1 math-rb-v1 h (1- v) nil t) diff --git a/lisp/calc/calc.el b/lisp/calc/calc.el index d684c7ba97f..ec09abb34c4 100644 --- a/lisp/calc/calc.el +++ b/lisp/calc/calc.el @@ -2144,7 +2144,7 @@ the United States." (let ((w (split-window nil (/ (* (window-width) 2) 3) t))) (set-window-buffer w calc-trail-buffer) (and calc-make-windows-dedicated - (set-window-dedicated-p nil t)))) + (set-window-dedicated-p w t)))) (calc-wrapper (setq overlay-arrow-string calc-trail-overlay overlay-arrow-position calc-trail-pointer) diff --git a/lisp/calc/calccomp.el b/lisp/calc/calccomp.el index 07e70cad0a8..bd81d7fe406 100644 --- a/lisp/calc/calccomp.el +++ b/lisp/calc/calccomp.el @@ -138,19 +138,19 @@ (math-format-number (nth 2 aa)))))) (if (= calc-number-radix 10) c - (list 'horiz "(" c - (list 'subscr ")" - (int-to-string calc-number-radix))))) + (list 'subscr (math--comp-round-bracket c) + (int-to-string calc-number-radix)))) (math-format-number a))) (if (not (eq calc-language 'big)) (math-format-number a prec) (if (memq (car-safe a) '(cplx polar)) (if (math-zerop (nth 2 a)) (math-compose-expr (nth 1 a) prec) - (list 'horiz "(" - (math-compose-expr (nth 1 a) 0) - (if (eq (car a) 'cplx) ", " "; ") - (math-compose-expr (nth 2 a) 0) ")")) + (math--comp-round-bracket + (list 'horiz + (math-compose-expr (nth 1 a) 0) + (if (eq (car a) 'cplx) ", " "; ") + (math-compose-expr (nth 2 a) 0)))) (if (or (= calc-number-radix 10) (not (Math-realp a)) (and calc-group-digits @@ -340,12 +340,13 @@ (funcall spfn a prec) (math-compose-var a))))) ((eq (car a) 'intv) - (list 'horiz - (if (memq (nth 1 a) '(0 1)) "(" "[") - (math-compose-expr (nth 2 a) 0) - " .. " - (math-compose-expr (nth 3 a) 0) - (if (memq (nth 1 a) '(0 2)) ")" "]"))) + (math--comp-bracket + (if (memq (nth 1 a) '(0 1)) ?\( ?\[) + (if (memq (nth 1 a) '(0 2)) ?\) ?\]) + (list 'horiz + (math-compose-expr (nth 2 a) 0) + " .. " + (math-compose-expr (nth 3 a) 0)))) ((eq (car a) 'date) (if (eq (car calc-date-format) 'X) (math-format-date a) @@ -377,7 +378,7 @@ (and (eq (car-safe (nth 1 a)) 'cplx) (math-negp (nth 1 (nth 1 a))) (eq (nth 2 (nth 1 a)) 0))) - (list 'horiz "(" (math-compose-expr (nth 1 a) 0) ")") + (math--comp-round-bracket (math-compose-expr (nth 1 a) 0)) (math-compose-expr (nth 1 a) 201)) (let ((calc-language 'flat) (calc-number-radix 10) @@ -444,7 +445,7 @@ (if (> prec (nth 2 a)) (if (setq spfn (get calc-language 'math-big-parens)) (list 'horiz (car spfn) c (cdr spfn)) - (list 'horiz "(" c ")")) + (math--comp-round-bracket c)) c))) ((and (eq (car a) 'calcFunc-choriz) (not (eq calc-language 'unform)) @@ -612,7 +613,7 @@ (list 'horiz "{left ( " (math-compose-expr a -1) " right )}"))) - (list 'horiz "(" (math-compose-expr a 0) ")")))) + (math--comp-round-bracket (math-compose-expr a 0))))) ((and (memq calc-language '(tex latex)) (memq (car a) '(/ calcFunc-choose calcFunc-evalto)) (>= prec 0)) @@ -638,7 +639,7 @@ (rhs (math-compose-expr (nth 2 a) (nth 3 op) (eq (nth 1 op) '/)))) (and (equal (car op) "^") (eq (math-comp-first-char lhs) ?-) - (setq lhs (list 'horiz "(" lhs ")"))) + (setq lhs (math--comp-round-bracket lhs))) (and (memq calc-language '(tex latex)) (or (equal (car op) "^") (equal (car op) "_")) (not (and (stringp rhs) (= (length rhs) 1))) @@ -721,7 +722,7 @@ (list 'horiz "{left ( " (math-compose-expr a -1) " right )}"))) - (list 'horiz "(" (math-compose-expr a 0) ")")))) + (math--comp-round-bracket (math-compose-expr a 0))))) (t (let ((lhs (math-compose-expr (nth 1 a) (nth 2 op)))) (list 'horiz @@ -759,7 +760,7 @@ (list 'horiz "{left ( " (math-compose-expr a -1) " right )}"))) - (list 'horiz "(" (math-compose-expr a 0) ")")))) + (math--comp-round-bracket (math-compose-expr a 0))))) (t (let ((rhs (math-compose-expr (nth 1 a) (nth 3 op)))) (list 'horiz @@ -821,9 +822,16 @@ (if (setq spfn (get calc-language 'math-func-formatter)) (funcall spfn func a) - (list 'horiz func calc-function-open - (math-compose-vector (cdr a) ", " 0) - calc-function-close)))))))))) + (let ((args (math-compose-vector (cdr a) ", " 0))) + (if (and (member calc-function-open '("(" "[" "{")) + (member calc-function-close '(")" "]" "}"))) + (list 'horiz func + (math--comp-bracket + (string-to-char calc-function-open) + (string-to-char calc-function-close) + args)) + (list 'horiz func calc-function-open + args calc-function-close)))))))))))) (defun math-prod-first-term (x) @@ -966,6 +974,69 @@ (and (memq (car a) '(^ calcFunc-subscr)) (math-tex-expr-is-flat (nth 1 a))))) +;; FIXME: maybe try box drawing chars if big bracket chars are unavailable, +;; like ┌ ┐n +;; │a + b│ ┌ a + b ┐n +;; │-----│ or │ ----- │ ? +;; │ c │ └ c ┘ +;; └ ┘ +;; They are more common than the chars below, but look a bit square. +;; Rounded corners exist but are less commonly available. + +(defconst math--big-bracket-alist + '((?\( . (?⎛ ?⎝ ?⎜)) + (?\) . (?⎞ ?⎠ ?⎟)) + (?\[ . (?⎡ ?⎣ ?⎢)) + (?\] . (?⎤ ?⎦ ?⎥)) + (?\{ . (?⎧ ?⎩ ?⎪ ?⎨)) + (?\} . (?⎫ ?⎭ ?⎪ ?⎬))) + "Alist mapping bracket chars to (UPPER LOWER EXTENSION MIDPIECE). +Not all brackets have midpieces.") + +(defun math--big-bracket (bracket-char height baseline) + "Composition for BRACKET-CHAR of HEIGHT with BASELINE." + (if (<= height 1) + (char-to-string bracket-char) + (let ((pieces (cdr (assq bracket-char math--big-bracket-alist)))) + (if (memq nil (mapcar #'char-displayable-p pieces)) + (char-to-string bracket-char) + (let* ((upper (nth 0 pieces)) + (lower (nth 1 pieces)) + (extension (nth 2 pieces)) + (midpiece (nth 3 pieces))) + (cons 'vleft ; alignment doesn't matter; width is 1 char + (cons baseline + (mapcar + #'char-to-string + (append + (list upper) + (if midpiece + (let ((lower-ext (/ (- height 3) 2))) + (append + (make-list (- height 3 lower-ext) extension) + (list midpiece) + (make-list lower-ext extension))) + (make-list (- height 2) extension)) + (list lower)))))))))) + +(defun math--comp-bracket (left-bracket right-bracket comp) + "Put the composition COMP inside LEFT-BRACKET and RIGHT-BRACKET." + (if (eq calc-language 'big) + (let ((height (math-comp-height comp)) + (baseline (1- (math-comp-ascent comp)))) + (list 'horiz + (math--big-bracket left-bracket height baseline) + comp + (math--big-bracket right-bracket height baseline))) + (list 'horiz + (char-to-string left-bracket) + comp + (char-to-string right-bracket)))) + +(defun math--comp-round-bracket (comp) + "Put the composition COMP inside plain brackets." + (math--comp-bracket ?\( ?\) comp)) + (put 'calcFunc-log 'math-compose-big #'math-compose-log) (defun math-compose-log (a _prec) (and (= (length a) 3) @@ -973,18 +1044,14 @@ (list 'subscr "log" (let ((calc-language 'flat)) (math-compose-expr (nth 2 a) 1000))) - "(" - (math-compose-expr (nth 1 a) 1000) - ")"))) + (math--comp-round-bracket (math-compose-expr (nth 1 a) 1000))))) (put 'calcFunc-log10 'math-compose-big #'math-compose-log10) (defun math-compose-log10 (a _prec) (and (= (length a) 2) (list 'horiz - (list 'subscr "log" "10") - "(" - (math-compose-expr (nth 1 a) 1000) - ")"))) + (list 'subscr "log" "10") + (math--comp-round-bracket (math-compose-expr (nth 1 a) 1000))))) (put 'calcFunc-deriv 'math-compose-big #'math-compose-deriv) (put 'calcFunc-tderiv 'math-compose-big #'math-compose-deriv) @@ -1027,12 +1094,9 @@ (defun math-compose-choose (a _prec) (let ((a1 (math-compose-expr (nth 1 a) 0)) (a2 (math-compose-expr (nth 2 a) 0))) - (list 'horiz - "(" - (list 'vcent - (math-comp-height a1) - a1 " " a2) - ")"))) + (math--comp-round-bracket (list 'vcent + (+ (math-comp-height a1)) + a1 " " a2)))) (put 'calcFunc-integ 'math-compose-big #'math-compose-integ) (defun math-compose-integ (a prec) @@ -1052,9 +1116,12 @@ "d%s" (nth 1 (nth 2 a))))) (nth 1 a)) 185)) - (calc-language 'flat) - (low (and (nth 3 a) (math-compose-expr (nth 3 a) 0))) - (high (and (nth 4 a) (math-compose-expr (nth 4 a) 0))) + (low (and (nth 3 a) + (let ((calc-language 'flat)) + (math-compose-expr (nth 3 a) 0)))) + (high (and (nth 4 a) + (let ((calc-language 'flat)) + (math-compose-expr (nth 4 a) 0)))) ;; Check if we have Unicode integral top/bottom parts. (fancy (and (char-displayable-p ?⌠) (char-displayable-p ?⌡))) @@ -1066,40 +1133,47 @@ ((char-displayable-p ?│) "│ ") ;; U+007C VERTICAL LINE (t "| ")))) - (list 'horiz - (if parens "(" "") - (append (list 'vcent (if fancy - (if high 2 1) - (if high 3 2))) - (and high (list (if fancy - (list 'horiz high " ") - (list 'horiz " " high)))) - (if fancy - (list "⌠ " fancy-stem "⌡ ") - '(" /" - " | " - " | " - " | " - "/ ")) - (and low (list (if fancy - (list 'horiz low " ") - (list 'horiz low " "))))) - expr - (if over - "" - (list 'horiz " d" var)) - (if parens ")" ""))))) + (let ((comp + (list 'horiz + (append (list 'vcent (if fancy + (if high 2 1) + (if high 3 2))) + (and high (list (if fancy + (list 'horiz high " ") + (list 'horiz " " high)))) + (if fancy + (list "⌠ " fancy-stem "⌡ ") + '(" /" + " | " + " | " + " | " + "/ ")) + (and low (list (if fancy + (list 'horiz low " ") + (list 'horiz low " "))))) + expr + (if over + "" + (list 'horiz " d" var))))) + (if parens + (math--comp-round-bracket comp) + comp))))) (put 'calcFunc-sum 'math-compose-big #'math-compose-sum) (defun math-compose-sum (a prec) (and (memq (length a) '(3 5 6)) (let* ((expr (math-compose-expr (nth 1 a) 185)) - (calc-language 'flat) - (var (math-compose-expr (nth 2 a) 0)) - (low (and (nth 3 a) (math-compose-expr (nth 3 a) 0))) - (high (and (nth 4 a) (math-compose-vector (nthcdr 4 a) ", " 0)))) - (list 'horiz - (if (memq prec '(180 201)) "(" "") + (var + (let ((calc-language 'flat)) + (math-compose-expr (nth 2 a) 0))) + (low (and (nth 3 a) + (let ((calc-language 'flat)) + (math-compose-expr (nth 3 a) 0)))) + (high (and (nth 4 a) + (let ((calc-language 'flat)) + (math-compose-vector (nthcdr 4 a) ", " 0)))) + (comp + (list 'horiz (append (list 'vcent (if high 3 2)) (and high (list high)) '("---- " @@ -1112,32 +1186,42 @@ (list var))) (if (memq (car-safe (nth 1 a)) '(calcFunc-sum calcFunc-prod)) " " "") - expr - (if (memq prec '(180 201)) ")" ""))))) + expr))) + (if (memq prec '(180 201)) + (math--comp-round-bracket comp) + comp)))) (put 'calcFunc-prod 'math-compose-big #'math-compose-prod) (defun math-compose-prod (a prec) (and (memq (length a) '(3 5 6)) (let* ((expr (math-compose-expr (nth 1 a) 198)) - (calc-language 'flat) - (var (math-compose-expr (nth 2 a) 0)) - (low (and (nth 3 a) (math-compose-expr (nth 3 a) 0))) - (high (and (nth 4 a) (math-compose-vector (nthcdr 4 a) ", " 0)))) - (list 'horiz - (if (memq prec '(196 201)) "(" "") - (append (list 'vcent (if high 3 2)) - (and high (list high)) - '("----- " - " | | " - " | | " - " | | ") - (if low - (list (list 'horiz var " = " low)) - (list var))) - (if (memq (car-safe (nth 1 a)) '(calcFunc-sum calcFunc-prod)) - " " "") - expr - (if (memq prec '(196 201)) ")" ""))))) + (var + (let ((calc-language 'flat)) + (math-compose-expr (nth 2 a) 0))) + (low (and (nth 3 a) + (let ((calc-language 'flat)) + (math-compose-expr (nth 3 a) 0)))) + (high (and (nth 4 a) + (let ((calc-language 'flat)) + (math-compose-vector (nthcdr 4 a) ", " 0)))) + (comp + (list 'horiz + (append (list 'vcent (if high 3 2)) + (and high (list high)) + '("----- " + " | | " + " | | " + " | | ") + (if low + (list (list 'horiz var " = " low)) + (list var))) + (if (memq (car-safe (nth 1 a)) + '(calcFunc-sum calcFunc-prod)) + " " "") + expr))) + (if (memq prec '(196 201)) + (math--comp-round-bracket comp) + comp)))) ;; The variables math-svo-c, math-svo-wid and math-svo-off are local ;; to math-stack-value-offset in calc.el, but are used by diff --git a/lisp/calendar/cal-bahai.el b/lisp/calendar/cal-bahai.el index 22e4cdbcd52..c2e4205c0bc 100644 --- a/lisp/calendar/cal-bahai.el +++ b/lisp/calendar/cal-bahai.el @@ -1,4 +1,4 @@ -;;; cal-bahai.el --- calendar functions for the Bahá’í calendar. +;;; cal-bahai.el --- calendar functions for the Bahá’í calendar. -*- lexical-binding: t; -*- ;; Copyright (C) 2001-2021 Free Software Foundation, Inc. @@ -124,9 +124,10 @@ Defaults to today's date if DATE is not given." (y (calendar-extract-year bahai-date))) (if (< y 1) "" ; pre-Bahai - (let* ((m (calendar-extract-month bahai-date)) - (d (calendar-extract-day bahai-date)) - (monthname (if (and (= m 19) + (let ((m (calendar-extract-month bahai-date)) + (d (calendar-extract-day bahai-date))) + (calendar-dlet* + ((monthname (if (and (= m 19) (<= d 0)) "Ayyám-i-Há" (aref calendar-bahai-month-name-array (1- m)))) @@ -137,8 +138,8 @@ Defaults to today's date if DATE is not given." (year (number-to-string y)) (month (number-to-string m)) dayname) - ;; Can't call calendar-date-string because of monthname oddity. - (mapconcat 'eval calendar-date-display-form ""))))) + ;; Can't call calendar-date-string because of monthname oddity. + (mapconcat #'eval calendar-date-display-form "")))))) ;;;###cal-autoload (defun calendar-bahai-print-date () @@ -153,13 +154,12 @@ Defaults to today's date if DATE is not given." "Interactively read the arguments for a Bahá’í date command. Reads a year, month and day." (let* ((today (calendar-current-date)) - (year (calendar-read - "Bahá’í calendar year (not 0): " + (year (calendar-read-sexp + "Bahá’í calendar year (not 0)" (lambda (x) (not (zerop x))) - (number-to-string - (calendar-extract-year - (calendar-bahai-from-absolute - (calendar-absolute-from-gregorian today)))))) + (calendar-extract-year + (calendar-bahai-from-absolute + (calendar-absolute-from-gregorian today))))) (completion-ignore-case t) (month (cdr (assoc (completing-read @@ -169,8 +169,8 @@ Reads a year, month and day." nil t) (calendar-make-alist calendar-bahai-month-name-array 1)))) - (day (calendar-read "Bahá’í calendar day (1-19): " - (lambda (x) (and (< 0 x) (<= x 19)))))) + (day (calendar-read-sexp "Bahá’í calendar day (1-19)" + (lambda (x) (and (< 0 x) (<= x 19)))))) (list (list month day year)))) ;;;###cal-autoload diff --git a/lisp/calendar/cal-china.el b/lisp/calendar/cal-china.el index 7e5d0c46e11..9a28984a7ab 100644 --- a/lisp/calendar/cal-china.el +++ b/lisp/calendar/cal-china.el @@ -1,4 +1,4 @@ -;;; cal-china.el --- calendar functions for the Chinese calendar +;;; cal-china.el --- calendar functions for the Chinese calendar -*- lexical-binding: t; -*- ;; Copyright (C) 1995, 1997, 2001-2021 Free Software Foundation, Inc. @@ -185,7 +185,9 @@ N congruent to 1 gives the first name, N congruent to 2 gives the second name, (defun calendar-chinese-zodiac-sign-on-or-after (d) "Absolute date of first new Zodiac sign on or after absolute date D. The Zodiac signs begin when the sun's longitude is a multiple of 30 degrees." - (let* ((year (calendar-extract-year (calendar-gregorian-from-absolute d))) + (with-suppressed-warnings ((lexical year)) + (defvar year)) + (let* ((year (calendar-extract-year (calendar-gregorian-from-absolute d))) (calendar-time-zone (eval calendar-chinese-time-zone)) ; uses year (calendar-daylight-time-offset calendar-chinese-daylight-time-offset) @@ -207,6 +209,8 @@ The Zodiac signs begin when the sun's longitude is a multiple of 30 degrees." (defun calendar-chinese-new-moon-on-or-after (d) "Absolute date of first new moon on or after absolute date D." + (with-suppressed-warnings ((lexical year)) + (defvar year)) (let* ((year (calendar-extract-year (calendar-gregorian-from-absolute d))) (calendar-time-zone (eval calendar-chinese-time-zone)) (calendar-daylight-time-offset @@ -602,14 +606,14 @@ Echo Chinese date unless NOECHO is non-nil." (interactive (let* ((c (calendar-chinese-from-absolute (calendar-absolute-from-gregorian (calendar-current-date)))) - (cycle (calendar-read - "Chinese calendar cycle number (>44): " + (cycle (calendar-read-sexp + "Chinese calendar cycle number (>44)" (lambda (x) (> x 44)) - (number-to-string (car c)))) - (year (calendar-read - "Year in Chinese cycle (1..60): " + (car c))) + (year (calendar-read-sexp + "Year in Chinese cycle (1..60)" (lambda (x) (and (<= 1 x) (<= x 60))) - (number-to-string (cadr c)))) + (cadr c))) (month-list (calendar-chinese-months-to-alist (calendar-chinese-months cycle year))) (month (cdr (assoc @@ -624,9 +628,11 @@ Echo Chinese date unless NOECHO is non-nil." (list cycle year month 1)))))) 30 29)) - (day (calendar-read - (format "Chinese calendar day (1-%d): " last) - (lambda (x) (and (<= 1 x) (<= x last)))))) + (day (calendar-read-sexp + "Chinese calendar day (1-%d)" + (lambda (x) (and (<= 1 x) (<= x last))) + nil + last))) (list (list cycle year month day)))) (calendar-goto-date (calendar-gregorian-from-absolute (calendar-chinese-to-absolute date))) @@ -663,17 +669,17 @@ Echo Chinese date unless NOECHO is non-nil." ["正月" "二月" "三月" "四月" "五月" "六月" "七月" "八月" "九月" "十月" "冬月" "臘月"]) -;;; NOTE: In the diary the cycle and year of a Chinese date is -;;; combined using this formula: (+ (* cycle 100) year). +;; NOTE: In the diary the cycle and year of a Chinese date is +;; combined using this formula: (+ (* cycle 100) year). ;;; -;;; These two functions convert to and back from this representation. -(defun calendar-chinese-from-absolute-for-diary (date) - (pcase-let ((`(,c ,y ,m ,d) (calendar-chinese-from-absolute date))) +;; These two functions convert to and back from this representation. +(defun calendar-chinese-from-absolute-for-diary (thedate) + (pcase-let ((`(,c ,y ,m ,d) (calendar-chinese-from-absolute thedate))) ;; Note: For leap months M is a float. (list (floor m) d (+ (* c 100) y)))) -(defun calendar-chinese-to-absolute-for-diary (date &optional prefer-leap) - (pcase-let* ((`(,m ,d ,y) date) +(defun calendar-chinese-to-absolute-for-diary (thedate &optional prefer-leap) + (pcase-let* ((`(,m ,d ,y) thedate) (cycle (floor y 100)) (year (mod y 100)) (months (calendar-chinese-months cycle year)) @@ -691,7 +697,8 @@ Echo Chinese date unless NOECHO is non-nil." (unless (zerop month) (calendar-mark-1 month day year #'calendar-chinese-from-absolute-for-diary - (lambda (date) (calendar-chinese-to-absolute-for-diary date t)) + (lambda (thedate) + (calendar-chinese-to-absolute-for-diary thedate t)) color))) ;;;###cal-autoload diff --git a/lisp/calendar/cal-coptic.el b/lisp/calendar/cal-coptic.el index 3461f3259b9..346585e1817 100644 --- a/lisp/calendar/cal-coptic.el +++ b/lisp/calendar/cal-coptic.el @@ -1,4 +1,4 @@ -;;; cal-coptic.el --- calendar functions for the Coptic/Ethiopic calendars +;;; cal-coptic.el --- calendar functions for the Coptic/Ethiopic calendars -*- lexical-binding: t; -*- ;; Copyright (C) 1995, 1997, 2001-2021 Free Software Foundation, Inc. @@ -116,12 +116,13 @@ Defaults to today's date if DATE is not given." (m (calendar-extract-month coptic-date))) (if (< y 1) "" - (let ((monthname (aref calendar-coptic-month-name-array (1- m))) - (day (number-to-string (calendar-extract-day coptic-date))) - (dayname nil) - (month (number-to-string m)) - (year (number-to-string y))) - (mapconcat 'eval calendar-date-display-form ""))))) + (calendar-dlet* + ((monthname (aref calendar-coptic-month-name-array (1- m))) + (day (number-to-string (calendar-extract-day coptic-date))) + (dayname nil) + (month (number-to-string m)) + (year (number-to-string y))) + (mapconcat #'eval calendar-date-display-form ""))))) ;;;###cal-autoload (defun calendar-coptic-print-date () @@ -136,13 +137,13 @@ Defaults to today's date if DATE is not given." "Interactively read the arguments for a Coptic date command. Reads a year, month, and day." (let* ((today (calendar-current-date)) - (year (calendar-read - (format "%s calendar year (>0): " calendar-coptic-name) + (year (calendar-read-sexp + "%s calendar year (>0)" (lambda (x) (> x 0)) - (number-to-string - (calendar-extract-year - (calendar-coptic-from-absolute - (calendar-absolute-from-gregorian today)))))) + (calendar-extract-year + (calendar-coptic-from-absolute + (calendar-absolute-from-gregorian today))) + calendar-coptic-name)) (completion-ignore-case t) (month (cdr (assoc-string (completing-read @@ -151,11 +152,14 @@ Reads a year, month, and day." (append calendar-coptic-month-name-array nil)) nil t) (calendar-make-alist calendar-coptic-month-name-array - 1) t))) + 1) + t))) (last (calendar-coptic-last-day-of-month month year)) - (day (calendar-read - (format "%s calendar day (1-%d): " calendar-coptic-name last) - (lambda (x) (and (< 0 x) (<= x last)))))) + (day (calendar-read-sexp + "%s calendar day (1-%d)" + (lambda (x) (and (< 0 x) (<= x last))) + nil + calendar-coptic-name last))) (list (list month day year)))) ;;;###cal-autoload @@ -194,30 +198,30 @@ Echo Coptic date unless NOECHO is t." (defconst calendar-ethiopic-name "Ethiopic" "Used in some message strings.") -(defun calendar-ethiopic-to-absolute (date) +(defun calendar-ethiopic-to-absolute (thedate) "Compute absolute date from Ethiopic date DATE. The absolute date is the number of days elapsed since the (imaginary) Gregorian date Sunday, December 31, 1 BC." (let ((calendar-coptic-epoch calendar-ethiopic-epoch)) - (calendar-coptic-to-absolute date))) + (calendar-coptic-to-absolute thedate))) -(defun calendar-ethiopic-from-absolute (date) +(defun calendar-ethiopic-from-absolute (thedate) "Compute the Ethiopic equivalent for absolute date DATE. The result is a list of the form (MONTH DAY YEAR). The absolute date is the number of days elapsed since the imaginary Gregorian date Sunday, December 31, 1 BC." (let ((calendar-coptic-epoch calendar-ethiopic-epoch)) - (calendar-coptic-from-absolute date))) + (calendar-coptic-from-absolute thedate))) ;;;###cal-autoload -(defun calendar-ethiopic-date-string (&optional date) +(defun calendar-ethiopic-date-string (&optional thedate) "String of Ethiopic date of Gregorian DATE. Returns the empty string if DATE is pre-Ethiopic calendar. Defaults to today's date if DATE is not given." (let ((calendar-coptic-epoch calendar-ethiopic-epoch) (calendar-coptic-name calendar-ethiopic-name) (calendar-coptic-month-name-array calendar-ethiopic-month-name-array)) - (calendar-coptic-date-string date))) + (calendar-coptic-date-string thedate))) ;;;###cal-autoload (defun calendar-ethiopic-print-date () @@ -229,8 +233,8 @@ Defaults to today's date if DATE is not given." (call-interactively 'calendar-coptic-print-date))) ;;;###cal-autoload -(defun calendar-ethiopic-goto-date (date &optional noecho) - "Move cursor to Ethiopic date DATE. +(defun calendar-ethiopic-goto-date (thedate &optional noecho) + "Move cursor to Ethiopic date THEDATE. Echo Ethiopic date unless NOECHO is t." (interactive (let ((calendar-coptic-epoch calendar-ethiopic-epoch) @@ -238,7 +242,7 @@ Echo Ethiopic date unless NOECHO is t." (calendar-coptic-month-name-array calendar-ethiopic-month-name-array)) (calendar-coptic-read-date))) (calendar-goto-date (calendar-gregorian-from-absolute - (calendar-ethiopic-to-absolute date))) + (calendar-ethiopic-to-absolute thedate))) (or noecho (calendar-ethiopic-print-date))) ;; To be called from diary-list-sexp-entries, where DATE is bound. diff --git a/lisp/calendar/cal-french.el b/lisp/calendar/cal-french.el index e759b5dad95..639bae700cc 100644 --- a/lisp/calendar/cal-french.el +++ b/lisp/calendar/cal-french.el @@ -1,4 +1,4 @@ -;;; cal-french.el --- calendar functions for the French Revolutionary calendar +;;; cal-french.el --- calendar functions for the French Revolutionary calendar -*- lexical-binding: t; -*- ;; Copyright (C) 1988-1989, 1992, 1994-1995, 1997, 2001-2021 Free ;; Software Foundation, Inc. @@ -35,54 +35,45 @@ (defconst calendar-french-epoch (calendar-absolute-from-gregorian '(9 22 1792)) "Absolute date of start of French Revolutionary calendar = Sept 22, 1792.") -(defconst calendar-french-month-name-array - ["Vende'miaire" "Brumaire" "Frimaire" "Nivo^se" "Pluvio^se" "Vento^se" - "Germinal" "Flore'al" "Prairial" "Messidor" "Thermidor" "Fructidor"] - "Array of month names in the French calendar.") +(define-obsolete-variable-alias 'calendar-french-multibyte-month-name-array + 'calendar-french-month-name-array "28.1") -(defconst calendar-french-multibyte-month-name-array +(defconst calendar-french-month-name-array ["Vendémiaire" "Brumaire" "Frimaire" "Nivôse" "Pluviôse" "Ventôse" "Germinal" "Floréal" "Prairial" "Messidor" "Thermidor" "Fructidor"] - "Array of multibyte month names in the French calendar.") + "Array of month names in the French calendar.") (defconst calendar-french-day-name-array ["Primidi" "Duodi" "Tridi" "Quartidi" "Quintidi" "Sextidi" "Septidi" "Octidi" "Nonidi" "Decadi"] "Array of day names in the French calendar.") -(defconst calendar-french-special-days-array - ["de la Vertu" "du Ge'nie" "du Travail" "de la Raison" "des Re'compenses" - "de la Re'volution"] - "Array of special day names in the French calendar.") +(define-obsolete-variable-alias 'calendar-french-multibyte-special-days-array + 'calendar-french-special-days-array "28.1") -(defconst calendar-french-multibyte-special-days-array +(defconst calendar-french-special-days-array ["de la Vertu" "du Génie" "du Travail" "de la Raison" "des Récompenses" "de la Révolution"] - "Array of multibyte special day names in the French calendar.") + "Array of special day names in the French calendar.") (defun calendar-french-accents-p () - "Return non-nil if diacritical marks are available." - (and (or window-system - (terminal-coding-system)) - (or enable-multibyte-characters - (and (char-table-p standard-display-table) - (equal (aref standard-display-table 161) [161]))))) + (declare (obsolete nil "28.1")) + t) (defun calendar-french-month-name-array () "Return the array of month names, depending on whether accents are available." - (if (calendar-french-accents-p) - calendar-french-multibyte-month-name-array - calendar-french-month-name-array)) + (declare (obsolete "use the variable of the same name instead" "28.1")) + calendar-french-month-name-array) (defun calendar-french-day-name-array () "Return the array of day names." + (declare (obsolete "use the variable of the same name instead" "28.1")) calendar-french-day-name-array) (defun calendar-french-special-days-array () "Return the special day names, depending on whether accents are available." - (if (calendar-french-accents-p) - calendar-french-multibyte-special-days-array - calendar-french-special-days-array)) + (declare (obsolete "use the variable of the same name instead" "28.1")) + calendar-french-special-days-array) (defun calendar-french-leap-year-p (year) "True if YEAR is a leap year on the French Revolutionary calendar. @@ -171,17 +162,13 @@ Defaults to today's date if DATE is not given." (d (calendar-extract-day french-date))) (cond ((< y 1) "") - ((= m 13) (format (if (calendar-french-accents-p) - "Jour %s de l'Année %d de la Révolution" - "Jour %s de l'Anne'e %d de la Re'volution") - (aref (calendar-french-special-days-array) (1- d)) + ((= m 13) (format "Jour %s de l'Année %d de la Révolution" + (aref calendar-french-special-days-array (1- d)) y)) (t (format - (if (calendar-french-accents-p) - "%d %s an %d de la Révolution" - "%d %s an %d de la Re'volution") + "%d %s an %d de la Révolution" d - (aref (calendar-french-month-name-array) (1- m)) + (aref calendar-french-month-name-array (1- m)) y))))) ;;;###cal-autoload @@ -198,19 +185,16 @@ Defaults to today's date if DATE is not given." "Move cursor to French Revolutionary date DATE. Echo French Revolutionary date unless NOECHO is non-nil." (interactive - (let* ((months (calendar-french-month-name-array)) - (special-days (calendar-french-special-days-array)) + (let* ((months calendar-french-month-name-array) + (special-days calendar-french-special-days-array) (year (progn - (calendar-read - (if (calendar-french-accents-p) - "Année de la Révolution (>0): " - "Anne'e de la Re'volution (>0): ") + (calendar-read-sexp + "Année de la Révolution (>0)" (lambda (x) (> x 0)) - (number-to-string - (calendar-extract-year - (calendar-french-from-absolute - (calendar-absolute-from-gregorian - (calendar-current-date)))))))) + (calendar-extract-year + (calendar-french-from-absolute + (calendar-absolute-from-gregorian + (calendar-current-date))))))) (month-list (mapcar 'list (append months @@ -234,8 +218,8 @@ Echo French Revolutionary date unless NOECHO is non-nil." (calendar-make-alist month-list 1 'car) t))) (day (if (> month 12) (- month 12) - (calendar-read - "Jour (1-30): " + (calendar-read-sexp + "Jour (1-30)" (lambda (x) (and (<= 1 x) (<= x 30)))))) (month (if (> month 12) 13 month))) (list (list month day year)))) diff --git a/lisp/calendar/cal-hebrew.el b/lisp/calendar/cal-hebrew.el index bcc80f0877b..50b4fc363bb 100644 --- a/lisp/calendar/cal-hebrew.el +++ b/lisp/calendar/cal-hebrew.el @@ -1,4 +1,4 @@ -;;; cal-hebrew.el --- calendar functions for the Hebrew calendar +;;; cal-hebrew.el --- calendar functions for the Hebrew calendar -*- lexical-binding: t; -*- ;; Copyright (C) 1995, 1997, 2001-2021 Free Software Foundation, Inc. @@ -225,13 +225,12 @@ Driven by the variable `calendar-date-display-form'." "Interactively read the arguments for a Hebrew date command. Reads a year, month, and day." (let* ((today (calendar-current-date)) - (year (calendar-read - "Hebrew calendar year (>3760): " + (year (calendar-read-sexp + "Hebrew calendar year (>3760)" (lambda (x) (> x 3760)) - (number-to-string - (calendar-extract-year - (calendar-hebrew-from-absolute - (calendar-absolute-from-gregorian today)))))) + (calendar-extract-year + (calendar-hebrew-from-absolute + (calendar-absolute-from-gregorian today))))) (month-array (if (calendar-hebrew-leap-year-p year) calendar-hebrew-month-name-array-leap-year calendar-hebrew-month-name-array-common-year)) @@ -258,10 +257,11 @@ Reads a year, month, and day." (last (calendar-hebrew-last-day-of-month month year)) (first (if (and (= year 3761) (= month 10)) 18 1)) - (day (calendar-read - (format "Hebrew calendar day (%d-%d): " - first last) - (lambda (x) (and (<= first x) (<= x last)))))) + (day (calendar-read-sexp + "Hebrew calendar day (%d-%d)" + (lambda (x) (and (<= first x) (<= x last))) + nil + first last))) (list (list month day year)))) ;;;###cal-autoload @@ -399,19 +399,20 @@ is non-nil." (list m (calendar-last-day-of-month m y) y)))))) (abs-h (calendar-hebrew-to-absolute (list 9 25 h-y))) (ord ["first" "second" "third" "fourth" "fifth" "sixth" - "seventh" "eighth"]) - han) + "seventh" "eighth"])) (holiday-filter-visible-calendar (if (or all calendar-hebrew-all-holidays-flag) (append (list (list (calendar-gregorian-from-absolute (1- abs-h)) "Erev Hanukkah")) - (dotimes (i 8 (nreverse han)) - (push (list - (calendar-gregorian-from-absolute (+ abs-h i)) - (format "Hanukkah (%s day)" (aref ord i))) - han))) + (let (han) + (dotimes (i 8) + (push (list + (calendar-gregorian-from-absolute (+ abs-h i)) + (format "Hanukkah (%s day)" (aref ord i))) + han)) + (nreverse han))) (list (list (calendar-gregorian-from-absolute abs-h) "Hanukkah"))))))) ;;;###holiday-autoload @@ -681,10 +682,10 @@ from the cursor position." (if (equal (current-buffer) (get-buffer calendar-buffer)) (calendar-cursor-to-date t) (let* ((today (calendar-current-date)) - (year (calendar-read - "Year of death (>0): " + (year (calendar-read-sexp + "Year of death (>0)" (lambda (x) (> x 0)) - (number-to-string (calendar-extract-year today)))) + (calendar-extract-year today))) (month-array calendar-month-name-array) (completion-ignore-case t) (month (cdr (assoc-string @@ -694,20 +695,23 @@ from the cursor position." nil t) (calendar-make-alist month-array 1) t))) (last (calendar-last-day-of-month month year)) - (day (calendar-read - (format "Day of death (1-%d): " last) - (lambda (x) (and (< 0 x) (<= x last)))))) + (day (calendar-read-sexp + "Day of death (1-%d)" + (lambda (x) (and (< 0 x) (<= x last))) + nil + last))) (list month day year)))) (death-year (calendar-extract-year death-date)) - (start-year (calendar-read - (format "Starting year of Yahrzeit table (>%d): " - death-year) + (start-year (calendar-read-sexp + "Starting year of Yahrzeit table (>%d)" (lambda (x) (> x death-year)) - (number-to-string (1+ death-year)))) - (end-year (calendar-read - (format "Ending year of Yahrzeit table (>=%d): " - start-year) - (lambda (x) (>= x start-year))))) + (1+ death-year) + death-year)) + (end-year (calendar-read-sexp + "Ending year of Yahrzeit table (>=%d)" + (lambda (x) (>= x start-year)) + nil + start-year))) (list death-date start-year end-year))) (message "Computing Yahrzeits...") (let* ((h-date (calendar-hebrew-from-absolute diff --git a/lisp/calendar/cal-html.el b/lisp/calendar/cal-html.el index 3d7cc938437..e5810c3f027 100644 --- a/lisp/calendar/cal-html.el +++ b/lisp/calendar/cal-html.el @@ -1,4 +1,4 @@ -;;; cal-html.el --- functions for printing HTML calendars +;;; cal-html.el --- functions for printing HTML calendars -*- lexical-binding: t; -*- ;; Copyright (C) 2002-2021 Free Software Foundation, Inc. @@ -250,7 +250,7 @@ Contains links to previous and next month and year, and current minical." calendar-week-start-day)) 7)) (monthpage-name (cal-html-monthpage-name month year)) - date) + ) ;; date ;; Start writing table. (insert (cal-html-comment "MINICAL") (cal-html-b-table "class=minical border=1 align=center")) @@ -276,7 +276,7 @@ Contains links to previous and next month and year, and current minical." (insert cal-html-e-tablerow-string cal-html-b-tablerow-string))) ;; End empty slots (for some browsers like konqueror). - (dotimes (i end-blank-days) + (dotimes (_ end-blank-days) (insert cal-html-b-tabledata-string cal-html-e-tabledata-string))) @@ -431,12 +431,11 @@ holidays in HOLIDAY-LIST." ;;; User commands. ;;;###cal-autoload -(defun cal-html-cursor-month (month year dir &optional event) +(defun cal-html-cursor-month (month year dir &optional _event) "Write an HTML calendar file for numeric MONTH of four-digit YEAR. The output directory DIR is created if necessary. Interactively, -MONTH and YEAR are taken from the calendar cursor position, or from -the position specified by EVENT. Note that any existing output files -are overwritten." +MONTH and YEAR are taken from the calendar cursor position. +Note that any existing output files are overwritten." (interactive (let* ((event last-nonmenu-event) (date (calendar-cursor-to-date t event)) (month (calendar-extract-month date)) @@ -446,11 +445,11 @@ are overwritten." (cal-html-one-month month year dir)) ;;;###cal-autoload -(defun cal-html-cursor-year (year dir &optional event) +(defun cal-html-cursor-year (year dir &optional _event) "Write HTML calendar files (index and monthly pages) for four-digit YEAR. The output directory DIR is created if necessary. Interactively, -YEAR is taken from the calendar cursor position, or from the position -specified by EVENT. Note that any existing output files are overwritten." +YEAR is taken from the calendar cursor position. +Note that any existing output files are overwritten." (interactive (let* ((event last-nonmenu-event) (year (calendar-extract-year (calendar-cursor-to-date t event)))) diff --git a/lisp/calendar/cal-islam.el b/lisp/calendar/cal-islam.el index d256310ba6c..45c6ffa7bd7 100644 --- a/lisp/calendar/cal-islam.el +++ b/lisp/calendar/cal-islam.el @@ -1,4 +1,4 @@ -;;; cal-islam.el --- calendar functions for the Islamic calendar +;;; cal-islam.el --- calendar functions for the Islamic calendar -*- lexical-binding: t; -*- ;; Copyright (C) 1995, 1997, 2001-2021 Free Software Foundation, Inc. @@ -67,8 +67,8 @@ "Absolute date of Islamic DATE. The absolute date is the number of days elapsed since the (imaginary) Gregorian date Sunday, December 31, 1 BC." - (let* ((month (calendar-extract-month date)) - (day (calendar-extract-day date)) + (let* (;;(month (calendar-extract-month date)) + ;;(day (calendar-extract-day date)) (year (calendar-extract-year date)) (y (% year 30)) (leap-years-in-cycle (cond ((< y 3) 0) @@ -143,13 +143,12 @@ Driven by the variable `calendar-date-display-form'." "Interactively read the arguments for an Islamic date command. Reads a year, month, and day." (let* ((today (calendar-current-date)) - (year (calendar-read - "Islamic calendar year (>0): " + (year (calendar-read-sexp + "Islamic calendar year (>0)" (lambda (x) (> x 0)) - (number-to-string - (calendar-extract-year - (calendar-islamic-from-absolute - (calendar-absolute-from-gregorian today)))))) + (calendar-extract-year + (calendar-islamic-from-absolute + (calendar-absolute-from-gregorian today))))) (month-array calendar-islamic-month-name-array) (completion-ignore-case t) (month (cdr (assoc-string @@ -159,9 +158,11 @@ Reads a year, month, and day." nil t) (calendar-make-alist month-array 1) t))) (last (calendar-islamic-last-day-of-month month year)) - (day (calendar-read - (format "Islamic calendar day (1-%d): " last) - (lambda (x) (and (< 0 x) (<= x last)))))) + (day (calendar-read-sexp + "Islamic calendar day (1-%d)" + (lambda (x) (and (< 0 x) (<= x last))) + nil + last))) (list (list month day year)))) ;;;###cal-autoload diff --git a/lisp/calendar/cal-iso.el b/lisp/calendar/cal-iso.el index 956433e4a20..90f57c25e9d 100644 --- a/lisp/calendar/cal-iso.el +++ b/lisp/calendar/cal-iso.el @@ -1,4 +1,4 @@ -;;; cal-iso.el --- calendar functions for the ISO calendar +;;; cal-iso.el --- calendar functions for the ISO calendar -*- lexical-binding: t; -*- ;; Copyright (C) 1995, 1997, 2001-2021 Free Software Foundation, Inc. @@ -92,22 +92,23 @@ date Sunday, December 31, 1 BC." "Interactively read the arguments for an ISO date command. Reads a year and week, and if DAYFLAG is non-nil a day (otherwise taken to be 1)." - (let* ((year (calendar-read - "ISO calendar year (>0): " + (let* ((year (calendar-read-sexp + "ISO calendar year (>0)" (lambda (x) (> x 0)) - (number-to-string (calendar-extract-year - (calendar-current-date))))) + (calendar-extract-year (calendar-current-date)))) (no-weeks (calendar-extract-month (calendar-iso-from-absolute (1- (calendar-dayname-on-or-before 1 (calendar-absolute-from-gregorian (list 1 4 (1+ year)))))))) - (week (calendar-read - (format "ISO calendar week (1-%d): " no-weeks) - (lambda (x) (and (> x 0) (<= x no-weeks))))) - (day (if dayflag (calendar-read - "ISO day (1-7): " + (week (calendar-read-sexp + "ISO calendar week (1-%d)" + (lambda (x) (and (> x 0) (<= x no-weeks))) + nil + no-weeks)) + (day (if dayflag (calendar-read-sexp + "ISO day (1-7)" (lambda (x) (and (<= 1 x) (<= x 7)))) 1))) (list (list week day year)))) diff --git a/lisp/calendar/cal-julian.el b/lisp/calendar/cal-julian.el index 235b4d00900..47880a4e974 100644 --- a/lisp/calendar/cal-julian.el +++ b/lisp/calendar/cal-julian.el @@ -95,14 +95,13 @@ Driven by the variable `calendar-date-display-form'." "Move cursor to Julian DATE; echo Julian date unless NOECHO is non-nil." (interactive (let* ((today (calendar-current-date)) - (year (calendar-read - "Julian calendar year (>0): " + (year (calendar-read-sexp + "Julian calendar year (>0)" (lambda (x) (> x 0)) - (number-to-string - (calendar-extract-year - (calendar-julian-from-absolute - (calendar-absolute-from-gregorian - today)))))) + (calendar-extract-year + (calendar-julian-from-absolute + (calendar-absolute-from-gregorian + today))))) (month-array calendar-month-name-array) (completion-ignore-case t) (month (cdr (assoc-string @@ -115,12 +114,13 @@ Driven by the variable `calendar-date-display-form'." (if (and (zerop (% year 4)) (= month 2)) 29 (aref [31 28 31 30 31 30 31 31 30 31 30 31] (1- month)))) - (day (calendar-read - (format "Julian calendar day (%d-%d): " - (if (and (= year 1) (= month 1)) 3 1) last) + (day (calendar-read-sexp + "Julian calendar day (%d-%d)" (lambda (x) (and (< (if (and (= year 1) (= month 1)) 2 0) x) - (<= x last)))))) + (<= x last))) + nil + (if (and (= year 1) (= month 1)) 3 1) last))) (list (list month day year)))) (calendar-goto-date (calendar-gregorian-from-absolute (calendar-julian-to-absolute date))) @@ -173,8 +173,8 @@ Defaults to today's date if DATE is not given." (defun calendar-astro-goto-day-number (daynumber &optional noecho) "Move cursor to astronomical (Julian) DAYNUMBER. Echo astronomical (Julian) day number unless NOECHO is non-nil." - (interactive (list (calendar-read - "Astronomical (Julian) day number (>1721425): " + (interactive (list (calendar-read-sexp + "Astronomical (Julian) day number (>1721425)" (lambda (x) (> x 1721425))))) (calendar-goto-date (calendar-gregorian-from-absolute diff --git a/lisp/calendar/cal-mayan.el b/lisp/calendar/cal-mayan.el index 8d894ebd986..9a221921130 100644 --- a/lisp/calendar/cal-mayan.el +++ b/lisp/calendar/cal-mayan.el @@ -1,4 +1,4 @@ -;;; cal-mayan.el --- calendar functions for the Mayan calendars +;;; cal-mayan.el --- calendar functions for the Mayan calendars -*- lexical-binding: t; -*- ;; Copyright (C) 1992-1993, 1995, 1997, 2001-2021 Free Software ;; Foundation, Inc. @@ -135,8 +135,8 @@ but some use 1137140. Using 1232041 gives you Spinden's correlation; using (defun calendar-mayan-read-haab-date () "Prompt for a Mayan haab date." (let* ((completion-ignore-case t) - (haab-day (calendar-read - "Haab kin (0-19): " + (haab-day (calendar-read-sexp + "Haab kin (0-19)" (lambda (x) (and (>= x 0) (< x 20))))) (haab-month-list (append calendar-mayan-haab-month-name-array (and (< haab-day 5) '("Uayeb")))) @@ -151,8 +151,8 @@ but some use 1137140. Using 1232041 gives you Spinden's correlation; using (defun calendar-mayan-read-tzolkin-date () "Prompt for a Mayan tzolkin date." (let* ((completion-ignore-case t) - (tzolkin-count (calendar-read - "Tzolkin kin (1-13): " + (tzolkin-count (calendar-read-sexp + "Tzolkin kin (1-13)" (lambda (x) (and (> x 0) (< x 14))))) (tzolkin-name-list (append calendar-mayan-tzolkin-names-array nil)) (tzolkin-name (cdr diff --git a/lisp/calendar/cal-menu.el b/lisp/calendar/cal-menu.el index a30c681a897..497f3329055 100644 --- a/lisp/calendar/cal-menu.el +++ b/lisp/calendar/cal-menu.el @@ -1,4 +1,4 @@ -;;; cal-menu.el --- calendar functions for menu bar and popup menu support +;;; cal-menu.el --- calendar functions for menu bar and popup menu support -*- lexical-binding: t; -*- ;; Copyright (C) 1994-1995, 2001-2021 Free Software Foundation, Inc. @@ -183,6 +183,8 @@ Signals an error if popups are unavailable." ;; Autoloaded in diary-lib. (declare-function calendar-check-holidays "holidays" (date)) +(defvar diary-list-include-blanks) + (defun calendar-mouse-view-diary-entries (&optional date diary event) "Pop up menu of diary entries for mouse-selected date. Use optional DATE and alternative file DIARY. EVENT is the event diff --git a/lisp/calendar/cal-move.el b/lisp/calendar/cal-move.el index 710ce37ccbf..9294362cb43 100644 --- a/lisp/calendar/cal-move.el +++ b/lisp/calendar/cal-move.el @@ -1,4 +1,4 @@ -;;; cal-move.el --- calendar functions for movement in the calendar +;;; cal-move.el --- calendar functions for movement in the calendar -*- lexical-binding: t; -*- ;; Copyright (C) 1995, 2001-2021 Free Software Foundation, Inc. @@ -386,15 +386,16 @@ Moves forward if ARG is negative." "Move cursor to YEAR, DAY number; echo DAY/YEAR unless NOECHO is non-nil. Negative DAY counts backward from end of year." (interactive - (let* ((year (calendar-read - "Year (>0): " + (let* ((year (calendar-read-sexp + "Year (>0)" (lambda (x) (> x 0)) - (number-to-string (calendar-extract-year - (calendar-current-date))))) + (calendar-extract-year (calendar-current-date)))) (last (if (calendar-leap-year-p year) 366 365)) - (day (calendar-read - (format "Day number (+/- 1-%d): " last) - (lambda (x) (and (<= 1 (abs x)) (<= (abs x) last)))))) + (day (calendar-read-sexp + "Day number (+/- 1-%d)" + (lambda (x) (and (<= 1 (abs x)) (<= (abs x) last))) + nil + last))) (list year day))) (calendar-goto-date (calendar-gregorian-from-absolute diff --git a/lisp/calendar/cal-persia.el b/lisp/calendar/cal-persia.el index a9c99fedbdb..ca37d803224 100644 --- a/lisp/calendar/cal-persia.el +++ b/lisp/calendar/cal-persia.el @@ -1,4 +1,4 @@ -;;; cal-persia.el --- calendar functions for the Persian calendar +;;; cal-persia.el --- calendar functions for the Persian calendar -*- lexical-binding: t; -*- ;; Copyright (C) 1996-1997, 2001-2021 Free Software Foundation, Inc. @@ -139,13 +139,14 @@ Gregorian date Sunday, December 31, 1 BC." (calendar-absolute-from-gregorian (or date (calendar-current-date))))) (y (calendar-extract-year persian-date)) - (m (calendar-extract-month persian-date)) - (monthname (aref calendar-persian-month-name-array (1- m))) + (m (calendar-extract-month persian-date))) + (calendar-dlet* + ((monthname (aref calendar-persian-month-name-array (1- m))) (day (number-to-string (calendar-extract-day persian-date))) (year (number-to-string y)) (month (number-to-string m)) dayname) - (mapconcat 'eval calendar-date-display-form ""))) + (mapconcat #'eval calendar-date-display-form "")))) ;;;###cal-autoload (defun calendar-persian-print-date () @@ -157,14 +158,13 @@ Gregorian date Sunday, December 31, 1 BC." (defun calendar-persian-read-date () "Interactively read the arguments for a Persian date command. Reads a year, month, and day." - (let* ((year (calendar-read - "Persian calendar year (not 0): " + (let* ((year (calendar-read-sexp + "Persian calendar year (not 0)" (lambda (x) (not (zerop x))) - (number-to-string - (calendar-extract-year - (calendar-persian-from-absolute - (calendar-absolute-from-gregorian - (calendar-current-date))))))) + (calendar-extract-year + (calendar-persian-from-absolute + (calendar-absolute-from-gregorian + (calendar-current-date)))))) (completion-ignore-case t) (month (cdr (assoc (completing-read @@ -175,9 +175,11 @@ Reads a year, month, and day." (calendar-make-alist calendar-persian-month-name-array 1)))) (last (calendar-persian-last-day-of-month month year)) - (day (calendar-read - (format "Persian calendar day (1-%d): " last) - (lambda (x) (and (< 0 x) (<= x last)))))) + (day (calendar-read-sexp + "Persian calendar day (1-%d)" + (lambda (x) (and (< 0 x) (<= x last))) + nil + last))) (list (list month day year)))) ;;;###cal-autoload diff --git a/lisp/calendar/cal-tex.el b/lisp/calendar/cal-tex.el index 9df9f4cbedf..f5932014dd9 100644 --- a/lisp/calendar/cal-tex.el +++ b/lisp/calendar/cal-tex.el @@ -1,4 +1,4 @@ -;;; cal-tex.el --- calendar functions for printing calendars with LaTeX +;;; cal-tex.el --- calendar functions for printing calendars with LaTeX -*- lexical-binding: t; -*- ;; Copyright (C) 1995, 2001-2021 Free Software Foundation, Inc. @@ -248,6 +248,8 @@ This definition is the heart of the calendar!") (autoload 'diary-list-entries "diary-lib") +(defvar diary-list-include-blanks) + (defun cal-tex-list-diary-entries (d1 d2) "Generate a list of all diary-entries from absolute date D1 to D2." (let (diary-list-include-blanks) @@ -591,6 +593,8 @@ indicates a buffer position to use instead of point." LaTeX commands are inserted for the days of the MONTH in YEAR. Diary entries on DIARY-LIST are included. Holidays on HOLIDAYS are included. Each day is formatted using format DAY-FORMAT." + (with-suppressed-warnings ((lexical date)) + (defvar date)) ;For `cal-tex-daily-string'. (let ((blank-days ; at start of month (mod (- (calendar-day-of-week (list month 1 year)) @@ -605,7 +609,7 @@ are included. Each day is formatted using format DAY-FORMAT." (insert (format day-format (cal-tex-month-name month) j)) (cal-tex-arg (cal-tex-latexify-list diary-list date)) (cal-tex-arg (cal-tex-latexify-list holidays date)) - (cal-tex-arg (eval cal-tex-daily-string)) + (cal-tex-arg (eval cal-tex-daily-string t)) (cal-tex-arg) (cal-tex-comment)) (when (and (zerop (mod (+ j blank-days) 7)) @@ -885,13 +889,15 @@ argument EVENT specifies a different buffer position." (interactive (list (prefix-numeric-value current-prefix-arg) last-nonmenu-event)) (or n (setq n 1)) + (with-suppressed-warnings ((lexical date)) + (defvar date)) ;For `cal-tex-daily-string'. (let* ((date (calendar-gregorian-from-absolute (calendar-dayname-on-or-before 1 (calendar-absolute-from-gregorian (calendar-cursor-to-date t event))))) (month (calendar-extract-month date)) - (year (calendar-extract-year date)) + ;; (year (calendar-extract-year date)) (day (calendar-extract-day date)) (d1 (calendar-absolute-from-gregorian date)) (d2 (+ (* 7 n) d1)) @@ -932,7 +938,7 @@ argument EVENT specifies a different buffer position." (insert ": ") (cal-tex-large-bf s)) (cal-tex-hfill) - (insert " " (eval cal-tex-daily-string)) + (insert " " (eval cal-tex-daily-string t)) (cal-tex-e-parbox) (cal-tex-nl) (cal-tex-noindent) @@ -951,7 +957,8 @@ argument EVENT specifies a different buffer position." (cal-tex-e-parbox "2cm") (cal-tex-nl) (setq month (calendar-extract-month date) - year (calendar-extract-year date))) + ;; year (calendar-extract-year date) + )) (cal-tex-e-parbox) (unless (= i (1- n)) (run-hooks 'cal-tex-week-hook) @@ -961,13 +968,16 @@ argument EVENT specifies a different buffer position." ;; TODO respect cal-tex-daily-start,end? ;; Using different numbers of hours will probably break some layouts. -(defun cal-tex-week-hours (date holidays height) - "Insert hourly entries for DATE with HOLIDAYS, with line height HEIGHT. +(defun cal-tex-week-hours (thedate holidays height) + "Insert hourly entries for THEDATE with HOLIDAYS, with line height HEIGHT. Uses the 24-hour clock if `cal-tex-24' is non-nil. Note that the hours shown are hard-coded to 8-12, 13-17." - (let ((month (calendar-extract-month date)) + (with-suppressed-warnings ((lexical date)) + (defvar date)) ;For `cal-tex-daily-string'. + (let ((date thedate) + (month (calendar-extract-month date)) (day (calendar-extract-day date)) - (year (calendar-extract-year date)) + ;; (year (calendar-extract-year date)) morning afternoon s) (cal-tex-comment "begin cal-tex-week-hours") (cal-tex-cmd "\\ \\\\[-.2cm]") @@ -983,7 +993,7 @@ shown are hard-coded to 8-12, 13-17." (insert ": ") (cal-tex-large-bf s)) (cal-tex-hfill) - (insert " " (eval cal-tex-daily-string)) + (insert " " (eval cal-tex-daily-string t)) (cal-tex-e-parbox) (cal-tex-nl "-.3cm") (cal-tex-rule "0pt" "6.8in" ".2mm") @@ -1088,14 +1098,16 @@ shown are hard-coded to 8-12, 13-17." (defun cal-tex-weekly-common (n event &optional filofax) "Common code for weekly calendars." (or n (setq n 1)) + (with-suppressed-warnings ((lexical date)) + (defvar date)) ;For `cal-tex-daily-string'. (let* ((date (calendar-gregorian-from-absolute (calendar-dayname-on-or-before 1 (calendar-absolute-from-gregorian (calendar-cursor-to-date t event))))) - (month (calendar-extract-month date)) - (year (calendar-extract-year date)) - (day (calendar-extract-day date)) + ;; (month (calendar-extract-month date)) + ;; (year (calendar-extract-year date)) + ;; (day (calendar-extract-day date)) (d1 (calendar-absolute-from-gregorian date)) (d2 (+ (* 7 n) d1)) (holidays (if cal-tex-holidays @@ -1161,7 +1173,7 @@ shown are hard-coded to 8-12, 13-17." (cal-tex-arg (number-to-string (calendar-extract-day date))) (cal-tex-arg (cal-tex-latexify-list diary-list date)) (cal-tex-arg (cal-tex-latexify-list holidays date)) - (cal-tex-arg (eval cal-tex-daily-string)) + (cal-tex-arg (eval cal-tex-daily-string t)) (insert "%\n") (setq date (cal-tex-incr-date date))) (insert "\\noindent\\rule{\\textwidth}{0.3pt}\\\\%\n") @@ -1258,14 +1270,16 @@ Optional EVENT indicates a buffer position to use instead of point." (interactive (list (prefix-numeric-value current-prefix-arg) last-nonmenu-event)) (or n (setq n 1)) + (with-suppressed-warnings ((lexical date)) + (defvar date)) ;For `cal-tex-daily-string'. (let* ((date (calendar-gregorian-from-absolute (calendar-dayname-on-or-before calendar-week-start-day (calendar-absolute-from-gregorian (calendar-cursor-to-date t event))))) - (month (calendar-extract-month date)) - (year (calendar-extract-year date)) - (day (calendar-extract-day date)) + ;; (month (calendar-extract-month date)) + ;; (year (calendar-extract-year date)) + ;; (day (calendar-extract-day date)) (d1 (calendar-absolute-from-gregorian date)) (d2 (+ (* 7 n) d1)) (holidays (if cal-tex-holidays @@ -1311,7 +1325,7 @@ Optional EVENT indicates a buffer position to use instead of point." (cal-tex-arg (number-to-string (calendar-extract-day date))) (cal-tex-arg (cal-tex-latexify-list diary-list date)) (cal-tex-arg (cal-tex-latexify-list holidays date)) - (cal-tex-arg (eval cal-tex-daily-string)) + (cal-tex-arg (eval cal-tex-daily-string t)) (insert "%\n") (setq date (cal-tex-incr-date date))) (unless (= i (1- n)) @@ -1342,14 +1356,16 @@ Optional EVENT indicates a buffer position to use instead of point." (interactive (list (prefix-numeric-value current-prefix-arg) last-nonmenu-event)) (or n (setq n 1)) + (with-suppressed-warnings ((lexical date)) + (defvar date)) ;For `cal-tex-daily-string'. (let* ((date (calendar-gregorian-from-absolute (calendar-dayname-on-or-before 1 (calendar-absolute-from-gregorian (calendar-cursor-to-date t event))))) - (month (calendar-extract-month date)) - (year (calendar-extract-year date)) - (day (calendar-extract-day date)) + ;; (month (calendar-extract-month date)) + ;; (year (calendar-extract-year date)) + ;; (day (calendar-extract-day date)) (d1 (calendar-absolute-from-gregorian date)) (d2 (+ (* 7 n) d1)) (holidays (if cal-tex-holidays @@ -1383,11 +1399,11 @@ Optional EVENT indicates a buffer position to use instead of point." "\\leftday"))) (cal-tex-arg (cal-tex-latexify-list diary-list date)) (cal-tex-arg (cal-tex-latexify-list holidays date "\\\\" t)) - (cal-tex-arg (eval cal-tex-daily-string)) + (cal-tex-arg (eval cal-tex-daily-string t)) (insert "%\n") - (if cal-tex-rules - (insert "\\linesfill\n") - (insert "\\vfill\\noindent\\rule{\\textwidth}{0.3pt}\\\\%\n")) + (insert (if cal-tex-rules + "\\linesfill\n" + "\\vfill\\noindent\\rule{\\textwidth}{0.3pt}\\\\%\n")) (cal-tex-newpage) (setq date (cal-tex-incr-date date))) (insert "%\n") @@ -1397,11 +1413,11 @@ Optional EVENT indicates a buffer position to use instead of point." (insert "\\weekend") (cal-tex-arg (cal-tex-latexify-list diary-list date)) (cal-tex-arg (cal-tex-latexify-list holidays date "\\\\" t)) - (cal-tex-arg (eval cal-tex-daily-string)) + (cal-tex-arg (eval cal-tex-daily-string t)) (insert "%\n") - (if cal-tex-rules - (insert "\\linesfill\n") - (insert "\\vfill")) + (insert (if cal-tex-rules + "\\linesfill\n" + "\\vfill")) (setq date (cal-tex-incr-date date))) (or cal-tex-rules (insert "\\noindent\\rule{\\textwidth}{0.3pt}\\\\%\n")) @@ -1442,12 +1458,15 @@ a buffer position to use instead of point." (cal-tex-end-document) (run-hooks 'cal-tex-hook))) -(defun cal-tex-daily-page (date) - "Make a calendar page for Gregorian DATE on 8.5 by 11 paper. +(defun cal-tex-daily-page (thedate) + "Make a calendar page for Gregorian THEDATE on 8.5 by 11 paper. Uses the 24-hour clock if `cal-tex-24' is non-nil. Produces hourly sections for the period specified by `cal-tex-daily-start' and `cal-tex-daily-end'." - (let ((month-name (cal-tex-month-name (calendar-extract-month date))) + (with-suppressed-warnings ((lexical date)) + (defvar date)) ;For `cal-tex-daily-string'. + (let ((date thedate) + (month-name (cal-tex-month-name (calendar-extract-month date))) (i (1- cal-tex-daily-start)) hour) (cal-tex-banner "cal-tex-daily-page") @@ -1459,7 +1478,7 @@ and `cal-tex-daily-end'." (cal-tex-bf month-name ) (cal-tex-e-parbox) (cal-tex-hspace "1cm") - (cal-tex-scriptsize (eval cal-tex-daily-string)) + (cal-tex-scriptsize (eval cal-tex-daily-string t)) (cal-tex-hspace "3.5cm") (cal-tex-e-makebox) (cal-tex-hfill) diff --git a/lisp/calendar/cal-x.el b/lisp/calendar/cal-x.el index 1c19a60db10..ca303ce39ae 100644 --- a/lisp/calendar/cal-x.el +++ b/lisp/calendar/cal-x.el @@ -1,4 +1,4 @@ -;;; cal-x.el --- calendar windows in dedicated frames +;;; cal-x.el --- calendar windows in dedicated frames -*- lexical-binding: t; -*- ;; Copyright (C) 1994-1995, 2001-2021 Free Software Foundation, Inc. diff --git a/lisp/calendar/calendar.el b/lisp/calendar/calendar.el index 21cea212e18..3f9fe1c9d8f 100644 --- a/lisp/calendar/calendar.el +++ b/lisp/calendar/calendar.el @@ -112,6 +112,8 @@ ;;; Code: +(eval-when-compile (require 'subr-x)) + (load "cal-loaddefs" nil t) ;; Calendar has historically relied heavily on dynamic scoping. @@ -1459,7 +1461,7 @@ Optional integers MON and YR are used instead of today's date." Inserts STRING so that it ends at INDENT. STRING is either a literal string, or a sexp to evaluate to return such. Truncates STRING to length TRUNCATE, and ensures a trailing space." - (if (not (ignore-errors (stringp (setq string (eval string))))) + (if (not (ignore-errors (stringp (setq string (eval string t))))) (calendar-move-to-column indent) (if (> (string-width string) truncate) (setq string (truncate-string-to-width string truncate))) @@ -1526,7 +1528,7 @@ first INDENT characters on the line." (format (format "%%%dd" calendar-day-digit-width) day) 'mouse-face 'highlight 'help-echo (calendar-dlet* ((day day) (month month) (year year)) - (eval calendar-date-echo-text)) + (eval calendar-date-echo-text t)) ;; 'date property prevents intermonth text confusing re-searches. ;; (Tried intangible, it did not really work.) 'date t) @@ -2054,23 +2056,40 @@ With argument ARG, jump to mark, pop it, and put point at end of ring." (error "%s not available in the calendar" (global-key-binding (this-command-keys)))) +(defun calendar-read-sexp (prompt predicate &optional default &rest args) + "Return an object read from the minibuffer. +Passes PROMPT, DEFAULT, and ARGS to `format-prompt' to build +the actual prompt. PREDICATE is called with a single value (the object +the user entered) and it should return non-nil if that value is a valid choice. +DEFAULT is the default value to use." + (unless (stringp default) (setq default (format "%S" default))) + (named-let query () + ;; The call to `read-from-minibuffer' is copied from `read-minibuffer', + ;; except it's changed to use the DEFAULT arg instead of INITIAL-CONTENTS. + (let ((value (read-from-minibuffer + (apply #'format-prompt prompt default args) + nil minibuffer-local-map t 'minibuffer-history default))) + (if (funcall predicate value) + value + (query))))) + (defun calendar-read (prompt acceptable &optional initial-contents) "Return an object read from the minibuffer. Prompt with the string PROMPT and use the function ACCEPTABLE to decide if entered item is acceptable. If non-nil, optional third arg INITIAL-CONTENTS is a string to insert in the minibuffer before reading." + (declare (obsolete calendar-read-sexp "28.1")) (let ((value (read-minibuffer prompt initial-contents))) (while (not (funcall acceptable value)) (setq value (read-minibuffer prompt initial-contents))) value)) - (defun calendar-customized-p (symbol) "Return non-nil if SYMBOL has been customized." (and (default-boundp symbol) (let ((standard (get symbol 'standard-value))) (and standard - (not (equal (eval (car standard)) (default-value symbol))))))) + (not (equal (eval (car standard) t) (default-value symbol))))))) (defun calendar-abbrev-construct (full &optional maxlen) "From sequence FULL, return a vector of abbreviations. @@ -2284,32 +2303,38 @@ arguments SEQUENCES." (append (list sequence) sequences)) (reverse alist))) -(defun calendar-read-date (&optional noday) +(defun calendar-read-date (&optional noday default-date) "Prompt for Gregorian date. Return a list (month day year). If optional NODAY is t, does not ask for day, but just returns \(month 1 year); if NODAY is any other non-nil value the value returned is (month year)." - (let* ((year (calendar-read - "Year (>0): " - (lambda (x) (> x 0)) - (number-to-string (calendar-extract-year - (calendar-current-date))))) + (unless default-date (setq default-date (calendar-current-date))) + (let* ((defyear (calendar-extract-year default-date)) + (year (calendar-read-sexp "Year (>0)" + (lambda (x) (> x 0)) + defyear)) (month-array calendar-month-name-array) + (defmon (aref month-array (1- (calendar-extract-month default-date)))) (completion-ignore-case t) (month (cdr (assoc-string - (completing-read - "Month name: " - (mapcar #'list (append month-array nil)) - nil t) + (completing-read + (format-prompt "Month name" defmon) + (append month-array nil) + nil t nil nil defmon) (calendar-make-alist month-array 1) t))) + (defday (calendar-extract-day default-date)) (last (calendar-last-day-of-month month year))) (if noday (if (eq noday t) (list month 1 year) (list month year)) (list month - (calendar-read (format "Day (1-%d): " last) - (lambda (x) (and (< 0 x) (<= x last)))) + (calendar-read-sexp "Day (1-%d)" + (lambda (x) (and (< 0 x) (<= x last))) + ;; Don't offer today's day as default + ;; if it's not valid for the chosen + ;; month/year. + (if (<= defday last) defday) last) year)))) (defun calendar-interval (mon1 yr1 mon2 yr2) diff --git a/lisp/calendar/diary-lib.el b/lisp/calendar/diary-lib.el index aad70161f9f..4efa3669967 100644 --- a/lisp/calendar/diary-lib.el +++ b/lisp/calendar/diary-lib.el @@ -2221,8 +2221,8 @@ Prefix argument ARG makes the entry nonmarking." (diary-make-entry (format "%s(diary-cyclic %d %s)" diary-sexp-entry-symbol - (calendar-read "Repeat every how many days: " - (lambda (x) (> x 0))) + (calendar-read-sexp "Repeat every how many days" + (lambda (x) (> x 0))) (calendar-date-string (calendar-cursor-to-date t) nil t)) arg))) diff --git a/lisp/calendar/holidays.el b/lisp/calendar/holidays.el index 932993beba0..4bc17de3067 100644 --- a/lisp/calendar/holidays.el +++ b/lisp/calendar/holidays.el @@ -423,16 +423,15 @@ of a holiday list. The optional LABEL is used to label the buffer created." (interactive - (let* ((start-year (calendar-read - "Starting year of holidays (>0): " + (let* ((start-year (calendar-read-sexp + "Starting year of holidays (>0)" (lambda (x) (> x 0)) - (number-to-string (calendar-extract-year - (calendar-current-date))))) - (end-year (calendar-read - (format "Ending year (inclusive) of holidays (>=%s): " - start-year) + (calendar-extract-year (calendar-current-date)))) + (end-year (calendar-read-sexp + "Ending year (inclusive) of holidays (>=%s)" (lambda (x) (>= x start-year)) - (number-to-string start-year))) + start-year + start-year)) (completion-ignore-case t) (lists (list diff --git a/lisp/cedet/ede/base.el b/lisp/cedet/ede/base.el index 7799746e0c4..810d6ef3bd4 100644 --- a/lisp/cedet/ede/base.el +++ b/lisp/cedet/ede/base.el @@ -160,16 +160,13 @@ and querying them will cause the actual project to get loaded.") ;; Projects can also affect how EDE works, by changing what appears in ;; the EDE menu, or how some keys are bound. ;; -(unless (fboundp 'ede-target-list-p) - (cl-deftype ede-target-list () '(list-of ede-target))) - (defclass ede-project (ede-project-placeholder) ((subproj :initform nil :type list :documentation "Sub projects controlled by this project. For Automake based projects, each directory is treated as a project.") (targets :initarg :targets - :type ede-target-list + :type (list-of ede-target) :custom (repeat (object :objectcreatefcn ede-new-target-custom)) :label "Local Targets" :group (targets) diff --git a/lisp/cedet/ede/proj.el b/lisp/cedet/ede/proj.el index 59628ebf4c9..4af8b4104f5 100644 --- a/lisp/cedet/ede/proj.el +++ b/lisp/cedet/ede/proj.el @@ -184,7 +184,7 @@ Target variables are always renamed such as foo_CFLAGS, then included into commands where the variable would usually appear.") (rules :initarg :rules :initform nil - :type list + :type (list-of ede-makefile-rule) :custom (repeat (object :objecttype ede-makefile-rule)) :label "Additional Rules" :group (make) diff --git a/lisp/comint.el b/lisp/comint.el index 53153af7d27..e52d67d0e50 100644 --- a/lisp/comint.el +++ b/lisp/comint.el @@ -3863,7 +3863,11 @@ REGEXP-GROUP is the regular expression group in REGEXP to use." (push (buffer-substring-no-properties (match-beginning regexp-group) (match-end regexp-group)) - results)) + results) + (when (zerop (length (match-string 0))) + ;; If the regexp can be empty (for instance, "^.*$"), we + ;; don't advance, so ensure forward progress. + (forward-line 1))) (nreverse results)))) ;; Converting process modes to use comint mode diff --git a/lisp/cus-start.el b/lisp/cus-start.el index 0293d34d1cd..27fdb723441 100644 --- a/lisp/cus-start.el +++ b/lisp/cus-start.el @@ -880,7 +880,7 @@ since it could result in memory overflow and make Emacs crash." ;; Don't re-add to custom-delayed-init-variables post-startup. (unless after-init-time ;; Note this is the _only_ initialize property we handle. - (if (eq (cadr (memq :initialize rest)) 'custom-initialize-delay) + (if (eq (cadr (memq :initialize rest)) #'custom-initialize-delay) ;; These vars are defined early and should hence be initialized ;; early, even if this file happens to be loaded late. so add them ;; to the end of custom-delayed-init-variables. Otherwise, diff --git a/lisp/custom.el b/lisp/custom.el index 58ecd0439ad..5e354c4c595 100644 --- a/lisp/custom.el +++ b/lisp/custom.el @@ -125,17 +125,7 @@ This is used in files that are preloaded (or for autoloaded variables), so that the initialization is done in the run-time context rather than the build-time context. This also has the side-effect that the (delayed) initialization is performed with -the :set function. - -For variables in preloaded files, you can simply use this -function for the :initialize property. For autoloaded variables, -you will also need to add an autoload stanza calling this -function, and another one setting the standard-value property. -Or you can wrap the defcustom in a progn, to force the autoloader -to include all of it." ; see eg vc-sccs-search-project-dir - ;; No longer true: - ;; "See `send-mail-function' in sendmail.el for an example." - +the :set function." ;; Defvar it so as to mark it special, etc (bug#25770). (internal--define-uninitialized-variable symbol) diff --git a/lisp/dired-aux.el b/lisp/dired-aux.el index 5a96742fda9..c765e4be45d 100644 --- a/lisp/dired-aux.el +++ b/lisp/dired-aux.el @@ -1168,7 +1168,10 @@ ARGS are command switches passed to PROGRAM.") ("\\.tar\\.bz2\\'" . "tar -cf - %i | bzip2 -c9 > %o") ("\\.tar\\.xz\\'" . "tar -cf - %i | xz -c9 > %o") ("\\.tar\\.zst\\'" . "tar -cf - %i | zstd -19 -o %o") - ("\\.zip\\'" . "zip %o -r --filesync %i")) + ("\\.tar\\.lz\\'" . "tar -cf - %i | lzip -c9 > %o") + ("\\.tar\\.lzo\\'" . "tar -cf - %i | lzop -c9 > %o") + ("\\.zip\\'" . "zip %o -r --filesync %i") + ("\\.pax\\'" . "pax -wf %o %i")) "Control the compression shell command for `dired-do-compress-to'. Each element is (REGEXP . CMD), where REGEXP is the name of the diff --git a/lisp/dired-x.el b/lisp/dired-x.el index aebffe339eb..5a52eccbbe3 100644 --- a/lisp/dired-x.el +++ b/lisp/dired-x.el @@ -1483,7 +1483,7 @@ a prefix argument, when it offers the filename near point as a default." ;;; Internal functions. ;; Fixme: This should probably use `thing-at-point'. -- fx -(define-obsolete-function-alias 'dired-file-name-at-point +(define-obsolete-function-alias 'dired-filename-at-point #'dired-x-guess-file-name-at-point "28.1") (defun dired-x-guess-file-name-at-point () "Return the filename closest to point, expanded. diff --git a/lisp/emacs-lisp/byte-opt.el b/lisp/emacs-lisp/byte-opt.el index cf89456541e..66a117fccc8 100644 --- a/lisp/emacs-lisp/byte-opt.el +++ b/lisp/emacs-lisp/byte-opt.el @@ -284,8 +284,10 @@ ;; If `fn' is from the same file, it has already ;; been preprocessed! `(function ,fn) - (byte-compile-preprocess - (byte-compile--reify-function fn))))) + ;; Try and process it "in its original environment". + (let ((byte-compile-bound-variables nil)) + (byte-compile-preprocess + (byte-compile--reify-function fn)))))) (if (eq (car-safe newfn) 'function) (byte-compile-unfold-lambda `(,(cadr newfn) ,@(cdr form))) ;; This can happen because of macroexp-warn-and-return &co. @@ -374,185 +376,184 @@ ;; the important aspect is that they are subrs that don't evaluate all of ;; their args.) ;; - (let ((fn (car-safe form)) - tmp) - (cond ((not (consp form)) - (if (not (and for-effect - (or byte-compile-delete-errors - (not (symbolp form)) - (eq form t)))) - form)) - ((eq fn 'quote) - (if (cdr (cdr form)) - (byte-compile-warn "malformed quote form: `%s'" - (prin1-to-string form))) - ;; map (quote nil) to nil to simplify optimizer logic. - ;; map quoted constants to nil if for-effect (just because). - (and (nth 1 form) - (not for-effect) - form)) - ((memq fn '(let let*)) - ;; recursively enter the optimizer for the bindings and body - ;; of a let or let*. This for depth-firstness: forms that - ;; are more deeply nested are optimized first. - (cons fn + ;; FIXME: There are a bunch of `byte-compile-warn' here which arguably + ;; have no place in an optimizer: the corresponding tests should be + ;; performed in `macroexpand-all', or in `cconv', or in `bytecomp'. + (let ((fn (car-safe form))) + (pcase form + ((pred (not consp)) + (if (not (and for-effect + (or byte-compile-delete-errors + (not (symbolp form)) + (eq form t)))) + form)) + (`(quote . ,v) + (if (cdr v) + (byte-compile-warn "malformed quote form: `%s'" + (prin1-to-string form))) + ;; Map (quote nil) to nil to simplify optimizer logic. + ;; Map quoted constants to nil if for-effect (just because). + (and (car v) + (not for-effect) + form)) + (`(,(or 'let 'let*) . ,(or `(,bindings . ,exps) pcase--dontcare)) + ;; Recursively enter the optimizer for the bindings and body + ;; of a let or let*. This for depth-firstness: forms that + ;; are more deeply nested are optimized first. + (cons fn (cons (mapcar (lambda (binding) - (if (symbolp binding) - binding - (if (cdr (cdr binding)) - (byte-compile-warn "malformed let binding: `%s'" - (prin1-to-string binding))) - (list (car binding) - (byte-optimize-form (nth 1 binding) nil)))) - (nth 1 form)) - (byte-optimize-body (cdr (cdr form)) for-effect)))) - ((eq fn 'cond) - (cons fn - (mapcar (lambda (clause) - (if (consp clause) - (cons - (byte-optimize-form (car clause) nil) - (byte-optimize-body (cdr clause) for-effect)) - (byte-compile-warn "malformed cond form: `%s'" - (prin1-to-string clause)) - clause)) - (cdr form)))) - ((eq fn 'progn) - ;; As an extra added bonus, this simplifies (progn <x>) --> <x>. - (if (cdr (cdr form)) - (macroexp-progn (byte-optimize-body (cdr form) for-effect)) - (byte-optimize-form (nth 1 form) for-effect))) - ((eq fn 'prog1) - (if (cdr (cdr form)) - (cons 'prog1 - (cons (byte-optimize-form (nth 1 form) for-effect) - (byte-optimize-body (cdr (cdr form)) t))) - (byte-optimize-form (nth 1 form) for-effect))) - - ((memq fn '(save-excursion save-restriction save-current-buffer)) - ;; those subrs which have an implicit progn; it's not quite good - ;; enough to treat these like normal function calls. - ;; This can turn (save-excursion ...) into (save-excursion) which - ;; will be optimized away in the lap-optimize pass. - (cons fn (byte-optimize-body (cdr form) for-effect))) - - ((eq fn 'if) - (when (< (length form) 3) - (byte-compile-warn "too few arguments for `if'")) - (cons fn - (cons (byte-optimize-form (nth 1 form) nil) - (cons - (byte-optimize-form (nth 2 form) for-effect) - (byte-optimize-body (nthcdr 3 form) for-effect))))) - - ((memq fn '(and or)) ; Remember, and/or are control structures. - ;; Take forms off the back until we can't any more. - ;; In the future it could conceivably be a problem that the - ;; subexpressions of these forms are optimized in the reverse - ;; order, but it's ok for now. - (if for-effect - (let ((backwards (reverse (cdr form)))) - (while (and backwards - (null (setcar backwards - (byte-optimize-form (car backwards) - for-effect)))) - (setq backwards (cdr backwards))) - (if (and (cdr form) (null backwards)) - (byte-compile-log - " all subforms of %s called for effect; deleted" form)) - (and backwards - (cons fn (nreverse (mapcar 'byte-optimize-form - backwards))))) - (cons fn (mapcar 'byte-optimize-form (cdr form))))) - - ((eq fn 'while) - (unless (consp (cdr form)) - (byte-compile-warn "too few arguments for `while'")) - (cons fn - (cons (byte-optimize-form (cadr form) nil) - (byte-optimize-body (cddr form) t)))) - - ((eq fn 'interactive) - (byte-compile-warn "misplaced interactive spec: `%s'" - (prin1-to-string form)) - nil) - - ((eq fn 'function) - ;; This forms is compiled as constant or by breaking out - ;; all the subexpressions and compiling them separately. - form) - - ((eq fn 'condition-case) - `(condition-case ,(nth 1 form) ;Not evaluated. - ,(byte-optimize-form (nth 2 form) for-effect) - ,@(mapcar (lambda (clause) - `(,(car clause) - ,@(byte-optimize-body (cdr clause) for-effect))) - (nthcdr 3 form)))) - - ((eq fn 'unwind-protect) - ;; the "protected" part of an unwind-protect is compiled (and thus - ;; optimized) as a top-level form, so don't do it here. But the - ;; non-protected part has the same for-effect status as the - ;; unwind-protect itself. (The protected part is always for effect, - ;; but that isn't handled properly yet.) - (cons fn - (cons (byte-optimize-form (nth 1 form) for-effect) - (cdr (cdr form))))) - - ((eq fn 'catch) - (cons fn - (cons (byte-optimize-form (nth 1 form) nil) - (byte-optimize-body (cdr form) for-effect)))) - - ((eq fn 'ignore) - ;; Don't treat the args to `ignore' as being - ;; computed for effect. We want to avoid the warnings - ;; that might occur if they were treated that way. - ;; However, don't actually bother calling `ignore'. - `(prog1 nil . ,(mapcar 'byte-optimize-form (cdr form)))) - - ;; Needed as long as we run byte-optimize-form after cconv. - ((eq fn 'internal-make-closure) form) - - ((eq (car-safe fn) 'lambda) - (let ((newform (byte-compile-unfold-lambda form))) - (if (eq newform form) - ;; Some error occurred, avoid infinite recursion - form - (byte-optimize-form newform for-effect)))) - - ((eq (car-safe fn) 'closure) form) - - ((byte-code-function-p fn) - (cons fn (mapcar #'byte-optimize-form (cdr form)))) - - ((not (symbolp fn)) - (byte-compile-warn "`%s' is a malformed function" - (prin1-to-string fn)) - form) - - ((and for-effect (setq tmp (get fn 'side-effect-free)) - (or byte-compile-delete-errors - (eq tmp 'error-free) - (progn - (byte-compile-warn "value returned from %s is unused" - (prin1-to-string form)) - nil))) - (byte-compile-log " %s called for effect; deleted" fn) - ;; appending a nil here might not be necessary, but it can't hurt. - (byte-optimize-form - (cons 'progn (append (cdr form) '(nil))) t)) + (if (symbolp binding) + binding + (if (cdr (cdr binding)) + (byte-compile-warn "malformed let binding: `%s'" + (prin1-to-string binding))) + (list (car binding) + (byte-optimize-form (nth 1 binding) nil)))) + bindings) + (byte-optimize-body exps for-effect)))) + (`(cond . ,clauses) + (cons fn + (mapcar (lambda (clause) + (if (consp clause) + (cons + (byte-optimize-form (car clause) nil) + (byte-optimize-body (cdr clause) for-effect)) + (byte-compile-warn "malformed cond form: `%s'" + (prin1-to-string clause)) + clause)) + clauses))) + (`(progn . ,exps) + ;; As an extra added bonus, this simplifies (progn <x>) --> <x>. + (if (cdr exps) + (macroexp-progn (byte-optimize-body exps for-effect)) + (byte-optimize-form (car exps) for-effect))) + (`(prog1 . ,(or `(,exp . ,exps) pcase--dontcare)) + (if exps + `(prog1 ,(byte-optimize-form exp for-effect) + . ,(byte-optimize-body exps t)) + (byte-optimize-form exp for-effect))) + + (`(,(or `save-excursion `save-restriction `save-current-buffer) . ,exps) + ;; Those subrs which have an implicit progn; it's not quite good + ;; enough to treat these like normal function calls. + ;; This can turn (save-excursion ...) into (save-excursion) which + ;; will be optimized away in the lap-optimize pass. + (cons fn (byte-optimize-body exps for-effect))) + + (`(if ,test ,then . ,else) + `(if ,(byte-optimize-form test nil) + ,(byte-optimize-form then for-effect) + . ,(byte-optimize-body else for-effect))) + (`(if . ,_) + (byte-compile-warn "too few arguments for `if'")) + + (`(,(or 'and 'or) . ,exps) ; Remember, and/or are control structures. + ;; Take forms off the back until we can't any more. + ;; In the future it could conceivably be a problem that the + ;; subexpressions of these forms are optimized in the reverse + ;; order, but it's ok for now. + (if for-effect + (let ((backwards (reverse exps))) + (while (and backwards + (null (setcar backwards + (byte-optimize-form (car backwards) + for-effect)))) + (setq backwards (cdr backwards))) + (if (and exps (null backwards)) + (byte-compile-log + " all subforms of %s called for effect; deleted" form)) + (and backwards + (cons fn (nreverse (mapcar #'byte-optimize-form + backwards))))) + (cons fn (mapcar #'byte-optimize-form exps)))) + + (`(while ,exp . ,exps) + `(while ,(byte-optimize-form exp nil) + . ,(byte-optimize-body exps t))) + (`(while . ,_) + (byte-compile-warn "too few arguments for `while'")) + + (`(interactive . ,_) + (byte-compile-warn "misplaced interactive spec: `%s'" + (prin1-to-string form)) + nil) + + (`(function . ,_) + ;; This forms is compiled as constant or by breaking out + ;; all the subexpressions and compiling them separately. + form) - (t - ;; Otherwise, no args can be considered to be for-effect, - ;; even if the called function is for-effect, because we - ;; don't know anything about that function. - (let ((form (cons fn (mapcar #'byte-optimize-form (cdr form))))) - (if (get fn 'pure) - (byte-optimize-constant-args form) - form)))))) + (`(condition-case . ,(or `(,var ,exp . ,clauses) pcase--dontcare)) + `(condition-case ,var ;Not evaluated. + ,(byte-optimize-form exp for-effect) + ,@(mapcar (lambda (clause) + `(,(car clause) + ,@(byte-optimize-body (cdr clause) for-effect))) + clauses))) + + (`(unwind-protect . ,(or `(,exp . ,exps) pcase--dontcare)) + ;; The "protected" part of an unwind-protect is compiled (and thus + ;; optimized) as a top-level form, so don't do it here. But the + ;; non-protected part has the same for-effect status as the + ;; unwind-protect itself. (The protected part is always for effect, + ;; but that isn't handled properly yet.) + `(unwind-protect ,(byte-optimize-form exp for-effect) . ,exps)) + + (`(catch . ,(or `(,tag . ,exps) pcase--dontcare)) + `(catch ,(byte-optimize-form tag nil) + . ,(byte-optimize-body exps for-effect))) + + (`(ignore . ,exps) + ;; Don't treat the args to `ignore' as being + ;; computed for effect. We want to avoid the warnings + ;; that might occur if they were treated that way. + ;; However, don't actually bother calling `ignore'. + `(prog1 nil . ,(mapcar #'byte-optimize-form exps))) + + ;; Needed as long as we run byte-optimize-form after cconv. + (`(internal-make-closure . ,_) form) + + (`((lambda . ,_) . ,_) + (let ((newform (byte-compile-unfold-lambda form))) + (if (eq newform form) + ;; Some error occurred, avoid infinite recursion. + form + (byte-optimize-form newform for-effect)))) + + ;; FIXME: Strictly speaking, I think this is a bug: (closure...) + ;; is a *value* and shouldn't appear in the car. + (`((closure . ,_) . ,_) form) + + (`(,(pred byte-code-function-p) . ,exps) + (cons fn (mapcar #'byte-optimize-form exps))) + + (`(,(pred (not symbolp)) . ,_) + (byte-compile-warn "`%s' is a malformed function" + (prin1-to-string fn)) + form) + + ((guard (when for-effect + (if-let ((tmp (get fn 'side-effect-free))) + (or byte-compile-delete-errors + (eq tmp 'error-free) + (progn + (byte-compile-warn "value returned from %s is unused" + (prin1-to-string form)) + nil))))) + (byte-compile-log " %s called for effect; deleted" fn) + ;; appending a nil here might not be necessary, but it can't hurt. + (byte-optimize-form + (cons 'progn (append (cdr form) '(nil))) t)) + + (_ + ;; Otherwise, no args can be considered to be for-effect, + ;; even if the called function is for-effect, because we + ;; don't know anything about that function. + (let ((form (cons fn (mapcar #'byte-optimize-form (cdr form))))) + (if (get fn 'pure) + (byte-optimize-constant-args form) + form)))))) (defun byte-optimize-form (form &optional for-effect) "The source-level pass of the optimizer." @@ -1562,467 +1563,548 @@ If FOR-EFFECT is non-nil, the return value is assumed to be of no importance." ;; You may notice that sequences like "dup varset discard" are ;; optimized but sequences like "dup varset TAG1: discard" are not. ;; You may be tempted to change this; resist that temptation. - (cond ;; - ;; <side-effect-free> pop --> <deleted> - ;; ...including: - ;; const-X pop --> <deleted> - ;; varref-X pop --> <deleted> - ;; dup pop --> <deleted> - ;; - ((and (eq 'byte-discard (car lap1)) - (memq (car lap0) side-effect-free)) - (setq keep-going t) - (setq tmp (aref byte-stack+-info (symbol-value (car lap0)))) - (setq rest (cdr rest)) - (cond ((= tmp 1) - (byte-compile-log-lap - " %s discard\t-->\t<deleted>" lap0) - (setq lap (delq lap0 (delq lap1 lap)))) - ((= tmp 0) - (byte-compile-log-lap - " %s discard\t-->\t<deleted> discard" lap0) - (setq lap (delq lap0 lap))) - ((= tmp -1) - (byte-compile-log-lap - " %s discard\t-->\tdiscard discard" lap0) - (setcar lap0 'byte-discard) - (setcdr lap0 0)) - ((error "Optimizer error: too much on the stack")))) - ;; - ;; goto*-X X: --> X: - ;; - ((and (memq (car lap0) byte-goto-ops) - (eq (cdr lap0) lap1)) - (cond ((eq (car lap0) 'byte-goto) - (setq lap (delq lap0 lap)) - (setq tmp "<deleted>")) - ((memq (car lap0) byte-goto-always-pop-ops) - (setcar lap0 (setq tmp 'byte-discard)) - (setcdr lap0 0)) - ((error "Depth conflict at tag %d" (nth 2 lap0)))) - (and (memq byte-optimize-log '(t byte)) - (byte-compile-log " (goto %s) %s:\t-->\t%s %s:" - (nth 1 lap1) (nth 1 lap1) - tmp (nth 1 lap1))) - (setq keep-going t)) - ;; - ;; varset-X varref-X --> dup varset-X - ;; varbind-X varref-X --> dup varbind-X - ;; const/dup varset-X varref-X --> const/dup varset-X const/dup - ;; const/dup varbind-X varref-X --> const/dup varbind-X const/dup - ;; The latter two can enable other optimizations. - ;; - ;; For lexical variables, we could do the same - ;; stack-set-X+1 stack-ref-X --> dup stack-set-X+2 - ;; but this is a very minor gain, since dup is stack-ref-0, - ;; i.e. it's only better if X>5, and even then it comes - ;; at the cost of an extra stack slot. Let's not bother. - ((and (eq 'byte-varref (car lap2)) - (eq (cdr lap1) (cdr lap2)) - (memq (car lap1) '(byte-varset byte-varbind))) - (if (and (setq tmp (memq (car (cdr lap2)) byte-boolean-vars)) - (not (eq (car lap0) 'byte-constant))) - nil - (setq keep-going t) - (if (memq (car lap0) '(byte-constant byte-dup)) - (progn - (setq tmp (if (or (not tmp) - (macroexp--const-symbol-p - (car (cdr lap0)))) - (cdr lap0) - (byte-compile-get-constant t))) - (byte-compile-log-lap " %s %s %s\t-->\t%s %s %s" - lap0 lap1 lap2 lap0 lap1 - (cons (car lap0) tmp)) - (setcar lap2 (car lap0)) - (setcdr lap2 tmp)) - (byte-compile-log-lap " %s %s\t-->\tdup %s" lap1 lap2 lap1) - (setcar lap2 (car lap1)) - (setcar lap1 'byte-dup) - (setcdr lap1 0) - ;; The stack depth gets locally increased, so we will - ;; increase maxdepth in case depth = maxdepth here. - ;; This can cause the third argument to byte-code to - ;; be larger than necessary. - (setq add-depth 1)))) - ;; - ;; dup varset-X discard --> varset-X - ;; dup varbind-X discard --> varbind-X - ;; dup stack-set-X discard --> stack-set-X-1 - ;; (the varbind variant can emerge from other optimizations) - ;; - ((and (eq 'byte-dup (car lap0)) - (eq 'byte-discard (car lap2)) - (memq (car lap1) '(byte-varset byte-varbind - byte-stack-set))) - (byte-compile-log-lap " dup %s discard\t-->\t%s" lap1 lap1) - (setq keep-going t - rest (cdr rest)) - (if (eq 'byte-stack-set (car lap1)) (cl-decf (cdr lap1))) - (setq lap (delq lap0 (delq lap2 lap)))) - ;; - ;; not goto-X-if-nil --> goto-X-if-non-nil - ;; not goto-X-if-non-nil --> goto-X-if-nil - ;; - ;; it is wrong to do the same thing for the -else-pop variants. - ;; - ((and (eq 'byte-not (car lap0)) - (memq (car lap1) '(byte-goto-if-nil byte-goto-if-not-nil))) - (byte-compile-log-lap " not %s\t-->\t%s" - lap1 - (cons - (if (eq (car lap1) 'byte-goto-if-nil) - 'byte-goto-if-not-nil - 'byte-goto-if-nil) - (cdr lap1))) - (setcar lap1 (if (eq (car lap1) 'byte-goto-if-nil) - 'byte-goto-if-not-nil - 'byte-goto-if-nil)) - (setq lap (delq lap0 lap)) - (setq keep-going t)) - ;; - ;; goto-X-if-nil goto-Y X: --> goto-Y-if-non-nil X: - ;; goto-X-if-non-nil goto-Y X: --> goto-Y-if-nil X: - ;; - ;; it is wrong to do the same thing for the -else-pop variants. - ;; - ((and (memq (car lap0) - '(byte-goto-if-nil byte-goto-if-not-nil)) ; gotoX - (eq 'byte-goto (car lap1)) ; gotoY - (eq (cdr lap0) lap2)) ; TAG X - (let ((inverse (if (eq 'byte-goto-if-nil (car lap0)) - 'byte-goto-if-not-nil 'byte-goto-if-nil))) - (byte-compile-log-lap " %s %s %s:\t-->\t%s %s:" - lap0 lap1 lap2 - (cons inverse (cdr lap1)) lap2) - (setq lap (delq lap0 lap)) - (setcar lap1 inverse) - (setq keep-going t))) - ;; - ;; const goto-if-* --> whatever - ;; - ((and (eq 'byte-constant (car lap0)) - (memq (car lap1) byte-conditional-ops) - ;; If the `byte-constant's cdr is not a cons cell, it has - ;; to be an index into the constant pool); even though - ;; it'll be a constant, that constant is not known yet - ;; (it's typically a free variable of a closure, so will - ;; only be known when the closure will be built at - ;; run-time). - (consp (cdr lap0))) - (cond ((if (memq (car lap1) '(byte-goto-if-nil - byte-goto-if-nil-else-pop)) - (car (cdr lap0)) - (not (car (cdr lap0)))) - (byte-compile-log-lap " %s %s\t-->\t<deleted>" - lap0 lap1) - (setq rest (cdr rest) - lap (delq lap0 (delq lap1 lap)))) - (t - (byte-compile-log-lap " %s %s\t-->\t%s" - lap0 lap1 - (cons 'byte-goto (cdr lap1))) - (when (memq (car lap1) byte-goto-always-pop-ops) - (setq lap (delq lap0 lap))) - (setcar lap1 'byte-goto))) - (setq keep-going t)) - ;; - ;; varref-X varref-X --> varref-X dup - ;; varref-X [dup ...] varref-X --> varref-X [dup ...] dup - ;; stackref-X [dup ...] stackref-X+N --> stackref-X [dup ...] dup - ;; We don't optimize the const-X variations on this here, - ;; because that would inhibit some goto optimizations; we - ;; optimize the const-X case after all other optimizations. - ;; - ((and (memq (car lap0) '(byte-varref byte-stack-ref)) - (progn - (setq tmp (cdr rest)) - (setq tmp2 0) - (while (eq (car (car tmp)) 'byte-dup) - (setq tmp2 (1+ tmp2)) - (setq tmp (cdr tmp))) - t) - (eq (if (eq 'byte-stack-ref (car lap0)) - (+ tmp2 1 (cdr lap0)) - (cdr lap0)) - (cdr (car tmp))) - (eq (car lap0) (car (car tmp)))) - (if (memq byte-optimize-log '(t byte)) - (let ((str "")) - (setq tmp2 (cdr rest)) - (while (not (eq tmp tmp2)) - (setq tmp2 (cdr tmp2) - str (concat str " dup"))) - (byte-compile-log-lap " %s%s %s\t-->\t%s%s dup" - lap0 str lap0 lap0 str))) - (setq keep-going t) - (setcar (car tmp) 'byte-dup) - (setcdr (car tmp) 0) - (setq rest tmp)) - ;; - ;; TAG1: TAG2: --> TAG1: <deleted> - ;; (and other references to TAG2 are replaced with TAG1) - ;; - ((and (eq (car lap0) 'TAG) - (eq (car lap1) 'TAG)) - (and (memq byte-optimize-log '(t byte)) - (byte-compile-log " adjacent tags %d and %d merged" - (nth 1 lap1) (nth 1 lap0))) - (setq tmp3 lap) - (while (setq tmp2 (rassq lap0 tmp3)) - (setcdr tmp2 lap1) - (setq tmp3 (cdr (memq tmp2 tmp3)))) - (setq lap (delq lap0 lap) - keep-going t) - ;; replace references to tag in jump tables, if any - (dolist (table byte-compile-jump-tables) - (maphash #'(lambda (value tag) - (when (equal tag lap0) - (puthash value lap1 table))) - table))) - ;; - ;; unused-TAG: --> <deleted> - ;; - ((and (eq 'TAG (car lap0)) - (not (rassq lap0 lap)) - ;; make sure this tag isn't used in a jump-table - (cl-loop for table in byte-compile-jump-tables - when (member lap0 (hash-table-values table)) - return nil finally return t)) - (and (memq byte-optimize-log '(t byte)) - (byte-compile-log " unused tag %d removed" (nth 1 lap0))) - (setq lap (delq lap0 lap) - keep-going t)) - ;; - ;; goto ... --> goto <delete until TAG or end> - ;; return ... --> return <delete until TAG or end> - ;; (unless a jump-table is being used, where deleting may affect - ;; other valid case bodies) - ;; - ((and (memq (car lap0) '(byte-goto byte-return)) - (not (memq (car lap1) '(TAG nil))) - ;; FIXME: Instead of deferring simply when jump-tables are - ;; being used, keep a list of tags used for switch tags and - ;; use them instead (see `byte-compile-inline-lapcode'). - (not byte-compile-jump-tables)) - (setq tmp rest) - (let ((i 0) - (opt-p (memq byte-optimize-log '(t lap))) - str deleted) - (while (and (setq tmp (cdr tmp)) - (not (eq 'TAG (car (car tmp))))) - (if opt-p (setq deleted (cons (car tmp) deleted) - str (concat str " %s") - i (1+ i)))) - (if opt-p - (let ((tagstr - (if (eq 'TAG (car (car tmp))) - (format "%d:" (car (cdr (car tmp)))) - (or (car tmp) "")))) - (if (< i 6) - (apply 'byte-compile-log-lap-1 - (concat " %s" str - " %s\t-->\t%s <deleted> %s") - lap0 - (nconc (nreverse deleted) - (list tagstr lap0 tagstr))) - (byte-compile-log-lap - " %s <%d unreachable op%s> %s\t-->\t%s <deleted> %s" - lap0 i (if (= i 1) "" "s") - tagstr lap0 tagstr)))) - (rplacd rest tmp)) - (setq keep-going t)) - ;; - ;; <safe-op> unbind --> unbind <safe-op> - ;; (this may enable other optimizations.) - ;; - ((and (eq 'byte-unbind (car lap1)) - (memq (car lap0) byte-after-unbind-ops)) - (byte-compile-log-lap " %s %s\t-->\t%s %s" lap0 lap1 lap1 lap0) - (setcar rest lap1) - (setcar (cdr rest) lap0) - (setq keep-going t)) - ;; - ;; varbind-X unbind-N --> discard unbind-(N-1) - ;; save-excursion unbind-N --> unbind-(N-1) - ;; save-restriction unbind-N --> unbind-(N-1) - ;; - ((and (eq 'byte-unbind (car lap1)) - (memq (car lap0) '(byte-varbind byte-save-excursion - byte-save-restriction)) - (< 0 (cdr lap1))) - (if (zerop (setcdr lap1 (1- (cdr lap1)))) - (delq lap1 rest)) - (if (eq (car lap0) 'byte-varbind) - (setcar rest (cons 'byte-discard 0)) + (cond + ;; <side-effect-free> pop --> <deleted> + ;; ...including: + ;; const-X pop --> <deleted> + ;; varref-X pop --> <deleted> + ;; dup pop --> <deleted> + ;; + ((and (eq 'byte-discard (car lap1)) + (memq (car lap0) side-effect-free)) + (setq keep-going t) + (setq tmp (aref byte-stack+-info (symbol-value (car lap0)))) + (setq rest (cdr rest)) + (cond ((= tmp 1) + (byte-compile-log-lap + " %s discard\t-->\t<deleted>" lap0) + (setq lap (delq lap0 (delq lap1 lap)))) + ((= tmp 0) + (byte-compile-log-lap + " %s discard\t-->\t<deleted> discard" lap0) (setq lap (delq lap0 lap))) - (byte-compile-log-lap " %s %s\t-->\t%s %s" - lap0 (cons (car lap1) (1+ (cdr lap1))) - (if (eq (car lap0) 'byte-varbind) - (car rest) - (car (cdr rest))) - (if (and (/= 0 (cdr lap1)) - (eq (car lap0) 'byte-varbind)) - (car (cdr rest)) - "")) - (setq keep-going t)) - ;; - ;; goto*-X ... X: goto-Y --> goto*-Y - ;; goto-X ... X: return --> return - ;; - ((and (memq (car lap0) byte-goto-ops) - (memq (car (setq tmp (nth 1 (memq (cdr lap0) lap)))) - '(byte-goto byte-return))) - (cond ((and (not (eq tmp lap0)) - (or (eq (car lap0) 'byte-goto) - (eq (car tmp) 'byte-goto))) - (byte-compile-log-lap " %s [%s]\t-->\t%s" - (car lap0) tmp tmp) - (if (eq (car tmp) 'byte-return) - (setcar lap0 'byte-return)) - (setcdr lap0 (cdr tmp)) - (setq keep-going t)))) - ;; - ;; goto-*-else-pop X ... X: goto-if-* --> whatever - ;; goto-*-else-pop X ... X: discard --> whatever - ;; - ((and (memq (car lap0) '(byte-goto-if-nil-else-pop - byte-goto-if-not-nil-else-pop)) - (memq (car (car (setq tmp (cdr (memq (cdr lap0) lap))))) - (eval-when-compile - (cons 'byte-discard byte-conditional-ops))) - (not (eq lap0 (car tmp)))) - (setq tmp2 (car tmp)) - (setq tmp3 (assq (car lap0) '((byte-goto-if-nil-else-pop - byte-goto-if-nil) - (byte-goto-if-not-nil-else-pop - byte-goto-if-not-nil)))) - (if (memq (car tmp2) tmp3) - (progn (setcar lap0 (car tmp2)) - (setcdr lap0 (cdr tmp2)) - (byte-compile-log-lap " %s-else-pop [%s]\t-->\t%s" - (car lap0) tmp2 lap0)) - ;; Get rid of the -else-pop's and jump one step further. + ((= tmp -1) + (byte-compile-log-lap + " %s discard\t-->\tdiscard discard" lap0) + (setcar lap0 'byte-discard) + (setcdr lap0 0)) + ((error "Optimizer error: too much on the stack")))) + ;; + ;; goto*-X X: --> X: + ;; + ((and (memq (car lap0) byte-goto-ops) + (eq (cdr lap0) lap1)) + (cond ((eq (car lap0) 'byte-goto) + (setq lap (delq lap0 lap)) + (setq tmp "<deleted>")) + ((memq (car lap0) byte-goto-always-pop-ops) + (setcar lap0 (setq tmp 'byte-discard)) + (setcdr lap0 0)) + ((error "Depth conflict at tag %d" (nth 2 lap0)))) + (and (memq byte-optimize-log '(t byte)) + (byte-compile-log " (goto %s) %s:\t-->\t%s %s:" + (nth 1 lap1) (nth 1 lap1) + tmp (nth 1 lap1))) + (setq keep-going t)) + ;; + ;; varset-X varref-X --> dup varset-X + ;; varbind-X varref-X --> dup varbind-X + ;; const/dup varset-X varref-X --> const/dup varset-X const/dup + ;; const/dup varbind-X varref-X --> const/dup varbind-X const/dup + ;; The latter two can enable other optimizations. + ;; + ;; For lexical variables, we could do the same + ;; stack-set-X+1 stack-ref-X --> dup stack-set-X+2 + ;; but this is a very minor gain, since dup is stack-ref-0, + ;; i.e. it's only better if X>5, and even then it comes + ;; at the cost of an extra stack slot. Let's not bother. + ((and (eq 'byte-varref (car lap2)) + (eq (cdr lap1) (cdr lap2)) + (memq (car lap1) '(byte-varset byte-varbind))) + (if (and (setq tmp (memq (car (cdr lap2)) byte-boolean-vars)) + (not (eq (car lap0) 'byte-constant))) + nil + (setq keep-going t) + (if (memq (car lap0) '(byte-constant byte-dup)) + (progn + (setq tmp (if (or (not tmp) + (macroexp--const-symbol-p + (car (cdr lap0)))) + (cdr lap0) + (byte-compile-get-constant t))) + (byte-compile-log-lap " %s %s %s\t-->\t%s %s %s" + lap0 lap1 lap2 lap0 lap1 + (cons (car lap0) tmp)) + (setcar lap2 (car lap0)) + (setcdr lap2 tmp)) + (byte-compile-log-lap " %s %s\t-->\tdup %s" lap1 lap2 lap1) + (setcar lap2 (car lap1)) + (setcar lap1 'byte-dup) + (setcdr lap1 0) + ;; The stack depth gets locally increased, so we will + ;; increase maxdepth in case depth = maxdepth here. + ;; This can cause the third argument to byte-code to + ;; be larger than necessary. + (setq add-depth 1)))) + ;; + ;; dup varset-X discard --> varset-X + ;; dup varbind-X discard --> varbind-X + ;; dup stack-set-X discard --> stack-set-X-1 + ;; (the varbind variant can emerge from other optimizations) + ;; + ((and (eq 'byte-dup (car lap0)) + (eq 'byte-discard (car lap2)) + (memq (car lap1) '(byte-varset byte-varbind + byte-stack-set))) + (byte-compile-log-lap " dup %s discard\t-->\t%s" lap1 lap1) + (setq keep-going t + rest (cdr rest)) + (if (eq 'byte-stack-set (car lap1)) (cl-decf (cdr lap1))) + (setq lap (delq lap0 (delq lap2 lap)))) + ;; + ;; not goto-X-if-nil --> goto-X-if-non-nil + ;; not goto-X-if-non-nil --> goto-X-if-nil + ;; + ;; it is wrong to do the same thing for the -else-pop variants. + ;; + ((and (eq 'byte-not (car lap0)) + (memq (car lap1) '(byte-goto-if-nil byte-goto-if-not-nil))) + (byte-compile-log-lap " not %s\t-->\t%s" + lap1 + (cons + (if (eq (car lap1) 'byte-goto-if-nil) + 'byte-goto-if-not-nil + 'byte-goto-if-nil) + (cdr lap1))) + (setcar lap1 (if (eq (car lap1) 'byte-goto-if-nil) + 'byte-goto-if-not-nil + 'byte-goto-if-nil)) + (setq lap (delq lap0 lap)) + (setq keep-going t)) + ;; + ;; goto-X-if-nil goto-Y X: --> goto-Y-if-non-nil X: + ;; goto-X-if-non-nil goto-Y X: --> goto-Y-if-nil X: + ;; + ;; it is wrong to do the same thing for the -else-pop variants. + ;; + ((and (memq (car lap0) + '(byte-goto-if-nil byte-goto-if-not-nil)) ; gotoX + (eq 'byte-goto (car lap1)) ; gotoY + (eq (cdr lap0) lap2)) ; TAG X + (let ((inverse (if (eq 'byte-goto-if-nil (car lap0)) + 'byte-goto-if-not-nil 'byte-goto-if-nil))) + (byte-compile-log-lap " %s %s %s:\t-->\t%s %s:" + lap0 lap1 lap2 + (cons inverse (cdr lap1)) lap2) + (setq lap (delq lap0 lap)) + (setcar lap1 inverse) + (setq keep-going t))) + ;; + ;; const goto-if-* --> whatever + ;; + ((and (eq 'byte-constant (car lap0)) + (memq (car lap1) byte-conditional-ops) + ;; If the `byte-constant's cdr is not a cons cell, it has + ;; to be an index into the constant pool); even though + ;; it'll be a constant, that constant is not known yet + ;; (it's typically a free variable of a closure, so will + ;; only be known when the closure will be built at + ;; run-time). + (consp (cdr lap0))) + (cond ((if (memq (car lap1) '(byte-goto-if-nil + byte-goto-if-nil-else-pop)) + (car (cdr lap0)) + (not (car (cdr lap0)))) + (byte-compile-log-lap " %s %s\t-->\t<deleted>" + lap0 lap1) + (setq rest (cdr rest) + lap (delq lap0 (delq lap1 lap)))) + (t + (byte-compile-log-lap " %s %s\t-->\t%s" + lap0 lap1 + (cons 'byte-goto (cdr lap1))) + (when (memq (car lap1) byte-goto-always-pop-ops) + (setq lap (delq lap0 lap))) + (setcar lap1 'byte-goto))) + (setq keep-going t)) + ;; + ;; varref-X varref-X --> varref-X dup + ;; varref-X [dup ...] varref-X --> varref-X [dup ...] dup + ;; stackref-X [dup ...] stackref-X+N --> stackref-X [dup ...] dup + ;; We don't optimize the const-X variations on this here, + ;; because that would inhibit some goto optimizations; we + ;; optimize the const-X case after all other optimizations. + ;; + ((and (memq (car lap0) '(byte-varref byte-stack-ref)) + (progn + (setq tmp (cdr rest)) + (setq tmp2 0) + (while (eq (car (car tmp)) 'byte-dup) + (setq tmp2 (1+ tmp2)) + (setq tmp (cdr tmp))) + t) + (eq (if (eq 'byte-stack-ref (car lap0)) + (+ tmp2 1 (cdr lap0)) + (cdr lap0)) + (cdr (car tmp))) + (eq (car lap0) (car (car tmp)))) + (if (memq byte-optimize-log '(t byte)) + (let ((str "")) + (setq tmp2 (cdr rest)) + (while (not (eq tmp tmp2)) + (setq tmp2 (cdr tmp2) + str (concat str " dup"))) + (byte-compile-log-lap " %s%s %s\t-->\t%s%s dup" + lap0 str lap0 lap0 str))) + (setq keep-going t) + (setcar (car tmp) 'byte-dup) + (setcdr (car tmp) 0) + (setq rest tmp)) + ;; + ;; TAG1: TAG2: --> TAG1: <deleted> + ;; (and other references to TAG2 are replaced with TAG1) + ;; + ((and (eq (car lap0) 'TAG) + (eq (car lap1) 'TAG)) + (and (memq byte-optimize-log '(t byte)) + (byte-compile-log " adjacent tags %d and %d merged" + (nth 1 lap1) (nth 1 lap0))) + (setq tmp3 lap) + (while (setq tmp2 (rassq lap0 tmp3)) + (setcdr tmp2 lap1) + (setq tmp3 (cdr (memq tmp2 tmp3)))) + (setq lap (delq lap0 lap) + keep-going t) + ;; replace references to tag in jump tables, if any + (dolist (table byte-compile-jump-tables) + (maphash #'(lambda (value tag) + (when (equal tag lap0) + (puthash value lap1 table))) + table))) + ;; + ;; unused-TAG: --> <deleted> + ;; + ((and (eq 'TAG (car lap0)) + (not (rassq lap0 lap)) + ;; make sure this tag isn't used in a jump-table + (cl-loop for table in byte-compile-jump-tables + when (member lap0 (hash-table-values table)) + return nil finally return t)) + (and (memq byte-optimize-log '(t byte)) + (byte-compile-log " unused tag %d removed" (nth 1 lap0))) + (setq lap (delq lap0 lap) + keep-going t)) + ;; + ;; goto ... --> goto <delete until TAG or end> + ;; return ... --> return <delete until TAG or end> + ;; (unless a jump-table is being used, where deleting may affect + ;; other valid case bodies) + ;; + ((and (memq (car lap0) '(byte-goto byte-return)) + (not (memq (car lap1) '(TAG nil))) + ;; FIXME: Instead of deferring simply when jump-tables are + ;; being used, keep a list of tags used for switch tags and + ;; use them instead (see `byte-compile-inline-lapcode'). + (not byte-compile-jump-tables)) + (setq tmp rest) + (let ((i 0) + (opt-p (memq byte-optimize-log '(t lap))) + str deleted) + (while (and (setq tmp (cdr tmp)) + (not (eq 'TAG (car (car tmp))))) + (if opt-p (setq deleted (cons (car tmp) deleted) + str (concat str " %s") + i (1+ i)))) + (if opt-p + (let ((tagstr + (if (eq 'TAG (car (car tmp))) + (format "%d:" (car (cdr (car tmp)))) + (or (car tmp) "")))) + (if (< i 6) + (apply 'byte-compile-log-lap-1 + (concat " %s" str + " %s\t-->\t%s <deleted> %s") + lap0 + (nconc (nreverse deleted) + (list tagstr lap0 tagstr))) + (byte-compile-log-lap + " %s <%d unreachable op%s> %s\t-->\t%s <deleted> %s" + lap0 i (if (= i 1) "" "s") + tagstr lap0 tagstr)))) + (rplacd rest tmp)) + (setq keep-going t)) + ;; + ;; <safe-op> unbind --> unbind <safe-op> + ;; (this may enable other optimizations.) + ;; + ((and (eq 'byte-unbind (car lap1)) + (memq (car lap0) byte-after-unbind-ops)) + (byte-compile-log-lap " %s %s\t-->\t%s %s" lap0 lap1 lap1 lap0) + (setcar rest lap1) + (setcar (cdr rest) lap0) + (setq keep-going t)) + ;; + ;; varbind-X unbind-N --> discard unbind-(N-1) + ;; save-excursion unbind-N --> unbind-(N-1) + ;; save-restriction unbind-N --> unbind-(N-1) + ;; + ((and (eq 'byte-unbind (car lap1)) + (memq (car lap0) '(byte-varbind byte-save-excursion + byte-save-restriction)) + (< 0 (cdr lap1))) + (if (zerop (setcdr lap1 (1- (cdr lap1)))) + (delq lap1 rest)) + (if (eq (car lap0) 'byte-varbind) + (setcar rest (cons 'byte-discard 0)) + (setq lap (delq lap0 lap))) + (byte-compile-log-lap " %s %s\t-->\t%s %s" + lap0 (cons (car lap1) (1+ (cdr lap1))) + (if (eq (car lap0) 'byte-varbind) + (car rest) + (car (cdr rest))) + (if (and (/= 0 (cdr lap1)) + (eq (car lap0) 'byte-varbind)) + (car (cdr rest)) + "")) + (setq keep-going t)) + ;; + ;; goto*-X ... X: goto-Y --> goto*-Y + ;; goto-X ... X: return --> return + ;; + ((and (memq (car lap0) byte-goto-ops) + (memq (car (setq tmp (nth 1 (memq (cdr lap0) lap)))) + '(byte-goto byte-return))) + (cond ((and (not (eq tmp lap0)) + (or (eq (car lap0) 'byte-goto) + (eq (car tmp) 'byte-goto))) + (byte-compile-log-lap " %s [%s]\t-->\t%s" + (car lap0) tmp tmp) + (if (eq (car tmp) 'byte-return) + (setcar lap0 'byte-return)) + (setcdr lap0 (cdr tmp)) + (setq keep-going t)))) + ;; + ;; goto-*-else-pop X ... X: goto-if-* --> whatever + ;; goto-*-else-pop X ... X: discard --> whatever + ;; + ((and (memq (car lap0) '(byte-goto-if-nil-else-pop + byte-goto-if-not-nil-else-pop)) + (memq (car (car (setq tmp (cdr (memq (cdr lap0) lap))))) + (eval-when-compile + (cons 'byte-discard byte-conditional-ops))) + (not (eq lap0 (car tmp)))) + (setq tmp2 (car tmp)) + (setq tmp3 (assq (car lap0) '((byte-goto-if-nil-else-pop + byte-goto-if-nil) + (byte-goto-if-not-nil-else-pop + byte-goto-if-not-nil)))) + (if (memq (car tmp2) tmp3) + (progn (setcar lap0 (car tmp2)) + (setcdr lap0 (cdr tmp2)) + (byte-compile-log-lap " %s-else-pop [%s]\t-->\t%s" + (car lap0) tmp2 lap0)) + ;; Get rid of the -else-pop's and jump one step further. + (or (eq 'TAG (car (nth 1 tmp))) + (setcdr tmp (cons (byte-compile-make-tag) + (cdr tmp)))) + (byte-compile-log-lap " %s [%s]\t-->\t%s <skip>" + (car lap0) tmp2 (nth 1 tmp3)) + (setcar lap0 (nth 1 tmp3)) + (setcdr lap0 (nth 1 tmp))) + (setq keep-going t)) + ;; + ;; const goto-X ... X: goto-if-* --> whatever + ;; const goto-X ... X: discard --> whatever + ;; + ((and (eq (car lap0) 'byte-constant) + (eq (car lap1) 'byte-goto) + (memq (car (car (setq tmp (cdr (memq (cdr lap1) lap))))) + (eval-when-compile + (cons 'byte-discard byte-conditional-ops))) + (not (eq lap1 (car tmp)))) + (setq tmp2 (car tmp)) + (cond ((when (consp (cdr lap0)) + (memq (car tmp2) + (if (null (car (cdr lap0))) + '(byte-goto-if-nil byte-goto-if-nil-else-pop) + '(byte-goto-if-not-nil + byte-goto-if-not-nil-else-pop)))) + (byte-compile-log-lap " %s goto [%s]\t-->\t%s %s" + lap0 tmp2 lap0 tmp2) + (setcar lap1 (car tmp2)) + (setcdr lap1 (cdr tmp2)) + ;; Let next step fix the (const,goto-if*) sequence. + (setq rest (cons nil rest)) + (setq keep-going t)) + ((or (consp (cdr lap0)) + (eq (car tmp2) 'byte-discard)) + ;; Jump one step further + (byte-compile-log-lap + " %s goto [%s]\t-->\t<deleted> goto <skip>" + lap0 tmp2) (or (eq 'TAG (car (nth 1 tmp))) (setcdr tmp (cons (byte-compile-make-tag) (cdr tmp)))) - (byte-compile-log-lap " %s [%s]\t-->\t%s <skip>" - (car lap0) tmp2 (nth 1 tmp3)) - (setcar lap0 (nth 1 tmp3)) - (setcdr lap0 (nth 1 tmp))) - (setq keep-going t)) - ;; - ;; const goto-X ... X: goto-if-* --> whatever - ;; const goto-X ... X: discard --> whatever - ;; - ((and (eq (car lap0) 'byte-constant) - (eq (car lap1) 'byte-goto) - (memq (car (car (setq tmp (cdr (memq (cdr lap1) lap))))) - (eval-when-compile - (cons 'byte-discard byte-conditional-ops))) - (not (eq lap1 (car tmp)))) - (setq tmp2 (car tmp)) - (cond ((when (consp (cdr lap0)) - (memq (car tmp2) - (if (null (car (cdr lap0))) - '(byte-goto-if-nil byte-goto-if-nil-else-pop) - '(byte-goto-if-not-nil - byte-goto-if-not-nil-else-pop)))) - (byte-compile-log-lap " %s goto [%s]\t-->\t%s %s" - lap0 tmp2 lap0 tmp2) - (setcar lap1 (car tmp2)) - (setcdr lap1 (cdr tmp2)) - ;; Let next step fix the (const,goto-if*) sequence. - (setq rest (cons nil rest)) - (setq keep-going t)) - ((or (consp (cdr lap0)) - (eq (car tmp2) 'byte-discard)) - ;; Jump one step further - (byte-compile-log-lap - " %s goto [%s]\t-->\t<deleted> goto <skip>" - lap0 tmp2) - (or (eq 'TAG (car (nth 1 tmp))) - (setcdr tmp (cons (byte-compile-make-tag) - (cdr tmp)))) - (setcdr lap1 (car (cdr tmp))) - (setq lap (delq lap0 lap)) - (setq keep-going t)))) - ;; - ;; X: varref-Y ... varset-Y goto-X --> - ;; X: varref-Y Z: ... dup varset-Y goto-Z - ;; (varset-X goto-BACK, BACK: varref-X --> copy the varref down.) - ;; (This is so usual for while loops that it is worth handling). - ;; - ;; Here again, we could do it for stack-ref/stack-set, but - ;; that's replacing a stack-ref-Y with a stack-ref-0, which - ;; is a very minor improvement (if any), at the cost of - ;; more stack use and more byte-code. Let's not do it. - ;; - ((and (eq (car lap1) 'byte-varset) - (eq (car lap2) 'byte-goto) - (not (memq (cdr lap2) rest)) ;Backwards jump - (eq (car (car (setq tmp (cdr (memq (cdr lap2) lap))))) - 'byte-varref) - (eq (cdr (car tmp)) (cdr lap1)) - (not (memq (car (cdr lap1)) byte-boolean-vars))) - ;;(byte-compile-log-lap " Pulled %s to end of loop" (car tmp)) - (let ((newtag (byte-compile-make-tag))) - (byte-compile-log-lap - " %s: %s ... %s %s\t-->\t%s: %s %s: ... %s %s %s" - (nth 1 (cdr lap2)) (car tmp) - lap1 lap2 - (nth 1 (cdr lap2)) (car tmp) - (nth 1 newtag) 'byte-dup lap1 - (cons 'byte-goto newtag) - ) - (setcdr rest (cons (cons 'byte-dup 0) (cdr rest))) - (setcdr tmp (cons (setcdr lap2 newtag) (cdr tmp)))) - (setq add-depth 1) - (setq keep-going t)) - ;; - ;; goto-X Y: ... X: goto-if*-Y --> goto-if-not-*-X+1 Y: - ;; (This can pull the loop test to the end of the loop) - ;; - ((and (eq (car lap0) 'byte-goto) - (eq (car lap1) 'TAG) - (eq lap1 - (cdr (car (setq tmp (cdr (memq (cdr lap0) lap)))))) - (memq (car (car tmp)) - '(byte-goto byte-goto-if-nil byte-goto-if-not-nil - byte-goto-if-nil-else-pop))) -;; (byte-compile-log-lap " %s %s, %s %s --> moved conditional" -;; lap0 lap1 (cdr lap0) (car tmp)) - (let ((newtag (byte-compile-make-tag))) - (byte-compile-log-lap - "%s %s: ... %s: %s\t-->\t%s ... %s:" - lap0 (nth 1 lap1) (nth 1 (cdr lap0)) (car tmp) - (cons (cdr (assq (car (car tmp)) - '((byte-goto-if-nil . byte-goto-if-not-nil) - (byte-goto-if-not-nil . byte-goto-if-nil) - (byte-goto-if-nil-else-pop . - byte-goto-if-not-nil-else-pop) - (byte-goto-if-not-nil-else-pop . - byte-goto-if-nil-else-pop)))) - newtag) - - (nth 1 newtag) - ) - (setcdr tmp (cons (setcdr lap0 newtag) (cdr tmp))) - (if (eq (car (car tmp)) 'byte-goto-if-nil-else-pop) - ;; We can handle this case but not the -if-not-nil case, - ;; because we won't know which non-nil constant to push. - (setcdr rest (cons (cons 'byte-constant - (byte-compile-get-constant nil)) - (cdr rest)))) - (setcar lap0 (nth 1 (memq (car (car tmp)) - '(byte-goto-if-nil-else-pop - byte-goto-if-not-nil - byte-goto-if-nil - byte-goto-if-not-nil - byte-goto byte-goto)))) - ) - (setq keep-going t)) - ) + (setcdr lap1 (car (cdr tmp))) + (setq lap (delq lap0 lap)) + (setq keep-going t)))) + ;; + ;; X: varref-Y ... varset-Y goto-X --> + ;; X: varref-Y Z: ... dup varset-Y goto-Z + ;; (varset-X goto-BACK, BACK: varref-X --> copy the varref down.) + ;; (This is so usual for while loops that it is worth handling). + ;; + ;; Here again, we could do it for stack-ref/stack-set, but + ;; that's replacing a stack-ref-Y with a stack-ref-0, which + ;; is a very minor improvement (if any), at the cost of + ;; more stack use and more byte-code. Let's not do it. + ;; + ((and (eq (car lap1) 'byte-varset) + (eq (car lap2) 'byte-goto) + (not (memq (cdr lap2) rest)) ;Backwards jump + (eq (car (car (setq tmp (cdr (memq (cdr lap2) lap))))) + 'byte-varref) + (eq (cdr (car tmp)) (cdr lap1)) + (not (memq (car (cdr lap1)) byte-boolean-vars))) + ;;(byte-compile-log-lap " Pulled %s to end of loop" (car tmp)) + (let ((newtag (byte-compile-make-tag))) + (byte-compile-log-lap + " %s: %s ... %s %s\t-->\t%s: %s %s: ... %s %s %s" + (nth 1 (cdr lap2)) (car tmp) + lap1 lap2 + (nth 1 (cdr lap2)) (car tmp) + (nth 1 newtag) 'byte-dup lap1 + (cons 'byte-goto newtag) + ) + (setcdr rest (cons (cons 'byte-dup 0) (cdr rest))) + (setcdr tmp (cons (setcdr lap2 newtag) (cdr tmp)))) + (setq add-depth 1) + (setq keep-going t)) + ;; + ;; goto-X Y: ... X: goto-if*-Y --> goto-if-not-*-X+1 Y: + ;; (This can pull the loop test to the end of the loop) + ;; + ((and (eq (car lap0) 'byte-goto) + (eq (car lap1) 'TAG) + (eq lap1 + (cdr (car (setq tmp (cdr (memq (cdr lap0) lap)))))) + (memq (car (car tmp)) + '(byte-goto byte-goto-if-nil byte-goto-if-not-nil + byte-goto-if-nil-else-pop))) + ;; (byte-compile-log-lap " %s %s, %s %s --> moved conditional" + ;; lap0 lap1 (cdr lap0) (car tmp)) + (let ((newtag (byte-compile-make-tag))) + (byte-compile-log-lap + "%s %s: ... %s: %s\t-->\t%s ... %s:" + lap0 (nth 1 lap1) (nth 1 (cdr lap0)) (car tmp) + (cons (cdr (assq (car (car tmp)) + '((byte-goto-if-nil . byte-goto-if-not-nil) + (byte-goto-if-not-nil . byte-goto-if-nil) + (byte-goto-if-nil-else-pop . + byte-goto-if-not-nil-else-pop) + (byte-goto-if-not-nil-else-pop . + byte-goto-if-nil-else-pop)))) + newtag) + + (nth 1 newtag) + ) + (setcdr tmp (cons (setcdr lap0 newtag) (cdr tmp))) + (if (eq (car (car tmp)) 'byte-goto-if-nil-else-pop) + ;; We can handle this case but not the -if-not-nil case, + ;; because we won't know which non-nil constant to push. + (setcdr rest (cons (cons 'byte-constant + (byte-compile-get-constant nil)) + (cdr rest)))) + (setcar lap0 (nth 1 (memq (car (car tmp)) + '(byte-goto-if-nil-else-pop + byte-goto-if-not-nil + byte-goto-if-nil + byte-goto-if-not-nil + byte-goto byte-goto)))) + ) + (setq keep-going t)) + + ;; + ;; stack-set-M [discard/discardN ...] --> discardN-preserve-tos + ;; stack-set-M [discard/discardN ...] --> discardN + ;; + ((and (eq (car lap0) 'byte-stack-set) + (memq (car lap1) '(byte-discard byte-discardN)) + (progn + ;; See if enough discard operations follow to expose or + ;; destroy the value stored by the stack-set. + (setq tmp (cdr rest)) + (setq tmp2 (1- (cdr lap0))) + (setq tmp3 0) + (while (memq (car (car tmp)) '(byte-discard byte-discardN)) + (setq tmp3 + (+ tmp3 (if (eq (car (car tmp)) 'byte-discard) + 1 + (cdr (car tmp))))) + (setq tmp (cdr tmp))) + (>= tmp3 tmp2))) + ;; Do the optimization. + (setq lap (delq lap0 lap)) + (setcar lap1 + (if (= tmp2 tmp3) + ;; The value stored is the new TOS, so pop one more + ;; value (to get rid of the old value) using the + ;; TOS-preserving discard operator. + 'byte-discardN-preserve-tos + ;; Otherwise, the value stored is lost, so just use a + ;; normal discard. + 'byte-discardN)) + (setcdr lap1 (1+ tmp3)) + (setcdr (cdr rest) tmp) + (byte-compile-log-lap " %s [discard/discardN]...\t-->\t%s" + lap0 lap1)) + + ;; + ;; discardN-preserve-tos return --> return + ;; dup return --> return + ;; stack-set-N return --> return ; where N is TOS-1 + ;; + ((and (eq (car lap1) 'byte-return) + (or (memq (car lap0) '(byte-discardN-preserve-tos byte-dup)) + (and (eq (car lap0) 'byte-stack-set) + (= (cdr lap0) 1)))) + (setq keep-going t) + ;; The byte-code interpreter will pop the stack for us, so + ;; we can just leave stuff on it. + (setq lap (delq lap0 lap)) + (byte-compile-log-lap " %s %s\t-->\t%s" lap0 lap1 lap1)) + + ;; + ;; goto-X ... X: discard ==> discard goto-Y ... X: discard Y: + ;; + ((and (eq (car lap0) 'byte-goto) + (setq tmp (cdr (memq (cdr lap0) lap))) + (memq (caar tmp) '(byte-discard byte-discardN + byte-discardN-preserve-tos))) + (byte-compile-log-lap + " goto-X .. X: \t-->\t%s goto-X.. X: %s Y:" + (car tmp) (car tmp)) + (setq keep-going t) + (let* ((newtag (byte-compile-make-tag)) + ;; Make a copy, since we sometimes modify insts in-place! + (newdiscard (cons (caar tmp) (cdar tmp))) + (newjmp (cons (car lap0) newtag))) + (push newtag (cdr tmp)) ;Push new tag after the discard. + (setcar rest newdiscard) + (push newjmp (cdr rest)))) + + ;; + ;; const discardN-preserve-tos ==> discardN const + ;; + ((and (eq (car lap0) 'byte-constant) + (eq (car lap1) 'byte-discardN-preserve-tos)) + (setq keep-going t) + (let ((newdiscard (cons 'byte-discardN (cdr lap1)))) + (byte-compile-log-lap + " %s %s\t-->\t%s %s" lap0 lap1 newdiscard lap0) + (setf (car rest) newdiscard) + (setf (cadr rest) lap0))) + ) (setq rest (cdr rest))) ) ;; Cleanup stage: @@ -2086,41 +2168,6 @@ If FOR-EFFECT is non-nil, the return value is assumed to be of no importance." (setcdr lap1 (+ (cdr lap1) (cdr lap0)))) ;; - ;; stack-set-M [discard/discardN ...] --> discardN-preserve-tos - ;; stack-set-M [discard/discardN ...] --> discardN - ;; - ((and (eq (car lap0) 'byte-stack-set) - (memq (car lap1) '(byte-discard byte-discardN)) - (progn - ;; See if enough discard operations follow to expose or - ;; destroy the value stored by the stack-set. - (setq tmp (cdr rest)) - (setq tmp2 (1- (cdr lap0))) - (setq tmp3 0) - (while (memq (car (car tmp)) '(byte-discard byte-discardN)) - (setq tmp3 - (+ tmp3 (if (eq (car (car tmp)) 'byte-discard) - 1 - (cdr (car tmp))))) - (setq tmp (cdr tmp))) - (>= tmp3 tmp2))) - ;; Do the optimization. - (setq lap (delq lap0 lap)) - (setcar lap1 - (if (= tmp2 tmp3) - ;; The value stored is the new TOS, so pop one more - ;; value (to get rid of the old value) using the - ;; TOS-preserving discard operator. - 'byte-discardN-preserve-tos - ;; Otherwise, the value stored is lost, so just use a - ;; normal discard. - 'byte-discardN)) - (setcdr lap1 (1+ tmp3)) - (setcdr (cdr rest) tmp) - (byte-compile-log-lap " %s [discard/discardN]...\t-->\t%s" - lap0 lap1)) - - ;; ;; discard/discardN/discardN-preserve-tos-X discard/discardN-Y --> ;; discardN-(X+Y) ;; @@ -2147,20 +2194,6 @@ If FOR-EFFECT is non-nil, the return value is assumed to be of no importance." (setq lap (delq lap0 lap)) (setcdr lap1 (+ (cdr lap0) (cdr lap1))) (byte-compile-log-lap " %s %s\t-->\t%s" lap0 lap1 (car rest))) - - ;; - ;; discardN-preserve-tos return --> return - ;; dup return --> return - ;; stack-set-N return --> return ; where N is TOS-1 - ;; - ((and (eq (car lap1) 'byte-return) - (or (memq (car lap0) '(byte-discardN-preserve-tos byte-dup)) - (and (eq (car lap0) 'byte-stack-set) - (= (cdr lap0) 1)))) - ;; The byte-code interpreter will pop the stack for us, so - ;; we can just leave stuff on it. - (setq lap (delq lap0 lap)) - (byte-compile-log-lap " %s %s\t-->\t%s" lap0 lap1 lap1)) ) (setq rest (cdr rest))) (setq byte-compile-maxdepth (+ byte-compile-maxdepth add-depth))) diff --git a/lisp/emacs-lisp/byte-run.el b/lisp/emacs-lisp/byte-run.el index 3ed299864b7..a3ad43038e7 100644 --- a/lisp/emacs-lisp/byte-run.el +++ b/lisp/emacs-lisp/byte-run.el @@ -238,8 +238,11 @@ The return value is undefined. #'(lambda (x) (let ((f (cdr (assq (car x) macro-declarations-alist)))) (if f (apply (car f) name arglist (cdr x)) - (message "Warning: Unknown macro property %S in %S" - (car x) name)))) + (macroexp--warn-and-return + (format-message + "Unknown macro property %S in %S" + (car x) name) + nil)))) decls))) ;; Refresh font-lock if this is a new macro, or it is an ;; existing macro whose 'no-font-lock-keyword declaration @@ -307,9 +310,12 @@ The return value is undefined. (cdr body) body))) nil) - (t (message "Warning: Unknown defun property `%S' in %S" - (car x) name))))) - decls)) + (t + (macroexp--warn-and-return + (format-message "Unknown defun property `%S' in %S" + (car x) name) + nil))))) + decls)) (def (list 'defalias (list 'quote name) (list 'function diff --git a/lisp/emacs-lisp/bytecomp.el b/lisp/emacs-lisp/bytecomp.el index 54f8301b085..c0f8db69e51 100644 --- a/lisp/emacs-lisp/bytecomp.el +++ b/lisp/emacs-lisp/bytecomp.el @@ -2577,7 +2577,8 @@ list that represents a doc string reference. (when (memq sym byte-compile-lexical-variables) (setq byte-compile-lexical-variables (delq sym byte-compile-lexical-variables)) - (byte-compile-warn "Variable `%S' declared after its first use" sym)) + (when (byte-compile-warning-enabled-p 'lexical sym) + (byte-compile-warn "Variable `%S' declared after its first use" sym))) (push sym byte-compile-bound-variables) (push sym byte-compile--seen-defvars)) diff --git a/lisp/emacs-lisp/checkdoc.el b/lisp/emacs-lisp/checkdoc.el index 2e204ff7aea..76638ec13b1 100644 --- a/lisp/emacs-lisp/checkdoc.el +++ b/lisp/emacs-lisp/checkdoc.el @@ -241,7 +241,12 @@ system. Possible values are: defun - Spell-check when style checking a single defun. buffer - Spell-check when style checking the whole buffer. interactive - Spell-check during any interactive check. - t - Always spell-check." + t - Always spell-check. + +There is a list of Lisp-specific words which checkdoc will +install into Ispell on the fly, but only if Ispell is not already +running. Use `ispell-kill-ispell' to make checkdoc restart it +with these words enabled." :type '(choice (const nil) (const defun) (const buffer) diff --git a/lisp/emacs-lisp/ert.el b/lisp/emacs-lisp/ert.el index 58517549454..fdbf95319ff 100644 --- a/lisp/emacs-lisp/ert.el +++ b/lisp/emacs-lisp/ert.el @@ -487,7 +487,7 @@ Errors during evaluation are caught and handled like nil." Returns nil if they are." (if (not (eq (type-of a) (type-of b))) `(different-types ,a ,b) - (pcase-exhaustive a + (pcase a ((pred consp) (let ((a-length (proper-list-p a)) (b-length (proper-list-p b))) @@ -538,7 +538,7 @@ Returns nil if they are." for xi = (ert--explain-equal-rec ai bi) do (when xi (cl-return `(array-elt ,i ,xi))) finally (cl-assert (equal a b) t)))) - ((pred atom) + (_ (if (not (equal a b)) (if (and (symbolp a) (symbolp b) (string= a b)) `(different-symbols-with-the-same-name ,a ,b) diff --git a/lisp/emacs-lisp/macroexp.el b/lisp/emacs-lisp/macroexp.el index 37844977f8f..aa49bccc8d0 100644 --- a/lisp/emacs-lisp/macroexp.el +++ b/lisp/emacs-lisp/macroexp.el @@ -127,7 +127,7 @@ and also to avoid outputting the warning during normal execution." (cond ((null msg) form) ((macroexp--compiling-p) - (if (gethash form macroexp--warned) + (if (and (consp form) (gethash form macroexp--warned)) ;; Already wrapped this exp with a warning: avoid inf-looping ;; where we keep adding the same warning onto `form' because ;; macroexpand-all gets right back to macroexpanding `form'. @@ -138,9 +138,10 @@ and also to avoid outputting the warning during normal execution." ,form))) (t (unless compile-only - (message "%s%s" (if (stringp load-file-name) - (concat (file-relative-name load-file-name) ": ") - "") + (message "%sWarning: %s" + (if (stringp load-file-name) + (concat (file-relative-name load-file-name) ": ") + "") msg)) form)))) @@ -180,8 +181,9 @@ and also to avoid outputting the warning during normal execution." (defun macroexp-macroexpand (form env) "Like `macroexpand' but checking obsolescence." - (let ((new-form - (macroexpand form env))) + (let* ((macroexpand-all-environment env) + (new-form + (macroexpand form env))) (if (and (not (eq form new-form)) ;It was a macro call. (car-safe form) (symbolp (car form)) diff --git a/lisp/emacs-lisp/package.el b/lisp/emacs-lisp/package.el index 125fbe09961..9f155bad394 100644 --- a/lisp/emacs-lisp/package.el +++ b/lisp/emacs-lisp/package.el @@ -3288,9 +3288,9 @@ To unhide a package, type `\\[customize-variable] RET package-hidden-regexps'. Type \\[package-menu-toggle-hiding] to toggle package hiding." + (declare (interactive-only "change `package-hidden-regexps' instead.")) (interactive) (package--ensure-package-menu-mode) - (declare (interactive-only "change `package-hidden-regexps' instead.")) (let* ((name (when (derived-mode-p 'package-menu-mode) (concat "\\`" (regexp-quote (symbol-name (package-desc-name (tabulated-list-get-id)))) diff --git a/lisp/emacs-lisp/pcase.el b/lisp/emacs-lisp/pcase.el index 72ea1ba0188..bfd577c5d14 100644 --- a/lisp/emacs-lisp/pcase.el +++ b/lisp/emacs-lisp/pcase.el @@ -39,10 +39,10 @@ ;; - along these lines, provide patterns to match CL structs. ;; - provide something like (setq VAR) so a var can be set rather than ;; let-bound. -;; - provide a way to fallthrough to subsequent cases (not sure what I meant by -;; this :-() +;; - provide a way to fallthrough to subsequent cases +;; (e.g. Like Racket's (=> ID). ;; - try and be more clever to reduce the size of the decision tree, and -;; to reduce the number of leaves that need to be turned into function: +;; to reduce the number of leaves that need to be turned into functions: ;; - first, do the tests shared by all remaining branches (it will have ;; to be performed anyway, so better do it first so it's shared). ;; - then choose the test that discriminates more (?). @@ -97,11 +97,15 @@ (declare-function get-edebug-spec "edebug" (symbol)) (declare-function edebug-match "edebug" (cursor specs)) +(defun pcase--get-macroexpander (s) + "Return the macroexpander for pcase pattern head S, or nil" + (get s 'pcase-macroexpander)) + (defun pcase--edebug-match-macro (cursor) (let (specs) (mapatoms (lambda (s) - (let ((m (get s 'pcase-macroexpander))) + (let ((m (pcase--get-macroexpander s))) (when (and m (get-edebug-spec m)) (push (cons (symbol-name s) (get-edebug-spec m)) specs))))) @@ -128,6 +132,7 @@ PATTERN matches. PATTERN can take one of the forms: If a SYMBOL is used twice in the same pattern the second occurrence becomes an `eq'uality test. (pred FUN) matches if FUN called on EXPVAL returns non-nil. + (pred (not FUN)) matches if FUN called on EXPVAL returns nil. (app FUN PAT) matches if FUN called on EXPVAL matches PAT. (guard BOOLEXP) matches if BOOLEXP evaluates to non-nil. (let PAT EXPR) matches if EXPR matches PAT. @@ -193,7 +198,7 @@ Emacs Lisp manual for more information and examples." (let (more) ;; Collect all the extensions. (mapatoms (lambda (symbol) - (let ((me (get symbol 'pcase-macroexpander))) + (let ((me (pcase--get-macroexpander symbol))) (when me (push (cons symbol me) more))))) @@ -424,7 +429,7 @@ of the elements of LIST is performed as if by `pcase-let'. ((eq head 'let) `(let ,(pcase--macroexpand (cadr pat)) ,@(cddr pat))) ((eq head 'app) `(app ,(nth 1 pat) ,(pcase--macroexpand (nth 2 pat)))) (t - (let* ((expander (get head 'pcase-macroexpander)) + (let* ((expander (pcase--get-macroexpander head)) (npat (if expander (apply expander (cdr pat))))) (if (null npat) (error (if expander @@ -658,6 +663,14 @@ MATCH is the pattern that needs to be matched, of the form: '(:pcase--succeed . nil)))) (defun pcase--split-pred (vars upat pat) + "Indicate the overlap or mutual-exclusion between UPAT and PAT. +More specifically retuns a pair (A . B) where A indicates whether PAT +can match when UPAT has matched, and B does the same for the case +where UPAT failed to match. +A and B can be one of: +- nil if we don't know +- `:pcase--fail' if UPAT match's result implies that PAT can't match +- `:pcase--succeed' if UPAT match's result implies that PAT matches" (let (test) (cond ((and (equal upat pat) @@ -670,6 +683,19 @@ MATCH is the pattern that needs to be matched, of the form: ;; and catch at least the easy cases such as (bug#14773). (not (macroexp--fgrep (mapcar #'car vars) (cadr upat))))) '(:pcase--succeed . :pcase--fail)) + ;; In case UPAT is of the form (pred (not PRED)) + ((and (eq 'pred (car upat)) (eq 'not (car-safe (cadr upat)))) + (let* ((test (cadr (cadr upat))) + (res (pcase--split-pred vars `(pred ,test) pat))) + (cons (cdr res) (car res)))) + ;; In case PAT is of the form (pred (not PRED)) + ((and (eq 'pred (car-safe pat)) (eq 'not (car-safe (cadr pat)))) + (let* ((test (cadr (cadr pat))) + (res (pcase--split-pred vars upat `(pred ,test))) + (reverse (lambda (x) (cond ((eq x :pcase--succeed) :pcase--fail) + ((eq x :pcase--fail) :pcase--succeed))))) + (cons (funcall reverse (car res)) + (funcall reverse (cdr res))))) ((and (eq 'pred (car upat)) (let ((otherpred (cond ((eq 'pred (car-safe pat)) (cadr pat)) @@ -728,8 +754,10 @@ MATCH is the pattern that needs to be matched, of the form: (defun pcase--funcall (fun arg vars) "Build a function call to FUN with arg ARG." - (if (symbolp fun) - `(,fun ,arg) + (cond + ((symbolp fun) `(,fun ,arg)) + ((eq 'not (car-safe fun)) `(not ,(pcase--funcall (cadr fun) arg vars))) + (t (let* (;; `env' is an upper bound on the bindings we need. (env (mapcar (lambda (x) (list (car x) (cdr x))) (macroexp--fgrep vars fun))) @@ -747,7 +775,7 @@ MATCH is the pattern that needs to be matched, of the form: ;; Let's not replace `vars' in `fun' since it's ;; too difficult to do it right, instead just ;; let-bind `vars' around `fun'. - `(let* ,env ,call))))) + `(let* ,env ,call)))))) (defun pcase--eval (exp vars) "Build an expression that will evaluate EXP." diff --git a/lisp/emacs-lisp/radix-tree.el b/lisp/emacs-lisp/radix-tree.el index 6a483a6d498..0905ac608bb 100644 --- a/lisp/emacs-lisp/radix-tree.el +++ b/lisp/emacs-lisp/radix-tree.el @@ -198,9 +198,10 @@ If not found, return nil." (pcase-defmacro radix-tree-leaf (vpat) "Pattern which matches a radix-tree leaf. The pattern VPAT is matched against the leaf's carried value." - ;; FIXME: We'd like to use a negative pattern (not consp), but pcase - ;; doesn't support it. Using `atom' works but generates sub-optimal code. - `(or `(t . ,,vpat) (and (pred atom) ,vpat)))) + ;; We used to use `(pred atom)', but `pcase' doesn't understand that + ;; `atom' is equivalent to the negation of `consp' and hence generates + ;; suboptimal code. + `(or `(t . ,,vpat) (and (pred (not consp)) ,vpat)))) (defun radix-tree-iter-subtrees (tree fun) "Apply FUN to every immediate subtree of radix TREE. diff --git a/lisp/emacs-lisp/subr-x.el b/lisp/emacs-lisp/subr-x.el index b90227da42f..a4514454c0b 100644 --- a/lisp/emacs-lisp/subr-x.el +++ b/lisp/emacs-lisp/subr-x.el @@ -389,6 +389,28 @@ it makes no sense to convert it to a string using (set-buffer source-buffer) (replace-buffer-contents tmp-buffer max-secs max-costs))))))))) +(defmacro named-let (name bindings &rest body) + "Looping construct taken from Scheme. +Like `let', bind variables in BINDINGS and then evaluate BODY, +but with the twist that BODY can evaluate itself recursively by +calling NAME, where the arguments passed to NAME are used +as the new values of the bound variables in the recursive invocation." + (declare (indent 2) (debug (symbolp (&rest (symbolp form)) body))) + (require 'cl-lib) + (let ((fargs (mapcar (lambda (b) (if (consp b) (car b) b)) bindings)) + (aargs (mapcar (lambda (b) (if (consp b) (cadr b))) bindings))) + ;; According to the Scheme semantics of named let, `name' is not in scope + ;; while evaluating the expressions in `bindings', and for this reason, the + ;; "initial" function call below needs to be outside of the `cl-labels'. + ;; When the "self-tco" eliminates all recursive calls, the `cl-labels' + ;; expands to a lambda which the byte-compiler then combines with the + ;; funcall to make a `let' so we end up with a plain `while' loop and no + ;; remaining `lambda' at all. + `(funcall + (cl-labels ((,name ,fargs . ,body)) #',name) + . ,aargs))) + + (provide 'subr-x) ;;; subr-x.el ends here diff --git a/lisp/emulation/cua-gmrk.el b/lisp/emulation/cua-gmrk.el index 195bba1f317..6f6b9fce130 100644 --- a/lisp/emulation/cua-gmrk.el +++ b/lisp/emulation/cua-gmrk.el @@ -87,9 +87,11 @@ (defun cua-toggle-global-mark (stay) "Set or cancel the global marker. -When the global marker is set, CUA cut and copy commands will automatically -insert the deleted or copied text before the global marker, even when the -global marker is in another buffer. +When the global marker is set, CUA cut and copy commands will +automatically insert the inserted, deleted or copied text before +the global marker, even when the global marker is in another +buffer. + If the global marker isn't set, set the global marker at point in the current buffer. Otherwise jump to the global marker position and cancel it. With prefix argument, don't jump to global mark when canceling it." diff --git a/lisp/epa.el b/lisp/epa.el index db2b1271473..197cd92f977 100644 --- a/lisp/epa.el +++ b/lisp/epa.el @@ -359,8 +359,8 @@ DOC is documentation text to insert at the start." ;; Find the end of the documentation text at the start. ;; Set POINT to where it ends, or nil if ends at eob. - (unless (get-text-property point 'epa-list-keys) - (setq point (next-single-property-change point 'epa-list-keys))) + (unless (get-text-property point 'epa-key) + (setq point (next-single-property-change point 'epa-key))) ;; If caller specified documentation text for that, replace the old ;; documentation text (if any) with what was specified. diff --git a/lisp/facemenu.el b/lisp/facemenu.el index 2609397b0d9..dc5f8f46aba 100644 --- a/lisp/facemenu.el +++ b/lisp/facemenu.el @@ -606,9 +606,14 @@ color. The function should accept a single argument, the color name." (defun list-colors-print (list &optional callback) (let ((callback-fn - (if callback - `(lambda (button) - (funcall ,callback (button-get button 'color-name)))))) + ;; Expect CALLBACK to be a function, but allow it to be a form that + ;; evaluates to a function, for backward-compatibility. (Bug#45831) + (cond ((functionp callback) + (lambda (button) + (funcall callback (button-get button 'color-name)))) + (callback + `(lambda (button) + (funcall ,callback (button-get button 'color-name))))))) (dolist (color list) (if (consp color) (if (cdr color) diff --git a/lisp/faces.el b/lisp/faces.el index 4e98338432f..d654b1f0e2a 100644 --- a/lisp/faces.el +++ b/lisp/faces.el @@ -2199,7 +2199,7 @@ the above example." (not (funcall pred type))) ;; Strip off last hyphen and what follows, then try again (setq type - (if (setq hyphend (string-match-p "[-_][^-_]+$" type)) + (if (setq hyphend (string-match-p "[-_.][^-_.]+$" type)) (substring type 0 hyphend) nil)))) type) diff --git a/lisp/files.el b/lisp/files.el index 695afae8c56..e9be7c7e75c 100644 --- a/lisp/files.el +++ b/lisp/files.el @@ -4067,7 +4067,7 @@ Return the new variables list." (subdirs (assq 'subdirs alist))) (if (or (not subdirs) (progn - (setq alist (delq subdirs alist)) + (setq alist (remq subdirs alist)) (cdr-safe subdirs)) ;; TODO someone might want to extend this to allow ;; integer values for subdir, where N means diff --git a/lisp/font-lock.el b/lisp/font-lock.el index a51434c38c9..a9fc69d419a 100644 --- a/lisp/font-lock.el +++ b/lisp/font-lock.el @@ -1104,8 +1104,8 @@ Called with two arguments BEG and END.") "Reinitialize the font-lock machinery and (re-)fontify the buffer. This functions is a convenience functions when developing font locking for a mode, and is not meant to be called from lisp functions." - (interactive) (declare (interactive-only t)) + (interactive) ;; Make font-lock recalculate all the mode-specific data. (setq font-lock-major-mode nil) ;; Make the syntax machinery discard all information. diff --git a/lisp/frame.el b/lisp/frame.el index e2d7f21a498..06aab269ddd 100644 --- a/lisp/frame.el +++ b/lisp/frame.el @@ -2552,13 +2552,15 @@ Use 0 or negative value to blink forever." This starts the timer `blink-cursor-timer', which makes the cursor blink if appropriate. It also arranges to cancel that timer when the next command starts, by installing a pre-command hook." - (when (null blink-cursor-timer) + (cond + ((null blink-cursor-mode) (blink-cursor-mode -1)) + ((null blink-cursor-timer) ;; Set up the timer first, so that if this signals an error, ;; blink-cursor-end is not added to pre-command-hook. (setq blink-cursor-blinks-done 1) (blink-cursor--start-timer) (add-hook 'pre-command-hook #'blink-cursor-end) - (internal-show-cursor nil nil))) + (internal-show-cursor nil nil)))) (defun blink-cursor-timer-function () "Timer function of timer `blink-cursor-timer'." @@ -2615,7 +2617,7 @@ stopped by `blink-cursor-suspend'. Internally calls `blink-cursor--should-blink' and returns its result." (let ((should-blink (blink-cursor--should-blink))) (when (and should-blink (not blink-cursor-idle-timer)) - (remove-hook 'post-command-hook 'blink-cursor-check) + (remove-hook 'post-command-hook #'blink-cursor-check) (blink-cursor--start-idle-timer)) should-blink)) @@ -2637,16 +2639,16 @@ This command is effective only on graphical frames. On text-only terminals, cursor blinking is controlled by the terminal." :init-value (not (or noninteractive no-blinking-cursor - (eq system-type 'ms-dos) - (not (display-blink-cursor-p)))) - :initialize 'custom-initialize-delay + (eq system-type 'ms-dos))) + :initialize #'custom-initialize-delay :group 'cursor :global t (blink-cursor-suspend) (remove-hook 'after-delete-frame-functions #'blink-cursor--rescan-frames) (remove-function after-focus-change-function #'blink-cursor--rescan-frames) (when blink-cursor-mode - (add-function :after after-focus-change-function #'blink-cursor--rescan-frames) + (add-function :after after-focus-change-function + #'blink-cursor--rescan-frames) (add-hook 'after-delete-frame-functions #'blink-cursor--rescan-frames) (blink-cursor-check))) diff --git a/lisp/gnus/gnus-agent.el b/lisp/gnus/gnus-agent.el index 56640ea8302..686623029ed 100644 --- a/lisp/gnus/gnus-agent.el +++ b/lisp/gnus/gnus-agent.el @@ -1789,6 +1789,7 @@ variables. Returns the first non-nil value found." . gnus-agent-enable-expiration) (agent-predicate . gnus-agent-predicate))))))) +;; FIXME: This looks an awful lot like `gnus-agent-retrieve-headers'. (defun gnus-agent-fetch-headers (group) "Fetch interesting headers into the agent. The group's overview file will be updated to include the headers while a list of available @@ -1810,10 +1811,9 @@ article numbers will be returned." (cdr active)))) (gnus-uncompress-range (gnus-active group))) (gnus-list-of-unread-articles group))) - (gnus-decode-encoded-word-function 'identity) - (gnus-decode-encoded-address-function 'identity) (file (gnus-agent-article-name ".overview" group)) - (file-name-coding-system nnmail-pathname-coding-system)) + (file-name-coding-system nnmail-pathname-coding-system) + headers fetched-headers) (unless fetch-all ;; Add articles with marks to the list of article headers we want to @@ -1824,7 +1824,7 @@ article numbers will be returned." (dolist (arts (gnus-info-marks (gnus-get-info group))) (unless (memq (car arts) '(seen recent killed cache)) (setq articles (gnus-range-add articles (cdr arts))))) - (setq articles (sort (gnus-uncompress-sequence articles) '<))) + (setq articles (sort (gnus-uncompress-range articles) '<))) ;; At this point, I have the list of articles to consider for ;; fetching. This is the list that I'll return to my caller. Some @@ -1867,38 +1867,52 @@ article numbers will be returned." 10 "gnus-agent-fetch-headers: undownloaded articles are `%s'" (gnus-compress-sequence articles t))) - (with-current-buffer nntp-server-buffer - (if articles - (progn - (gnus-message 8 "Fetching headers for %s..." group) - - ;; Fetch them. - (gnus-make-directory (nnheader-translate-file-chars - (file-name-directory file) t)) - - (unless (eq 'nov (gnus-retrieve-headers articles group)) - (nnvirtual-convert-headers)) - (gnus-agent-check-overview-buffer) - ;; Move these headers to the overview buffer so that - ;; gnus-agent-braid-nov can merge them with the contents - ;; of FILE. - (copy-to-buffer - gnus-agent-overview-buffer (point-min) (point-max)) - ;; NOTE: Call g-a-brand-nov even when the file does not - ;; exist. As a minimum, it will validate the article - ;; numbers already in the buffer. - (gnus-agent-braid-nov articles file) - (let ((coding-system-for-write - gnus-agent-file-coding-system)) - (gnus-agent-check-overview-buffer) - (write-region (point-min) (point-max) file nil 'silent)) - (gnus-agent-update-view-total-fetched-for group t) - (gnus-agent-save-alist group articles nil) - articles) - (ignore-errors - (erase-buffer) - (nnheader-insert-file-contents file))))) - articles)) + ;; Parse known headers from FILE. + (if (file-exists-p file) + (with-current-buffer gnus-agent-overview-buffer + (erase-buffer) + (let ((nnheader-file-coding-system + gnus-agent-file-coding-system)) + (nnheader-insert-nov-file file (car articles)) + (with-current-buffer nntp-server-buffer + (erase-buffer) + (insert-buffer-substring gnus-agent-overview-buffer) + (setq headers + (gnus-get-newsgroup-headers-xover + articles nil (buffer-local-value + 'gnus-newsgroup-dependencies + gnus-summary-buffer) + gnus-newsgroup-name))))) + (gnus-make-directory (nnheader-translate-file-chars + (file-name-directory file) t))) + + ;; Fetch our new headers. + (gnus-message 8 "Fetching headers for %s..." group) + (if articles + (setq fetched-headers (gnus-fetch-headers articles))) + + ;; Merge two sets of headers. + (setq headers + (if (and headers fetched-headers) + (delete-dups + (sort (append headers (copy-sequence fetched-headers)) + (lambda (l r) + (< (mail-header-number l) + (mail-header-number r))))) + (or headers fetched-headers))) + + ;; Save the new set of headers to FILE. + (let ((coding-system-for-write + gnus-agent-file-coding-system)) + (with-current-buffer gnus-agent-overview-buffer + (goto-char (point-max)) + (mapc #'nnheader-insert-nov fetched-headers) + (sort-numeric-fields 1 (point-min) (point-max)) + (gnus-agent-check-overview-buffer) + (write-region (point-min) (point-max) file nil 'silent)) + (gnus-agent-update-view-total-fetched-for group t) + (gnus-agent-save-alist group articles nil))) + headers)) (defsubst gnus-agent-read-article-number () "Read the article number at point. @@ -1924,96 +1938,6 @@ Return nil when a valid article number can not be read." (set-buffer nntp-server-buffer) (insert-buffer-substring gnus-agent-overview-buffer b e)))) -(defun gnus-agent-braid-nov (articles file) - "Merge agent overview data with given file. -Takes unvalidated headers for ARTICLES from -`gnus-agent-overview-buffer' and validated headers from the given -FILE and places the combined valid headers into -`nntp-server-buffer'. This function can be used, when file -doesn't exist, to valid the overview buffer." - (let (start last) - (set-buffer gnus-agent-overview-buffer) - (goto-char (point-min)) - (set-buffer nntp-server-buffer) - (erase-buffer) - (when (file-exists-p file) - (nnheader-insert-file-contents file)) - (goto-char (point-max)) - (forward-line -1) - - (unless (or (= (point-min) (point-max)) - (< (setq last (read (current-buffer))) (car articles))) - ;; Old and new overlap -- We do it the hard way. - (when (nnheader-find-nov-line (car articles)) - ;; Replacing existing NOV entry - (delete-region (point) (progn (forward-line 1) (point)))) - (gnus-agent-copy-nov-line (pop articles)) - - (ignore-errors - (while articles - (while (let ((art (read (current-buffer)))) - (cond ((< art (car articles)) - (forward-line 1) - t) - ((= art (car articles)) - (beginning-of-line) - (delete-region - (point) (progn (forward-line 1) (point))) - nil) - (t - (beginning-of-line) - nil)))) - - (gnus-agent-copy-nov-line (pop articles))))) - - (goto-char (point-max)) - - ;; Append the remaining lines - (when articles - (when last - (set-buffer gnus-agent-overview-buffer) - (setq start (point)) - (set-buffer nntp-server-buffer)) - - (let ((p (point))) - (insert-buffer-substring gnus-agent-overview-buffer start) - (goto-char p)) - - (setq last (or last -134217728)) - (while (catch 'problems - (let (sort art) - (while (not (eobp)) - (setq art (gnus-agent-read-article-number)) - (cond ((not art) - ;; Bad art num - delete this line - (beginning-of-line) - (delete-region (point) (progn (forward-line 1) (point)))) - ((< art last) - ;; Art num out of order - enable sort - (setq sort t) - (forward-line 1)) - ((= art last) - ;; Bad repeat of art number - delete this line - (beginning-of-line) - (delete-region (point) (progn (forward-line 1) (point)))) - (t - ;; Good art num - (setq last art) - (forward-line 1)))) - (when sort - ;; something is seriously wrong as we simply shouldn't see out-of-order data. - ;; First, we'll fix the sort. - (sort-numeric-fields 1 (point-min) (point-max)) - - ;; but now we have to consider that we may have duplicate rows... - ;; so reset to beginning of file - (goto-char (point-min)) - (setq last -134217728) - - ;; and throw a code that restarts this scan - (throw 'problems t)) - nil)))))) - ;; Keeps the compiler from warning about the free variable in ;; gnus-agent-read-agentview. (defvar gnus-agent-read-agentview) @@ -2386,10 +2310,9 @@ modified) original contents, they are first saved to their own file." (gnus-orphan-score gnus-orphan-score) ;; Maybe some other gnus-summary local variables should also ;; be put here. - + fetched-headers gnus-headers gnus-score - articles predicate info marks ) (unless (gnus-check-group group) @@ -2410,38 +2333,35 @@ modified) original contents, they are first saved to their own file." (setq info (gnus-get-info group))))))) (when arts (setq marked-articles (nconc (gnus-uncompress-range arts) - marked-articles)) - )))) + marked-articles)))))) (setq marked-articles (sort marked-articles '<)) - ;; Fetch any new articles from the server - (setq articles (gnus-agent-fetch-headers group)) + (setq gnus-newsgroup-dependencies + (or gnus-newsgroup-dependencies + (gnus-make-hashtable))) - ;; Merge new articles with marked - (setq articles (sort (append marked-articles articles) '<)) + ;; Fetch headers for any new articles from the server. + (setq fetched-headers (gnus-agent-fetch-headers group)) - (when articles - ;; Parse them and see which articles we want to fetch. - (setq gnus-newsgroup-dependencies - (or gnus-newsgroup-dependencies - (gnus-make-hashtable (length articles)))) + (when fetched-headers (setq gnus-newsgroup-headers - (or gnus-newsgroup-headers - (gnus-get-newsgroup-headers-xover articles nil nil - group))) - ;; `gnus-agent-overview-buffer' may be killed for - ;; timeout reason. If so, recreate it. + (or gnus-newsgroup-headers + fetched-headers))) + (when marked-articles + ;; `gnus-agent-overview-buffer' may be killed for timeout + ;; reason. If so, recreate it. (gnus-agent-create-buffer) (setq predicate - (gnus-get-predicate - (gnus-agent-find-parameter group 'agent-predicate))) + (gnus-get-predicate + (gnus-agent-find-parameter group 'agent-predicate))) + + ;; If the selection predicate requires scoring, score each header. - ;; If the selection predicate requires scoring, score each header (unless (memq predicate '(gnus-agent-true gnus-agent-false)) (let ((score-param (gnus-agent-find-parameter group 'agent-score-file))) - ;; Translate score-param into real one + ;; Translate score-param into real one. (cond ((not score-param)) ((eq score-param 'file) @@ -3661,11 +3581,9 @@ has been fetched." (defun gnus-agent-retrieve-headers (articles group &optional fetch-old) (save-excursion (gnus-agent-create-buffer) - (let ((gnus-decode-encoded-word-function 'identity) - (gnus-decode-encoded-address-function 'identity) - (file (gnus-agent-article-name ".overview" group)) - uncached-articles - (file-name-coding-system nnmail-pathname-coding-system)) + (let ((file (gnus-agent-article-name ".overview" group)) + (file-name-coding-system nnmail-pathname-coding-system) + uncached-articles headers fetched-headers) (gnus-make-directory (nnheader-translate-file-chars (file-name-directory file) t)) @@ -3676,122 +3594,63 @@ has been fetched." 1) (car (last articles)))))) - ;; Populate temp buffer with known headers + ;; See if we've got cached headers for ARTICLES and put them in + ;; HEADERS. Articles with no cached headers go in + ;; UNCACHED-ARTICLES to be fetched from the server. (when (file-exists-p file) (with-current-buffer gnus-agent-overview-buffer (erase-buffer) (let ((nnheader-file-coding-system gnus-agent-file-coding-system)) - (nnheader-insert-nov-file file (car articles))))) - - (if (setq uncached-articles (gnus-agent-uncached-articles articles group - t)) - (progn - ;; Populate nntp-server-buffer with uncached headers - (set-buffer nntp-server-buffer) - (erase-buffer) - (cond ((not (eq 'nov (let (gnus-agent) ; Turn off agent - (gnus-retrieve-headers - uncached-articles group)))) - (nnvirtual-convert-headers)) - ((eq 'nntp (car gnus-current-select-method)) - ;; The author of gnus-get-newsgroup-headers-xover - ;; reports that the XOVER command is commonly - ;; unreliable. The problem is that recently - ;; posted articles may not be entered into the - ;; NOV database in time to respond to my XOVER - ;; query. - ;; - ;; I'm going to use his assumption that the NOV - ;; database is updated in order of ascending - ;; article ID. Therefore, a response containing - ;; article ID N implies that all articles from 1 - ;; to N-1 are up-to-date. Therefore, missing - ;; articles in that range have expired. - - (set-buffer nntp-server-buffer) - (let* ((fetched-articles (list nil)) - (tail-fetched-articles fetched-articles) - (min (car articles)) - (max (car (last articles)))) - - ;; Get the list of articles that were fetched - (goto-char (point-min)) - (let ((pm (point-max)) - art) - (while (< (point) pm) - (when (setq art (gnus-agent-read-article-number)) - (gnus-agent-append-to-list tail-fetched-articles art)) - (forward-line 1))) - - ;; Clip this list to the headers that will - ;; actually be returned - (setq fetched-articles (gnus-list-range-intersection - (cdr fetched-articles) - (cons min max))) - - ;; Clip the uncached articles list to exclude - ;; IDs after the last FETCHED header. The - ;; excluded IDs may be fetchable using HEAD. - (if (car tail-fetched-articles) - (setq uncached-articles - (gnus-list-range-intersection - uncached-articles - (cons (car uncached-articles) - (car tail-fetched-articles))))) - - ;; Create the list of articles that were - ;; "successfully" fetched. Success, in this - ;; case, means that the ID should not be - ;; fetched again. In the case of an expired - ;; article, the header will not be fetched. - (setq uncached-articles - (gnus-sorted-nunion fetched-articles - uncached-articles)) - ))) - - ;; Erase the temp buffer - (set-buffer gnus-agent-overview-buffer) - (erase-buffer) - - ;; Copy the nntp-server-buffer to the temp buffer - (set-buffer nntp-server-buffer) - (copy-to-buffer gnus-agent-overview-buffer (point-min) (point-max)) - - ;; Merge the temp buffer with the known headers (found on - ;; disk in FILE) into the nntp-server-buffer - (when uncached-articles - (gnus-agent-braid-nov uncached-articles file)) - - ;; Save the new set of known headers to FILE - (set-buffer nntp-server-buffer) + (nnheader-insert-nov-file file (car articles)) + (with-current-buffer nntp-server-buffer + (erase-buffer) + (insert-buffer-substring gnus-agent-overview-buffer) + (setq headers + (gnus-get-newsgroup-headers-xover + articles nil (buffer-local-value + 'gnus-newsgroup-dependencies + gnus-summary-buffer) + gnus-newsgroup-name)))))) + + (setq uncached-articles + (gnus-agent-uncached-articles articles group t)) + + (when uncached-articles + (let ((gnus-newsgroup-name group) + gnus-agent) ; Prevent loop. + ;; Fetch additional headers for the uncached articles. + (setq fetched-headers (gnus-fetch-headers uncached-articles)) + ;; Merge headers we got from the overview file with our + ;; newly-fetched headers. + (when fetched-headers + (setq headers + (delete-dups + (sort (append headers (copy-sequence fetched-headers)) + (lambda (l r) + (< (mail-header-number l) + (mail-header-number r)))))) + + ;; Add the new set of known headers to the overview file. (let ((coding-system-for-write gnus-agent-file-coding-system)) - (gnus-agent-check-overview-buffer) - (write-region (point-min) (point-max) file nil 'silent)) - - (gnus-agent-update-view-total-fetched-for group t) - - ;; Update the group's article alist to include the newly - ;; fetched articles. - (gnus-agent-load-alist group) - (gnus-agent-save-alist group uncached-articles nil) - ) - - ;; Copy the temp buffer to the nntp-server-buffer - (set-buffer nntp-server-buffer) - (erase-buffer) - (insert-buffer-substring gnus-agent-overview-buffer))) - - (if (and fetch-old - (not (numberp fetch-old))) - t ; Don't remove anything. - (nnheader-nov-delete-outside-range - (car articles) - (car (last articles))) - t) - - 'nov)) + (with-current-buffer gnus-agent-overview-buffer + ;; We stick the new headers in at the end, then + ;; re-sort the whole buffer with + ;; `sort-numeric-fields'. If this turns out to be + ;; slow, we could consider a loop to add the headers + ;; in sorted order to begin with. + (goto-char (point-max)) + (mapc #'nnheader-insert-nov fetched-headers) + (sort-numeric-fields 1 (point-min) (point-max)) + (gnus-agent-check-overview-buffer) + (write-region (point-min) (point-max) file nil 'silent) + (gnus-agent-update-view-total-fetched-for group t) + ;; Update the group's article alist to include the + ;; newly fetched articles. + (gnus-agent-load-alist group) + (gnus-agent-save-alist group uncached-articles nil)))))) + headers))) (defun gnus-agent-request-article (article group) "Retrieve ARTICLE in GROUP from the agent cache." diff --git a/lisp/gnus/gnus-async.el b/lisp/gnus/gnus-async.el index fefd02c7bfb..ed948a26c0b 100644 --- a/lisp/gnus/gnus-async.el +++ b/lisp/gnus/gnus-async.el @@ -357,8 +357,13 @@ that was fetched." (let ((nntp-server-buffer (current-buffer)) (nnheader-callback-function (lambda (_arg) - (setq gnus-async-header-prefetched - (cons group unread))))) + (setq gnus-async-header-prefetched + (cons group unread))))) + ;; FIXME: If header prefetch is ever put into use, we'll + ;; have to handle the possibility that + ;; `gnus-retrieve-headers' might return a list of header + ;; vectors directly, rather than writing them into the + ;; current buffer. (gnus-retrieve-headers unread group gnus-fetch-old-headers)))))) (defun gnus-async-retrieve-fetched-headers (articles group) diff --git a/lisp/gnus/gnus-cache.el b/lisp/gnus/gnus-cache.el index 36657e46219..9423d9f2f6b 100644 --- a/lisp/gnus/gnus-cache.el +++ b/lisp/gnus/gnus-cache.el @@ -294,49 +294,47 @@ it's not cached." (defun gnus-cache-retrieve-headers (articles group &optional fetch-old) "Retrieve the headers for ARTICLES in GROUP." (let ((cached - (setq gnus-newsgroup-cached (gnus-cache-articles-in-group group)))) + (setq gnus-newsgroup-cached (gnus-cache-articles-in-group group))) + (gnus-newsgroup-name group) + (gnus-fetch-old-headers fetch-old)) (if (not cached) ;; No cached articles here, so we just retrieve them ;; the normal way. (let ((gnus-use-cache nil)) - (gnus-retrieve-headers articles group fetch-old)) + (gnus-retrieve-headers articles group)) (let ((uncached-articles (gnus-sorted-difference articles cached)) (cache-file (gnus-cache-file-name group ".overview")) - type - (file-name-coding-system nnmail-pathname-coding-system)) + (file-name-coding-system nnmail-pathname-coding-system) + headers) ;; We first retrieve all the headers that we don't have in ;; the cache. (let ((gnus-use-cache nil)) (when uncached-articles - (setq type (and articles - (gnus-retrieve-headers - uncached-articles group fetch-old))))) + (setq headers (and articles + (gnus-fetch-headers uncached-articles))))) (gnus-cache-save-buffers) - ;; Then we insert the cached headers. - (save-excursion - (cond - ((not (file-exists-p cache-file)) - ;; There are no cached headers. - type) - ((null type) - ;; There were no uncached headers (or retrieval was - ;; unsuccessful), so we use the cached headers exclusively. - (set-buffer nntp-server-buffer) - (erase-buffer) - (let ((coding-system-for-read - gnus-cache-overview-coding-system)) - (insert-file-contents cache-file)) - 'nov) - ((eq type 'nov) - ;; We have both cached and uncached NOV headers, so we - ;; braid them. - (gnus-cache-braid-nov group cached) - type) - (t - ;; We braid HEADs. - (gnus-cache-braid-heads group (gnus-sorted-intersection - cached articles)) - type))))))) + ;; Then we include the cached headers. + (when (file-exists-p cache-file) + (setq headers + (delete-dups + (sort + (append headers + (let ((coding-system-for-read + gnus-cache-overview-coding-system)) + (with-current-buffer nntp-server-buffer + (erase-buffer) + (insert-file-contents cache-file) + (gnus-get-newsgroup-headers-xover + (gnus-sorted-difference + cached uncached-articles) + nil (buffer-local-value + 'gnus-newsgroup-dependencies + gnus-summary-buffer) + group)))) + (lambda (l r) + (< (mail-header-number l) + (mail-header-number r))))))) + headers)))) (defun gnus-cache-enter-article (&optional n) "Enter the next N articles into the cache. @@ -529,70 +527,6 @@ Returns the list of articles removed." (setq gnus-cache-active-altered t))) articles))) -(defun gnus-cache-braid-nov (group cached &optional file) - (let ((cache-buf (gnus-get-buffer-create " *gnus-cache*")) - beg end) - (gnus-cache-save-buffers) - (with-current-buffer cache-buf - (erase-buffer) - (let ((coding-system-for-read gnus-cache-overview-coding-system) - (file-name-coding-system nnmail-pathname-coding-system)) - (insert-file-contents - (or file (gnus-cache-file-name group ".overview")))) - (goto-char (point-min)) - (insert "\n") - (goto-char (point-min))) - (set-buffer nntp-server-buffer) - (goto-char (point-min)) - (while cached - (while (and (not (eobp)) - (< (read (current-buffer)) (car cached))) - (forward-line 1)) - (beginning-of-line) - (set-buffer cache-buf) - (if (search-forward (concat "\n" (int-to-string (car cached)) "\t") - nil t) - (setq beg (point-at-bol) - end (progn (end-of-line) (point))) - (setq beg nil)) - (set-buffer nntp-server-buffer) - (when beg - (insert-buffer-substring cache-buf beg end) - (insert "\n")) - (setq cached (cdr cached))) - (kill-buffer cache-buf))) - -(defun gnus-cache-braid-heads (group cached) - (let ((cache-buf (gnus-get-buffer-create " *gnus-cache*"))) - (with-current-buffer cache-buf - (erase-buffer)) - (set-buffer nntp-server-buffer) - (goto-char (point-min)) - (dolist (entry cached) - (while (and (not (eobp)) - (looking-at "2.. +\\([0-9]+\\) ") - (< (progn (goto-char (match-beginning 1)) - (read (current-buffer))) - entry)) - (search-forward "\n.\n" nil 'move)) - (beginning-of-line) - (set-buffer cache-buf) - (erase-buffer) - (let ((coding-system-for-read gnus-cache-coding-system) - (file-name-coding-system nnmail-pathname-coding-system)) - (insert-file-contents (gnus-cache-file-name group entry))) - (goto-char (point-min)) - (insert "220 ") - (princ (pop cached) (current-buffer)) - (insert " Article retrieved.\n") - (search-forward "\n\n" nil 'move) - (delete-region (point) (point-max)) - (forward-char -1) - (insert ".") - (set-buffer nntp-server-buffer) - (insert-buffer-substring cache-buf)) - (kill-buffer cache-buf))) - ;;;###autoload (defun gnus-jog-cache () "Go through all groups and put the articles into the cache. diff --git a/lisp/gnus/gnus-cloud.el b/lisp/gnus/gnus-cloud.el index f7c71f43ce8..00b85f546c2 100644 --- a/lisp/gnus/gnus-cloud.el +++ b/lisp/gnus/gnus-cloud.el @@ -30,6 +30,8 @@ (require 'parse-time) (require 'nnimap) +(declare-function gnus-fetch-headers "gnus-sum") +(defvar gnus-alter-header-function) (eval-when-compile (require 'epg)) ;; setf-method for `epg-context-armor' (autoload 'epg-make-context "epg") @@ -391,8 +393,6 @@ When FULL is t, upload everything, not just a difference from the last full." (gnus-group-refresh-group group)) (gnus-error 2 "Failed to upload Gnus Cloud data to %s" group))))) -(defvar gnus-alter-header-function) - (defun gnus-cloud-add-timestamps (elems) (dolist (elem elems) (let* ((file-name (plist-get elem :file-name)) @@ -407,14 +407,10 @@ When FULL is t, upload everything, not just a difference from the last full." (gnus-activate-group gnus-cloud-group-name nil nil gnus-cloud-method) (let* ((group (gnus-group-full-name gnus-cloud-group-name gnus-cloud-method)) (active (gnus-active group)) - headers head) - (when (gnus-retrieve-headers (gnus-uncompress-range active) group) - (with-current-buffer nntp-server-buffer - (goto-char (point-min)) - (while (setq head (nnheader-parse-head)) - (when gnus-alter-header-function - (funcall gnus-alter-header-function head)) - (push head headers)))) + (gnus-newsgroup-name group) + (headers (gnus-fetch-headers (gnus-uncompress-range active)))) + (when gnus-alter-header-function + (mapc gnus-alter-header-function headers)) (sort (nreverse headers) (lambda (h1 h2) (> (gnus-cloud-chunk-sequence (mail-header-subject h1)) diff --git a/lisp/gnus/gnus-search.el b/lisp/gnus/gnus-search.el index 5c6a5b9efd0..44780609af7 100644 --- a/lisp/gnus/gnus-search.el +++ b/lisp/gnus/gnus-search.el @@ -909,6 +909,7 @@ quirks.") (defclass gnus-search-namazu (gnus-search-indexed) ((index-directory :initarg :index-directory + :initform (symbol-value 'gnus-search-namazu-index-directory) :type string :custom directory) (program diff --git a/lisp/gnus/gnus-start.el b/lisp/gnus/gnus-start.el index fbdbf41dc05..cf37a1ccdfc 100644 --- a/lisp/gnus/gnus-start.el +++ b/lisp/gnus/gnus-start.el @@ -637,7 +637,7 @@ the first newsgroup." ;; We subscribe the group by changing its level to `subscribed'. (gnus-group-change-level newsgroup gnus-level-default-subscribed - gnus-level-killed (or next "dummy.group")) + gnus-level-killed next) (gnus-request-update-group-status newsgroup 'subscribe) (gnus-message 5 "Subscribe newsgroup: %s" newsgroup) (run-hook-with-args 'gnus-subscribe-newsgroup-functions newsgroup) @@ -1282,7 +1282,8 @@ string name) to insert this group before." (gnus-dribble-enter (format "(gnus-group-change-level %S %S %S %S %S)" group level oldlevel - (cadr (member previous gnus-group-list)) + (when previous + (cadr (member previous gnus-group-list))) fromkilled))) ;; Then we remove the newgroup from any old structures, if needed. @@ -1341,9 +1342,10 @@ string name) to insert this group before." ;; at the head of `gnus-newsrc-alist'. (push info (cdr gnus-newsrc-alist)) (puthash group (list num info) gnus-newsrc-hashtb) - (when (stringp previous) + (when (and previous (stringp previous)) (setq previous (gnus-group-entry previous))) - (let ((idx (or (seq-position gnus-group-list (caadr previous)) + (let ((idx (or (and previous + (seq-position gnus-group-list (caadr previous))) (length gnus-group-list)))) (push group (nthcdr idx gnus-group-list))) (gnus-dribble-enter diff --git a/lisp/gnus/gnus-sum.el b/lisp/gnus/gnus-sum.el index b0f9ed4c6f0..5bd58b690af 100644 --- a/lisp/gnus/gnus-sum.el +++ b/lisp/gnus/gnus-sum.el @@ -5658,10 +5658,21 @@ or a straight list of headers." (setf (mail-header-subject header) subject)))))) (defun gnus-fetch-headers (articles &optional limit force-new dependencies) - "Fetch headers of ARTICLES." + "Fetch headers of ARTICLES. +This calls the `gnus-retrieve-headers' function of the current +group's backend server. The server can do one of two things: + +1. Write the headers for ARTICLES into the + `nntp-server-buffer' (the current buffer) in a parseable format, or +2. Return the headers directly as a list of vectors. + +In the first case, `gnus-retrieve-headers' returns a symbol +value, either `nov' or `headers'. This value determines which +parsing function is used to read the headers. It is also stored +into the variable `gnus-headers-retrieved-by', which is consulted +later when possibly building full threads." (gnus-message 7 "Fetching headers for %s..." gnus-newsgroup-name) - (prog1 - (pcase (setq gnus-headers-retrieved-by + (let ((res (setq gnus-headers-retrieved-by (gnus-retrieve-headers articles gnus-newsgroup-name (or limit @@ -5671,22 +5682,34 @@ or a straight list of headers." (not (eq gnus-fetch-old-headers 'some)) (not (numberp gnus-fetch-old-headers))) (> (length articles) 1)) - gnus-fetch-old-headers)))) - ('nov - (gnus-get-newsgroup-headers-xover - articles force-new dependencies gnus-newsgroup-name t)) - ('headers - (gnus-get-newsgroup-headers dependencies force-new)) - ((pred listp) - (let ((dependencies - (or dependencies - (with-current-buffer gnus-summary-buffer - gnus-newsgroup-dependencies)))) - (delq nil (mapcar #'(lambda (header) - (gnus-dependencies-add-header - header dependencies force-new)) - gnus-headers-retrieved-by))))) - (gnus-message 7 "Fetching headers for %s...done" gnus-newsgroup-name))) + gnus-fetch-old-headers)))))) + (prog1 + (pcase res + ('nov + (gnus-get-newsgroup-headers-xover + articles force-new dependencies gnus-newsgroup-name t)) + ;; For now, assume that any backend returning its own + ;; headers takes some effort to do so, so return `headers'. + ((pred listp) + (setq gnus-headers-retrieved-by 'headers) + (let ((dependencies + (or dependencies + (buffer-local-value + 'gnus-newsgroup-dependencies gnus-summary-buffer)))) + (when (functionp gnus-alter-header-function) + (mapc gnus-alter-header-function res)) + (mapc (lambda (header) + ;; The agent or the cache may have already + ;; registered this header in the dependency + ;; table. + (unless (gethash (mail-header-id header) dependencies) + (gnus-dependencies-add-header + header dependencies force-new))) + res) + res)) + (_ (gnus-get-newsgroup-headers dependencies force-new))) + (gnus-message 7 "Fetching headers for %s...done" + gnus-newsgroup-name)))) (defun gnus-select-newsgroup (group &optional read-all select-articles) "Select newsgroup GROUP. @@ -6443,6 +6466,10 @@ The resulting hash table is returned, or nil if no Xrefs were found." (unless (gnus-ephemeral-group-p group) (gnus-group-update-group group t)))))) +;; FIXME: Refactor this with `gnus-get-newsgroup-headers-xover' and +;; extract the necessary bits for the direct-header-return case. Also +;; look at this and see how similar it is to +;; `nnheader-parse-naked-head'. (defun gnus-get-newsgroup-headers (&optional dependencies force-new) (let ((dependencies (or dependencies diff --git a/lisp/gnus/gnus.el b/lisp/gnus/gnus.el index 91ab878b22f..4241f30ba9d 100644 --- a/lisp/gnus/gnus.el +++ b/lisp/gnus/gnus.el @@ -2388,7 +2388,14 @@ Typical marks are those that make no sense in a standalone back end, such as a mark that says whether an article is stored in the cache \(which doesn't make sense in a standalone back end).") -(defvar gnus-headers-retrieved-by nil) +(defvar gnus-headers-retrieved-by nil + "Holds the return value of `gnus-retrieve-headers'. +This is either the symbol `nov' or the symbol `headers'. This +value is checked during the summary creation process, when +building threads. A value of `nov' indicates that header +retrieval is relatively cheap and threading is encouraged to +include more old articles. A value of `headers' indicates that +retrieval is expensive and should be minimized.") (defvar gnus-article-reply nil) (defvar gnus-override-method nil) (defvar gnus-opened-servers nil) diff --git a/lisp/gnus/message.el b/lisp/gnus/message.el index 50e02187484..1409a4384ab 100644 --- a/lisp/gnus/message.el +++ b/lisp/gnus/message.el @@ -47,7 +47,7 @@ (require 'rfc2047) (require 'puny) (require 'rmc) ; read-multiple-choice -(eval-when-compile (require 'subr-x)) +(require 'subr-x) (autoload 'mailclient-send-it "mailclient") @@ -620,8 +620,8 @@ Done before generating the new subject of a forward." (defcustom message-forward-ignored-headers "^Content-Transfer-Encoding:\\|^X-Gnus" "All headers that match this regexp will be deleted when forwarding a message. -This variable is not consulted when forwarding encrypted messages -and `message-forward-show-mml' is `best'. +Also see `message-forward-included-headers' -- both variables are applied. +In addition, see `message-forward-included-mime-headers'. This may also be a list of regexps." :version "21.1" @@ -637,7 +637,14 @@ This may also be a list of regexps." '("^From:" "^Subject:" "^Date:" "^To:" "^Cc:") "If non-nil, delete non-matching headers when forwarding a message. Only headers that match this regexp will be included. This -variable should be a regexp or a list of regexps." +variable should be a regexp or a list of regexps. + +Also see `message-forward-ignored-headers' -- both variables are applied. +In addition, see `message-forward-included-mime-headers'. + +When forwarding messages as MIME, but when +`message-forward-show-mml' results in MML not being used, +`message-forward-included-mime-headers' take precedence." :version "27.1" :group 'message-forwarding :type '(repeat :value-to-internal (lambda (widget value) @@ -647,6 +654,24 @@ variable should be a regexp or a list of regexps." (widget-editable-list-match widget value))) regexp)) +(defcustom message-forward-included-mime-headers + '("^Content-Type:" "^MIME-Version:") + "When forwarding as MIME, but not using MML, don't delete these headers. +Also see `message-forward-ignored-headers' and +`message-forward-ignored-headers'. + +When forwarding messages as MIME, but when +`message-forward-show-mml' results in MML not being used, +`message-forward-included-mime-headers' take precedence." + :version "28.1" + :group 'message-forwarding + :type '(repeat :value-to-internal (lambda (widget value) + (custom-split-regexp-maybe value)) + :match (lambda (widget value) + (or (stringp value) + (widget-editable-list-match widget value))) + regexp)) + (defcustom message-ignored-cited-headers "." "Delete these headers from the messages you yank." :group 'message-insertion @@ -3057,22 +3082,23 @@ See also `message-forbidden-properties'." (defun message--syntax-propertize (beg end) "Syntax-propertize certain message text specially." - (let ((citation-regexp (concat "^" message-cite-prefix-regexp ".*$")) - (smiley-regexp (regexp-opt message-smileys))) - (goto-char beg) - (while (search-forward-regexp citation-regexp - end 'noerror) - (let ((start (match-beginning 0)) - (end (match-end 0))) - (add-text-properties start (1+ start) - `(syntax-table ,(string-to-syntax "<"))) - (add-text-properties end (min (1+ end) (point-max)) - `(syntax-table ,(string-to-syntax ">"))))) - (goto-char beg) - (while (search-forward-regexp smiley-regexp - end 'noerror) - (add-text-properties (match-beginning 0) (match-end 0) - `(syntax-table ,(string-to-syntax ".")))))) + (with-syntax-table message-mode-syntax-table + (let ((citation-regexp (concat "^" message-cite-prefix-regexp ".*$")) + (smiley-regexp (regexp-opt message-smileys))) + (goto-char beg) + (while (search-forward-regexp citation-regexp + end 'noerror) + (let ((start (match-beginning 0)) + (end (match-end 0))) + (add-text-properties start (1+ start) + `(syntax-table ,(string-to-syntax "<"))) + (add-text-properties end (min (1+ end) (point-max)) + `(syntax-table ,(string-to-syntax ">"))))) + (goto-char beg) + (while (search-forward-regexp smiley-regexp + end 'noerror) + (add-text-properties (match-beginning 0) (match-end 0) + `(syntax-table ,(string-to-syntax "."))))))) ;;;###autoload (define-derived-mode message-mode text-mode "Message" @@ -7616,14 +7642,28 @@ Optional DIGEST will use digest to forward." "-------------------- End of forwarded message --------------------\n") (message-remove-ignored-headers b e))) -(defun message-remove-ignored-headers (b e) +(defun message-remove-ignored-headers (b e &optional preserve-mime) (when (or message-forward-ignored-headers message-forward-included-headers) + (let ((saved-headers nil)) (save-restriction (narrow-to-region b e) (goto-char b) (narrow-to-region (point) (or (search-forward "\n\n" nil t) (point))) + ;; When forwarding as MIME, preserve some MIME headers. + (when preserve-mime + (let ((headers (buffer-string))) + (with-temp-buffer + (insert headers) + (message-remove-header + (if (listp message-forward-included-mime-headers) + (mapconcat + #'identity (cons "^$" message-forward-included-mime-headers) + "\\|") + message-forward-included-mime-headers) + t nil t) + (setq saved-headers (string-lines (buffer-string) t))))) (when message-forward-ignored-headers (let ((ignored (if (stringp message-forward-ignored-headers) (list message-forward-ignored-headers) @@ -7636,10 +7676,14 @@ Optional DIGEST will use digest to forward." (mapconcat #'identity (cons "^$" message-forward-included-headers) "\\|") message-forward-included-headers) - t nil t))))) + t nil t)) + ;; Insert the MIME headers, if any. + (goto-char (point-max)) + (forward-line -1) + (dolist (header saved-headers) + (insert header "\n")))))) -(defun message-forward-make-body-mime (forward-buffer &optional beg end - remove-headers) +(defun message-forward-make-body-mime (forward-buffer &optional beg end) (let ((b (point))) (insert "\n\n<#part type=message/rfc822 disposition=inline raw=t>\n") (save-restriction @@ -7649,8 +7693,7 @@ Optional DIGEST will use digest to forward." (goto-char (point-min)) (when (looking-at "From ") (replace-match "X-From-Line: ")) - (when remove-headers - (message-remove-ignored-headers (point-min) (point-max))) + (message-remove-ignored-headers (point-min) (point-max) t) (goto-char (point-max))) (insert "<#/part>\n") ;; Consider there is no illegible text. @@ -7789,8 +7832,7 @@ is for the internal use." (message-signed-or-encrypted-p) (error t)))))) (message-forward-make-body-mml forward-buffer) - (message-forward-make-body-mime - forward-buffer nil nil (not (eq message-forward-show-mml 'best)))) + (message-forward-make-body-mime forward-buffer)) (message-forward-make-body-plain forward-buffer))) (message-position-point)) diff --git a/lisp/gnus/nnml.el b/lisp/gnus/nnml.el index ebececa3ce2..3cdfc749703 100644 --- a/lisp/gnus/nnml.el +++ b/lisp/gnus/nnml.el @@ -769,8 +769,24 @@ article number. This function is called narrowed to an article." (let ((headers (nnheader-parse-head t))) (setf (mail-header-chars headers) chars) (setf (mail-header-number headers) number) + ;; If there's non-ASCII raw characters in the data, + ;; RFC2047-encode them to avoid having arbitrary data in the + ;; .overview file. + (nnml--encode-headers headers) headers)))) +(defun nnml--encode-headers (headers) + (let ((subject (mail-header-subject headers)) + (rfc2047-encoding-type 'mime)) + (unless (string-match "\\`[[:ascii:]]*\\'" subject) + (setf (mail-header-subject headers) + (mail-encode-encoded-word-string subject t)))) + (let ((from (mail-header-from headers)) + (rfc2047-encoding-type 'address-mime)) + (unless (string-match "\\`[[:ascii:]]*\\'" from) + (setf (mail-header-from headers) + (rfc2047-encode-string from t))))) + (defun nnml-get-nov-buffer (group &optional incrementalp) (let ((buffer (gnus-get-buffer-create (format " *nnml %soverview %s*" diff --git a/lisp/gnus/nntp.el b/lisp/gnus/nntp.el index 7e10e151a4d..c2bb960f945 100644 --- a/lisp/gnus/nntp.el +++ b/lisp/gnus/nntp.el @@ -1209,7 +1209,7 @@ If SEND-IF-FORCE, only send authinfo to the server if the (read-passwd (format "NNTP (%s@%s) password: " user nntp-address))))))) (if (not result) - (signal 'nntp-authinfo-rejected "Password rejected") + (error "Password rejected") result)))))) ;;; Internal functions. diff --git a/lisp/gnus/nnvirtual.el b/lisp/gnus/nnvirtual.el index 1e2feda6365..ba2934351d6 100644 --- a/lisp/gnus/nnvirtual.el +++ b/lisp/gnus/nnvirtual.el @@ -101,15 +101,10 @@ It is computed from the marks of individual component groups.") (erase-buffer) (if (stringp (car articles)) 'headers - (let ((vbuf (nnheader-set-temp-buffer - (gnus-get-buffer-create " *virtual headers*"))) - (carticles (nnvirtual-partition-sequence articles)) + (let ((carticles (nnvirtual-partition-sequence articles)) (sysname (system-name)) - cgroup carticle article result prefix) - (while carticles - (setq cgroup (caar carticles)) - (setq articles (cdar carticles)) - (pop carticles) + cgroup headers all-headers article prefix) + (pcase-dolist (`(,cgroup . ,articles) carticles) (when (and articles (gnus-check-server (gnus-find-method-for-group cgroup) t) @@ -119,69 +114,37 @@ It is computed from the marks of individual component groups.") ;; This is probably evil if people have set ;; gnus-use-cache to nil themselves, but I ;; have no way of finding the true value of it. - (let ((gnus-use-cache t)) - (setq result (gnus-retrieve-headers - articles cgroup nil)))) - (set-buffer nntp-server-buffer) - ;; If we got HEAD headers, we convert them into NOV - ;; headers. This is slow, inefficient and, come to think - ;; of it, downright evil. So sue me. I couldn't be - ;; bothered to write a header parse routine that could - ;; parse a mixed HEAD/NOV buffer. - (when (eq result 'headers) - (nnvirtual-convert-headers)) - (goto-char (point-min)) - (while (not (eobp)) - (delete-region (point) - (progn - (setq carticle (read nntp-server-buffer)) - (point))) - - ;; We remove this article from the articles list, if - ;; anything is left in the articles list after going through - ;; the entire buffer, then those articles have been - ;; expired or canceled, so we appropriately update the - ;; component group below. They should be coming up - ;; generally in order, so this shouldn't be slow. - (setq articles (delq carticle articles)) - - (setq article (nnvirtual-reverse-map-article cgroup carticle)) - (if (null article) - ;; This line has no reverse mapping, that means it - ;; was an extra article reference returned by nntp. - (progn - (beginning-of-line) - (delete-region (point) (progn (forward-line 1) (point)))) - ;; Otherwise insert the virtual article number, - ;; and clean up the xrefs. - (princ article nntp-server-buffer) - (nnvirtual-update-xref-header cgroup carticle - prefix sysname) - (forward-line 1)) - ) - - (set-buffer vbuf) - (goto-char (point-max)) - (insert-buffer-substring nntp-server-buffer)) - ;; Anything left in articles is expired or canceled. - ;; Could be smart and not tell it about articles already known? - (when articles - (gnus-group-make-articles-read cgroup articles)) - ) - - ;; The headers are ready for reading, so they are inserted into - ;; the nntp-server-buffer, which is where Gnus expects to find - ;; them. - (prog1 - (with-current-buffer nntp-server-buffer - (erase-buffer) - (insert-buffer-substring vbuf) - ;; FIX FIX FIX, we should be able to sort faster than - ;; this if needed, since each cgroup is sorted, we just - ;; need to merge - (sort-numeric-fields 1 (point-min) (point-max)) - 'nov) - (kill-buffer vbuf))))))) + (let ((gnus-use-cache t) + (gnus-newsgroup-name cgroup) + (gnus-fetch-old-headers nil)) + (setq headers (gnus-fetch-headers articles)))) + (erase-buffer) + ;; Remove all header article numbers from `articles'. + ;; If there's anything left, those are expired or + ;; canceled articles, so we update the component group + ;; below. + (dolist (h headers) + (setq articles (delq (mail-header-number h) articles) + article (nnvirtual-reverse-map-article + cgroup (mail-header-number h))) + ;; Update all the header numbers according to their + ;; reverse mapping, and drop any with no such mapping. + (when article + ;; Do this first, before we re-set the header's + ;; article number. + (nnvirtual-update-xref-header + h cgroup prefix sysname) + (setf (mail-header-number h) article) + (push h all-headers))) + ;; Anything left in articles is expired or canceled. + ;; Could be smart and not tell it about articles already + ;; known? + (when articles + (gnus-group-make-articles-read cgroup articles)))) + + (sort all-headers (lambda (h1 h2) + (< (mail-header-number h1) + (mail-header-number h2))))))))) (defvoo nnvirtual-last-accessed-component-group nil) @@ -372,61 +335,18 @@ It is computed from the marks of individual component groups.") ;;; Internal functions. -(defun nnvirtual-convert-headers () - "Convert HEAD headers into NOV headers." - (with-current-buffer nntp-server-buffer - (let* ((dependencies (make-hash-table :test #'equal)) - (headers (gnus-get-newsgroup-headers dependencies))) - (erase-buffer) - (mapc 'nnheader-insert-nov headers)))) - - -(defun nnvirtual-update-xref-header (group article prefix sysname) - "Edit current NOV header in current buffer to have an xref to the component group, and also server prefix any existing xref lines." - ;; Move to beginning of Xref field, creating a slot if needed. - (beginning-of-line) - (looking-at - "[^\t]*\t[^\t]*\t[^\t]*\t[^\t]*\t[^\t]*\t[^\t]*\t[^\t]*\t") - (goto-char (match-end 0)) - (unless (search-forward "\t" (point-at-eol) 'move) - (insert "\t")) - - ;; Remove any spaces at the beginning of the Xref field. - (while (eq (char-after (1- (point))) ? ) - (forward-char -1) - (delete-char 1)) - - (insert "Xref: " sysname " " group ":") - (princ article (current-buffer)) - (insert " ") - - ;; If there were existing xref lines, clean them up to have the correct - ;; component server prefix. - (save-restriction - (narrow-to-region (point) - (or (search-forward "\t" (point-at-eol) t) - (point-at-eol))) - (goto-char (point-min)) - (when (re-search-forward "Xref: *[^\n:0-9 ]+ *" nil t) - (replace-match "" t t)) - (goto-char (point-min)) - (when (re-search-forward - (concat (regexp-quote (gnus-group-real-name group)) ":[0-9]+") - nil t) - (replace-match "" t t)) - (unless (eobp) - (insert " ") - (when (not (string= "" prefix)) - (while (re-search-forward "[^ ]+:[0-9]+" nil t) - (save-excursion - (goto-char (match-beginning 0)) - (insert prefix)))))) - - ;; Ensure a trailing \t. - (end-of-line) - (or (eq (char-after (1- (point))) ?\t) - (insert ?\t))) - +(defun nnvirtual-update-xref-header (header group prefix sysname) + "Add xref to component GROUP to HEADER. +Also add a server PREFIX any existing xref lines." + (let ((bits (split-string (mail-header-xref header) + nil t "[[:blank:]]")) + (art-no (mail-header-number header))) + (setf (mail-header-xref header) + (concat + (format "%s %s:%d " sysname group art-no) + (mapconcat (lambda (bit) + (concat prefix bit)) + bits " "))))) (defun nnvirtual-possibly-change-server (server) (or (not server) diff --git a/lisp/help-fns.el b/lisp/help-fns.el index 8ce936ad164..879653057d0 100644 --- a/lisp/help-fns.el +++ b/lisp/help-fns.el @@ -1655,6 +1655,9 @@ in `describe-keymap'. See also `Searching the Active Keymaps'." (get-char-property (point) 'local-map) (current-local-map))))) +(defvar keymap-name-history nil + "History for input to `describe-keymap'.") + ;;;###autoload (defun describe-keymap (keymap) "Describe key bindings in KEYMAP. diff --git a/lisp/hl-line.el b/lisp/hl-line.el index 73870f9579e..82952e934b6 100644 --- a/lisp/hl-line.el +++ b/lisp/hl-line.el @@ -45,11 +45,7 @@ ;; An overlay is used. In the non-sticky cases, this overlay is ;; active only on the selected window. A hook is added to ;; `post-command-hook' to activate the overlay and move it to the line -;; about point. To get the non-sticky behavior, `hl-line-unhighlight' -;; is added to `pre-command-hook' as well. This function deactivates -;; the overlay unconditionally in case the command changes the -;; selected window. (It does so rather than keeping track of changes -;; in the selected window). +;; about point. ;; You could make variable `global-hl-line-mode' buffer-local and set ;; it to nil to avoid highlighting specific buffers, when the global @@ -91,9 +87,9 @@ when `global-hl-line-sticky-flag' is non-nil.") (set symbol value) (dolist (buffer (buffer-list)) (with-current-buffer buffer - (when hl-line-overlay + (when (overlayp hl-line-overlay) (overlay-put hl-line-overlay 'face hl-line-face)))) - (when global-hl-line-overlay + (when (overlayp global-hl-line-overlay) (overlay-put global-hl-line-overlay 'face hl-line-face)))) (defcustom hl-line-sticky-flag t @@ -141,9 +137,7 @@ non-selected window. Hl-Line mode uses the function `hl-line-highlight' on `post-command-hook' in this case. When `hl-line-sticky-flag' is nil, Hl-Line mode highlights the -line about point in the selected window only. In this case, it -uses the function `hl-line-maybe-unhighlight' in -addition to `hl-line-highlight' on `post-command-hook'." +line about point in the selected window only." :group 'hl-line (if hl-line-mode (progn @@ -151,12 +145,10 @@ addition to `hl-line-highlight' on `post-command-hook'." (add-hook 'change-major-mode-hook #'hl-line-unhighlight nil t) (hl-line-highlight) (setq hl-line-overlay-buffer (current-buffer)) - (add-hook 'post-command-hook #'hl-line-highlight nil t) - (add-hook 'post-command-hook #'hl-line-maybe-unhighlight nil t)) + (add-hook 'post-command-hook #'hl-line-highlight nil t)) (remove-hook 'post-command-hook #'hl-line-highlight t) (hl-line-unhighlight) - (remove-hook 'change-major-mode-hook #'hl-line-unhighlight t) - (remove-hook 'post-command-hook #'hl-line-maybe-unhighlight t))) + (remove-hook 'change-major-mode-hook #'hl-line-unhighlight t))) (defun hl-line-make-overlay () (let ((ol (make-overlay (point) (point)))) @@ -168,17 +160,19 @@ addition to `hl-line-highlight' on `post-command-hook'." "Activate the Hl-Line overlay on the current line." (if hl-line-mode ; Might be changed outside the mode function. (progn - (unless hl-line-overlay + (unless (overlayp hl-line-overlay) (setq hl-line-overlay (hl-line-make-overlay))) ; To be moved. (overlay-put hl-line-overlay 'window (unless hl-line-sticky-flag (selected-window))) - (hl-line-move hl-line-overlay)) + (hl-line-move hl-line-overlay) + (hl-line-maybe-unhighlight)) (hl-line-unhighlight))) (defun hl-line-unhighlight () "Deactivate the Hl-Line overlay on the current line." - (when hl-line-overlay - (delete-overlay hl-line-overlay))) + (when (overlayp hl-line-overlay) + (delete-overlay hl-line-overlay) + (setq hl-line-overlay nil))) (defun hl-line-maybe-unhighlight () "Maybe deactivate the Hl-Line overlay on the current line. @@ -191,8 +185,7 @@ such overlays in all buffers except the current one." (not (eq curbuf hlob)) (not (minibufferp))) (with-current-buffer hlob - (when (overlayp hl-line-overlay) - (delete-overlay hl-line-overlay)))) + (hl-line-unhighlight))) (when (and (overlayp hl-line-overlay) (eq (overlay-buffer hl-line-overlay) curbuf)) (setq hl-line-overlay-buffer curbuf)))) @@ -205,8 +198,8 @@ If `global-hl-line-sticky-flag' is non-nil, Global Hl-Line mode highlights the line about the current buffer's point in all live windows. -Global-Hl-Line mode uses the functions `global-hl-line-highlight' -and `global-hl-line-maybe-unhighlight' on `post-command-hook'." +Global-Hl-Line mode uses the function `global-hl-line-highlight' +on `post-command-hook'." :global t :group 'hl-line (if global-hl-line-mode @@ -214,25 +207,24 @@ and `global-hl-line-maybe-unhighlight' on `post-command-hook'." ;; In case `kill-all-local-variables' is called. (add-hook 'change-major-mode-hook #'global-hl-line-unhighlight) (global-hl-line-highlight-all) - (add-hook 'post-command-hook #'global-hl-line-highlight) - (add-hook 'post-command-hook #'global-hl-line-maybe-unhighlight)) + (add-hook 'post-command-hook #'global-hl-line-highlight)) (global-hl-line-unhighlight-all) (remove-hook 'post-command-hook #'global-hl-line-highlight) - (remove-hook 'change-major-mode-hook #'global-hl-line-unhighlight) - (remove-hook 'post-command-hook #'global-hl-line-maybe-unhighlight))) + (remove-hook 'change-major-mode-hook #'global-hl-line-unhighlight))) (defun global-hl-line-highlight () "Highlight the current line in the current window." (when global-hl-line-mode ; Might be changed outside the mode function. (unless (window-minibuffer-p) - (unless global-hl-line-overlay + (unless (overlayp global-hl-line-overlay) (setq global-hl-line-overlay (hl-line-make-overlay))) ; To be moved. (unless (member global-hl-line-overlay global-hl-line-overlays) (push global-hl-line-overlay global-hl-line-overlays)) (overlay-put global-hl-line-overlay 'window (unless global-hl-line-sticky-flag (selected-window))) - (hl-line-move global-hl-line-overlay)))) + (hl-line-move global-hl-line-overlay) + (global-hl-line-maybe-unhighlight)))) (defun global-hl-line-highlight-all () "Highlight the current line in all live windows." @@ -243,8 +235,9 @@ and `global-hl-line-maybe-unhighlight' on `post-command-hook'." (defun global-hl-line-unhighlight () "Deactivate the Global-Hl-Line overlay on the current line." - (when global-hl-line-overlay - (delete-overlay global-hl-line-overlay))) + (when (overlayp global-hl-line-overlay) + (delete-overlay global-hl-line-overlay) + (setq global-hl-line-overlay nil))) (defun global-hl-line-maybe-unhighlight () "Maybe deactivate the Global-Hl-Line overlay on the current line. @@ -256,9 +249,8 @@ all such overlays in all buffers except the current one." (bufferp ovb) (not (eq ovb (current-buffer))) (not (minibufferp))) - (with-current-buffer ovb - (when (overlayp global-hl-line-overlay) - (delete-overlay global-hl-line-overlay)))))) + (with-current-buffer ovb + (global-hl-line-unhighlight))))) global-hl-line-overlays)) (defun global-hl-line-unhighlight-all () diff --git a/lisp/ibuf-ext.el b/lisp/ibuf-ext.el index 7be1b3d16c9..44574abd46a 100644 --- a/lisp/ibuf-ext.el +++ b/lisp/ibuf-ext.el @@ -1497,10 +1497,10 @@ Ordering is lexicographic." (string-lessp ;; FIXME: For now just compare the file name and the process name ;; (if it exists). Is there a better way to do this? - (or (buffer-file-name (car a)) + (or (with-current-buffer (car a) (ibuffer-buffer-file-name)) (let ((pr-a (get-buffer-process (car a)))) (and (processp pr-a) (process-name pr-a)))) - (or (buffer-file-name (car b)) + (or (with-current-buffer (car b) (ibuffer-buffer-file-name)) (let ((pr-b (get-buffer-process (car b)))) (and (processp pr-b) (process-name pr-b)))))) @@ -1823,18 +1823,12 @@ When BUF nil, default to the buffer at current line." ;;;###autoload (defun ibuffer-mark-by-file-name-regexp (regexp) "Mark all buffers whose file name matches REGEXP." - (interactive "sMark by file name (regexp): ") + (interactive (list (read-regexp "Mark by file name (regexp)"))) (ibuffer-mark-on-buffer - #'(lambda (buf) - (let ((name (or (buffer-file-name buf) - (with-current-buffer buf - (and - (boundp 'dired-directory) - (stringp dired-directory) - dired-directory))))) - (when name - ;; Match on the displayed file name (which is abbreviated). - (string-match regexp (abbreviate-file-name name))))))) + (lambda (buf) + (when-let ((name (with-current-buffer buf (ibuffer-buffer-file-name)))) + ;; Match on the displayed file name (which is abbreviated). + (string-match-p regexp (ibuffer--abbreviate-file-name name)))))) ;;;###autoload (defun ibuffer-mark-by-content-regexp (regexp &optional all-buffers) diff --git a/lisp/ibuffer.el b/lisp/ibuffer.el index 4800e0243d7..84c53b16acf 100644 --- a/lisp/ibuffer.el +++ b/lisp/ibuffer.el @@ -1308,6 +1308,11 @@ a new window in the current frame, splitting vertically." (car dired-directory))))) (and dirname (expand-file-name dirname)))))) +(defun ibuffer--abbreviate-file-name (filename) + "Abbreviate FILENAME using `ibuffer-directory-abbrev-alist'." + (let ((directory-abbrev-alist ibuffer-directory-abbrev-alist)) + (abbreviate-file-name filename))) + (define-ibuffer-op ibuffer-do-save () "Save marked buffers as with `save-buffer'." (:complex t @@ -1885,9 +1890,7 @@ If point is on a group name, this function operates on that group." (cond ((zerop total) "No files") ((= 1 total) "1 file") (t (format "%d files" total)))))) - (let ((directory-abbrev-alist ibuffer-directory-abbrev-alist)) - (abbreviate-file-name - (or (ibuffer-buffer-file-name) "")))) + (ibuffer--abbreviate-file-name (or (ibuffer-buffer-file-name) ""))) (define-ibuffer-column filename-and-process (:name "Filename/Process" diff --git a/lisp/image.el b/lisp/image.el index 814035594b6..6955a90de77 100644 --- a/lisp/image.el +++ b/lisp/image.el @@ -264,9 +264,9 @@ compatibility with versions of Emacs that lack the variable ;; Used to be in image-type-header-regexps, but now not used anywhere ;; (since 2009-08-28). (defun image-jpeg-p (data) - (declare (obsolete "It is unused inside Emacs and will be removed." "27.1")) "Value is non-nil if DATA, a string, consists of JFIF image data. We accept the tag Exif because that is the same format." + (declare (obsolete "It is unused inside Emacs and will be removed." "27.1")) (setq data (ignore-errors (string-to-unibyte data))) (when (and data (string-match-p "\\`\xff\xd8" data)) (catch 'jfif diff --git a/lisp/international/fontset.el b/lisp/international/fontset.el index 14e7b89dd1f..8f0f263dcce 100644 --- a/lisp/international/fontset.el +++ b/lisp/international/fontset.el @@ -719,6 +719,7 @@ georgian cherokee canadian-aboriginal + cham ogham runic symbol diff --git a/lisp/isearch.el b/lisp/isearch.el index c6f7fe7bd4a..a86678572c4 100644 --- a/lisp/isearch.el +++ b/lisp/isearch.el @@ -3757,23 +3757,27 @@ since they have special meaning in a regexp." (overlay-put isearch-overlay 'priority 1001) (overlay-put isearch-overlay 'face isearch-face))) - (when (and search-highlight-submatches - isearch-regexp) + (when (and search-highlight-submatches isearch-regexp) (mapc 'delete-overlay isearch-submatches-overlays) (setq isearch-submatches-overlays nil) - (let ((submatch-data (cddr (butlast match-data))) + ;; 'cddr' removes whole expression match from match-data + (let ((submatch-data (cddr match-data)) (group 0) - ov face) + b e ov face) (while submatch-data - (setq group (1+ group)) - (setq ov (make-overlay (pop submatch-data) (pop submatch-data)) - face (intern-soft (format "isearch-group-%d" group))) - ;; Recycle faces from beginning. - (unless (facep face) - (setq group 1 face 'isearch-group-1)) - (overlay-put ov 'face face) - (overlay-put ov 'priority 1002) - (push ov isearch-submatches-overlays))))) + (setq b (pop submatch-data) + e (pop submatch-data)) + (when (and (integer-or-marker-p b) + (integer-or-marker-p e)) + (setq ov (make-overlay b e) + group (1+ group) + face (intern-soft (format "isearch-group-%d" group))) + ;; Recycle faces from beginning + (unless (facep face) + (setq group 1 face 'isearch-group-1)) + (overlay-put ov 'face face) + (overlay-put ov 'priority 1002) + (push ov isearch-submatches-overlays)))))) (defun isearch-dehighlight () (when isearch-overlay diff --git a/lisp/language/cham.el b/lisp/language/cham.el index eef6d6f8f9f..089988da918 100644 --- a/lisp/language/cham.el +++ b/lisp/language/cham.el @@ -34,6 +34,12 @@ (set-language-info-alist "Cham" '((charset unicode) (coding-system utf-8) - (coding-priority utf-8))) + (coding-priority utf-8) + (input-method . "cham") + (sample-text . "Cham (ꨌꩌ)\tꨦꨤꩌ ꨦꨁꨰ") + (documentation . "\ +The Cham script is a Brahmic script used to write Cham, +an Austronesian language spoken by some 245,000 Chams +in Vietnam and Cambodia."))) (provide 'cham) diff --git a/lisp/leim/quail/cham.el b/lisp/leim/quail/cham.el new file mode 100644 index 00000000000..d12ae6cddf0 --- /dev/null +++ b/lisp/leim/quail/cham.el @@ -0,0 +1,116 @@ +;;; cham.el --- Quail package for inputting Cham characters -*- coding: utf-8; lexical-binding:t -*- + +;; Copyright (C) 2021 Free Software Foundation, Inc. + +;; Author: Eli Zaretskii <eliz@gnu.org> +;; Keywords: i18n + +;; This file is part of GNU Emacs. + +;; GNU Emacs 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. + +;; GNU Emacs 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 GNU Emacs. If not, see <https://www.gnu.org/licenses/>. + +;;; Commentary: + +;; This file defines the following Cham keyboards: +;; +;; - QWERTY-based Cham. + +;;; Code: + +(require 'quail) + +(quail-define-package + "cham" "Cham" "ꨌꩌ" t + "A QWERTY-based Cham input method." + nil t nil nil t nil nil nil nil nil t) + +(quail-define-rules + ("a" ?ꨀ) + ("A" ?ꨄ) + ("i" ?ꨁ) + ("u" ?ꨂ) + ("e" ?ꨃ) + ("o" ?ꨅ) + ("k" ?ꨆ) + ("K" ?ꨇ) + ("g" ?ꨈ) + ("G" ?ꨉ) + ("q" ?ꨊ) + ("Q" ?ꨋ) + ("c" ?ꨌ) + ("C" ?ꨍ) + ("j" ?ꨎ) + ("J" ?ꨏ) + ("z" ?ꨐ) + ("Z" ?ꨑ) + ("zz" ?ꨒ) + ("t" ?ꨓ) + ("T" ?ꨔ) + ("d" ?ꨕ) + ("D" ?ꨖ) + ("n" ?ꨗ) + ("N" ?ꨘ) + ("p" ?ꨚ) + ("P" ?ꨛ) + ("f" ?ꨜ) + ("b" ?ꨝ) + ("B" ?ꨞ) + ("m" ?ꨟ) + ("M" ?ꨠ) + ("mm" ?ꨡ) + ("y" ?ꨢ) + ("r" ?ꨣ) + ("l" ?ꨤ) + ("w" ?ꨥ) + ("v" ?ꨥ) + ("x" ?ꨦ) + ("s" ?ꨧ) + ("h" ?ꨨ) + ("kk" ?ꩀ) + ("ww" ?ꩁ) + ("vv" ?ꩁ) + ("qq" ?ꩂ) + ("cc" ?ꩄ) + ("tt" ?ꩅ) + ("nn" ?ꩆ) + ("pp" ?ꩇ) + ("yy" ?ꩈ) + ("rr" ?ꩉ) + ("ll" ?ꩊ) + ("gg" ?ꩊ) + ("xx" ?ꩋ) + ("." ?ꩌ) + ("H" ?ꩍ) + ("0" ?꩐) + ("1" ?꩑) + ("2" ?꩒) + ("3" ?꩓) + ("4" ?꩔) + ("5" ?꩕) + ("6" ?꩖) + ("7" ?꩗) + ("8" ?꩘) + ("9" ?꩙) + ("!" ?ꨩ) + ("#" ?ꨪ) + ("$" ?ꨫ) + ("^" ?ꨬ) + ("&" ?ꨮ) + ("`" ?꩜) + ("=" ?ꨱ) + ("-" ?ꩃ) + ("~" ?꩟) + ) + +;;; cham.el ends here diff --git a/lisp/mail/flow-fill.el b/lisp/mail/flow-fill.el index e93ba547a89..0fab1b21b47 100644 --- a/lisp/mail/flow-fill.el +++ b/lisp/mail/flow-fill.el @@ -174,8 +174,8 @@ lines." (defvar fill-flowed-encode-tests) (defun fill-flowed-test () - (interactive "") (declare (obsolete nil "27.1")) + (interactive "") (user-error (concat "This function is obsolete. Please see " "test/lisp/mail/flow-fill-tests.el " "in the Emacs source tree"))) diff --git a/lisp/mail/footnote.el b/lisp/mail/footnote.el index ea109eec12a..995ae5f9160 100644 --- a/lisp/mail/footnote.el +++ b/lisp/mail/footnote.el @@ -910,7 +910,31 @@ play around with the following keys: (unless (assoc bullet-regexp filladapt-token-table) (setq filladapt-token-table (append filladapt-token-table - (list (list bullet-regexp 'bullet))))))))) + (list (list bullet-regexp 'bullet))))))) + (footnote--regenerate-alist))) + +(defun footnote--regenerate-alist () + (save-excursion + (goto-char (point-min)) + (when (re-search-forward footnote-section-tag-regexp nil t) + (setq footnote--markers-alist + (cl-loop + with start-of-footnotes = (match-beginning 0) + with regexp = (footnote--current-regexp) + for (note text) in + (cl-loop for pos = (re-search-forward regexp nil t) + while pos + collect (list (match-string 1) + (copy-marker (match-beginning 0) t))) + do (goto-char (point-min)) + collect (cl-list* + (string-to-number note) + text + (cl-loop + for pos = (re-search-forward regexp start-of-footnotes t) + while pos + when (equal note (match-string 1)) + collect (copy-marker (match-beginning 0) t)))))))) (provide 'footnote) diff --git a/lisp/mail/rmailedit.el b/lisp/mail/rmailedit.el index 2680ed7f3a3..c3b351d7bc8 100644 --- a/lisp/mail/rmailedit.el +++ b/lisp/mail/rmailedit.el @@ -145,8 +145,9 @@ This function runs the hooks `text-mode-hook' and `rmail-edit-mode-hook'. (declare-function rmail-summary-enable "rmailsum" ()) (declare-function rmail-summary-update-line "rmailsum" (n)) -(defun rmail-cease-edit () - "Finish editing message; switch back to Rmail proper." +(defun rmail-cease-edit (&optional abort) + "Finish editing message; switch back to Rmail proper. +If ABORT, this is the result of aborting an edit." (interactive) (if (rmail-summary-exists) (with-current-buffer rmail-summary-buffer @@ -271,6 +272,8 @@ This function runs the hooks `text-mode-hook' and `rmail-edit-mode-hook'. ;; No match for rmail-mime-charset-pattern, but there was some ;; other Content-Type. We should not insert another. (Bug#4624) (content-type) + ;; Don't insert anything if aborting. + (abort) ((null old-coding) ;; If there was no charset= spec, insert one. (backward-char 1) @@ -352,7 +355,7 @@ This function runs the hooks `text-mode-hook' and `rmail-edit-mode-hook'. (widen) (delete-region (point-min) (point-max)) (insert rmail-old-text) - (rmail-cease-edit) + (rmail-cease-edit t) (rmail-highlight-headers)) (defun rmail-edit-headers-alist (&optional widen markers) diff --git a/lisp/mail/rmailsum.el b/lisp/mail/rmailsum.el index 60b67edf85a..d29115a9570 100644 --- a/lisp/mail/rmailsum.el +++ b/lisp/mail/rmailsum.el @@ -51,10 +51,10 @@ Setting this option to nil might speed up the generation of summaries." :group 'rmail-summary) (defvar rmail-summary-font-lock-keywords - '(("^.....D.*" . font-lock-string-face) ; Deleted. - ("^.....-.*" . font-lock-type-face) ; Unread. + '(("^ *[0-9]+D.*" . font-lock-string-face) ; Deleted. + ("^ *[0-9]+-.*" . font-lock-type-face) ; Unread. ;; Neither of the below will be highlighted if either of the above are: - ("^.....[^D-] \\(......\\)" 1 font-lock-keyword-face) ; Date. + ("^ *[0-9]+[^D-] \\(......\\)" 1 font-lock-keyword-face) ; Date. ("{ \\([^\n}]+\\) }" 1 font-lock-comment-face)) ; Labels. "Additional expressions to highlight in Rmail Summary mode.") diff --git a/lisp/mh-e/mh-speed.el b/lisp/mh-e/mh-speed.el index 35d5884b16c..7cbd42c8ea2 100644 --- a/lisp/mh-e/mh-speed.el +++ b/lisp/mh-e/mh-speed.el @@ -125,11 +125,10 @@ With non-nil FORCE, the update is always carried out." ;; Otherwise on to your regular programming (t t))) -(defun mh-speed-toggle (&rest ignored) +(defun mh-speed-toggle (&rest _ignored) "Toggle the display of child folders in the speedbar. The optional arguments from speedbar are IGNORED." (interactive) - (declare (ignore args)) (beginning-of-line) (let ((parent (get-text-property (point) 'mh-folder)) (kids-p (get-text-property (point) 'mh-children-p)) @@ -164,11 +163,10 @@ The optional arguments from speedbar are IGNORED." (mh-line-beginning-position) (1+ (line-beginning-position)) '(mh-expanded t))))))) -(defun mh-speed-view (&rest ignored) +(defun mh-speed-view (&rest _ignored) "Visits the selected folder just as if you had used \\<mh-folder-mode-map>\\[mh-visit-folder]. The optional arguments from speedbar are IGNORED." (interactive) - (declare (ignore args)) (let* ((folder (get-text-property (mh-line-beginning-position) 'mh-folder)) (range (and (stringp folder) (mh-read-range "Scan" folder t nil nil diff --git a/lisp/net/eww.el b/lisp/net/eww.el index d131b2bf8c9..e39a4c33b20 100644 --- a/lisp/net/eww.el +++ b/lisp/net/eww.el @@ -1050,9 +1050,16 @@ the like." ;; multi-page isearch support (setq-local multi-isearch-next-buffer-function #'eww-isearch-next-buffer) (setq truncate-lines t) + (setq-local thing-at-point-provider-alist + (append thing-at-point-provider-alist + '((url . eww--url-at-point)))) (buffer-disable-undo) (setq buffer-read-only t)) +(defun eww--url-at-point () + "`thing-at-point' provider function." + (get-text-property (point) 'shr-url)) + ;;;###autoload (defun eww-browse-url (url &optional new-window) "Ask the EWW browser to load URL. diff --git a/lisp/net/tramp-sh.el b/lisp/net/tramp-sh.el index e8ee372cb25..ed3d15377c3 100644 --- a/lisp/net/tramp-sh.el +++ b/lisp/net/tramp-sh.el @@ -181,10 +181,9 @@ The string is used in `tramp-methods'.") `("scpx" (tramp-login-program "ssh") (tramp-login-args (("-l" "%u") ("-p" "%p") ("%c") - ("-e" "none") ("-t" "-t") ("%h") - ("%l"))) + ("-e" "none") ("-t" "-t") + ("-o" "RemoteCommand='%l'") ("%h"))) (tramp-async-args (("-q"))) - (tramp-direct-async t) (tramp-remote-shell ,tramp-default-remote-shell) (tramp-remote-shell-login ("-l")) (tramp-remote-shell-args ("-c")) @@ -238,10 +237,9 @@ The string is used in `tramp-methods'.") `("sshx" (tramp-login-program "ssh") (tramp-login-args (("-l" "%u") ("-p" "%p") ("%c") - ("-e" "none") ("-t" "-t") ("%h") - ("%l"))) + ("-e" "none") ("-t" "-t") + ("-o" "RemoteCommand='%l'") ("%h"))) (tramp-async-args (("-q"))) - (tramp-direct-async t) (tramp-remote-shell ,tramp-default-remote-shell) (tramp-remote-shell-login ("-l")) (tramp-remote-shell-args ("-c")))) @@ -2608,23 +2606,19 @@ The method used must be an out-of-band method." (defun tramp-sh-handle-insert-directory (filename switches &optional wildcard full-directory-p) "Like `insert-directory' for Tramp files." - (setq filename (expand-file-name filename)) (unless switches (setq switches "")) ;; Check, whether directory is accessible. (unless wildcard (access-file filename "Reading directory")) - (with-parsed-tramp-file-name filename nil + (with-parsed-tramp-file-name (expand-file-name filename) nil (if (and (featurep 'ls-lisp) (not (symbol-value 'ls-lisp-use-insert-directory-program))) (tramp-handle-insert-directory filename switches wildcard full-directory-p) (when (stringp switches) (setq switches (split-string switches))) - (when (tramp-get-ls-command-with ;FIXME: tramp-sh--quoting-style-options? - v "--quoting-style=literal --show-control-chars") - (setq switches - (append - switches '("--quoting-style=literal" "--show-control-chars")))) + (setq switches + (append switches (split-string (tramp-sh--quoting-style-options v)))) (unless (tramp-get-ls-command-with v "--dired") (setq switches (delete "--dired" switches))) (when wildcard @@ -4306,11 +4300,14 @@ file exists and nonzero exit status otherwise." ;; ensure they have the correct values when the shell starts, not ;; just processes run within the shell. (Which processes include ;; our initial probes to ensure the remote shell is usable.) + ;; For the time being, we assume that all shells interpret -i as + ;; interactive shell. Must be the last argument, because (for + ;; example) bash expects long options first. (tramp-send-command vec (format (concat "exec env TERM='%s' INSIDE_EMACS='%s,tramp:%s' " - "ENV=%s %s PROMPT_COMMAND='' PS1=%s PS2='' PS3='' %s %s") + "ENV=%s %s PROMPT_COMMAND='' PS1=%s PS2='' PS3='' %s %s -i") tramp-terminal-type (or (getenv "INSIDE_EMACS") emacs-version) tramp-version (or (getenv-internal "ENV" tramp-remote-process-environment) "") @@ -5122,7 +5119,7 @@ connection if a previous connection has died for some reason." options (format-spec options spec) spec (format-spec-make ?h l-host ?u l-user ?p l-port ?c options - ?l (concat remote-shell " " extra-args)) + ?l (concat remote-shell " " extra-args " -i")) command (concat ;; We do not want to see the trailing local diff --git a/lisp/net/tramp-smb.el b/lisp/net/tramp-smb.el index 1604e8962c0..c5a74a5c653 100644 --- a/lisp/net/tramp-smb.el +++ b/lisp/net/tramp-smb.el @@ -156,6 +156,7 @@ this variable (\"client min protocol=NT1\") ." "NT_STATUS_NO_SUCH_FILE" "NT_STATUS_NO_SUCH_USER" "NT_STATUS_NOT_A_DIRECTORY" + "NT_STATUS_NOT_SUPPORTED" "NT_STATUS_OBJECT_NAME_COLLISION" "NT_STATUS_OBJECT_NAME_INVALID" "NT_STATUS_OBJECT_NAME_NOT_FOUND" @@ -371,17 +372,17 @@ pass to the OPERATION." (tramp-error v2 'file-error "add-name-to-file: %s must not be a directory" filename)) - ;; Do the 'confirm if exists' thing. - (when (file-exists-p newname) - ;; What to do? - (if (or (null ok-if-already-exists) ; not allowed to exist - (and (numberp ok-if-already-exists) - (not (yes-or-no-p - (format - "File %s already exists; make it a link anyway? " - v2-localname))))) - (tramp-error v2 'file-already-exists newname) - (delete-file newname))) + ;; Do the 'confirm if exists' thing. + (when (file-exists-p newname) + ;; What to do? + (if (or (null ok-if-already-exists) ; not allowed to exist + (and (numberp ok-if-already-exists) + (not (yes-or-no-p + (format + "File %s already exists; make it a link anyway? " + v2-localname))))) + (tramp-error v2 'file-already-exists newname) + (delete-file newname))) ;; We must also flush the cache of the directory, because ;; `file-attributes' reads the values from there. (tramp-flush-file-properties v2 v2-localname) @@ -1166,7 +1167,6 @@ PRESERVE-UID-GID and PRESERVE-EXTENDED-ATTRIBUTES are completely ignored." (insert " -> " (tramp-compat-file-attribute-type attr)))) (insert "\n") - (forward-line) (beginning-of-line))) entries)))))) diff --git a/lisp/net/tramp.el b/lisp/net/tramp.el index 2816c58fe7f..7b34a748822 100644 --- a/lisp/net/tramp.el +++ b/lisp/net/tramp.el @@ -1990,6 +1990,8 @@ the resulting error message." (tramp-dissect-file-name default-directory) 0 fmt-string arguments) (apply #'message fmt-string arguments))) +(put #'tramp-test-message 'tramp-suppress-trace t) + ;; This function provides traces in case of errors not triggered by ;; Tramp functions. (defun tramp-signal-hook-function (error-symbol data) @@ -3801,15 +3803,20 @@ It does not support `:stderr'." (get-buffer-create buffer) ;; BUFFER can be nil. We use a temporary buffer. (generate-new-buffer tramp-temp-buffer-name))) - ;; We use as environment the difference to toplevel - ;; `process-environment'. (env (mapcar (lambda (elt) - (unless - (member - elt (default-toplevel-value 'process-environment)) - (when (string-match-p "=" elt) elt))) - process-environment)) + (when (string-match-p "=" elt) elt)) + tramp-remote-process-environment)) + ;; We use as environment the difference to toplevel + ;; `process-environment'. + (env (dolist (elt process-environment env) + (when + (and + (string-match-p "=" elt) + (not + (member + elt (default-toplevel-value 'process-environment)))) + (setq env (cons elt env))))) (env (setenv-internal env "INSIDE_EMACS" (concat (or (getenv "INSIDE_EMACS") emacs-version) diff --git a/lisp/net/webjump.el b/lisp/net/webjump.el index 9bcf1d37345..e5941ae652e 100644 --- a/lisp/net/webjump.el +++ b/lisp/net/webjump.el @@ -2,9 +2,10 @@ ;; Copyright (C) 1996-1997, 2001-2021 Free Software Foundation, Inc. -;; Author: Neil W. Van Dyke <nwv@acm.org> -;; Created: 09-Aug-1996 -;; Keywords: comm www +;; Author: Neil W. Van Dyke <nwv@acm.org> +;; Maintainer: emacs-devel@gnu.org +;; Created: 09-Aug-1996 +;; Keywords: comm www ;; This file is part of GNU Emacs. diff --git a/lisp/nxml/nxml-mode.el b/lisp/nxml/nxml-mode.el index 5bc3049d90f..0602943db20 100644 --- a/lisp/nxml/nxml-mode.el +++ b/lisp/nxml/nxml-mode.el @@ -54,26 +54,30 @@ "Non-nil means display glyph following character reference. The glyph is displayed in face `nxml-glyph'." :group 'nxml - :type 'boolean) + :type 'boolean + :safe #'booleanp) (defcustom nxml-sexp-element-flag t "Non-nil means sexp commands treat an element as a single expression." :version "27.1" ; nil -> t :group 'nxml - :type 'boolean) + :type 'boolean + :safe #'booleanp) (defcustom nxml-slash-auto-complete-flag nil "Non-nil means typing a slash automatically completes the end-tag. This is used by `nxml-electric-slash'." :group 'nxml - :type 'boolean) + :type 'boolean + :safe #'booleanp) (defcustom nxml-child-indent 2 "Indentation for the children of an element relative to the start-tag. This only applies when the line or lines containing the start-tag contains nothing else other than that start-tag." :group 'nxml - :type 'integer) + :type 'integer + :safe #'integerp) (defcustom nxml-attribute-indent 4 "Indentation for the attributes of an element relative to the start-tag. @@ -81,12 +85,14 @@ This only applies when the first attribute of a tag starts a line. In other cases, the first attribute on one line is indented the same as the first attribute on the previous line." :group 'nxml - :type 'integer) + :type 'integer + :safe #'integerp) (defcustom nxml-bind-meta-tab-to-complete-flag t "Non-nil means to use nXML completion in \\[completion-at-point]." :group 'nxml - :type 'boolean) + :type 'boolean + :safe #'booleanp) (defcustom nxml-prefer-utf-16-to-utf-8-flag nil "Non-nil means prefer UTF-16 to UTF-8 when saving a buffer. @@ -94,7 +100,8 @@ This is used only when a buffer does not contain an encoding declaration and when its current `buffer-file-coding-system' specifies neither UTF-16 nor UTF-8." :group 'nxml - :type 'boolean) + :type 'boolean + :safe #'booleanp) (defcustom nxml-prefer-utf-16-little-to-big-endian-flag (eq system-type 'windows-nt) @@ -103,7 +110,8 @@ This is used only for saving a buffer; when reading the byte-order is auto-detected. It may be relevant both when there is no encoding declaration and when the encoding declaration specifies `UTF-16'." :group 'nxml - :type 'boolean) + :type 'boolean + :safe #'booleanp) (defcustom nxml-default-buffer-file-coding-system nil "Default value for `buffer-file-coding-system' for a buffer for a new file. @@ -112,13 +120,15 @@ A value of nil means use the default value of A buffer's `buffer-file-coding-system' affects what \\[nxml-insert-xml-declaration] inserts." :group 'nxml - :type 'coding-system) + :type 'coding-system + :safe #'coding-system-p) (defcustom nxml-auto-insert-xml-declaration-flag nil "Non-nil means automatically insert an XML declaration in a new file. The XML declaration is inserted using `nxml-insert-xml-declaration'." :group 'nxml - :type 'boolean) + :type 'boolean + :safe #'booleanp) (defface nxml-delimited-data '((t (:inherit font-lock-doc-face))) diff --git a/lisp/obsolete/nnir.el b/lisp/obsolete/nnir.el index 147efed0057..0b7d1e454c3 100644 --- a/lisp/obsolete/nnir.el +++ b/lisp/obsolete/nnir.el @@ -504,7 +504,6 @@ Add an entry here when adding a new search engine.") ,@(mapcar (lambda (elem) (list 'const (car elem))) nnir-engines))))) - (defmacro nnir-add-result (dirnam artno score prefix server artlist) "Construct a result vector and add it to ARTLIST. DIRNAM, ARTNO, SCORE, PREFIX and SERVER are passed to diff --git a/lisp/progmodes/perl-mode.el b/lisp/progmodes/perl-mode.el index 2a2a4978c62..d047dd543c2 100644 --- a/lisp/progmodes/perl-mode.el +++ b/lisp/progmodes/perl-mode.el @@ -95,6 +95,12 @@ :prefix "perl-" :group 'languages) +(defface perl-non-scalar-variable + '((t :inherit font-lock-variable-name-face :underline t)) + "Face used for non-scalar variables." + :version "28.1" + :group 'perl) + (defvar perl-mode-abbrev-table nil "Abbrev table in use in perl-mode buffers.") (define-abbrev-table 'perl-mode-abbrev-table ()) @@ -187,11 +193,12 @@ ;; ;; Fontify function, variable and file name references. ("&\\(\\sw+\\(::\\sw+\\)*\\)" 1 font-lock-function-name-face) - ;; Additionally underline non-scalar variables. Maybe this is a bad idea. + ;; Additionally fontify non-scalar variables. `perl-non-scalar-variable' + ;; will underline them by default. ;;'("[$@%*][#{]?\\(\\sw+\\)" 1 font-lock-variable-name-face) ("[$*]{?\\(\\sw+\\(::\\sw+\\)*\\)" 1 font-lock-variable-name-face) ("\\([@%]\\|\\$#\\)\\(\\sw+\\(::\\sw+\\)*\\)" - (2 (cons font-lock-variable-name-face '(underline)))) + (2 'perl-non-scalar-variable)) ("<\\(\\sw+\\)>" 1 font-lock-constant-face) ;; ;; Fontify keywords with/and labels as we do in `c++-font-lock-keywords'. diff --git a/lisp/progmodes/project.el b/lisp/progmodes/project.el index 06966f33b72..768cd58ae44 100644 --- a/lisp/progmodes/project.el +++ b/lisp/progmodes/project.el @@ -928,6 +928,7 @@ if one already exists." ;;;###autoload (defun project-async-shell-command () "Run `async-shell-command' in the current project's root directory." + (declare (interactive-only async-shell-command)) (interactive) (let ((default-directory (project-root (project-current t)))) (call-interactively #'async-shell-command))) @@ -935,6 +936,7 @@ if one already exists." ;;;###autoload (defun project-shell-command () "Run `shell-command' in the current project's root directory." + (declare (interactive-only shell-command)) (interactive) (let ((default-directory (project-root (project-current t)))) (call-interactively #'shell-command))) @@ -972,6 +974,7 @@ loop using the command \\[fileloop-continue]." ;;;###autoload (defun project-compile () "Run `compile' in the project root." + (declare (interactive-only compile)) (interactive) (let ((default-directory (project-root (project-current t)))) (call-interactively #'compile))) diff --git a/lisp/progmodes/sh-script.el b/lisp/progmodes/sh-script.el index a417de32640..cc045a1b2d1 100644 --- a/lisp/progmodes/sh-script.el +++ b/lisp/progmodes/sh-script.el @@ -1556,7 +1556,7 @@ with your script for an edit-interpret-debug cycle." (sh-set-shell (cond ((save-excursion (goto-char (point-min)) - (looking-at "#![ \t]?\\([^ \t\n]*/bin/env[ \t]\\)?\\([^ \t\n]+\\)")) + (looking-at auto-mode-interpreter-regexp)) (match-string 2)) ((not buffer-file-name) sh-shell-file) ;; Checks that use `buffer-file-name' follow. @@ -2927,8 +2927,8 @@ option followed by a colon `:' if the option accepts an argument." (put 'sh-assignment 'delete-selection t) (defun sh-assignment (arg) "Remember preceding identifier for future completion and do self-insert." - (interactive "p") (declare (obsolete nil "27.1")) + (interactive "p") (self-insert-command arg) (sh--assignment-collect)) diff --git a/lisp/progmodes/xref.el b/lisp/progmodes/xref.el index b6778de807d..898cb4fb4c1 100644 --- a/lisp/progmodes/xref.el +++ b/lisp/progmodes/xref.el @@ -967,16 +967,15 @@ Return an alist of the form ((FILENAME . (XREF ...)) ...)." (let ((inhibit-read-only t) (buffer-undo-list t)) (save-excursion - (erase-buffer) (condition-case err - (xref--insert-xrefs - (xref--analyze (funcall xref--fetcher))) + (let ((alist (xref--analyze (funcall xref--fetcher)))) + (erase-buffer) + (xref--insert-xrefs alist)) (user-error (insert (propertize (error-message-string err) - 'face 'error)))) - (goto-char (point-min))))) + 'face 'error))))))) (defun xref-show-definitions-buffer (fetcher alist) "Show the definitions list in a regular window. @@ -1001,8 +1000,12 @@ When only one definition found, jump to it right away instead." When there is more than one definition, split the selected window and show the list in a small window at the bottom. And use a local keymap that binds `RET' to `xref-quit-and-goto-xref'." - (let ((xrefs (funcall fetcher)) - (dd default-directory)) + (let* ((xrefs (funcall fetcher)) + (dd default-directory) + ;; XXX: Make percentage customizable maybe? + (max-height (/ (window-height) 2)) + (size-fun (lambda (window) + (fit-window-to-buffer window max-height)))) (cond ((not (cdr xrefs)) (xref-pop-to-location (car xrefs) @@ -1013,7 +1016,8 @@ local keymap that binds `RET' to `xref-quit-and-goto-xref'." (xref--transient-buffer-mode) (xref--show-common-initialize (xref--analyze xrefs) fetcher alist) (pop-to-buffer (current-buffer) - '(display-buffer-in-direction . ((direction . below)))) + `(display-buffer-in-direction . ((direction . below) + (window-height . ,size-fun)))) (current-buffer)))))) (define-obsolete-function-alias 'xref--show-defs-buffer-at-bottom diff --git a/lisp/replace.el b/lisp/replace.el index d41dc98a0d9..db5b340631a 100644 --- a/lisp/replace.el +++ b/lisp/replace.el @@ -866,13 +866,10 @@ If nil, uses `regexp-history'." ;; Do not automatically add default to the history for empty input. (history-add-new-input nil) (input (read-from-minibuffer - (cond ((string-match-p ":[ \t]*\\'" prompt) - prompt) - ((and default (> (length default) 0)) - (format "%s (default %s): " prompt - (query-replace-descr default))) - (t - (format "%s: " prompt))) + (if (string-match-p ":[ \t]*\\'" prompt) + prompt + (format-prompt prompt (and (length> default 0) + (query-replace-descr default)))) nil nil nil (or history 'regexp-history) suggestions t))) (if (equal input "") ;; Return the default value when the user enters empty input. @@ -2428,23 +2425,27 @@ It is called with three arguments, as if it were (overlay-put replace-overlay 'priority 1001) ;higher than lazy overlays (overlay-put replace-overlay 'face 'query-replace))) - (when (and query-replace-highlight-submatches - regexp-flag) + (when (and query-replace-highlight-submatches regexp-flag) (mapc 'delete-overlay replace-submatches-overlays) (setq replace-submatches-overlays nil) - (let ((submatch-data (cddr (butlast (match-data t)))) + ;; 'cddr' removes whole expression match from match-data + (let ((submatch-data (cddr (match-data t))) (group 0) - ov face) + b e ov face) (while submatch-data - (setq group (1+ group)) - (setq ov (make-overlay (pop submatch-data) (pop submatch-data)) - face (intern-soft (format "isearch-group-%d" group))) - ;; Recycle faces from beginning. - (unless (facep face) - (setq group 1 face 'isearch-group-1)) - (overlay-put ov 'face face) - (overlay-put ov 'priority 1002) - (push ov replace-submatches-overlays)))) + (setq b (pop submatch-data) + e (pop submatch-data)) + (when (and (integer-or-marker-p b) + (integer-or-marker-p e)) + (setq ov (make-overlay b e) + group (1+ group) + face (intern-soft (format "isearch-group-%d" group))) + ;; Recycle faces from beginning + (unless (facep face) + (setq group 1 face 'isearch-group-1)) + (overlay-put ov 'face face) + (overlay-put ov 'priority 1002) + (push ov replace-submatches-overlays))))) (if query-replace-lazy-highlight (let ((isearch-string search-string) diff --git a/lisp/simple.el b/lisp/simple.el index 37c0885dcc5..8d4e4a7a6bb 100644 --- a/lisp/simple.el +++ b/lisp/simple.el @@ -820,9 +820,10 @@ With ARG, perform this action that many times." (delete-horizontal-space t) (unless arg (setq arg 1)) - (dotimes (_ arg) - (newline nil t) - (indent-according-to-mode))) + (let ((electric-indent-mode nil)) + (dotimes (_ arg) + (newline nil t) + (indent-according-to-mode)))) (defun reindent-then-newline-and-indent () "Reindent current line, insert newline, then indent the new line. @@ -832,7 +833,8 @@ In programming language modes, this is the same as TAB. In some text modes, where TAB inserts a tab, this indents to the column specified by the function `current-left-margin'." (interactive "*") - (let ((pos (point))) + (let ((pos (point)) + (electric-indent-mode nil)) ;; Be careful to insert the newline before indenting the line. ;; Otherwise, the indentation might be wrong. (newline) @@ -7338,10 +7340,7 @@ even beep.)" ;; of the kill before killing. (let ((opoint (point)) (kill-whole-line (and kill-whole-line (bolp))) - (orig-y (cdr (nth 2 (posn-at-point)))) - ;; FIXME: This tolerance should be zero! It isn't due to a - ;; bug in posn-at-point, see bug#45837. - (tol (/ (line-pixel-height) 2))) + (orig-vlnum (cdr (nth 6 (posn-at-point))))) (if arg (vertical-motion (prefix-numeric-value arg)) (end-of-visual-line 1) @@ -7352,8 +7351,8 @@ even beep.)" ;; end-of-visual-line didn't overshoot due to complications ;; like display or overlay strings, intangible text, etc.: ;; otherwise, we don't want to kill a character that's - ;; unrelated to the place where the visual line wrapped. - (and (< (abs (- (cdr (nth 2 (posn-at-point))) orig-y)) tol) + ;; unrelated to the place where the visual line wraps. + (and (= (cdr (nth 6 (posn-at-point))) orig-vlnum) ;; Make sure we delete the character where the line wraps ;; under visual-line-mode, be it whitespace or a ;; character whose category set allows to wrap at it. diff --git a/lisp/startup.el b/lisp/startup.el index 9325ab5acff..09635b12990 100644 --- a/lisp/startup.el +++ b/lisp/startup.el @@ -1180,6 +1180,7 @@ please check its value") ;; are dependencies between them. (nreverse custom-delayed-init-variables)) (mapc #'custom-reevaluate-setting custom-delayed-init-variables) + (setq custom-delayed-init-variables nil) ;; Warn for invalid user name. (when init-file-user @@ -1309,12 +1310,6 @@ please check its value") (startup--setup-quote-display) (setq internal--text-quoting-flag t)) - ;; Re-evaluate again the predefined variables whose initial value - ;; depends on the runtime context, in case some of them depend on - ;; the window-system features. Example: blink-cursor-mode. - (mapc #'custom-reevaluate-setting custom-delayed-init-variables) - (setq custom-delayed-init-variables nil) - (normal-erase-is-backspace-setup-frame) ;; Register default TTY colors for the case the terminal hasn't a @@ -1495,13 +1490,13 @@ to reading the init file), or afterwards when the user first opens a graphical frame. This can set the values of `menu-bar-mode', `tool-bar-mode', -`tab-bar-mode', and `no-blinking-cursor', as well as the `cursor' face. +`tab-bar-mode', and `blink-cursor-mode', as well as the `cursor' face. Changed settings will be marked as \"CHANGED outside of Customize\"." (let ((no-vals '("no" "off" "false" "0")) (settings '(("menuBar" "MenuBar" menu-bar-mode nil) ("toolBar" "ToolBar" tool-bar-mode nil) ("scrollBar" "ScrollBar" scroll-bar-mode nil) - ("cursorBlink" "CursorBlink" no-blinking-cursor t)))) + ("cursorBlink" "CursorBlink" blink-cursor-mode nil)))) (dolist (x settings) (if (member (x-get-resource (nth 0 x) (nth 1 x)) no-vals) (set (nth 2 x) (nth 3 x))))) diff --git a/lisp/term/ns-win.el b/lisp/term/ns-win.el index 5f4dd9ef587..94e9d5c5828 100644 --- a/lisp/term/ns-win.el +++ b/lisp/term/ns-win.el @@ -120,6 +120,15 @@ The properties returned may include `top', `left', `height', and `width'." (define-key global-map [?\s-d] 'isearch-repeat-backward) (define-key global-map [?\s-e] 'isearch-yank-kill) (define-key global-map [?\s-f] 'isearch-forward) +(define-key esc-map [?\s-f] 'isearch-forward-regexp) +(define-key minibuffer-local-isearch-map [?\s-f] + 'isearch-forward-exit-minibuffer) +(define-key isearch-mode-map [?\s-f] 'isearch-repeat-forward) +(define-key global-map [?\s-F] 'isearch-backward) +(define-key esc-map [?\s-F] 'isearch-backward-regexp) +(define-key minibuffer-local-isearch-map [?\s-F] + 'isearch-reverse-exit-minibuffer) +(define-key isearch-mode-map [?\s-F] 'isearch-repeat-backward) (define-key global-map [?\s-g] 'isearch-repeat-forward) (define-key global-map [?\s-h] 'ns-do-hide-emacs) (define-key global-map [?\s-H] 'ns-do-hide-others) diff --git a/lisp/textmodes/remember.el b/lisp/textmodes/remember.el index 98d3a3856ea..820ee38d101 100644 --- a/lisp/textmodes/remember.el +++ b/lisp/textmodes/remember.el @@ -159,7 +159,8 @@ ;; ;; This should be before other entries that may return t ;; (add-to-list 'remember-handler-functions 'remember-diary-extract-entries) ;; -;; This module recognizes entries of the form +;; This module recognizes entries of the form (defined by +;; `remember-diary-regexp') ;; ;; DIARY: .... ;; @@ -410,13 +411,24 @@ The default emulates `current-time-string' for backward compatibility." :group 'remember :version "27.1") +(defcustom remember-text-format-function nil + "The function to format the remembered text. +The function receives the remembered text as argument and should +return the text to be remembered." + :type '(choice (const nil) function) + :group 'remember + :version "28.1") + (defun remember-append-to-file () "Remember, with description DESC, the given TEXT." (let* ((text (buffer-string)) (desc (remember-buffer-desc)) - (remember-text (concat "\n" remember-leader-text - (format-time-string remember-time-format) - " (" desc ")\n\n" text + (remember-text (concat "\n" + (if remember-text-format-function + (funcall remember-text-format-function text) + (concat remember-leader-text + (format-time-string remember-time-format) + " (" desc ")\n\n" text)) (save-excursion (goto-char (point-max)) (if (bolp) nil "\n")))) (buf (find-buffer-visiting remember-data-file))) @@ -532,17 +544,28 @@ If this is nil, then `diary-file' will be used instead." (autoload 'diary-make-entry "diary-lib") +(defcustom remember-diary-regexp "^DIARY:\\s-*\\(.+\\)" + "Regexp to extract diary entries." + :type 'regexp + :version "28.1") + +(defvar diary-file) + ;;;###autoload (defun remember-diary-extract-entries () - "Extract diary entries from the region." + "Extract diary entries from the region based on `remember-diary-regexp'." (save-excursion (goto-char (point-min)) (let (list) - (while (re-search-forward "^DIARY:\\s-*\\(.+\\)" nil t) + (while (re-search-forward remember-diary-regexp nil t) (push (remember-diary-convert-entry (match-string 1)) list)) (when list (diary-make-entry (mapconcat 'identity list "\n") - nil remember-diary-file)) + nil remember-diary-file) + (when remember-save-after-remembering + (with-current-buffer (find-buffer-visiting (or remember-diary-file + diary-file)) + (save-buffer)))) nil))) ;; Continue processing ;;; Internal Functions: diff --git a/lisp/thingatpt.el b/lisp/thingatpt.el index d3ba941fcc2..c52fcfcc051 100644 --- a/lisp/thingatpt.el +++ b/lisp/thingatpt.el @@ -52,8 +52,30 @@ ;;; Code: +(require 'cl-lib) (provide 'thingatpt) +(defvar thing-at-point-provider-alist nil + "Alist of providers for returning a \"thing\" at point. +This variable can be set globally, or appended to buffer-locally +by modes, to provide functions that will return a \"thing\" at +point. The first provider for the \"thing\" that returns a +non-nil value wins. + +For instance, a major mode could say: + +\(setq-local thing-at-point-provider-alist + (append thing-at-point-provider-alist + \\='((url . my-mode--url-at-point)))) + +to provide a way to get an `url' at point in that mode. The +provider functions are called with no parameters at the point in +question. + +\"things\" include `symbol', `list', `sexp', `defun', `filename', +`url', `email', `uuid', `word', `sentence', `whitespace', `line', +and `page'.") + ;; Basic movement ;;;###autoload @@ -143,11 +165,18 @@ strip text properties from the return value. See the file `thingatpt.el' for documentation on how to define a symbol as a valid THING." (let ((text - (if (get thing 'thing-at-point) - (funcall (get thing 'thing-at-point)) + (cond + ((cl-loop for (pthing . function) in thing-at-point-provider-alist + when (eq pthing thing) + for result = (funcall function) + when result + return result)) + ((get thing 'thing-at-point) + (funcall (get thing 'thing-at-point))) + (t (let ((bounds (bounds-of-thing-at-point thing))) (when bounds - (buffer-substring (car bounds) (cdr bounds))))))) + (buffer-substring (car bounds) (cdr bounds)))))))) (when (and text no-properties (sequencep text)) (set-text-properties 0 (length text) nil text)) text)) @@ -218,6 +247,15 @@ The bounds of THING are determined by `bounds-of-thing-at-point'." (put 'sexp 'beginning-op 'thing-at-point--beginning-of-sexp) +;; Symbols + +(put 'symbol 'beginning-op 'thing-at-point--beginning-of-symbol) + +(defun thing-at-point--beginning-of-symbol () + "Move point to the beginning of the current symbol." + (and (re-search-backward "\\(\\sw\\|\\s_\\)+") + (skip-syntax-backward "w_"))) + ;; Lists (put 'list 'bounds-of-thing-at-point 'thing-at-point-bounds-of-list-at-point) diff --git a/lisp/type-break.el b/lisp/type-break.el index 84c240c9f8c..a6d5cd01702 100644 --- a/lisp/type-break.el +++ b/lisp/type-break.el @@ -487,7 +487,7 @@ Return nil if the file is missing or if the time is not a Lisp time value." (goto-char (point-min)) (read (current-buffer))) (end-of-file - (error "End of file in `%s'" file)))))))) + (warn "End of file in `%s'" file)))))))) (defun type-break-get-previous-count () "Get previous keystroke count from `type-break-file-name'. @@ -505,7 +505,7 @@ integer." (forward-line 1) (read (current-buffer))) (end-of-file - (error "End of file in `%s'" file))))))) + (warn "End of file in `%s'" file))))))) file 0))) diff --git a/lisp/vc/vc.el b/lisp/vc/vc.el index 6c96d8ca7c4..bc9f11202b1 100644 --- a/lisp/vc/vc.el +++ b/lisp/vc/vc.el @@ -2392,6 +2392,7 @@ If it contains `file', show short logs for files. Not all VC backends support short logs!") (defvar log-view-vc-fileset) +(defvar log-view-message-re) (defun vc-print-log-setup-buttons (working-revision is-start-revision limit pl-return) "Insert at the end of the current buffer buttons to show more log entries. @@ -2401,21 +2402,32 @@ Does nothing if IS-START-REVISION is non-nil, or if LIMIT is nil, or if PL-RETURN is `limit-unsupported'." (when (and limit (not (eq 'limit-unsupported pl-return)) (not is-start-revision)) - (goto-char (point-max)) - (insert "\n") - (insert-text-button "Show 2X entries" - 'action (lambda (&rest _ignore) - (vc-print-log-internal - log-view-vc-backend log-view-vc-fileset - working-revision nil (* 2 limit))) - 'help-echo "Show the log again, and double the number of log entries shown") - (insert " ") - (insert-text-button "Show unlimited entries" - 'action (lambda (&rest _ignore) - (vc-print-log-internal - log-view-vc-backend log-view-vc-fileset - working-revision nil nil)) - 'help-echo "Show the log again, including all entries"))) + (let ((entries 0)) + (goto-char (point-min)) + (while (re-search-forward log-view-message-re nil t) + (cl-incf entries)) + ;; If we got fewer entries than we asked for, then displaying + ;; the "more" buttons isn't useful. + (when (>= entries limit) + (goto-char (point-max)) + (insert "\n") + (insert-text-button + "Show 2X entries" + 'action (lambda (&rest _ignore) + (vc-print-log-internal + log-view-vc-backend log-view-vc-fileset + working-revision nil (* 2 limit))) + 'help-echo + "Show the log again, and double the number of log entries shown") + (insert " ") + (insert-text-button + "Show unlimited entries" + 'action (lambda (&rest _ignore) + (vc-print-log-internal + log-view-vc-backend log-view-vc-fileset + working-revision nil nil)) + 'help-echo "Show the log again, including all entries") + (insert "\n"))))) (defun vc-print-log-internal (backend files working-revision &optional is-start-revision limit type) diff --git a/lisp/version.el b/lisp/version.el index fcfc2f8b806..3a3093fdd4a 100644 --- a/lisp/version.el +++ b/lisp/version.el @@ -29,14 +29,12 @@ (defconst emacs-major-version (progn (string-match "^[0-9]+" emacs-version) (string-to-number (match-string 0 emacs-version))) - "Major version number of this version of Emacs. -This variable first existed in version 19.23.") + "Major version number of this version of Emacs.") (defconst emacs-minor-version (progn (string-match "^[0-9]+\\.\\([0-9]+\\)" emacs-version) (string-to-number (match-string 1 emacs-version))) - "Minor version number of this version of Emacs. -This variable first existed in version 19.23.") + "Minor version number of this version of Emacs.") (defconst emacs-build-system (system-name) "Name of the system on which Emacs was built, or nil if not available.") diff --git a/lisp/wid-edit.el b/lisp/wid-edit.el index 7dda04eda21..68a0d3d2356 100644 --- a/lisp/wid-edit.el +++ b/lisp/wid-edit.el @@ -4026,17 +4026,19 @@ is inline." ;;; The `color' Widget. -;; Fixme: match (define-widget 'color 'editable-field "Choose a color name (with sample)." :format "%{%t%}: %v (%{sample%})\n" :value-create 'widget-color-value-create - :size 10 + :size (1+ (apply #'max 13 ; Longest RGB hex string. + (mapcar #'length (defined-colors)))) :tag "Color" :value "black" :completions (or facemenu-color-alist (defined-colors)) :sample-face-get 'widget-color-sample-face-get :notify 'widget-color-notify + :match #'widget-color-match + :validate #'widget-color-validate :action 'widget-color-action) (defun widget-color-value-create (widget) @@ -4085,6 +4087,19 @@ is inline." (overlay-put (widget-get widget :sample-overlay) 'face (widget-apply widget :sample-face-get)) (widget-default-notify widget child event)) + +(defun widget-color-match (_widget value) + "Non-nil if VALUE is a defined color or a RGB hex string." + (and (stringp value) + (or (color-defined-p value) + (string-match-p "^#\\(?:[[:xdigit:]]\\{3\\}\\)\\{1,4\\}$" value)))) + +(defun widget-color-validate (widget) + "Check that WIDGET's value is a valid color." + (let ((value (widget-value widget))) + (unless (widget-color-match widget value) + (widget-put widget :error (format "Invalid color: %S" value)) + widget))) ;;; The Help Echo |