Merge from origin/emacs-26

fc5cae7 ; Fix ChangeLog typo.
e17a5e5 ; make change-history-commit
f205928 * etc/HISTORY: Cite Brinkoff on early history.
4e58ca8 Document internal use of 'above-suspended' z-group frame para...
4bd43b0 Increase max-lisp-eval-depth adjustment while in debugger (bu...
ab98352 Improve on last change in replace-buffer-contents
2f149c0 Fix a factual error in Introduction to Emacs Lisp
8ad50a3 ; * lisp/files.el (buffer-offer-save): Doc fix.  (Bug#32000)
c80f31f Minor improvements in documentation of imenu.el
8ebb683 Avoid errors with recentering in 'skeleton-insert'
e980a3c * src/lisp.h: Omit obsolete comment re bytecode stack.
eec71eb Speed up replace-buffer-contents
93c41ce Remove extra process call from vc-git-find-file-hook
7ea0873 ; Update some commentary
4a7f423 Speed up vc-git-dir-status-files
9134c84 Avoid compiler warning using coding.h

Conflicts:
	src/editfns.c
This commit is contained in:
Glenn Morris 2018-07-02 19:19:26 -07:00
commit 02f2f336af
14 changed files with 1566 additions and 63 deletions

File diff suppressed because it is too large Load diff

View file

@ -2729,8 +2729,8 @@ In the old days, when you lacked a @file{~/.emacs} file and started an
Emacs session by typing the command @code{emacs} alone, without naming
any files, Emacs started with the @file{*scratch*} buffer visible.
Nowadays, you will see a splash screen. You can follow one of the
commands suggested on the splash screen, visit a file, or press the
spacebar to reach the @file{*scratch*} buffer.
commands suggested on the splash screen, visit a file, or press @kbd{q}
to quit the splash screen and reach the @file{*scratch*} buffer.
If you switch to the @file{*scratch*} buffer, type
@code{(buffer-name)}, position the cursor after it, and then type

View file

@ -12,10 +12,11 @@ development is sketchy, the following text summarizes what is known.
EMACS started out as a set of macros atop the TECO text editor, and
was first operational in late 1976. It was inspired by earlier work
such as the E editor of Stanford, and was based on older TECO macro
sets. EMACS in turn inspired several similar editors. See:
Stallman RM. EMACS: The Extensible, Customizable Self-Documenting
Display Editor. AI Memo 519a, MIT, 1981-03-26
sets. See: Stallman RM. EMACS: The Extensible, Customizable
Self-Documenting Display Editor. AI Memo 519a, MIT, 1981-03-26
<http://dspace.mit.edu/bitstream/handle/1721.1/5736/AIM-519A.pdf>.
EMACS in turn inspired several similar editors. For a summary of
this history, see <https://github.com/larsbrinkhoff/emacs-history>.
In 1984, work began on GNU Emacs, a fresh implementation designed to
run on GNU and GNU-like systems, with a full-featured Lisp at its

View file

@ -349,6 +349,7 @@ That buffer should be current already."
(backtrace-frames 'debug)))
(print-escape-newlines t)
(print-escape-control-characters t)
;; If you increase print-level, add more depth in call_debugger.
(print-level 8)
(print-length 50)
(pos (point)))

View file

@ -148,12 +148,16 @@ This variable is relevant only if `backup-by-copying' and
Called with an absolute file name as argument, it returns t to enable backup.")
(defcustom buffer-offer-save nil
"Non-nil in a buffer means always offer to save buffer on exit.
"Non-nil in a buffer means always offer to save buffer on exiting Emacs.
Do so even if the buffer is not visiting a file.
Automatically local in all buffers.
Set to the symbol `always' to offer to save buffer whenever
`save-some-buffers' is called."
`save-some-buffers' is called.
Note that this option has no effect on `kill-buffer';
if you want to control what happens when a buffer is killed,
use `kill-buffer-query-functions'."
:type '(choice (const :tag "Never" nil)
(const :tag "On Emacs exit" t)
(const :tag "Whenever save-some-buffers is called" always))

View file

@ -179,7 +179,9 @@ with name concatenation."
(defcustom imenu-generic-skip-comments-and-strings t
"When non-nil, ignore text inside comments and strings.
Only affects `imenu--generic-function'."
Only affects `imenu-default-create-index-function' (and any
alternative implementation of `imenu-create-index-function' that
uses `imenu--generic-function')."
:type 'boolean
:group 'imenu
:version "24.4")
@ -730,7 +732,7 @@ for modes which use `imenu--generic-function'. If it is not set, but
;; so it needs to be careful never to loop!
(defun imenu--generic-function (patterns)
"Return an index alist of the current buffer based on PATTERNS.
PATTERNS should be an alist with the same form as `imenu-generic-expression'.
PATTERNS should be an alist of the same form as `imenu-generic-expression'.
If `imenu-generic-skip-comments-and-strings' is non-nil, this ignores
text inside comments and strings.

View file

@ -268,7 +268,8 @@ available:
(or (eolp) (not skeleton-end-newline) (newline-and-indent))
(run-hooks 'skeleton-end-hook)
(sit-for 0)
(or (pos-visible-in-window-p beg)
(or (not (eq (window-buffer) (current-buffer)))
(pos-visible-in-window-p beg)
(progn
(goto-char beg)
(recenter 0)))

View file

@ -301,9 +301,6 @@ in the order given by 'git status'."
'("--ignored"))
"--"))
(status (apply #'vc-git--run-command-string file args)))
;; Alternatively, the `ignored' state could be detected with 'git
;; ls-files -i -o --exclude-standard', but that's an extra process
;; call, and the `ignored' state is rarely needed.
(if (null status)
;; If status is nil, there was an error calling git, likely because
;; the file is not in a git repo.
@ -568,6 +565,7 @@ or an empty string if none."
(declare-function vc-set-async-update "vc-dispatcher" (process-buffer))
(defun vc-git-dir-status-goto-stage (git-state)
;; TODO: Look into reimplementing this using `git status --porcelain=v2'.
(let ((files (vc-git-dir-status-state->files git-state)))
(erase-buffer)
(pcase (vc-git-dir-status-state->stage git-state)
@ -584,7 +582,7 @@ or an empty string if none."
"ls-files" "-z" "-c" "-s" "--"))
(`ls-files-conflict
(vc-git-command (current-buffer) 'async files
"ls-files" "-z" "-c" "-s" "--"))
"ls-files" "-z" "-u" "--"))
(`ls-files-unknown
(vc-git-command (current-buffer) 'async files
"ls-files" "-z" "-o" "--directory"
@ -947,9 +945,6 @@ This prompts for a branch to merge from."
(vc-git--run-command-string directory "status" "--porcelain" "--"))
(lines (when status (split-string status "\n" 'omit-nulls)))
files)
;; TODO: Look into reimplementing `vc-git-state', as well as
;; `vc-git-dir-status-files', based on this output, thus making the
;; extra process call in `vc-git-find-file-hook' unnecessary.
(dolist (line lines files)
(when (string-match "\\([ MADRCU?!][ MADRCU?!]\\) \\(.+\\)\\(?: -> \\(.+\\)\\)?"
line)
@ -984,15 +979,10 @@ This prompts for a branch to merge from."
(defun vc-git-find-file-hook ()
"Activate `smerge-mode' if there is a conflict."
(when (and buffer-file-name
;; FIXME
;; 1) the net result is to call git twice per file.
;; 2) v-g-c-f is documented to take a directory.
;; https://lists.gnu.org/r/emacs-devel/2014-01/msg01126.html
(vc-git-conflicted-files buffer-file-name)
(eq (vc-state buffer-file-name 'Git) 'conflict)
(save-excursion
(goto-char (point-min))
(re-search-forward "^<<<<<<< " nil 'noerror)))
(vc-file-setprop buffer-file-name 'vc-state 'conflict)
(smerge-start-session)
(when vc-git-resolve-conflicts
(add-hook 'after-save-hook 'vc-git-resolve-when-done nil 'local))

View file

@ -28,6 +28,8 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
#include "lisp.h"
INLINE_HEADER_BEGIN
/* Index to arguments of Fdefine_coding_system_internal. */
enum define_coding_system_arg_index
@ -771,4 +773,6 @@ extern struct coding_system safe_terminal_coding;
extern char emacs_mule_bytes[256];
INLINE_HEADER_END
#endif /* EMACS_CODING_H */

View file

@ -3127,6 +3127,9 @@ determines whether case is significant or ignored. */)
#undef ELEMENT
#undef EQUAL
/* Counter used to rarely_quit in replace-buffer-contents. */
static unsigned short rbc_quitcounter;
#define XVECREF_YVECREF_EQUAL(ctx, xoff, yoff) \
buffer_chars_equal ((ctx), (xoff), (yoff))
@ -3136,6 +3139,9 @@ determines whether case is significant or ignored. */)
/* Buffers to compare. */ \
struct buffer *buffer_a; \
struct buffer *buffer_b; \
/* Whether each buffer is unibyte/plain-ASCII or not. */ \
bool a_unibyte; \
bool b_unibyte; \
/* Bit vectors recording for each character whether it was deleted
or inserted. */ \
unsigned char *deletions; \
@ -3216,6 +3222,8 @@ differences between the two buffers. */)
struct context ctx = {
.buffer_a = a,
.buffer_b = b,
.a_unibyte = BUF_ZV (a) == BUF_ZV_BYTE (a),
.b_unibyte = BUF_ZV (b) == BUF_ZV_BYTE (b),
.deletions = SAFE_ALLOCA (del_bytes),
.insertions = SAFE_ALLOCA (ins_bytes),
.fdiag = buffer + size_b + 1,
@ -3232,9 +3240,36 @@ differences between the two buffers. */)
early. */
eassert (! early_abort);
rbc_quitcounter = 0;
Fundo_boundary ();
bool modification_hooks_inhibited = false;
record_unwind_protect_excursion ();
/* We are going to make a lot of small modifications, and having the
modification hooks called for each of them will slow us down.
Instead, we announce a single modification for the entire
modified region. But don't do that if the caller inhibited
modification hooks, because then they don't want that. */
ptrdiff_t from, to;
if (!inhibit_modification_hooks)
{
ptrdiff_t k, l;
/* Find the first character position to be changed. */
for (k = 0; k < size_a && !bit_is_set (ctx.deletions, k); k++)
;
from = BEGV + k;
/* Find the last character position to be changed. */
for (l = size_a; l > 0 && !bit_is_set (ctx.deletions, l - 1); l--)
;
to = BEGV + l;
prepare_to_modify_buffer (from, to, NULL);
specbind (Qinhibit_modification_hooks, Qt);
modification_hooks_inhibited = true;
}
ptrdiff_t i = size_a;
ptrdiff_t j = size_b;
/* Walk backwards through the lists of changes. This was also
@ -3243,15 +3278,13 @@ differences between the two buffers. */)
while (i >= 0 || j >= 0)
{
/* Allow the user to quit if this gets too slow. */
maybe_quit ();
rarely_quit (++rbc_quitcounter);
/* Check whether there is a change (insertion or deletion)
before the current position. */
if ((i > 0 && bit_is_set (ctx.deletions, i - 1)) ||
(j > 0 && bit_is_set (ctx.insertions, j - 1)))
{
maybe_quit ();
ptrdiff_t end_a = min_a + i;
ptrdiff_t end_b = min_b + j;
/* Find the beginning of the current change run. */
@ -3259,14 +3292,13 @@ differences between the two buffers. */)
--i;
while (j > 0 && bit_is_set (ctx.insertions, j - 1))
--j;
rarely_quit (rbc_quitcounter++);
ptrdiff_t beg_a = min_a + i;
ptrdiff_t beg_b = min_b + j;
eassert (beg_a >= BEGV);
eassert (beg_b >= BUF_BEGV (b));
eassert (beg_a <= end_a);
eassert (beg_b <= end_b);
eassert (end_a <= ZV);
eassert (end_b <= BUF_ZV (b));
eassert (beg_a < end_a || beg_b < end_b);
if (beg_a < end_a)
del_range (beg_a, end_a);
@ -3280,8 +3312,17 @@ differences between the two buffers. */)
--i;
--j;
}
SAFE_FREE_UNBIND_TO (count, Qnil);
rbc_quitcounter = 0;
return SAFE_FREE_UNBIND_TO (count, Qnil);
if (modification_hooks_inhibited)
{
ptrdiff_t updated_to = to + ZV - BEGV - size_a;
signal_after_change (from, to - from, updated_to - from);
update_compositions (from, updated_to, CHECK_INSIDE);
}
return Qnil;
}
static void
@ -3307,39 +3348,45 @@ bit_is_set (const unsigned char *a, ptrdiff_t i)
/* Return true if the characters at position POS_A of buffer
CTX->buffer_a and at position POS_B of buffer CTX->buffer_b are
equal. POS_A and POS_B are zero-based. Text properties are
ignored. */
ignored.
Implementation note: this function is called inside the inner-most
loops of compareseq, so it absolutely must be optimized for speed,
every last bit of it. E.g., each additional use of BEGV or such
likes will slow down replace-buffer-contents by dozens of percents,
because builtin_lisp_symbol will be called one more time in the
innermost loop. */
static bool
buffer_chars_equal (struct context *ctx,
ptrdiff_t pos_a, ptrdiff_t pos_b)
{
eassert (pos_a >= 0);
pos_a += BUF_BEGV (ctx->buffer_a);
eassert (pos_a >= BUF_BEGV (ctx->buffer_a));
eassert (pos_a < BUF_ZV (ctx->buffer_a));
eassert (pos_b >= 0);
pos_b += BUF_BEGV (ctx->buffer_b);
eassert (pos_b >= BUF_BEGV (ctx->buffer_b));
eassert (pos_b < BUF_ZV (ctx->buffer_b));
bool a_unibyte = BUF_ZV (ctx->buffer_a) == BUF_ZV_BYTE (ctx->buffer_a);
bool b_unibyte = BUF_ZV (ctx->buffer_b) == BUF_ZV_BYTE (ctx->buffer_b);
/* Allow the user to escape out of a slow compareseq call. */
maybe_quit ();
rarely_quit (++rbc_quitcounter);
ptrdiff_t bpos_a =
a_unibyte ? pos_a : buf_charpos_to_bytepos (ctx->buffer_a, pos_a);
ctx->a_unibyte ? pos_a : buf_charpos_to_bytepos (ctx->buffer_a, pos_a);
ptrdiff_t bpos_b =
b_unibyte ? pos_b : buf_charpos_to_bytepos (ctx->buffer_b, pos_b);
ctx->b_unibyte ? pos_b : buf_charpos_to_bytepos (ctx->buffer_b, pos_b);
if (a_unibyte && b_unibyte)
/* We make the below a series of specific test to avoid using
BUF_FETCH_CHAR_AS_MULTIBYTE, which references Lisp symbols, and
is therefore significantly slower (see the note in the commentary
to this function). */
if (ctx->a_unibyte && ctx->b_unibyte)
return BUF_FETCH_BYTE (ctx->buffer_a, bpos_a)
== BUF_FETCH_BYTE (ctx->buffer_b, bpos_b);
return BUF_FETCH_CHAR_AS_MULTIBYTE (ctx->buffer_a, bpos_a)
== BUF_FETCH_CHAR_AS_MULTIBYTE (ctx->buffer_b, bpos_b);
if (ctx->a_unibyte && !ctx->b_unibyte)
return UNIBYTE_TO_CHAR (BUF_FETCH_BYTE (ctx->buffer_a, bpos_a))
== BUF_FETCH_MULTIBYTE_CHAR (ctx->buffer_b, bpos_b);
if (!ctx->a_unibyte && ctx->b_unibyte)
return BUF_FETCH_MULTIBYTE_CHAR (ctx->buffer_a, bpos_a)
== UNIBYTE_TO_CHAR (BUF_FETCH_BYTE (ctx->buffer_b, bpos_b));
return BUF_FETCH_MULTIBYTE_CHAR (ctx->buffer_a, bpos_a)
== BUF_FETCH_MULTIBYTE_CHAR (ctx->buffer_b, bpos_b);
}

View file

@ -282,8 +282,12 @@ call_debugger (Lisp_Object arg)
/* Do not allow max_specpdl_size less than actual depth (Bug#16603). */
EMACS_INT old_max = max (max_specpdl_size, count);
if (lisp_eval_depth + 40 > max_lisp_eval_depth)
max_lisp_eval_depth = lisp_eval_depth + 40;
/* The previous value of 40 is too small now that the debugger
prints using cl-prin1 instead of prin1. Printing lists nested 8
deep (which is the value of print-level used in the debugger)
currently requires 77 additional frames. See bug#31919. */
if (lisp_eval_depth + 100 > max_lisp_eval_depth)
max_lisp_eval_depth = lisp_eval_depth + 100;
/* While debugging Bug#16603, previous value of 100 was found
too small to avoid specpdl overflow in the debugger itself. */

View file

@ -3012,15 +3012,13 @@ extern void defvar_kboard (struct Lisp_Kboard_Objfwd *, const char *, int);
} while (false)
/* Elisp uses several stacks:
- the C stack.
- the bytecode stack: used internally by the bytecode interpreter.
Allocated from the C stack.
- The specpdl stack: keeps track of active unwind-protect and
dynamic-let-bindings. Allocated from the `specpdl' array, a manually
managed stack.
- The handler stack: keeps track of active catch tags and condition-case
handlers. Allocated in a manually managed stack implemented by a
/* Elisp uses multiple stacks:
- The C stack.
- The specpdl stack keeps track of backtraces, unwind-protects and
dynamic let-bindings. It is allocated from the 'specpdl' array,
a manually managed stack.
- The handler stack keeps track of active catch tags and condition-case
handlers. It is allocated in a manually managed stack implemented by a
doubly-linked list allocated via xmalloc and never freed. */
/* Structure for recording Lisp call stack for backtrace purposes. */
@ -3113,7 +3111,7 @@ SPECPDL_INDEX (void)
control structures. A struct handler contains all the information needed to
restore the state of the interpreter after a non-local jump.
handler structures are chained together in a doubly linked list; the `next'
Handler structures are chained together in a doubly linked list; the `next'
member points to the next outer catchtag and the `nextfree' member points in
the other direction to the next inner element (which is typically the next
free element since we mostly use it on the deepest handler).

View file

@ -2192,6 +2192,11 @@ x_set_no_accept_focus (struct frame *f, Lisp_Object new_value, Lisp_Object old_v
*
* Some window managers may not honor this parameter. The value `below'
* is not supported on Windows.
*
* Internally, this function also handles a value 'above-suspended'.
* That value is used to temporarily remove F from the 'above' group
* to make sure that it does not obscure the window of a dialog in
* progress.
*/
static void
x_set_z_group (struct frame *f, Lisp_Object new_value, Lisp_Object old_value)
@ -7583,12 +7588,27 @@ file_dialog_callback (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
return 0;
}
/**
* w32_dialog_in_progress:
*
* This function is called by Fx_file_dialog and Fx_select_font and
* serves to temporarily remove any Emacs frame currently in the
* 'above' z-group from that group to assure that such a frame does
* not hide the dialog window. Frames that are temporarily removed
* from the 'above' group have their z_group bit-field set to
* z_group_above_suspended. Any such frame is moved back to the
* 'above' group as soon as the dialog finishes and has its z_group
* bit-field reset to z_group_above.
*
* This function does not affect the z-order or the z-group state of
* the dialog window itself.
*/
void
w32_dialog_in_progress (Lisp_Object in_progress)
{
Lisp_Object frames, frame;
/* Don't let frames in `above' z-group obscure popups. */
/* Don't let frames in `above' z-group obscure dialog windows. */
FOR_EACH_FRAME (frames, frame)
{
struct frame *f = XFRAME (frame);

View file

@ -10566,6 +10566,10 @@ x_set_skip_taskbar (struct frame *f, Lisp_Object new_value, Lisp_Object old_valu
* windows that do not have the `below' property set.
*
* Some window managers may not honor this parameter.
*
* Internally, this function also handles a value 'above-suspended'.
* That value is used to temporarily remove F from the 'above' group
* to make sure that it does not obscure a menu currently popped up.
*/
void
x_set_z_group (struct frame *f, Lisp_Object new_value, Lisp_Object old_value)