commit d60198d7a49acd8cd2c250625ac57deef484cee2 (HEAD, refs/remotes/origin/master) Author: Gerd Möllmann Date: Tue Jan 28 04:37:56 2025 +0100 Fix frame-visible-p for tty root frames * src/frame.c (Fframe_visible_p): Don't unconditionally return t for tty root frames. diff --git a/src/frame.c b/src/frame.c index dbed3f940fb..d59b4045c00 100644 --- a/src/frame.c +++ b/src/frame.c @@ -3299,8 +3299,6 @@ usually not displayed at all, even in a window system's \"taskbar\". */) if (FRAME_VISIBLE_P (f)) return Qt; - else if (is_tty_root_frame (f)) - return Qt; if (FRAME_ICONIFIED_P (f)) return Qicon; return Qnil; commit 1f1088188e8b9319f60141a093431f1f85c2b03c Author: Paul Eggert Date: Mon Jan 27 17:15:47 2025 -0800 Avoid some make_formatted_string mallocs * src/alloc.c (make_formatted_string): Grow the local buffer from 64 to MAX_ALLOCA bytes. diff --git a/src/alloc.c b/src/alloc.c index 2c0ccc9dd62..b13c3e49224 100644 --- a/src/alloc.c +++ b/src/alloc.c @@ -2547,7 +2547,7 @@ make_uninit_multibyte_string (EMACS_INT nchars, EMACS_INT nbytes) Lisp_Object make_formatted_string (const char *format, ...) { - char buf[64]; + char buf[MAX_ALLOCA]; char *cstr = buf; ptrdiff_t bufsize = sizeof buf; va_list ap; commit 8e7588a2675655b88dc3ac5b7ed46ab6f1b891ec Author: Paul Eggert Date: Mon Jan 27 17:13:02 2025 -0800 Make vmessage a bit safer * src/xdisp.c (vmessage): Avoid undefined behavior if FRAME_MESSAGE_BUF_SIZE (f) is zero, or if doprnt generates output containing only encoding errors. Although it’s not clear whether either is possible, it is better to be safe. Also, clarify via a new local message_bufsize. diff --git a/src/xdisp.c b/src/xdisp.c index 4933315166f..a801caae06f 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -12586,17 +12586,18 @@ vmessage (const char *m, va_list ap) { ptrdiff_t len; ptrdiff_t maxsize = FRAME_MESSAGE_BUF_SIZE (f); + ptrdiff_t message_bufsize = maxsize + MAX_MULTIBYTE_LENGTH; USE_SAFE_ALLOCA; - char *message_buf = SAFE_ALLOCA (maxsize + MAX_MULTIBYTE_LENGTH); + char *message_buf = SAFE_ALLOCA (message_bufsize); - len = doprnt (message_buf, maxsize + MAX_MULTIBYTE_LENGTH, m, 0, ap); + len = doprnt (message_buf, message_bufsize, m, 0, ap); /* doprnt returns the buffer size minus one when it truncated a multibyte sequence. Work around that by truncating to the last valid multibyte head. */ - if (len >= maxsize) + if (0 < maxsize && maxsize <= len) { len = maxsize - 1; - while (!CHAR_HEAD_P (message_buf[len])) + while (0 < len && !CHAR_HEAD_P (message_buf[len])) len--; message_buf[len] = 0; } commit 8812f526cfb145e00ee4cb74eac05b25953da02c Author: Pip Cet Date: Mon Jan 27 13:06:27 2025 -0800 Avoid printing NUL characters in 'message' (bug#75900) * src/xdisp.c (vmessage): Increase buffer size to fit an extra multibyte character. On buffer overflow, drop the last multibyte character to determine an accurate byte length. diff --git a/src/xdisp.c b/src/xdisp.c index 5b5cb3849fc..4933315166f 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -12587,10 +12587,19 @@ vmessage (const char *m, va_list ap) ptrdiff_t len; ptrdiff_t maxsize = FRAME_MESSAGE_BUF_SIZE (f); USE_SAFE_ALLOCA; - char *message_buf = SAFE_ALLOCA (maxsize + 1); - - len = doprnt (message_buf, maxsize, m, 0, ap); + char *message_buf = SAFE_ALLOCA (maxsize + MAX_MULTIBYTE_LENGTH); + len = doprnt (message_buf, maxsize + MAX_MULTIBYTE_LENGTH, m, 0, ap); + /* doprnt returns the buffer size minus one when it + truncated a multibyte sequence. Work around that by + truncating to the last valid multibyte head. */ + if (len >= maxsize) + { + len = maxsize - 1; + while (!CHAR_HEAD_P (message_buf[len])) + len--; + message_buf[len] = 0; + } message3 (make_string (message_buf, len)); SAFE_FREE (); } commit 0ed913cf46a8b07a39b065216272a7aa07123282 Author: Pip Cet Date: Mon Jan 27 13:05:07 2025 -0800 Fix buffer overflows in doprnt (bug#75900) * src/doprnt.c (doprnt): Clear rest of buffer on multibyte overflow. Always decrement bufsize when writing a byte. diff --git a/src/doprnt.c b/src/doprnt.c index 421c4f4d15f..d8403bedbe4 100644 --- a/src/doprnt.c +++ b/src/doprnt.c @@ -447,7 +447,8 @@ doprnt (char *buffer, ptrdiff_t bufsize, const char *format, while (tem != 0); memcpy (bufptr, string, tem); - bufptr[tem] = 0; + while (tem < bufsize) + bufptr[tem++] = 0; /* Trigger exit from the loop, but make sure we return to the caller a value which will indicate that the buffer was too small. */ @@ -499,6 +500,7 @@ doprnt (char *buffer, ptrdiff_t bufsize, const char *format, fmtchar = '\''; *bufptr++ = fmtchar; + bufsize--; continue; } else @@ -524,7 +526,10 @@ doprnt (char *buffer, ptrdiff_t bufsize, const char *format, else { do - *bufptr++ = *src++; + { + *bufptr++ = *src++; + bufsize--; + } while (--srclen != 0); } } commit 9b2e230c063f3e716c08a31685e16dff91130f4d Author: Paul Eggert Date: Mon Jan 27 13:01:47 2025 -0800 doprnt %X support * src/doprnt.c (doprnt): Also support %X, since callers now use %X. diff --git a/src/doprnt.c b/src/doprnt.c index 335223f972a..421c4f4d15f 100644 --- a/src/doprnt.c +++ b/src/doprnt.c @@ -61,7 +61,8 @@ along with GNU Emacs. If not, see . */ %d means print a 'signed int' argument in decimal. %o means print an 'unsigned int' argument in octal. %u means print an 'unsigned int' argument in decimal. - %x means print an 'unsigned int' argument in hex. + %x means print an 'unsigned int' argument in lower-case hex. + %X means print an 'unsigned int' argument in upper-case hex. %e means print a 'double' argument in exponential notation. %f means print a 'double' argument in decimal-point notation. %g means print a 'double' argument in exponential notation @@ -350,7 +351,7 @@ doprnt (char *buffer, ptrdiff_t bufsize, const char *format, case 'o': case 'u': - case 'x': + case 'x': case 'X': switch (length_modifier) { case no_modifier: commit ba60fa3deaa030eb4815caa8c180ac841709e86a Author: Stefan Kangas Date: Mon Jan 27 22:48:28 2025 +0100 Don't use obsolete face variables in lisp-mode.el * lisp/emacs-lisp/lisp-mode.el (lisp-el-font-lock-keywords-1) (lisp-cl-font-lock-keywords-1, lisp-el-font-lock-keywords-2) (lisp-cl-font-lock-keywords-2): Don't use obsolete face variables. diff --git a/lisp/emacs-lisp/lisp-mode.el b/lisp/emacs-lisp/lisp-mode.el index 9e8292b992a..bb9f2edac4e 100644 --- a/lisp/emacs-lisp/lisp-mode.el +++ b/lisp/emacs-lisp/lisp-mode.el @@ -433,10 +433,10 @@ This will generate compile-time constants from BINDINGS." "\\(([ \t']*\\)?" ;; An opening paren. "\\(\\(setf\\)[ \t]+" (rx lisp-mode-symbol) "\\|" (rx lisp-mode-symbol) "\\)?") - (1 font-lock-keyword-face) + (1 'font-lock-keyword-face) (3 (let ((type (get (intern-soft (match-string 1)) 'lisp-define-type))) - (cond ((eq type 'var) font-lock-variable-name-face) - ((eq type 'type) font-lock-type-face) + (cond ((eq type 'var) 'font-lock-variable-name-face) + ((eq type 'type) 'font-lock-type-face) ;; If match-string 2 is non-nil, we encountered a ;; form like (defalias (intern (concat s "-p"))), ;; unless match-string 4 is also there. Then its a @@ -444,12 +444,12 @@ This will generate compile-time constants from BINDINGS." ((or (not (match-string 2)) ;; Normal defun. (and (match-string 2) ;; Setf method. (match-string 4))) - font-lock-function-name-face))) + 'font-lock-function-name-face))) nil t)) ;; Emacs Lisp autoload cookies. Supports the slightly different ;; forms used by mh-e, calendar, etc. - (,lisp-mode-autoload-regexp (3 font-lock-warning-face prepend) - (2 font-lock-function-name-face prepend t))) + (,lisp-mode-autoload-regexp (3 'font-lock-warning-face prepend) + (2 'font-lock-function-name-face prepend t))) "Subdued level highlighting for Emacs Lisp mode.") (defconst lisp-cl-font-lock-keywords-1 @@ -460,14 +460,14 @@ This will generate compile-time constants from BINDINGS." "\\(([ \t']*\\)?" ;; An opening paren. "\\(\\(setf\\)[ \t]+" (rx lisp-mode-symbol) "\\|" (rx lisp-mode-symbol) "\\)?") - (1 font-lock-keyword-face) + (1 'font-lock-keyword-face) (3 (let ((type (get (intern-soft (match-string 1)) 'lisp-define-type))) - (cond ((eq type 'var) font-lock-variable-name-face) - ((eq type 'type) font-lock-type-face) + (cond ((eq type 'var) 'font-lock-variable-name-face) + ((eq type 'type) 'font-lock-type-face) ((or (not (match-string 2)) ;; Normal defun. (and (match-string 2) ;; Setf function. (match-string 4))) - font-lock-function-name-face))) + 'font-lock-function-name-face))) nil t))) "Subdued level highlighting for Lisp modes.") @@ -477,17 +477,17 @@ This will generate compile-time constants from BINDINGS." (append lisp-el-font-lock-keywords-1 `( ;; Regexp negated char group. - ("\\[\\(\\^\\)" 1 font-lock-negation-char-face prepend) + ("\\[\\(\\^\\)" 1 'font-lock-negation-char-face prepend) ;; Erroneous structures. (,(concat "(" el-errs-re "\\_>") - (1 font-lock-warning-face)) + (1 'font-lock-warning-face)) ;; Control structures. Common Lisp forms. (lisp--el-match-keyword . 1) ;; Exit/Feature symbols as constants. (,(concat "(\\(catch\\|throw\\|featurep\\|provide\\|require\\)\\_>" "[ \t']*\\(" (rx lisp-mode-symbol) "\\)?") - (1 font-lock-keyword-face) - (2 font-lock-constant-face nil t)) + (1 'font-lock-keyword-face) + (2 'font-lock-constant-face nil t)) ;; Words inside \\[], \\<>, \\{} or \\`' tend to be for ;; `substitute-command-keys'. (,(rx "\\\\" (or (seq "[" @@ -496,27 +496,27 @@ This will generate compile-time constants from BINDINGS." ;; allow multiple words, e.g. "C-x a" lisp-mode-symbol (* " " lisp-mode-symbol)) "'"))) - (1 font-lock-constant-face prepend)) + (1 'font-lock-constant-face prepend)) (,(rx "\\\\" (or (seq "<" (group-n 1 (seq lisp-mode-symbol (not "\\"))) ">") (seq "{" (group-n 1 (seq lisp-mode-symbol (not "\\"))) "}"))) - (1 font-lock-variable-name-face prepend)) + (1 'font-lock-variable-name-face prepend)) ;; Ineffective backslashes (typically in need of doubling). ("\\(\\\\\\)\\([^\"\\]\\)" (1 (elisp--font-lock-backslash) prepend)) ;; Words inside ‘’, '' and `' tend to be symbol names. (,(concat "[`‘']\\(" (rx lisp-mode-symbol) "\\)['’]") - (1 font-lock-constant-face prepend)) + (1 'font-lock-constant-face prepend)) ;; \\= tends to be an escape in doc strings. (,(rx "\\\\=") - (0 font-lock-builtin-face prepend)) + (0 'font-lock-builtin-face prepend)) ;; Constant values. (,(lambda (bound) (lisp-mode--search-key ":" bound)) - (0 font-lock-builtin-face)) + (0 'font-lock-builtin-face)) ;; ELisp and CLisp `&' keywords as types. (,(lambda (bound) (lisp-mode--search-key "&" bound)) - (0 font-lock-type-face)) + (0 'font-lock-type-face)) ;; ELisp regexp grouping constructs (,(lambda (bound) (catch 'found @@ -534,11 +534,11 @@ This will generate compile-time constants from BINDINGS." (1 'font-lock-regexp-grouping-backslash prepend) (3 'font-lock-regexp-grouping-construct prepend)) (lisp--match-hidden-arg - (0 '(face font-lock-warning-face + (0 '(face 'font-lock-warning-face help-echo "Easy to misread; consider moving the element to the next line") prepend)) (lisp--match-confusable-symbol-character - 0 '(face font-lock-warning-face + 0 '(face 'font-lock-warning-face help-echo "Confusable character")) )) "Gaudy level highlighting for Emacs Lisp mode.") @@ -547,29 +547,29 @@ This will generate compile-time constants from BINDINGS." (append lisp-cl-font-lock-keywords-1 `( ;; Regexp negated char group. - ("\\[\\(\\^\\)" 1 font-lock-negation-char-face prepend) + ("\\[\\(\\^\\)" 1 'font-lock-negation-char-face prepend) ;; Control structures. Common Lisp forms. (,(concat "(" cl-kws-re "\\_>") . 1) ;; Exit/Feature symbols as constants. (,(concat "(\\(catch\\|throw\\|provide\\|require\\)\\_>" "[ \t']*\\(" (rx lisp-mode-symbol) "\\)?") - (1 font-lock-keyword-face) - (2 font-lock-constant-face nil t)) + (1 'font-lock-keyword-face) + (2 'font-lock-constant-face nil t)) ;; Erroneous structures. (,(concat "(" cl-errs-re "\\_>") - (1 font-lock-warning-face)) + (1 'font-lock-warning-face)) ;; Words inside ‘’ and `' tend to be symbol names. (,(concat "[`‘]\\(" (rx lisp-mode-symbol) "\\)['’]") - (1 font-lock-constant-face prepend)) + (1 'font-lock-constant-face prepend)) ;; Uninterned symbols, e.g., (defpackage #:my-package ...) ;; must come before keywords below to have effect - (,(concat "#:" (rx lisp-mode-symbol) "") 0 font-lock-builtin-face) + (,(concat "#:" (rx lisp-mode-symbol) "") 0 'font-lock-builtin-face) ;; Constant values. (,(lambda (bound) (lisp-mode--search-key ":" bound)) - (0 font-lock-builtin-face)) + (0 'font-lock-builtin-face)) ;; ELisp and CLisp `&' keywords as types. (,(lambda (bound) (lisp-mode--search-key "&" bound)) - (0 font-lock-type-face)) + (0 'font-lock-type-face)) ;; ELisp regexp grouping constructs ;; This is too general -- rms. ;; A user complained that he has functions whose names start with `do' @@ -577,9 +577,9 @@ This will generate compile-time constants from BINDINGS." ;; That user has violated the https://www.cliki.net/Naming+conventions: ;; CL (but not EL!) `with-' (context) and `do-' (iteration) (,(concat "(\\(\\(do-\\|with-\\)" (rx lisp-mode-symbol) "\\)") - (1 font-lock-keyword-face)) + (1 'font-lock-keyword-face)) (lisp--match-hidden-arg - (0 '(face font-lock-warning-face + (0 '(face 'font-lock-warning-face help-echo "Easy to misread; consider moving the element to the next line") prepend)) )) commit 29c6dad78db6d599108612f120cd0fb1fb18e105 Author: Stephen Gildea Date: Mon Jan 27 10:44:37 2025 -0800 time-stamp: Don't get confused by newline in file name * lisp/time-stamp.el (time-stamp-filtered-buffer-file-name): New helper * test/lisp/time-stamp-tests.el: (time-stamp-custom-file-name): New test diff --git a/lisp/time-stamp.el b/lisp/time-stamp.el index 8d40d7cd194..a2e91246ae2 100644 --- a/lisp/time-stamp.el +++ b/lisp/time-stamp.el @@ -726,11 +726,12 @@ and all `time-stamp-format' compatibility." (time-stamp--format "%Z" time))) ((eq cur-char ?f) ;buffer-file-name, base name only (if buffer-file-name - (file-name-nondirectory buffer-file-name) + (time-stamp-filtered-buffer-file-name :nondirectory) time-stamp-no-file)) ((eq cur-char ?F) ;buffer-file-name, absolute name - (or buffer-file-name - time-stamp-no-file)) + (if buffer-file-name + (time-stamp-filtered-buffer-file-name :absolute) + time-stamp-no-file)) ((eq cur-char ?s) ;system name, legacy (time-stamp-conv-warn "%s" "%Q") (system-name)) @@ -803,6 +804,26 @@ This is an internal helper for `time-stamp-string-preprocess'." "" ;discourage "%:2d" and the like (string-to-number (time-stamp--format format-string time))))) +(defun time-stamp-filtered-buffer-file-name (type) + "Return the buffer file name, but with non-graphic characters replaced by ?. +TYPE is :absolute for the full name or :nondirectory for base name only." + (declare (ftype (function ((member :absolute :nondirectory)) string))) + (let ((file-name buffer-file-name) + (safe-character-filter + (lambda (chr) + (let ((category (get-char-code-property chr 'general-category))) + (if (or + ;; Letter, Mark, Number, Punctuation, or Symbol + (member (aref (symbol-name category) 0) '(?L ?M ?N ?P ?S)) + ;; spaces of various widths, but not ctrl chars like CR or LF + (eq category 'Zs)) + chr + ;; substitute "?" for format or control character + ??))))) + (when (eq type :nondirectory) + (setq file-name (file-name-nondirectory file-name))) + (apply #'string (mapcar safe-character-filter file-name)))) + (defvar time-stamp-conversion-warn t "Enable warnings about soon-to-be-unsupported forms in `time-stamp-format'. diff --git a/test/lisp/time-stamp-tests.el b/test/lisp/time-stamp-tests.el index eaca8d4d5ae..c59ae9f5356 100644 --- a/test/lisp/time-stamp-tests.el +++ b/test/lisp/time-stamp-tests.el @@ -29,7 +29,7 @@ (declare (indent 0) (debug t)) `(let ((user-login-name "test-logname") (user-full-name "100%d Tester") ;verify "%" passed unchanged - (buffer-file-name "/emacs/test/time-stamped-file") + (buffer-file-name "/emacs/test/0-9AZaz (time)_stamped.file$+^") (mail-host-address "test-mail-host-name") (ref-time1 '(17337 16613)) ;Monday, Jan 2, 2006, 3:04:05 PM (ref-time2 '(22574 61591)) ;Friday, Nov 18, 2016, 12:14:15 PM @@ -286,6 +286,24 @@ (time-stamp) (should (equal (buffer-string) buffer-expected-2))))))) +(ert-deftest time-stamp-custom-file-name () + "Test that `time-stamp' isn't confused by a newline in the file name." + (with-time-stamp-test-env + (let ((time-stamp-format "1 %f") ;changed later in the test + (buffer-original-contents "Time-stamp: <>") + (expected-1 "Time-stamp: <1 Embedded?Newline>") + (expected-2 "Time-stamp: <2 Embedded?Newline>")) + (with-temp-buffer + (let ((buffer-file-name "Embedded\nNewline")) + (insert buffer-original-contents) + (time-stamp) + (should (equal (buffer-string) expected-1)) + ;; If the first time-stamp inserted an unexpected newline, the + ;; next time-stamp would be unable to find the end pattern. + (setq time-stamp-format "2 %f") + (time-stamp) + (should (equal (buffer-string) expected-2))))))) + ;;; Tests of time-stamp-string formatting (ert-deftest time-stamp-format-day-of-week () @@ -690,9 +708,10 @@ ;; implemented and recommended since 1995 (should (equal (time-stamp-string "%%" ref-time1) "%")) ;% last char (should (equal (time-stamp-string "%%P" ref-time1) "%P")) ;% not last char - (should (equal (time-stamp-string "%f" ref-time1) "time-stamped-file")) + (should (equal (time-stamp-string "%f" ref-time1) + "0-9AZaz (time)_stamped.file$+^")) (should (equal (time-stamp-string "%F" ref-time1) - "/emacs/test/time-stamped-file")) + "/emacs/test/0-9AZaz (time)_stamped.file$+^")) (with-temp-buffer (should (equal (time-stamp-string "%f" ref-time1) "(no file)")) (should (equal (time-stamp-string "%F" ref-time1) "(no file)"))) commit 2d386fc4490c8e61ed05384ec486ef0d5e7164b1 Author: Stephen Gildea Date: Mon Jan 27 10:41:01 2025 -0800 time-stamp-tests: Make macro-defined tests findable * test/lisp/time-stamp-tests.el (define-formatz-tests): Use 'find-function-update-type-alist' to make defined tests findable. (formatz-find-test-def-function): New test-finding function. diff --git a/test/lisp/time-stamp-tests.el b/test/lisp/time-stamp-tests.el index 397e21f7bc7..eaca8d4d5ae 100644 --- a/test/lisp/time-stamp-tests.el +++ b/test/lisp/time-stamp-tests.el @@ -1067,41 +1067,63 @@ the other expected results for hours greater than 99 with non-zero seconds." ;; We will modify this list, so start with a list consed at runtime. (let ((ert-test-list (list 'progn)) (common-description - (concat "\nThis test expands from a call to" - " the macro `define-formatz-tests'.\n" - "To find the specific call, search the source file for \""))) + (concat "\nThis test is defined by a call to" + " the macro `define-formatz-tests'."))) (dolist (form-string form-strings ert-test-list) - (nconc - ert-test-list - (list - `(ert-deftest ,(intern (concat "formatz-" form-string "-hhmm")) () - ,(concat "Test `time-stamp' format " form-string - " with whole hours and whole minutes.\n" - common-description form-string "\".") - (should (equal (formatz ,form-string (fz-make+zone 0)) - ,(car hour-mod))) - (formatz-hours-exact-helper ,form-string ',(cdr hour-mod)) - (should (equal (formatz ,form-string (fz-make+zone 0 30)) - ,(car mins-mod))) - (formatz-nonzero-minutes-helper ,form-string ',(cdr mins-mod))) - `(ert-deftest ,(intern (concat "formatz-" form-string "-seconds")) () - ,(concat "Test `time-stamp' format " form-string - " with offsets that have non-zero seconds.\n" - common-description form-string "\".") - (should (equal (formatz ,form-string (fz-make+zone 0 0 30)) - ,(car secs-mod))) - (formatz-nonzero-seconds-helper ,form-string ',(cdr secs-mod))) - `(ert-deftest ,(intern (concat "formatz-" form-string "-threedigit")) () - ,(concat "Test `time-stamp' format " form-string - " with offsets of 100 hours or greater.\n" - common-description form-string "\".") - (should (equal (formatz ,form-string (fz-make+zone 100)) - ,(car big-mod))) - (formatz-hours-big-helper ,form-string ',(cdr big-mod)) - (should (equal (formatz ,form-string (fz-make+zone 100 0 30)) - ,(car secbig-mod))) - (formatz-seconds-big-helper ,form-string ',(cdr secbig-mod))) - ))))) + (let ((test-name-hhmm + (intern (concat "formatz-" form-string "-hhmm"))) + (test-name-seconds + (intern (concat "formatz-" form-string "-seconds"))) + (test-name-threedigit + (intern (concat "formatz-" form-string "-threedigit")))) + (nconc + ert-test-list + (list + `(find-function-update-type-alist + ',test-name-hhmm 'ert--test 'formatz-find-test-def-function) + `(ert-deftest ,test-name-hhmm () + ,(concat "Test `time-stamp' format " form-string + " with whole hours and whole minutes.\n" + common-description) + (should (equal (formatz ,form-string (fz-make+zone 0)) + ,(car hour-mod))) + (formatz-hours-exact-helper ,form-string ',(cdr hour-mod)) + (should (equal (formatz ,form-string (fz-make+zone 0 30)) + ,(car mins-mod))) + (formatz-nonzero-minutes-helper ,form-string ',(cdr mins-mod))) + `(find-function-update-type-alist + ',test-name-seconds 'ert--test 'formatz-find-test-def-function) + `(ert-deftest ,test-name-seconds () + ,(concat "Test `time-stamp' format " form-string + " with offsets that have non-zero seconds.\n" + common-description) + (should (equal (formatz ,form-string (fz-make+zone 0 0 30)) + ,(car secs-mod))) + (formatz-nonzero-seconds-helper ,form-string ',(cdr secs-mod))) + `(find-function-update-type-alist + ',test-name-threedigit 'ert--test 'formatz-find-test-def-function) + `(ert-deftest ,test-name-threedigit () + ,(concat "Test `time-stamp' format " form-string + " with offsets of 100 hours or greater.\n" + common-description) + (should (equal (formatz ,form-string (fz-make+zone 100)) + ,(car big-mod))) + (formatz-hours-big-helper ,form-string ',(cdr big-mod)) + (should (equal (formatz ,form-string (fz-make+zone 100 0 30)) + ,(car secbig-mod))) + (formatz-seconds-big-helper ,form-string ',(cdr secbig-mod))) + )))))) + +(defun formatz-find-test-def-function (test-name) + "Search for the `define-formatz-tests' call defining test TEST-NAME. +Return non-nil if the definition is found." + (let* ((z-format (replace-regexp-in-string "\\`formatz-\\([^z]+z\\)-.*\\'" + "\\1" + (symbol-name test-name))) + (regexp (concat "^(define-formatz-tests (" + "\\(?:[^)]\\|;.*\n\\)*" + "\"" (regexp-quote z-format) "\""))) + (re-search-forward regexp nil t))) ;;;; The actual test cases for %z commit 5eae7f5227c7789dea45cef26fec17c057024670 Author: jared Date: Sun Jan 26 14:43:51 2025 -0800 Fix clicking in child frames with GPM * src/term.c (handle_one_term_event): Store child frame coordinates in event. diff --git a/src/term.c b/src/term.c index e519813c7ac..a058cb1f62a 100644 --- a/src/term.c +++ b/src/term.c @@ -2767,9 +2767,11 @@ term_mouse_click (struct input_event *result, Gpm_Event *event, int handle_one_term_event (struct tty_display_info *tty, const Gpm_Event *event_in) { + int child_x, child_y; + Lisp_Object frame = tty_frame_at (event_in->x, event_in->y, &child_x, &child_y); Gpm_Event event = *event_in; - int gpm_x = event.x, gpm_y = event.y; - Lisp_Object frame = tty_frame_at (event_in->x, event_in->y, &gpm_x, &gpm_y); + event.x = child_x; + event.y = child_y; struct frame *f = decode_live_frame (frame); struct input_event ie; commit 59050c3e8c500e216ec7214195c9441ecb4a031c Author: Gerd Möllmann Date: Mon Jan 27 10:21:08 2025 +0100 ; Fix workaround for xt-mouse-tests * lisp/xt-mouse.el (xterm-mouse-event): For running this in batch mode, fix computation of x and y. diff --git a/lisp/xt-mouse.el b/lisp/xt-mouse.el index e395723d05c..250f4efebb4 100644 --- a/lisp/xt-mouse.el +++ b/lisp/xt-mouse.el @@ -297,11 +297,12 @@ which is the \"1006\" extension implemented in Xterm >= 277." 1000)))) ;; FIXME: The test for running in batch mode is here solely ;; for the sake of xt-mouse-tests where the only frame is - ;; the initial frame. + ;; the initial frame. The same goes for the computation of + ;; x and y. (frame-and-xy (unless noninteractive (tty-frame-at x y))) (frame (nth 0 frame-and-xy)) - (x (nth 1 frame-and-xy)) - (y (nth 2 frame-and-xy)) + (x (or (nth 1 frame-and-xy) x)) + (y (or (nth 2 frame-and-xy) y)) (w (window-at x y frame)) (ltrb (window-edges w)) (left (nth 0 ltrb)) commit 827dfe5a72f36cb6b61b435a85d50ac725616a09 Author: Martin Rudalics Date: Mon Jan 27 10:06:51 2025 +0100 In Elisp manual document new functions for changing window layouts * doc/lispref/windows.texi (Changing Window Layouts): New section to document the new functions for changing window layouts. * doc/lispref/elisp.texi (Top): Add entry for new section. diff --git a/doc/lispref/elisp.texi b/doc/lispref/elisp.texi index 1400cb37dd7..27be7ae7710 100644 --- a/doc/lispref/elisp.texi +++ b/doc/lispref/elisp.texi @@ -1080,6 +1080,7 @@ Windows * Recombining Windows:: Preserving the frame layout when splitting and deleting windows. * Resurrecting Windows:: Restoring deleted windows. +* Changing Window Layouts:: Transposing windows in an orderly manner. * Cyclic Window Ordering:: Moving around the existing windows. * Buffers and Windows:: Each window displays the contents of a buffer. * Switching Buffers:: Higher-level functions for switching to a buffer. diff --git a/doc/lispref/windows.texi b/doc/lispref/windows.texi index cb406c4e670..60a188590eb 100644 --- a/doc/lispref/windows.texi +++ b/doc/lispref/windows.texi @@ -23,6 +23,7 @@ is displayed in windows. * Recombining Windows:: Preserving the frame layout when splitting and deleting windows. * Resurrecting Windows:: Restoring deleted windows. +* Changing Window Layouts:: Transposing windows in an orderly manner. * Cyclic Window Ordering:: Moving around the existing windows. * Buffers and Windows:: Each window displays the contents of a buffer. * Switching Buffers:: Higher-level functions for switching to a buffer. @@ -2225,6 +2226,205 @@ limit is preserved which means that the window can be recombined (@pxref{Recombining Windows}) as before. +@node Changing Window Layouts +@section Changing Window Layouts + +Sometimes it can be useful to change the layout of windows such that two +or more windows occupy the locations of each other. The commands +described in this section do that in an orderly manner. Conceptually, +these commands affect a rectangular subset of the windows on a frame. +As a rule, they neither affect the location of a frame's minibuffer +window nor of any of its side windows (@pxref{Side Windows}). + + Common to all these commands is that they preserve the identity of +windows by deleting them first and resurrecting them +(@pxref{Resurrecting Windows}) in their new locations afterwards. No +window gets lost and no window is added or duplicated. Where possible, +these commands try to preserve the relative size of windows as well as +all other non-geometric properties including parameters. + + The @var{window} argument of all functions described in this section +must specify a valid parent window (@pxref{Windows and Frames}). If it +is @code{nil}, it stands for the main window (@pxref{Side Windows}) of +the selected frame. Interactively, a prefix argument means to operate +on the parent window of the selected window. In the examples given +below, we shall always assume that the windows displayed constitute +their frame's main window and the @var{window} argument is @code{nil} +unless stated otherwise. + + The first two commands rotate a window layout either clockwise or +counterclockwise. +@cindex rotate window layout + +@deffn Command rotate-window-layout-clockwise &optional window +This command rotates the window layout clockwise by 90 degrees. Imagine +a layout with three live windows @var{A}, @var{B} and @var{C} as +depicted on the left below. Then this command will produce the layout +on the right. + +@smallexample +@group + ___________ ___________ + | | | | | + | A | | B | | + |___________| --> |_____| A | + | | | | | | + | B | C | | C | | + |_____|_____| |_____|_____| + +@end group +@end smallexample + +With a prefix argument and window @var{B} selected, window @var{A} would +have remained unaffected and the layout would have changed as follows: + +@smallexample +@group + ___________ ___________ + | | | | + | A | | A | + |___________| --> |___________| + | | | | | | + | B | C | | C | B | + |_____|_____| |_____|_____| + +@end group +@end smallexample +@end deffn + +@deffn Command rotate-window-layout-counterclockwise &optional window +This is like @code{rotate-window-layout-clockwise} but rotates the +layout in the opposite direction as demonstrated in the example below. + +@smallexample +@group + ___________ ___________ + | | | | | + | A | | | C | + |___________| --> | A |_____| + | | | | | | + | B | C | | | B | + |_____|_____| |_____|_____| + +@end group +@end smallexample +@end deffn + +The next two commands @sc{flip} the window layout---rotate it around an +imaginary horizontal or vertical axis. +@cindex flip window layout + +@deffn Command flip-window-layout-vertically &optional window +This command flips windows such that windows on the bottom become +windows on the top and vice-versa as in the example below. + +@smallexample +@group + ___________ ___________ + | | | | | + | A | | B | C | + |___________| --> |_____|_____| + | | | | | + | B | C | | A | + |_____|_____| |___________| + +@end group +@end smallexample +@end deffn + +@deffn Command flip-window-layout-horizontally &optional window +This command rearranges window in a way that the windows on the right +become the window on the left, and vice-versa. + +@smallexample +@group + ___________ ___________ + | | | | + | A | | A | + |___________| --> |___________| + | | | | | | + | B | C | | C | B | + |_____|_____| |_____|_____| + +@end group +@end smallexample +@end deffn + +The next command can be used for @sc{transposing} windows---changing +horizontal splits to vertical ones and vice-versa. +@cindex transposing windows + +@deffn Command transpose-window-layout &optional window +This command reorganizes windows such that every horizontal split +becomes a vertical split and vice versa. + +@smallexample +@group + ___________ ___________ + | | | | | + | A | | | B | + |___________| --> | A |_____| + | | | | | | + | B | C | | | C | + |_____|_____| |_____|_____| + +@end group +@end smallexample +@end deffn + +The final two commands can be used to rotate windows within the existing +layout. They are like the commands that rotate the layout but leave the +underlying structure of the layout unchanged. What actually changes are +the positions of windows within the existing layout. +@cindex rotating windows + +@deffn Command rotate-windows &optional window reverse +This rotate windows under @var{window} in cyclic ordering. The optional +argument @var{reverse} means to rotate windows backward, in reverse +cyclic order. + +@smallexample +@group + ___________ ___________ +| | | | +| A | | B | +|___________| --> |___________| +| | | | | | +| B | C | | C | A | +|_____|_____| |_____|_____| + +@end group +@end smallexample +@end deffn + +@deffn Command rotate-windows-back &optional window +This command rotates windows under @var{window} backward in cyclic +ordering. + +@smallexample +@group + ___________ ___________ +| | | | +| A | | C | +|___________| --> |___________| +| | | | | | +| B | C | | A | B | +|_____|_____| |_____|_____| + +@end group +@end smallexample +@end deffn + +The last two commands are subject to the following option. + +@defopt rotate-windows-change-selected +If this is @code{nil}, the selected window will remain unaffected by +@code{rotate-windows} and @code{rotate-windows-back}. Otherwise, the +selected window will change to the window that appears at the location +of the selected window before any of these commands were invoked. +@end defopt + + @node Cyclic Window Ordering @section Cyclic Ordering of Windows @cindex cyclic ordering of windows diff --git a/etc/NEWS b/etc/NEWS index 249fcafd5cd..ec61f2bc430 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -173,6 +173,7 @@ the "*Completions*" buffer is hidden. ** Windows ++++ *** New functions to modify window layout. Several functions to modify the window layout have been added: 'rotate-window-layout-clockwise' commit d2ffa0fa488fcfec26c042d30d125915eb558444 Author: Stefan Kangas Date: Mon Jan 27 08:50:35 2025 +0100 ; Fix byte-compilation warnings diff --git a/lisp/cedet/semantic/idle.el b/lisp/cedet/semantic/idle.el index 515a6b439bb..caf581c56eb 100644 --- a/lisp/cedet/semantic/idle.el +++ b/lisp/cedet/semantic/idle.el @@ -820,12 +820,12 @@ visible, then highlight it." (point) (get-buffer-window (current-buffer) 'visible)) (if (< (overlay-end region) (line-end-position)) (pulse-momentary-highlight-overlay - region semantic-idle-symbol-highlight) + region 'semantic-idle-symbol-highlight) ;; Not the same (pulse-momentary-highlight-region (overlay-start region) (line-end-position) - semantic-idle-symbol-highlight)))))) + 'semantic-idle-symbol-highlight)))))) ((vectorp region) (let ((start (aref region 0)) (end (aref region 1))) @@ -844,7 +844,7 @@ visible, then highlight it." (pulse-momentary-highlight-region start (if (<= end (line-end-position)) end (line-end-position)) - semantic-idle-symbol-highlight))))))) + 'semantic-idle-symbol-highlight))))))) nil)) (define-semantic-idle-service semantic-idle-local-symbol-highlight @@ -874,7 +874,7 @@ Call `semantic-symref-hits-in-region' to identify local references." target (lambda (start end _prefix) (when (/= start (car Hbounds)) (pulse-momentary-highlight-region - start end semantic-idle-symbol-highlight)) + start end 'semantic-idle-symbol-highlight)) (semantic-throw-on-input 'symref-highlight)) (semantic-tag-start tag) (semantic-tag-end tag))))))) diff --git a/lisp/whitespace.el b/lisp/whitespace.el index 2f66950c7d3..efee11faf98 100644 --- a/lisp/whitespace.el +++ b/lisp/whitespace.el @@ -2544,7 +2544,7 @@ purposes)." (or (eq (aref vec i) ?\n) (aset vec i (make-glyph-code (aref vec i) - whitespace-newline))))) + 'whitespace-newline))))) ;; Display mapping (aset buffer-display-table (cadr entry) vec)))))))