From f3fd9591cfca5450b4bc74274340f24068f96fc7 Mon Sep 17 00:00:00 2001 From: Lars Ingebrigtsen Date: Tue, 9 Feb 2021 08:12:10 +0100 Subject: Fix count-lines problem in non-ASCII buffers * src/fns.c (Fline_number_at_pos): Get the correct start position in non-ASCII buffers (bug#22763). --- src/fns.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/fns.c') diff --git a/src/fns.c b/src/fns.c index 02743c62a57..c16f9c63998 100644 --- a/src/fns.c +++ b/src/fns.c @@ -5769,7 +5769,7 @@ visible part of the buffer. If ABSOLUTE is non-nil, count the lines from the absolute start of the buffer. */) (register Lisp_Object position, Lisp_Object absolute) { - ptrdiff_t pos, start = BEGV; + ptrdiff_t pos, start = BEGV_BYTE; if (MARKERP (position)) pos = marker_position (position); -- cgit v1.2.3 From 297c0e0306f111c1e7564b2bb49a7e1a925a55bb Mon Sep 17 00:00:00 2001 From: Juri Linkov Date: Thu, 25 Feb 2021 20:45:40 +0200 Subject: New variable 'use-short-answers' to use 'y-or-n-p' instead of 'yes-or-no-p' * lisp/cus-start.el: Add use-short-answers. * lisp/emacs-lisp/map-ynp.el (read-answer): Handle use-short-answers. (read-answer-short): Add use-short-answers to docstring. * src/fns.c (Fyes_or_no_p): Call y-or-n-p if use_short_answers is true. (syms_of_fns): Add DEFVAR_BOOL use-short-answers (bug#46594). --- etc/NEWS | 5 +++++ lisp/cus-start.el | 1 + lisp/emacs-lisp/map-ynp.el | 6 ++++-- src/fns.c | 14 ++++++++++++++ 4 files changed, 24 insertions(+), 2 deletions(-) (limited to 'src/fns.c') diff --git a/etc/NEWS b/etc/NEWS index caa366aaef8..1ec080a6db5 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -2414,6 +2414,11 @@ and display the result. When non-nil, then functions 'read-char-choice' and 'y-or-n-p' (respectively) use the function 'read-key' to read a character instead of using the minibuffer. +--- +** New variable 'use-short-answers' to use 'y-or-n-p' instead of 'yes-or-no-p'. +This relieves of the need to define an alias that maps one to another +in the init file. The same variable also affects the function 'read-answer'. + +++ ** 'set-window-configuration' now takes an optional 'dont-set-frame' parameter which, when non-nil, instructs the function not to select diff --git a/lisp/cus-start.el b/lisp/cus-start.el index c0a4a6dda06..7b05f5796a4 100644 --- a/lisp/cus-start.el +++ b/lisp/cus-start.el @@ -302,6 +302,7 @@ Leaving \"Default\" unchecked is equivalent with specifying a default of ;; fns.c (use-dialog-box menu boolean "21.1") (use-file-dialog menu boolean "22.1") + (use-short-answers menu boolean "28.1") (focus-follows-mouse frames (choice (const :tag "Off (nil)" :value nil) diff --git a/lisp/emacs-lisp/map-ynp.el b/lisp/emacs-lisp/map-ynp.el index 14112a1c147..86a0c76fd16 100644 --- a/lisp/emacs-lisp/map-ynp.el +++ b/lisp/emacs-lisp/map-ynp.el @@ -265,7 +265,8 @@ C-g to quit (cancel the whole command); "If non-nil, `read-answer' accepts single-character answers. If t, accept short (single key-press) answers to the question. If nil, require long answers. If `auto', accept short answers if -the function cell of `yes-or-no-p' is set to `y-or-n-p'." +`use-short-answers' is non-nil, or the function cell of `yes-or-no-p' +is set to `y-or-n-p'." :type '(choice (const :tag "Accept short answers" t) (const :tag "Require long answer" nil) (const :tag "Guess preference" auto)) @@ -304,7 +305,8 @@ Return a long answer even in case of accepting short ones. When `use-dialog-box' is t, pop up a dialog window to get user input." (let* ((short (if (eq read-answer-short 'auto) - (eq (symbol-function 'yes-or-no-p) 'y-or-n-p) + (or use-short-answers + (eq (symbol-function 'yes-or-no-p) 'y-or-n-p)) read-answer-short)) (answers-with-help (if (assoc "help" answers) diff --git a/src/fns.c b/src/fns.c index c16f9c63998..79b5a1e9930 100644 --- a/src/fns.c +++ b/src/fns.c @@ -2873,6 +2873,11 @@ if `last-nonmenu-event' is nil, and `use-dialog-box' is non-nil. */) return obj; } + if (use_short_answers) + { + return call1 (intern ("y-or-n-p"), prompt); + } + AUTO_STRING (yes_or_no, "(yes or no) "); prompt = CALLN (Fconcat, prompt, yes_or_no); @@ -5904,6 +5909,15 @@ that disables the use of a file dialog, regardless of the value of this variable. */); use_file_dialog = true; + DEFVAR_BOOL ("use-short-answers", use_short_answers, + doc: /* Non-nil means `yes-or-no-p' uses shorter answers "y" or "n". +It's discouraged to use single-key answers because `yes-or-no-p' is +intended to be used when it's thought that you should not respond too +quickly, so you take time and perhaps think more about the answer. +When non-nil, then `yes-or-no-p' uses `y-or-n-p' to read an answer. +The same variable also affects the function `read-answer'. */); + use_short_answers = false; + defsubr (&Sidentity); defsubr (&Srandom); defsubr (&Slength); -- cgit v1.2.3 From 6bf56a3614ccd23a31e34ae997b2a6bb0d158489 Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Thu, 25 Feb 2021 20:58:44 +0200 Subject: Fix documentation of a recent change * src/fns.c (Fyes_or_no_p): Don't use braces around one-line block. (syms_of_fns) : Improve the wording of the doc string. * etc/NEWS: Improve wording of the entry about 'use-short-answers'. --- etc/NEWS | 5 +++-- src/fns.c | 12 +++++------- 2 files changed, 8 insertions(+), 9 deletions(-) (limited to 'src/fns.c') diff --git a/etc/NEWS b/etc/NEWS index 1ec080a6db5..f8f41e21e2d 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -2416,8 +2416,9 @@ use the function 'read-key' to read a character instead of using the minibuffer. --- ** New variable 'use-short-answers' to use 'y-or-n-p' instead of 'yes-or-no-p'. -This relieves of the need to define an alias that maps one to another -in the init file. The same variable also affects the function 'read-answer'. +This eliminates the need to define an alias that maps one to another +in the init file. The same variable also controls whether the +function 'read-answer' accepts short answers. +++ ** 'set-window-configuration' now takes an optional 'dont-set-frame' diff --git a/src/fns.c b/src/fns.c index 79b5a1e9930..7914bd47790 100644 --- a/src/fns.c +++ b/src/fns.c @@ -2874,9 +2874,7 @@ if `last-nonmenu-event' is nil, and `use-dialog-box' is non-nil. */) } if (use_short_answers) - { - return call1 (intern ("y-or-n-p"), prompt); - } + return call1 (intern ("y-or-n-p"), prompt); AUTO_STRING (yes_or_no, "(yes or no) "); prompt = CALLN (Fconcat, prompt, yes_or_no); @@ -5911,10 +5909,10 @@ this variable. */); DEFVAR_BOOL ("use-short-answers", use_short_answers, doc: /* Non-nil means `yes-or-no-p' uses shorter answers "y" or "n". -It's discouraged to use single-key answers because `yes-or-no-p' is -intended to be used when it's thought that you should not respond too -quickly, so you take time and perhaps think more about the answer. -When non-nil, then `yes-or-no-p' uses `y-or-n-p' to read an answer. +When non-nil, `yes-or-no-p' will use `y-or-n-p' to read the answer. +We recommend against setting this variable non-nil, because `yes-or-no-p' +is intended to be used when users are expected not to respond too +quickly, but to take their time and perhaps think about the answer. The same variable also affects the function `read-answer'. */); use_short_answers = false; -- cgit v1.2.3 From d582356a7f704f8a209a3ef31d6ea970520c6224 Mon Sep 17 00:00:00 2001 From: Stefan Monnier Date: Fri, 5 Mar 2021 12:09:50 -0500 Subject: * src/fns.c (Frandom): Handle bignum `limit`s (ccall2, get_random_bignum): New functions. --- doc/lispref/numbers.texi | 2 +- src/fns.c | 53 +++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 53 insertions(+), 2 deletions(-) (limited to 'src/fns.c') diff --git a/doc/lispref/numbers.texi b/doc/lispref/numbers.texi index 63e3e0bace5..4c5f72126ed 100644 --- a/doc/lispref/numbers.texi +++ b/doc/lispref/numbers.texi @@ -1250,7 +1250,7 @@ other strings to choose various seed values. This function returns a pseudo-random integer. Repeated calls return a series of pseudo-random integers. -If @var{limit} is a positive fixnum, the value is chosen to be +If @var{limit} is a positive integer, the value is chosen to be nonnegative and less than @var{limit}. Otherwise, the value might be any fixnum, i.e., any integer from @code{most-negative-fixnum} through @code{most-positive-fixnum} (@pxref{Integer Basics}). diff --git a/src/fns.c b/src/fns.c index 7914bd47790..b193ad648a9 100644 --- a/src/fns.c +++ b/src/fns.c @@ -54,10 +54,55 @@ DEFUN ("identity", Fidentity, Sidentity, 1, 1, 0, return argument; } +static Lisp_Object +ccall2 (Lisp_Object (f) (ptrdiff_t nargs, Lisp_Object *args), + Lisp_Object arg1, Lisp_Object arg2) +{ + Lisp_Object args[2] = {arg1, arg2}; + return f (2, args); +} + +static Lisp_Object +get_random_bignum (Lisp_Object limit) +{ + /* This is a naive transcription into bignums of the fixnum algorithm. + I'd be quite surprised if that's anywhere near the best algorithm + for it. */ + while (true) + { + Lisp_Object val = make_fixnum (0); + Lisp_Object lim = limit; + int bits = 0; + int bitsperiteration = FIXNUM_BITS - 1; + do + { + /* Shift by one so it is a valid positive fixnum. */ + EMACS_INT rand = get_random () >> 1; + Lisp_Object lrand = make_fixnum (rand); + bits += bitsperiteration; + val = ccall2 (Flogior, + Fash (val, make_fixnum (bitsperiteration)), + lrand); + lim = Fash (lim, make_fixnum (- bitsperiteration)); + } + while (!EQ (lim, make_fixnum (0))); + /* Return the remainder, except reject the rare case where + get_random returns a number so close to INTMASK that the + remainder isn't random. */ + Lisp_Object remainder = Frem (val, limit); + if (!NILP (ccall2 (Fleq, + ccall2 (Fminus, val, remainder), + ccall2 (Fminus, + Fash (make_fixnum (1), make_fixnum (bits)), + limit)))) + return remainder; + } +} + DEFUN ("random", Frandom, Srandom, 0, 1, 0, doc: /* Return a pseudo-random integer. By default, return a fixnum; all fixnums are equally likely. -With positive fixnum LIMIT, return random integer in interval [0,LIMIT). +With positive integer LIMIT, return random integer in interval [0,LIMIT). With argument t, set the random number seed from the system's entropy pool if available, otherwise from less-random volatile data such as the time. With a string argument, set the seed based on the string's contents. @@ -71,6 +116,12 @@ See Info node `(elisp)Random Numbers' for more details. */) init_random (); else if (STRINGP (limit)) seed_random (SSDATA (limit), SBYTES (limit)); + if (BIGNUMP (limit)) + { + if (0 > mpz_sgn (*xbignum_val (limit))) + xsignal2 (Qwrong_type_argument, Qnatnump, limit); + return get_random_bignum (limit); + } val = get_random (); if (FIXNUMP (limit) && 0 < XFIXNUM (limit)) -- cgit v1.2.3 From b90c658492a2548f183bf072be50f4a57a2b5f0b Mon Sep 17 00:00:00 2001 From: Juri Linkov Date: Thu, 11 Mar 2021 21:08:09 +0200 Subject: Update docstrings of 'delete'/'remove' to interlink each other (bug#47054) * lisp/subr.el (remove): Add xref to 'delete'. * src/fns.c (Fdelete): Add xref to 'remove'. --- lisp/subr.el | 4 +++- src/fns.c | 3 ++- 2 files changed, 5 insertions(+), 2 deletions(-) (limited to 'src/fns.c') diff --git a/lisp/subr.el b/lisp/subr.el index 77bc7a33b38..ef0e5e6f780 100644 --- a/lisp/subr.el +++ b/lisp/subr.el @@ -887,7 +887,9 @@ Example: (defun remove (elt seq) "Return a copy of SEQ with all occurrences of ELT removed. -SEQ must be a list, vector, or string. The comparison is done with `equal'." +SEQ must be a list, vector, or string. The comparison is done with `equal'. +Contrary to `delete', this does not use side-effects, and the argument +SEQ is not modified." (declare (side-effect-free t)) (if (nlistp seq) ;; If SEQ isn't a list, there's no need to copy SEQ because diff --git a/src/fns.c b/src/fns.c index b193ad648a9..766e767e123 100644 --- a/src/fns.c +++ b/src/fns.c @@ -1867,7 +1867,8 @@ If SEQ is not a list, deletion is never performed destructively; instead this function creates and returns a new vector or string. Write `(setq foo (delete element foo))' to be sure of correctly -changing the value of a sequence `foo'. */) +changing the value of a sequence `foo'. See also `remove', which +does not modify the argument. */) (Lisp_Object elt, Lisp_Object seq) { if (VECTORP (seq)) -- cgit v1.2.3 From 7c2ebf6e23663fdc7b1880a4d7caeadc8c47c00e Mon Sep 17 00:00:00 2001 From: Alan Mackenzie Date: Sun, 21 Mar 2021 16:54:31 +0000 Subject: Prevent open minibuffers getting lost when their frame gets deleted This happened with minibuffer-follows-selected-frame set to t. * doc/emacs/mini.texi (Basic Minibuffer): State where a command's action takes place when a minibuffer's frame has been deleted. * lisp/window.el (window--before-delete-windows, record-window-buffer): Take into account that minibuffers are now recorded on w->prev_buffers field. * src/fns.c (merge_c): New version of `merge' taking a C function, rather than a Lisp function as the comparison function. * src/frame.c (do_switch_frame): Pass arguments sf and for_deletion to move_minibuffers_onnto_frame. * src/lisp.h (top level): Declare merge_c and move_minibuffers_onto_selected_frame. * src/minibuf.c (MB_frame): New Lisp_Object recording the minibuffer's frame. (choose_minibuf_frame): Remove all code except that which sets minibuf_window to the current frame's minibuffer. (minibuffer_ent_greater): New comparison function, passed to merge_c. (zip_minibuffer_stacks): New function. (move_minibuffers_onto_frame): Renamed from `move_minibuffer_onto_frame' given two arguments, the old frame and for_deletion, and simplified. Minibuffers are now stacked in the mini-window's ->prev_buffers field. (read_minibuf): Several detailed amendments. (exp_MB_frame): New Lisp_Object, the expired minibuffer's frame. (read_minibuf_unwind): Search for the expired minibuffer's frame, rather than taking it from (unreliable) variables. Switch temporarily to this frame for tidying up operations. (minibuffer_unwind): New function which pops a stacked minibuffer. (syms_of_minibuf): Call staticpro for the two new Lisp variables. * src/window.c (Fset_window_configuration): Don't record minibuffers with record-window-buffer. * src/xdisp.c (gui_consider_frame_title): Remove redundant Fselect_window, which caused an unwanted frame switch. Amend the arguments to format_mode_line_unwind_data to match. --- doc/emacs/mini.texi | 4 +- lisp/window.el | 5 +- src/fns.c | 46 +++++++++ src/frame.c | 2 +- src/lisp.h | 3 +- src/minibuf.c | 292 +++++++++++++++++++++++++++++++++------------------- src/window.c | 3 +- src/xdisp.c | 3 +- 8 files changed, 242 insertions(+), 116 deletions(-) (limited to 'src/fns.c') diff --git a/doc/emacs/mini.texi b/doc/emacs/mini.texi index 9c1b9757593..d0865c5d0bd 100644 --- a/doc/emacs/mini.texi +++ b/doc/emacs/mini.texi @@ -82,7 +82,9 @@ after a recursive minibuffer has been opened in the current command (@pxref{Recursive Mini,,, elisp}). This option is mainly to retain (approximately) the behavior prior to Emacs 28.1. Note that the effect of the command, when you finally finish using the minibuffer, -always takes place in the frame where you first opened it. +always takes place in the frame where you first opened it. The sole +exception is that when that frame no longer exists, the action takes +place in the currently selected frame. @node Minibuffer File @section Minibuffers for File Names diff --git a/lisp/window.el b/lisp/window.el index cfd9876ed05..f27631bb86a 100644 --- a/lisp/window.el +++ b/lisp/window.el @@ -4158,7 +4158,7 @@ returned by `window-start' and `window-point' respectively. This function is called only if `switch-to-buffer-preserve-window-point' evaluates non-nil." - (dolist (win (window-list)) + (dolist (win (window-list nil 'no-minibuf)) (let* ((buf (window-buffer (or window win))) (start (window-start win)) (pos (window-point win)) @@ -4416,7 +4416,8 @@ WINDOW must be a live window and defaults to the selected one." window (assq-delete-all buffer (window-prev-buffers window)))) ;; Don't record insignificant buffers. - (unless (eq (aref (buffer-name buffer) 0) ?\s) + (when (or (not (eq (aref (buffer-name buffer) 0) ?\s)) + (minibufferp buffer)) ;; Add an entry for buffer to WINDOW's previous buffers. (with-current-buffer buffer (let ((start (window-start window)) diff --git a/src/fns.c b/src/fns.c index 766e767e123..2cd59c83d91 100644 --- a/src/fns.c +++ b/src/fns.c @@ -2279,6 +2279,52 @@ merge (Lisp_Object org_l1, Lisp_Object org_l2, Lisp_Object pred) } } +Lisp_Object +merge_c (Lisp_Object org_l1, Lisp_Object org_l2, bool (*less) (Lisp_Object, Lisp_Object)) +{ + Lisp_Object l1 = org_l1; + Lisp_Object l2 = org_l2; + Lisp_Object tail = Qnil; + Lisp_Object value = Qnil; + + while (1) + { + if (NILP (l1)) + { + if (NILP (tail)) + return l2; + Fsetcdr (tail, l2); + return value; + } + if (NILP (l2)) + { + if (NILP (tail)) + return l1; + Fsetcdr (tail, l1); + return value; + } + + Lisp_Object tem; + if (less (Fcar (l1), Fcar (l2))) + { + tem = l1; + l1 = Fcdr (l1); + org_l1 = l1; + } + else + { + tem = l2; + l2 = Fcdr (l2); + org_l2 = l2; + } + if (NILP (tail)) + value = tem; + else + Fsetcdr (tail, tem); + tail = tem; + } +} + /* This does not check for quits. That is safe since it must terminate. */ diff --git a/src/frame.c b/src/frame.c index cfdf3b61938..66ae4943ba2 100644 --- a/src/frame.c +++ b/src/frame.c @@ -1487,7 +1487,7 @@ do_switch_frame (Lisp_Object frame, int track, int for_deletion, Lisp_Object nor #endif internal_last_event_frame = Qnil; - move_minibuffer_onto_frame (); + move_minibuffers_onto_frame (sf, for_deletion); return frame; } diff --git a/src/lisp.h b/src/lisp.h index b95f389b890..c67c8b08573 100644 --- a/src/lisp.h +++ b/src/lisp.h @@ -3610,6 +3610,7 @@ extern void validate_subarray (Lisp_Object, Lisp_Object, Lisp_Object, extern Lisp_Object substring_both (Lisp_Object, ptrdiff_t, ptrdiff_t, ptrdiff_t, ptrdiff_t); extern Lisp_Object merge (Lisp_Object, Lisp_Object, Lisp_Object); +extern Lisp_Object merge_c (Lisp_Object, Lisp_Object, bool (*) (Lisp_Object, Lisp_Object)); extern Lisp_Object do_yes_or_no_p (Lisp_Object); extern int string_version_cmp (Lisp_Object, Lisp_Object); extern Lisp_Object concat2 (Lisp_Object, Lisp_Object); @@ -4348,7 +4349,7 @@ extern void clear_regexp_cache (void); extern Lisp_Object Vminibuffer_list; extern Lisp_Object last_minibuf_string; -extern void move_minibuffer_onto_frame (void); +extern void move_minibuffers_onto_frame (struct frame *, bool); extern bool is_minibuffer (EMACS_INT, Lisp_Object); extern EMACS_INT this_minibuffer_depth (Lisp_Object); extern EMACS_INT minibuf_level; diff --git a/src/minibuf.c b/src/minibuf.c index 4b1f4b1ff72..d58924ae520 100644 --- a/src/minibuf.c +++ b/src/minibuf.c @@ -59,6 +59,12 @@ Lisp_Object last_minibuf_string; static Lisp_Object minibuf_prompt; +/* The frame containinug the most recently opened Minibuffer. This is + used only when `minibuffer-follows-selected-frame' is neither nil + nor t. */ + +static Lisp_Object MB_frame; + /* Width of current mini-buffer prompt. Only set after display_line of the line that contains the prompt. */ @@ -67,6 +73,7 @@ static ptrdiff_t minibuf_prompt_width; static Lisp_Object nth_minibuffer (EMACS_INT depth); static EMACS_INT minibuf_c_loop_level (EMACS_INT depth); static void set_minibuffer_mode (Lisp_Object buf, EMACS_INT depth); +static bool live_minibuffer_p (Lisp_Object); /* Return TRUE when a frame switch causes a minibuffer on the old @@ -78,6 +85,7 @@ minibuf_follows_frame (void) Qt); } +#if 0 /* Return TRUE when a minibuffer always remains on the frame where it was first invoked. */ static bool @@ -85,6 +93,7 @@ minibuf_stays_put (void) { return NILP (Fdefault_toplevel_value (Qminibuffer_follows_selected_frame)); } +#endif /* Return TRUE when opening a (recursive) minibuffer causes minibuffers on other frames to move to the selected frame. */ @@ -112,84 +121,85 @@ choose_minibuf_frame (void) emacs_abort (); minibuf_window = sf->minibuffer_window; - /* If we've still got another minibuffer open, use its mini-window - instead. */ - if (minibuf_level > 1 && minibuf_stays_put ()) - { - Lisp_Object buffer = get_minibuffer (minibuf_level); - Lisp_Object tail, frame; - - FOR_EACH_FRAME (tail, frame) - if (EQ (XWINDOW (XFRAME (frame)->minibuffer_window)->contents, - buffer)) - { - minibuf_window = XFRAME (frame)->minibuffer_window; - break; - } - } } +} - if (minibuf_moves_frame_when_opened () - && FRAMEP (selected_frame) - && FRAME_LIVE_P (XFRAME (selected_frame))) - /* Make sure no other frame has a minibuffer as its selected window, - because the text would not be displayed in it, and that would be - confusing. Only allow the selected frame to do this, - and that only if the minibuffer is active. */ - { - Lisp_Object tail, frame; - struct frame *of; - - FOR_EACH_FRAME (tail, frame) - if (!EQ (frame, selected_frame) - && minibuf_level > 1 - /* The frame's minibuffer can be on a different frame. */ - && ! EQ (XWINDOW ((of = XFRAME (frame))->minibuffer_window)->frame, - selected_frame)) - { - if (MINI_WINDOW_P (XWINDOW (FRAME_SELECTED_WINDOW (of)))) - Fset_frame_selected_window (frame, Fframe_first_window (frame), - Qnil); - - if (!EQ (XWINDOW (of->minibuffer_window)->contents, - nth_minibuffer (0))) - set_window_buffer (of->minibuffer_window, - nth_minibuffer (0), 0, 0); - } - } +/* If ENT1 has a higher minibuffer index than ENT2, return true. More +precisely, compare the buffer components of each window->prev_buffers +entry. */ +static bool +minibuffer_ent_greater (Lisp_Object ent1, Lisp_Object ent2) +{ + return this_minibuffer_depth (Fcar (ent1)) + > this_minibuffer_depth (Fcar (ent2)) ; } -/* If `minibuffer_follows_selected_frame' is t and we have a - minibuffer, move it from its current frame to the selected frame. - This function is intended to be called from `do_switch_frame' in - frame.c. */ -void move_minibuffer_onto_frame (void) +/* Move the ordered "stack" of minibuffers from SOURCE_WINDOW to + DEST_WINDOW, interleaving those minibuffers with any in DEST_WINDOW + to produce an ordered combination. The ordering is by minibuffer + depth. A stack of minibuffers consists of the minibuffer currently + in DEST/SOURCE_WINDOW together with any recorded in the + ->prev_buffers field of the struct window. */ +static void +zip_minibuffer_stacks (Lisp_Object dest_window, Lisp_Object source_window) { - if (!minibuf_level) - return; - if (!minibuf_follows_frame ()) - return; - if (FRAMEP (selected_frame) - && FRAME_LIVE_P (XFRAME (selected_frame)) - && !EQ (minibuf_window, XFRAME (selected_frame)->minibuffer_window)) + struct window *dw = XWINDOW (dest_window); + struct window *sw = XWINDOW (source_window); + Lisp_Object acc; + Lisp_Object d_ent; /* Entry from dw->prev_buffers */ + + if (!live_minibuffer_p (dw->contents) + && NILP (dw->prev_buffers)) { - EMACS_INT i; - struct frame *sf = XFRAME (selected_frame); - Lisp_Object old_frame = XWINDOW (minibuf_window)->frame; - struct frame *of = XFRAME (old_frame); + set_window_buffer (dest_window, sw->contents, 0, 0); + Fset_window_start (dest_window, Fwindow_start (source_window), Qnil); + Fset_window_point (dest_window, Fwindow_point (source_window)); + dw->prev_buffers = sw->prev_buffers; + set_window_buffer (source_window, get_minibuffer (0), 0, 0); + sw->prev_buffers = Qnil; + return; + } - /* Stack up all the (recursively) open minibuffers on the selected - mini_window. */ - for (i = 1; i <= minibuf_level; i++) - set_window_buffer (sf->minibuffer_window, nth_minibuffer (i), 0, 0); - minibuf_window = sf->minibuffer_window; - if (of != sf) - { - Lisp_Object temp = get_minibuffer (0); + if (live_minibuffer_p (dw->contents)) + call1 (Qrecord_window_buffer, dest_window); + if (live_minibuffer_p (sw->contents)) + call1 (Qrecord_window_buffer, source_window); - set_window_buffer (of->minibuffer_window, temp, 0, 0); - set_minibuffer_mode (temp, 0); - } + acc = merge_c (dw->prev_buffers, sw->prev_buffers, minibuffer_ent_greater); + + if (!NILP (acc)) + { + d_ent = Fcar (acc); + acc = Fcdr (acc); + set_window_buffer (dest_window, Fcar (d_ent), 0, 0); + Fset_window_start (dest_window, Fcar (Fcdr (d_ent)), Qnil); + Fset_window_point (dest_window, Fcar (Fcdr (Fcdr (d_ent)))); + } + dw->prev_buffers = acc; + sw->prev_buffers = Qnil; + set_window_buffer (source_window, get_minibuffer (0), 0, 0); +} + +/* If `minibuffer_follows_selected_frame' is t, or we're about to + delete a frame which potentially "contains" minibuffers, move them + from the old frame to the selected frame. This function is + intended to be called from `do_switch_frame' in frame.c. OF is the + old frame, FOR_DELETION is true if OF is about to be deleted. */ +void +move_minibuffers_onto_frame (struct frame *of, bool for_deletion) +{ + struct frame *f = XFRAME (selected_frame); + + minibuf_window = f->minibuffer_window; + if (!(minibuf_level + && (for_deletion || minibuf_follows_frame () || FRAME_INITIAL_P (of)))) + return; + if (FRAME_LIVE_P (f) + && !EQ (f->minibuffer_window, of->minibuffer_window)) + { + zip_minibuffer_stacks (f->minibuffer_window, of->minibuffer_window); + if (for_deletion && XFRAME (MB_frame) != of) + MB_frame = selected_frame; } } @@ -221,6 +231,7 @@ without invoking the usual minibuffer commands. */) /* Actual minibuffer invocation. */ static void read_minibuf_unwind (void); +static void minibuffer_unwind (void); static void run_exit_minibuf_hook (void); @@ -544,7 +555,6 @@ read_minibuf (Lisp_Object map, Lisp_Object initial, Lisp_Object prompt, Lisp_Object histval; Lisp_Object empty_minibuf; - Lisp_Object dummy, frame; specbind (Qminibuffer_default, defalt); specbind (Qinhibit_read_only, Qnil); @@ -626,17 +636,24 @@ read_minibuf (Lisp_Object map, Lisp_Object initial, Lisp_Object prompt, mini_frame = WINDOW_FRAME (XWINDOW (minibuf_window)); if (minibuf_level > 1 + && !EQ (XWINDOW (XFRAME (selected_frame)->minibuffer_window)->frame, + MB_frame) && minibuf_moves_frame_when_opened () - && (!minibuf_follows_frame () - || (!EQ (mini_frame, selected_frame)))) + && (!minibuf_follows_frame ())) { - EMACS_INT i; + struct frame *of = XFRAME (MB_frame); - /* Stack up the existing minibuffers on the current mini-window */ - for (i = 1; i < minibuf_level; i++) - set_window_buffer (minibuf_window, nth_minibuffer (i), 0, 0); + zip_minibuffer_stacks (minibuf_window, of->minibuffer_window); + /* MB_frame's minibuffer can be on a different frame. */ + if (MINI_WINDOW_P (XWINDOW (FRAME_SELECTED_WINDOW (of)))) + Fset_frame_selected_window (MB_frame, + Fframe_first_window (MB_frame), Qnil); } + MB_frame = XWINDOW (XFRAME (selected_frame)->minibuffer_window)->frame; + if (live_minibuffer_p (XWINDOW (minibuf_window)->contents)) + call1 (Qrecord_window_buffer, minibuf_window); + record_unwind_protect_void (minibuffer_unwind); record_unwind_protect (restore_window_configuration, Fcons (Qt, Fcurrent_window_configuration (Qnil))); @@ -771,23 +788,6 @@ read_minibuf (Lisp_Object map, Lisp_Object initial, Lisp_Object prompt, empty_minibuf = get_minibuffer (0); set_minibuffer_mode (empty_minibuf, 0); - FOR_EACH_FRAME (dummy, frame) - { - Lisp_Object root_window = Fframe_root_window (frame); - Lisp_Object mini_window = XWINDOW (root_window)->next; - Lisp_Object buffer; - - if (!NILP (mini_window) && !EQ (mini_window, minibuf_window) - && !NILP (Fwindow_minibuffer_p (mini_window))) - { - buffer = XWINDOW (mini_window)->contents; - if (!live_minibuffer_p (buffer)) - /* Use set_window_buffer instead of Fset_window_buffer (see - discussion of bug#11984, bug#12025, bug#12026). */ - set_window_buffer (mini_window, empty_minibuf, 0, 0); - } - } - /* Display this minibuffer in the proper window. */ /* Use set_window_buffer instead of Fset_window_buffer (see discussion of bug#11984, bug#12025, bug#12026). */ @@ -908,7 +908,9 @@ read_minibuf (Lisp_Object map, Lisp_Object initial, Lisp_Object prompt, unbind_to (count, Qnil); /* Switch the frame back to the calling frame. */ - if (!EQ (selected_frame, calling_frame) + if ((!EQ (selected_frame, calling_frame) + || !EQ (XWINDOW (XFRAME (calling_frame)->minibuffer_window)->frame, + calling_frame)) && FRAMEP (calling_frame) && FRAME_LIVE_P (XFRAME (calling_frame))) call2 (intern ("select-frame-set-input-focus"), calling_frame, Qnil); @@ -1026,6 +1028,14 @@ run_exit_minibuf_hook (void) safe_run_hooks (Qminibuffer_exit_hook); } +/* This variable records the expired minibuffer's frame between the + calls of `read_minibuf_unwind' and `minibuffer_unwind'. It should + be used only by these two functions. Note that the same search + method for the MB's frame won't always work in `minibuffer_unwind' + because the intervening `restore-window-configuration' will have + changed the buffer in the mini-window. */ +static Lisp_Object exp_MB_frame; + /* This function is called on exiting minibuffer, whether normally or not, and it restores the current window, buffer, etc. */ @@ -1036,6 +1046,28 @@ read_minibuf_unwind (void) Lisp_Object calling_frame; Lisp_Object calling_window; Lisp_Object future_mini_window; + Lisp_Object saved_selected_frame = selected_frame; + Lisp_Object window, frames; + struct window *w; + struct frame *f; + + /* Locate the expired minibuffer. */ + FOR_EACH_FRAME (frames, exp_MB_frame) + { + f = XFRAME (exp_MB_frame); + window = f->minibuffer_window; + w = XWINDOW (window); + if (EQ (w->frame, exp_MB_frame) + && EQ (w->contents, nth_minibuffer (minibuf_level))) + goto found; + } + return; /* expired minibuffer not found. Maybe we should output an + error, here. */ + + found: + if (!EQ (exp_MB_frame, saved_selected_frame)) + do_switch_frame (exp_MB_frame, 0, 0, Qt); /* This also sets + minibuff_window */ /* To keep things predictable, in case it matters, let's be in the minibuffer when we reset the relevant variables. Don't depend on @@ -1127,20 +1159,61 @@ read_minibuf_unwind (void) away from the expired minibuffer window, both in the current minibuffer's frame and the original calling frame. */ choose_minibuf_frame (); - if (!EQ (WINDOW_FRAME (XWINDOW (minibuf_window)), calling_frame)) - { - Lisp_Object prev = Fprevious_window (minibuf_window, Qnil, Qnil); - /* PREV can be on a different frame when we have a minibuffer only - frame, the other frame's minibuffer window is MINIBUF_WINDOW, - and its "focus window" is also MINIBUF_WINDOW. */ - if (!EQ (prev, minibuf_window) - && EQ (WINDOW_FRAME (XWINDOW (prev)), - WINDOW_FRAME (XWINDOW (minibuf_window)))) - Fset_frame_selected_window (selected_frame, prev, Qnil); - } - else - Fset_frame_selected_window (calling_frame, calling_window, Qnil); + if (NILP (XWINDOW (minibuf_window)->prev_buffers)) + { + if (!EQ (WINDOW_FRAME (XWINDOW (minibuf_window)), calling_frame)) + { + Lisp_Object prev = Fprevious_window (minibuf_window, Qnil, Qnil); + /* PREV can be on a different frame when we have a minibuffer only + frame, the other frame's minibuffer window is MINIBUF_WINDOW, + and its "focus window" is also MINIBUF_WINDOW. */ + if (!EQ (prev, minibuf_window) + && EQ (WINDOW_FRAME (XWINDOW (prev)), + WINDOW_FRAME (XWINDOW (minibuf_window)))) + Fset_frame_selected_window (selected_frame, prev, Qnil); + } + else + Fset_frame_selected_window (calling_frame, calling_window, Qnil); + } + + /* Restore the selected frame. */ + if (!EQ (exp_MB_frame, saved_selected_frame)) + do_switch_frame (saved_selected_frame, 0, 0, Qt); +} + +/* Replace the expired minibuffer in frame exp_MB_frame with the next less + nested minibuffer in that frame, if any. Otherwise, replace it + with the null minibuffer. MINIBUF_WINDOW is not changed. */ +static void +minibuffer_unwind (void) +{ + struct frame *f; + struct window *w; + Lisp_Object window; + Lisp_Object entry; + + f = XFRAME (exp_MB_frame); + window = f->minibuffer_window; + w = XWINDOW (window); + if (FRAME_LIVE_P (f)) + { + /* minibuf_window = sf->minibuffer_window; */ + if (!NILP (w->prev_buffers)) + { + entry = Fcar (w->prev_buffers); + w->prev_buffers = Fcdr (w->prev_buffers); + set_window_buffer (window, Fcar (entry), 0, 0); + Fset_window_start (window, Fcar (Fcdr (entry)), Qnil); + Fset_window_point (window, Fcar (Fcdr (Fcdr (entry)))); + /* set-window-configuration may/will have unselected the + mini-window as the selected window. Restore it. */ + Fset_frame_selected_window (exp_MB_frame, window, Qnil); + } + else + set_window_buffer (window, nth_minibuffer (0), 0, 0); + } } + void @@ -2213,6 +2286,9 @@ syms_of_minibuf (void) { staticpro (&minibuf_prompt); staticpro (&minibuf_save_list); + staticpro (&MB_frame); + MB_frame = Qnil; + staticpro (&exp_MB_frame); DEFSYM (Qminibuffer_follows_selected_frame, "minibuffer-follows-selected-frame"); diff --git a/src/window.c b/src/window.c index eb16e2a4338..4d5c7e763ec 100644 --- a/src/window.c +++ b/src/window.c @@ -6958,7 +6958,8 @@ the return value is nil. Otherwise the value is t. */) if (BUFFERP (w->contents) && !EQ (w->contents, p->buffer) - && BUFFER_LIVE_P (XBUFFER (p->buffer))) + && BUFFER_LIVE_P (XBUFFER (p->buffer)) + && (NILP (Fminibufferp (p->buffer, Qnil)))) /* If a window we restore gets another buffer, record the window's old buffer. */ call1 (Qrecord_window_buffer, window); diff --git a/src/xdisp.c b/src/xdisp.c index cc0a689ba32..a405d51f803 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -12650,9 +12650,8 @@ gui_consider_frame_title (Lisp_Object frame) mode_line_noprop_buf; then display the title. */ record_unwind_protect (unwind_format_mode_line, format_mode_line_unwind_data - (f, current_buffer, selected_window, false)); + (NULL, current_buffer, Qnil, false)); - Fselect_window (f->selected_window, Qt); set_buffer_internal_1 (XBUFFER (XWINDOW (f->selected_window)->contents)); fmt = FRAME_ICONIFIED_P (f) ? Vicon_title_format : Vframe_title_format; -- cgit v1.2.3 From 661f52f6d0d6576e8bddb8fcc6efec1bd1fd3d74 Mon Sep 17 00:00:00 2001 From: Lars Ingebrigtsen Date: Sun, 28 Mar 2021 14:58:43 +0200 Subject: Clarify the doc string of plist-memeber and plist-put * src/fns.c (Fplist_member): (Fplist_put): Clarify what comparison function is used for PROP (bug#47426) and don't claim that PROP has to be a symbol. --- src/fns.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'src/fns.c') diff --git a/src/fns.c b/src/fns.c index 2cd59c83d91..1758148ff2d 100644 --- a/src/fns.c +++ b/src/fns.c @@ -2369,7 +2369,10 @@ This is the last value stored with `(put SYMBOL PROPNAME VALUE)'. */) DEFUN ("plist-put", Fplist_put, Splist_put, 3, 3, 0, doc: /* Change value in PLIST of PROP to VAL. PLIST is a property list, which is a list of the form -\(PROP1 VALUE1 PROP2 VALUE2 ...). PROP is a symbol and VAL is any object. +\(PROP1 VALUE1 PROP2 VALUE2 ...). + +The comparison with PROP is done using `eq'. + If PROP is already a property on the list, its value is set to VAL, otherwise the new PROP VAL pair is added. The new plist is returned; use `(setq x (plist-put x prop val))' to be sure to use the new value. @@ -3211,7 +3214,10 @@ suppressed. */) DEFUN ("plist-member", Fplist_member, Splist_member, 2, 2, 0, doc: /* Return non-nil if PLIST has the property PROP. PLIST is a property list, which is a list of the form -\(PROP1 VALUE1 PROP2 VALUE2 ...). PROP is a symbol. +\(PROP1 VALUE1 PROP2 VALUE2 ...). + +The comparison with PROP is done using `eq'. + Unlike `plist-get', this allows you to distinguish between a missing property and a property with the value nil. The value is actually the tail of PLIST whose car is PROP. */) -- cgit v1.2.3 From 0eee48af9de308ef57a065ecd8b2c2c7b59012a0 Mon Sep 17 00:00:00 2001 From: Andrea Corallo Date: Wed, 21 Apr 2021 14:22:11 +0200 Subject: Introduce `sxhash-equal-including-properties'. * src/fns.c (collect_interval): Move it upwards. (Fsxhash_equal_including_properties): New function. (syms_of_fns): Register `sxhash-equal-including-properties'. * etc/NEWS: Add 'sxhash-equal-including-properties'. --- etc/NEWS | 5 +++++ src/fns.c | 43 ++++++++++++++++++++++++++++++++++--------- 2 files changed, 39 insertions(+), 9 deletions(-) (limited to 'src/fns.c') diff --git a/etc/NEWS b/etc/NEWS index fb0ec90fea8..6928cbc429f 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -2579,6 +2579,11 @@ the Emacs Lisp reference manual for background. * Lisp Changes in Emacs 28.1 ++++ +** New function 'sxhash-equal-including-properties'. +This is identical to 'sxhash-equal' but accounting also for string +properties. + +++ ** 'unlock-buffer' displays warnings instead of signaling. Instead of signaling 'file-error' conditions for file system level diff --git a/src/fns.c b/src/fns.c index 1758148ff2d..41429c8863d 100644 --- a/src/fns.c +++ b/src/fns.c @@ -4492,6 +4492,15 @@ check_mutable_hash_table (Lisp_Object obj, struct Lisp_Hash_Table *h) eassert (!PURE_P (h)); } +static void +collect_interval (INTERVAL interval, Lisp_Object collector) +{ + nconc2 (collector, + list1(list3 (make_fixnum (interval->position), + make_fixnum (interval->position + LENGTH (interval)), + interval->plist))); +} + /* Put an entry into hash table H that associates KEY with VALUE. HASH is a previously computed hash code of KEY. Value is the index of the entry in H matching KEY. */ @@ -4949,6 +4958,30 @@ Hash codes are not guaranteed to be preserved across Emacs sessions. */) return hashfn_equal (obj, NULL); } +DEFUN ("sxhash-equal-including-properties", Fsxhash_equal_including_properties, + Ssxhash_equal_including_properties, 1, 1, 0, + doc: /* Return an integer hash code for OBJ suitable for +`equal-including-properties'. +If (sxhash-equal-including-properties A B), then +(= (sxhash-equal-including-properties A) (sxhash-equal-including-properties B)). + +Hash codes are not guaranteed to be preserved across Emacs sessions. */) + (Lisp_Object obj) +{ + if (STRINGP (obj)) + { + Lisp_Object collector = Fcons (Qnil, Qnil); + traverse_intervals (string_intervals (obj), 0, collect_interval, + collector); + return + make_ufixnum ( + SXHASH_REDUCE (sxhash_combine (sxhash (obj), + sxhash (CDR (collector))))); + } + + return hashfn_equal (obj, NULL); +} + DEFUN ("make-hash-table", Fmake_hash_table, Smake_hash_table, 0, MANY, 0, doc: /* Create and return a new hash table. @@ -5832,15 +5865,6 @@ Case is always significant and text properties are ignored. */) return make_int (string_byte_to_char (haystack, res - SSDATA (haystack))); } -static void -collect_interval (INTERVAL interval, Lisp_Object collector) -{ - nconc2 (collector, - list1(list3 (make_fixnum (interval->position), - make_fixnum (interval->position + LENGTH (interval)), - interval->plist))); -} - DEFUN ("object-intervals", Fobject_intervals, Sobject_intervals, 1, 1, 0, doc: /* Return a copy of the text properties of OBJECT. OBJECT must be a buffer or a string. @@ -5922,6 +5946,7 @@ syms_of_fns (void) defsubr (&Ssxhash_eq); defsubr (&Ssxhash_eql); defsubr (&Ssxhash_equal); + defsubr (&Ssxhash_equal_including_properties); defsubr (&Smake_hash_table); defsubr (&Scopy_hash_table); defsubr (&Shash_table_count); -- cgit v1.2.3 From d68f2b8681f8eeb6bbf1b4476a88f00b2962179e Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Thu, 20 May 2021 09:55:28 +0300 Subject: ; * src/fns.c (Fline_number_at_pos): Fix doc string and comments. --- src/fns.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) (limited to 'src/fns.c') diff --git a/src/fns.c b/src/fns.c index 41429c8863d..e2442685732 100644 --- a/src/fns.c +++ b/src/fns.c @@ -5892,12 +5892,14 @@ in OBJECT. */) DEFUN ("line-number-at-pos", Fline_number_at_pos, Sline_number_at_pos, 0, 2, 0, - doc: /* Return the line number at POSITION. -If POSITION is nil, use the current buffer location. - -If the buffer is narrowed, the position returned is the position in the -visible part of the buffer. If ABSOLUTE is non-nil, count the lines -from the absolute start of the buffer. */) + doc: /* Return the line number at POSITION in the current buffer. +If POSITION is nil or omitted, it defaults to point's position in the +current buffer. + +If the buffer is narrowed, the return value by default counts the lines +from the beginning of the accessible portion of the buffer. But if the +second optional argument ABSOLUTE is non-nil, the value counts the lines +from the absolute start of the buffer, disregarding the narrowing. */) (register Lisp_Object position, Lisp_Object absolute) { ptrdiff_t pos, start = BEGV_BYTE; @@ -5915,7 +5917,7 @@ from the absolute start of the buffer. */) if (!NILP (absolute)) start = BEG_BYTE; - /* Check that POSITION is n the visible range of the buffer. */ + /* Check that POSITION is in the accessible range of the buffer. */ if (pos < BEGV || pos > ZV) args_out_of_range (make_int (start), make_int (ZV)); -- cgit v1.2.3 From 8b44740a6aee6254a60243df6ef3dd80ce3f3a36 Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Thu, 20 May 2021 12:01:40 +0300 Subject: Fix arg-out-of-range errors in 'line-number-at-pos' * src/fns.c (Fline_number_at_pos): Pass character position to args_out_of_range. Suggested by Andreas Schwab . Call args_out_of_range_3 to show both ends of the accessible portion. --- src/fns.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/fns.c') diff --git a/src/fns.c b/src/fns.c index e2442685732..40ade578008 100644 --- a/src/fns.c +++ b/src/fns.c @@ -5919,7 +5919,7 @@ from the absolute start of the buffer, disregarding the narrowing. */) /* Check that POSITION is in the accessible range of the buffer. */ if (pos < BEGV || pos > ZV) - args_out_of_range (make_int (start), make_int (ZV)); + args_out_of_range_3 (make_int (pos), make_int (BEGV), make_int (ZV)); return make_int (count_lines (start, CHAR_TO_BYTE (pos)) + 1); } -- cgit v1.2.3 From 7c22aa36cd622ba2a9176e319ce5fb2b06f87801 Mon Sep 17 00:00:00 2001 From: Mattias EngdegÄrd Date: Wed, 16 Jun 2021 18:05:41 +0200 Subject: Eliminate some GCC warnings * src/doprnt.c (exprintf, evxprintf): * src/lisp.h (exprintf, evxprintf): Don't use a pointer-to-const type for the `nonheapbuf` argument: although it is never dereferenced, GCC will warn when passing a pointer to uninitialised memory otherwise. * src/fns.c (sort_vector_copy, realize_face, realize_gui_face) (realize_tty_face): Use the same signatures in the prototypes as in the actual function definitions. --- src/doprnt.c | 4 ++-- src/fns.c | 5 +++-- src/lisp.h | 4 ++-- src/xfaces.c | 9 ++++++--- 4 files changed, 13 insertions(+), 9 deletions(-) (limited to 'src/fns.c') diff --git a/src/doprnt.c b/src/doprnt.c index b6b5978c891..fe484b8e766 100644 --- a/src/doprnt.c +++ b/src/doprnt.c @@ -563,7 +563,7 @@ esprintf (char *buf, char const *format, ...) BUFSIZE_MAX. */ ptrdiff_t exprintf (char **buf, ptrdiff_t *bufsize, - char const *nonheapbuf, ptrdiff_t bufsize_max, + char *nonheapbuf, ptrdiff_t bufsize_max, char const *format, ...) { ptrdiff_t nbytes; @@ -579,7 +579,7 @@ exprintf (char **buf, ptrdiff_t *bufsize, /* Act like exprintf, except take a va_list. */ ptrdiff_t evxprintf (char **buf, ptrdiff_t *bufsize, - char const *nonheapbuf, ptrdiff_t bufsize_max, + char *nonheapbuf, ptrdiff_t bufsize_max, char const *format, va_list ap) { for (;;) diff --git a/src/fns.c b/src/fns.c index 40ade578008..a1782166228 100644 --- a/src/fns.c +++ b/src/fns.c @@ -39,8 +39,9 @@ along with GNU Emacs. If not, see . */ #include "puresize.h" #include "gnutls.h" -static void sort_vector_copy (Lisp_Object, ptrdiff_t, - Lisp_Object *restrict, Lisp_Object *restrict); +static void sort_vector_copy (Lisp_Object pred, ptrdiff_t len, + Lisp_Object src[restrict VLA_ELEMS (len)], + Lisp_Object dest[restrict VLA_ELEMS (len)]); enum equal_kind { EQUAL_NO_QUIT, EQUAL_PLAIN, EQUAL_INCLUDING_PROPERTIES }; static bool internal_equal (Lisp_Object, Lisp_Object, enum equal_kind, int, Lisp_Object); diff --git a/src/lisp.h b/src/lisp.h index 91b7a89d0f5..4fb89236788 100644 --- a/src/lisp.h +++ b/src/lisp.h @@ -4064,10 +4064,10 @@ extern ptrdiff_t doprnt (char *, ptrdiff_t, const char *, const char *, va_list); extern ptrdiff_t esprintf (char *, char const *, ...) ATTRIBUTE_FORMAT_PRINTF (2, 3); -extern ptrdiff_t exprintf (char **, ptrdiff_t *, char const *, ptrdiff_t, +extern ptrdiff_t exprintf (char **, ptrdiff_t *, char *, ptrdiff_t, char const *, ...) ATTRIBUTE_FORMAT_PRINTF (5, 6); -extern ptrdiff_t evxprintf (char **, ptrdiff_t *, char const *, ptrdiff_t, +extern ptrdiff_t evxprintf (char **, ptrdiff_t *, char *, ptrdiff_t, char const *, va_list) ATTRIBUTE_FORMAT_PRINTF (5, 0); diff --git a/src/xfaces.c b/src/xfaces.c index ab4440f46ad..fed7b3336a2 100644 --- a/src/xfaces.c +++ b/src/xfaces.c @@ -353,10 +353,13 @@ static bool menu_face_changed_default; struct named_merge_point; -static struct face *realize_face (struct face_cache *, Lisp_Object *, +static struct face *realize_face (struct face_cache *, + Lisp_Object [LFACE_VECTOR_SIZE], int); -static struct face *realize_gui_face (struct face_cache *, Lisp_Object *); -static struct face *realize_tty_face (struct face_cache *, Lisp_Object *); +static struct face *realize_gui_face (struct face_cache *, + Lisp_Object [LFACE_VECTOR_SIZE]); +static struct face *realize_tty_face (struct face_cache *, + Lisp_Object [LFACE_VECTOR_SIZE]); static bool realize_basic_faces (struct frame *); static bool realize_default_face (struct frame *); static void realize_named_face (struct frame *, Lisp_Object, int); -- cgit v1.2.3 From bb2d1252e6da6202ebf7015ad9615b31fe993fdc Mon Sep 17 00:00:00 2001 From: Lars Ingebrigtsen Date: Wed, 21 Jul 2021 13:28:17 +0200 Subject: Fix final test for invalid base64url chars * src/fns.c (base64_decode_1): Fix test for invalid base64url (bug#45562). Noted by Andreas Schwab. --- src/fns.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/fns.c') diff --git a/src/fns.c b/src/fns.c index a1782166228..7b9e3b0f7fc 100644 --- a/src/fns.c +++ b/src/fns.c @@ -3955,7 +3955,7 @@ base64_decode_1 (const char *from, char *to, ptrdiff_t length, if (c == '=') continue; - if (v1 < 0) + if (v1 == 0) return -1; value += v1 - 1; -- cgit v1.2.3 From 4b1367ee97446ed29b76aa49782e675918d5ca35 Mon Sep 17 00:00:00 2001 From: Lars Ingebrigtsen Date: Sat, 24 Jul 2021 18:35:14 +0200 Subject: Fix Fdirectory_append check for whether strings have to be converted * src/coding.c (string_ascii_p): Make it non-static. * src/fileio.c (Fdirectory_append): Fix check for whether we need to convert to multibyte. * src/fns.c (string_ascii_p): Remove copy. * src/lisp.h: Declare string_ascii_p. --- src/coding.c | 2 +- src/fileio.c | 2 +- src/fns.c | 10 ---------- src/lisp.h | 1 + 4 files changed, 3 insertions(+), 12 deletions(-) (limited to 'src/fns.c') diff --git a/src/coding.c b/src/coding.c index 46e7fca0f43..87b55aecc05 100644 --- a/src/coding.c +++ b/src/coding.c @@ -9476,7 +9476,7 @@ not fully specified.) */) } /* Whether STRING only contains chars in the 0..127 range. */ -static bool +bool string_ascii_p (Lisp_Object string) { ptrdiff_t nbytes = SBYTES (string); diff --git a/src/fileio.c b/src/fileio.c index 643fc361689..60f5650302c 100644 --- a/src/fileio.c +++ b/src/fileio.c @@ -796,7 +796,7 @@ usage: (record DIRECTORY &rest COMPONENTS) */) { Lisp_Object arg = args[i]; /* Use multibyte or all-ASCII strings as is. */ - if (STRING_MULTIBYTE (arg) || SCHARS (arg) == SBYTES (arg)) + if (STRING_MULTIBYTE (arg) || string_ascii_p (arg)) elements[i] = arg; else elements[i] = make_multibyte_string (SSDATA (arg), SCHARS (arg), diff --git a/src/fns.c b/src/fns.c index 7b9e3b0f7fc..932800a3a49 100644 --- a/src/fns.c +++ b/src/fns.c @@ -5769,16 +5769,6 @@ characters. */ ) return list3 (make_int (lines), make_int (longest), make_float (mean)); } -static bool -string_ascii_p (Lisp_Object string) -{ - ptrdiff_t nbytes = SBYTES (string); - for (ptrdiff_t i = 0; i < nbytes; i++) - if (SREF (string, i) > 127) - return false; - return true; -} - DEFUN ("string-search", Fstring_search, Sstring_search, 2, 3, 0, doc: /* Search for the string NEEDLE in the string HAYSTACK. The return value is the position of the first occurrence of NEEDLE in diff --git a/src/lisp.h b/src/lisp.h index 80efd771139..15a42a44562 100644 --- a/src/lisp.h +++ b/src/lisp.h @@ -3586,6 +3586,7 @@ extern Lisp_Object detect_coding_system (const unsigned char *, ptrdiff_t, extern void init_coding (void); extern void init_coding_once (void); extern void syms_of_coding (void); +extern bool string_ascii_p (Lisp_Object); /* Defined in character.c. */ extern ptrdiff_t chars_in_text (const unsigned char *, ptrdiff_t); -- cgit v1.2.3 From 78b427648b85d0f7e93ad5f18537ad9f2da055cb Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Wed, 18 Aug 2021 22:07:30 +0300 Subject: Improve documentation of 'assoc' * doc/lispref/lists.texi (Association Lists): * src/fns.c (Fassoc): Document how TESTFN is called. (Bug#50110) --- doc/lispref/lists.texi | 10 ++++++---- src/fns.c | 3 ++- 2 files changed, 8 insertions(+), 5 deletions(-) (limited to 'src/fns.c') diff --git a/doc/lispref/lists.texi b/doc/lispref/lists.texi index ac99835f7b3..bbe1dce42d8 100644 --- a/doc/lispref/lists.texi +++ b/doc/lispref/lists.texi @@ -1557,10 +1557,12 @@ of property lists and association lists. @defun assoc key alist &optional testfn This function returns the first association for @var{key} in @var{alist}, comparing @var{key} against the alist elements using -@var{testfn} if it is non-@code{nil} and @code{equal} otherwise -(@pxref{Equality Predicates}). It returns @code{nil} if no -association in @var{alist} has a @sc{car} equal to @var{key}. For -example: +@var{testfn} if it is a function, and @code{equal} otherwise +(@pxref{Equality Predicates}). If @var{testfn} is a function, it is +called with two arguments: the @sc{car} of an element from @var{alist} +and @var{key}. The function returns @code{nil} if no +association in @var{alist} has a @sc{car} equal to @var{key}, as +tested by @var{testfn}. For example: @smallexample (setq trees '((pine . cones) (oak . acorns) (maple . seeds))) diff --git a/src/fns.c b/src/fns.c index 932800a3a49..5126439fd66 100644 --- a/src/fns.c +++ b/src/fns.c @@ -1755,7 +1755,8 @@ DEFUN ("assoc", Fassoc, Sassoc, 2, 3, 0, doc: /* Return non-nil if KEY is equal to the car of an element of ALIST. The value is actually the first element of ALIST whose car equals KEY. -Equality is defined by TESTFN if non-nil or by `equal' if nil. */) +Equality is defined by the function TESTFN, defaulting to `equal'. +TESTFN is called with 2 arguments: a car of an alist element and KEY. */) (Lisp_Object key, Lisp_Object alist, Lisp_Object testfn) { if (eq_comparable_value (key) && NILP (testfn)) -- cgit v1.2.3