diff options
author | Stefan Monnier <monnier@iro.umontreal.ca> | 2022-09-25 16:15:16 -0400 |
---|---|---|
committer | Stefan Monnier <monnier@iro.umontreal.ca> | 2022-09-25 16:15:16 -0400 |
commit | 650c20f1ca4e07591a727e1cfcc74b3363d15985 (patch) | |
tree | 85d11f6437cde22f410c25e0e5f71a3131ebd07d /src/buffer.c | |
parent | 8869332684c2302b5ba1ead4568bbc7ba1c0183e (diff) | |
parent | 4b85ae6a24380fb67a3315eaec9233f17a872473 (diff) | |
download | emacs-650c20f1ca4e07591a727e1cfcc74b3363d15985.tar.gz emacs-650c20f1ca4e07591a727e1cfcc74b3363d15985.tar.bz2 emacs-650c20f1ca4e07591a727e1cfcc74b3363d15985.zip |
Merge 'master' into noverlay
Diffstat (limited to 'src/buffer.c')
-rw-r--r-- | src/buffer.c | 1178 |
1 files changed, 701 insertions, 477 deletions
diff --git a/src/buffer.c b/src/buffer.c index 9ddc9c7e056..1bb2af98e75 100644 --- a/src/buffer.c +++ b/src/buffer.c @@ -1,7 +1,6 @@ /* Buffer manipulation primitives for GNU Emacs. -Copyright (C) 1985-1989, 1993-1995, 1997-2017 Free Software Foundation, -Inc. +Copyright (C) 1985-2022 Free Software Foundation, Inc. This file is part of GNU Emacs. @@ -45,16 +44,12 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ #include "frame.h" #include "xwidget.h" #include "itree.h" +#include "pdumper.h" #ifdef WINDOWSNT #include "w32heap.h" /* for mmap_* */ #endif -/* First buffer in chain of all buffers (in reverse order of creation). - Threaded through ->header.next.buffer. */ - -struct buffer *all_buffers; - /* This structure holds the default values of the buffer-local variables defined with DEFVAR_PER_BUFFER, that have special slots in each buffer. The default value occupies the same slot in this structure @@ -62,12 +57,13 @@ struct buffer *all_buffers; Setting the default value also goes through the alist of buffers and stores into each buffer that does not say it has a local value. */ -struct buffer alignas (GCALIGNMENT) buffer_defaults; +struct buffer buffer_defaults; /* This structure marks which slots in a buffer have corresponding default values in buffer_defaults. - Each such slot has a nonzero value in this structure. - The value has only one nonzero bit. + Each such slot has a value in this structure. + The value is a positive Lisp integer that must be smaller than + MAX_PER_BUFFER_VARS. When a buffer has its own local value for a slot, the entry for that slot (found in the same slot in this structure) @@ -85,7 +81,7 @@ struct buffer buffer_local_flags; /* This structure holds the names of symbols whose values may be buffer-local. It is indexed and accessed in the same way as the above. */ -struct buffer alignas (GCALIGNMENT) buffer_local_symbols; +struct buffer buffer_local_symbols; /* Return the symbol of the per-buffer variable at offset OFFSET in the buffer structure. */ @@ -104,12 +100,11 @@ static char buffer_permanent_local_flags[MAX_PER_BUFFER_VARS]; /* Number of per-buffer variables used. */ -int last_per_buffer_idx; +static int last_per_buffer_idx; static void call_overlay_mod_hooks (Lisp_Object list, Lisp_Object overlay, bool after, Lisp_Object arg1, Lisp_Object arg2, Lisp_Object arg3); -static void swap_out_buffer_local_variables (struct buffer *b); static void reset_buffer_local_variables (struct buffer *, bool); /* Alist of all buffer names vs the buffers. This used to be @@ -124,6 +119,7 @@ static void free_buffer_text (struct buffer *b); static void copy_overlays (struct buffer *, struct buffer *); static void modify_overlay (struct buffer *, ptrdiff_t, ptrdiff_t); static Lisp_Object buffer_lisp_local_variables (struct buffer *, bool); +static Lisp_Object buffer_local_variables_1 (struct buffer *buf, int offset, Lisp_Object sym); static void CHECK_OVERLAY (Lisp_Object x) @@ -131,6 +127,23 @@ CHECK_OVERLAY (Lisp_Object x) CHECK_TYPE (OVERLAYP (x), Qoverlayp, x); } +/* Convert the position POS to an EMACS_INT that fits in a fixnum. + Yield POS's value if POS is already a fixnum, POS's marker position + if POS is a marker, and MOST_NEGATIVE_FIXNUM or + MOST_POSITIVE_FIXNUM if POS is a negative or positive bignum. + Signal an error if POS is not of the proper form. */ + +EMACS_INT +fix_position (Lisp_Object pos) +{ + if (FIXNUMP (pos)) + return XFIXNUM (pos); + if (MARKERP (pos)) + return marker_position (pos); + CHECK_TYPE (BIGNUMP (pos), Qinteger_or_marker_p, pos); + return !NILP (Fnatnump (pos)) ? MOST_POSITIVE_FIXNUM : MOST_NEGATIVE_FIXNUM; +} + /* These setters are used only in this file, so they can be private. The public setters are inline functions defined in buffer.h. */ static void @@ -249,6 +262,11 @@ bset_header_line_format (struct buffer *b, Lisp_Object val) b->header_line_format_ = val; } static void +bset_tab_line_format (struct buffer *b, Lisp_Object val) +{ + b->tab_line_format_ = val; +} +static void bset_indicate_buffer_boundaries (struct buffer *b, Lisp_Object val) { b->indicate_buffer_boundaries_ = val; @@ -274,14 +292,14 @@ bset_major_mode (struct buffer *b, Lisp_Object val) b->major_mode_ = val; } static void -bset_mark (struct buffer *b, Lisp_Object val) +bset_local_minor_modes (struct buffer *b, Lisp_Object val) { - b->mark_ = val; + b->local_minor_modes_ = val; } static void -bset_minor_modes (struct buffer *b, Lisp_Object val) +bset_mark (struct buffer *b, Lisp_Object val) { - b->minor_modes_ = val; + b->mark_ = val; } static void bset_mode_line_format (struct buffer *b, Lisp_Object val) @@ -378,7 +396,7 @@ nsberror (Lisp_Object spec) } DEFUN ("buffer-live-p", Fbuffer_live_p, Sbuffer_live_p, 1, 1, 0, - doc: /* Return non-nil if OBJECT is a buffer which has not been killed. + doc: /* Return t if OBJECT is a buffer which has not been killed. Value is nil if OBJECT is not a buffer or if it has been killed. */) (Lisp_Object object) { @@ -387,9 +405,9 @@ Value is nil if OBJECT is not a buffer or if it has been killed. */) } DEFUN ("buffer-list", Fbuffer_list, Sbuffer_list, 0, 1, 0, - doc: /* Return a list of all existing live buffers. -If the optional arg FRAME is a frame, we return the buffer list in the -proper order for that frame: the buffers show in FRAME come first, + doc: /* Return a list of all live buffers. +If the optional arg FRAME is a frame, return the buffer list in the +proper order for that frame: the buffers shown in FRAME come first, followed by the rest of the buffers. */) (Lisp_Object frame) { @@ -468,7 +486,7 @@ See also `find-buffer-visiting'. */) filename = Fexpand_file_name (filename, Qnil); /* If the file name has special constructs in it, - call the corresponding file handler. */ + call the corresponding file name handler. */ handler = Ffind_file_name_handler (filename, Qget_file_buffer); if (!NILP (handler)) { @@ -500,16 +518,33 @@ get_truename_buffer (register Lisp_Object filename) return Qnil; } -DEFUN ("get-buffer-create", Fget_buffer_create, Sget_buffer_create, 1, 1, 0, +/* Run buffer-list-update-hook if Vrun_hooks is non-nil, and BUF is NULL + or does not have buffer hooks inhibited. BUF is NULL when called by + make-indirect-buffer, since it does not inhibit buffer hooks. */ + +static void +run_buffer_list_update_hook (struct buffer *buf) +{ + if (! (NILP (Vrun_hooks) || (buf && buf->inhibit_buffer_hooks))) + call1 (Vrun_hooks, Qbuffer_list_update_hook); +} + +DEFUN ("get-buffer-create", Fget_buffer_create, Sget_buffer_create, 1, 2, 0, doc: /* Return the buffer specified by BUFFER-OR-NAME, creating a new one if needed. If BUFFER-OR-NAME is a string and a live buffer with that name exists, return that buffer. If no such buffer exists, create a new buffer with -that name and return it. If BUFFER-OR-NAME starts with a space, the new -buffer does not keep undo information. +that name and return it. + +If BUFFER-OR-NAME starts with a space, the new buffer does not keep undo +information. If optional argument INHIBIT-BUFFER-HOOKS is non-nil, the +new buffer does not run the hooks `kill-buffer-hook', +`kill-buffer-query-functions', and `buffer-list-update-hook'. This +avoids slowing down internal or temporary buffers that are never +presented to users or passed on to other applications. If BUFFER-OR-NAME is a buffer instead of a string, return it as given, even if it is dead. The return value is never nil. */) - (register Lisp_Object buffer_or_name) + (register Lisp_Object buffer_or_name, Lisp_Object inhibit_buffer_hooks) { register Lisp_Object buffer, name; register struct buffer *b; @@ -531,6 +566,8 @@ even if it is dead. The return value is never nil. */) /* No one shows us now. */ b->window_count = 0; + memset (&b->local_flags, 0, sizeof (b->local_flags)); + BUF_GAP_SIZE (b) = 20; block_input (); /* We allocate extra 1-byte at the tail and keep it always '\0' for @@ -560,6 +597,7 @@ even if it is dead. The return value is never nil. */) set_buffer_intervals (b, NULL); BUF_UNCHANGED_MODIFIED (b) = 1; BUF_OVERLAY_UNCHANGED_MODIFIED (b) = 1; + BUF_CHARS_UNCHANGED_MODIFIED (b) = 1; BUF_END_UNCHANGED (b) = 0; BUF_BEG_UNCHANGED (b) = 0; *(BUF_GPT_ADDR (b)) = *(BUF_Z_ADDR (b)) = 0; /* Put an anchor '\0'. */ @@ -582,6 +620,7 @@ even if it is dead. The return value is never nil. */) set_string_intervals (name, NULL); bset_name (b, name); + b->inhibit_buffer_hooks = !NILP (inhibit_buffer_hooks); bset_undo_list (b, SREF (name, 0) != ' ' ? Qnil : Qt); reset_buffer (b); @@ -593,9 +632,8 @@ even if it is dead. The return value is never nil. */) /* Put this in the alist of all live buffers. */ XSETBUFFER (buffer, b); Vbuffer_alist = nconc2 (Vbuffer_alist, list1 (Fcons (name, buffer))); - /* And run buffer-list-update-hook. */ - if (!NILP (Vrun_hooks)) - call1 (Vrun_hooks, Qbuffer_list_update_hook); + + run_buffer_list_update_hook (b); return buffer; } @@ -622,6 +660,12 @@ copy_overlays (struct buffer *from, struct buffer *to) buffer_overlay_iter_finish (from); } +bool +valid_per_buffer_idx (int idx) +{ + return 0 <= idx && idx < last_per_buffer_idx; +} + /* Clone per-buffer values of buffer FROM. Buffer TO gets the same per-buffer values as FROM, with the @@ -711,15 +755,22 @@ fetch_buffer_markers (struct buffer *b) DEFUN ("make-indirect-buffer", Fmake_indirect_buffer, Smake_indirect_buffer, - 2, 3, + 2, 4, "bMake indirect buffer (to buffer): \nBName of indirect buffer: ", doc: /* Create and return an indirect buffer for buffer BASE-BUFFER, named NAME. BASE-BUFFER should be a live buffer, or the name of an existing buffer. + NAME should be a string which is not the name of an existing buffer. Optional argument CLONE non-nil means preserve BASE-BUFFER's state, such as major and minor modes, in the indirect buffer. -CLONE nil means the indirect buffer's state is reset to default values. */) - (Lisp_Object base_buffer, Lisp_Object name, Lisp_Object clone) + +CLONE nil means the indirect buffer's state is reset to default values. + +If optional argument INHIBIT-BUFFER-HOOKS is non-nil, the new buffer +does not run the hooks `kill-buffer-hook', +`kill-buffer-query-functions', and `buffer-list-update-hook'. */) + (Lisp_Object base_buffer, Lisp_Object name, Lisp_Object clone, + Lisp_Object inhibit_buffer_hooks) { Lisp_Object buf, tem; struct buffer *b; @@ -756,12 +807,15 @@ CLONE nil means the indirect buffer's state is reset to default values. */) /* Always -1 for an indirect buffer. */ b->window_count = -1; + memset (&b->local_flags, 0, sizeof (b->local_flags)); + b->pt = b->base_buffer->pt; b->begv = b->base_buffer->begv; b->zv = b->base_buffer->zv; b->pt_byte = b->base_buffer->pt_byte; b->begv_byte = b->base_buffer->begv_byte; b->zv_byte = b->base_buffer->zv_byte; + b->inhibit_buffer_hooks = !NILP (inhibit_buffer_hooks); b->newline_cache = 0; b->width_run_cache = 0; @@ -824,19 +878,23 @@ CLONE nil means the indirect buffer's state is reset to default values. */) clone_per_buffer_values (b->base_buffer, b); bset_filename (b, Qnil); bset_file_truename (b, Qnil); - bset_display_count (b, make_number (0)); + bset_display_count (b, make_fixnum (0)); bset_backed_up (b, Qnil); + bset_local_minor_modes (b, Qnil); bset_auto_save_file_name (b, Qnil); set_buffer_internal_1 (b); Fset (intern ("buffer-save-without-query"), Qnil); Fset (intern ("buffer-file-number"), Qnil); - Fset (intern ("buffer-stale-function"), Qnil); + if (!NILP (Flocal_variable_p (Qbuffer_stale_function, base_buffer))) + Fkill_local_variable (Qbuffer_stale_function); + /* Cloned buffers need extra setup, to do things such as deep + variable copies for list variables that might be mangled due + to destructive operations in the indirect buffer. */ + run_hook (Qclone_indirect_buffer_hook); set_buffer_internal_1 (old_b); } - /* Run buffer-list-update-hook. */ - if (!NILP (Vrun_hooks)) - call1 (Vrun_hooks, Qbuffer_list_update_hook); + run_buffer_list_update_hook (NULL); return buf; } @@ -944,7 +1002,9 @@ reset_buffer (register struct buffer *b) /* It is more conservative to start out "changed" than "unchanged". */ b->clip_changed = 0; b->prevent_redisplay_optimizations_p = 1; + b->long_line_optimizations_p = 0; bset_backed_up (b, Qnil); + bset_local_minor_modes (b, Qnil); BUF_AUTOSAVE_MODIFF (b) = 0; b->auto_save_failure_time = 0; bset_auto_save_file_name (b, Qnil); @@ -955,7 +1015,7 @@ reset_buffer (register struct buffer *b) bset_file_format (b, Qnil); bset_auto_save_file_format (b, Qt); bset_last_selected_window (b, Qnil); - bset_display_count (b, make_number (0)); + bset_display_count (b, make_fixnum (0)); bset_display_time (b, Qnil); bset_enable_multibyte_characters (b, BVAR (&buffer_defaults, enable_multibyte_characters)); @@ -985,7 +1045,6 @@ reset_buffer_local_variables (struct buffer *b, bool permanent_too) bset_major_mode (b, Qfundamental_mode); bset_keymap (b, Qnil); bset_mode_name (b, QSFundamental); - bset_minor_modes (b, Qnil); /* If the standard case table has been altered and invalidated, fix up its insides first. */ @@ -1006,10 +1065,29 @@ reset_buffer_local_variables (struct buffer *b, bool permanent_too) else { Lisp_Object tmp, last = Qnil; + Lisp_Object buffer; + XSETBUFFER (buffer, b); + for (tmp = BVAR (b, local_var_alist); CONSP (tmp); tmp = XCDR (tmp)) { Lisp_Object local_var = XCAR (XCAR (tmp)); Lisp_Object prop = Fget (local_var, Qpermanent_local); + Lisp_Object sym = local_var; + + /* Watchers are run *before* modifying the var. */ + if (XSYMBOL (local_var)->u.s.trapped_write == SYMBOL_TRAPPED_WRITE) + notify_variable_watchers (local_var, Qnil, + Qmakunbound, Fcurrent_buffer ()); + + eassert (XSYMBOL (sym)->u.s.redirect == SYMBOL_LOCALIZED); + /* Need not do anything if some other buffer's binding is + now cached. */ + if (BASE_EQ (SYMBOL_BLV (XSYMBOL (sym))->where, buffer)) + { + /* Symbol is set up for this buffer's old local value: + swap it out! */ + swap_in_global_binding (XSYMBOL (sym)); + } if (!NILP (prop)) { @@ -1027,16 +1105,17 @@ reset_buffer_local_variables (struct buffer *b, bool permanent_too) for (newlist = Qnil; CONSP (list); list = XCDR (list)) { Lisp_Object elt = XCAR (list); - /* Preserve element ELT if it's t, - if it is a function with a `permanent-local-hook' property, - or if it's not a symbol. */ - if (! SYMBOLP (elt) - || EQ (elt, Qt) - || !NILP (Fget (elt, Qpermanent_local_hook))) + /* Preserve element ELT if it's t, or if it is a + function with a `permanent-local-hook' + property. */ + if (EQ (elt, Qt) + || (SYMBOLP (elt) + && !NILP (Fget (elt, Qpermanent_local_hook)))) newlist = Fcons (elt, newlist); } newlist = Fnreverse (newlist); - if (XSYMBOL (local_var)->trapped_write == SYMBOL_TRAPPED_WRITE) + if (XSYMBOL (local_var)->u.s.trapped_write + == SYMBOL_TRAPPED_WRITE) notify_variable_watchers (local_var, newlist, Qmakunbound, Fcurrent_buffer ()); XSETCDR (XCAR (tmp), newlist); @@ -1048,10 +1127,6 @@ reset_buffer_local_variables (struct buffer *b, bool permanent_too) bset_local_var_alist (b, XCDR (tmp)); else XSETCDR (last, XCDR (tmp)); - - if (XSYMBOL (local_var)->trapped_write == SYMBOL_TRAPPED_WRITE) - notify_variable_watchers (local_var, Qnil, - Qmakunbound, Fcurrent_buffer ()); } } @@ -1100,8 +1175,11 @@ is first appended to NAME, to speed up finding a non-existent buffer. */) genbase = name; else { - char number[sizeof "-999999"]; - int i = XFASTINT (Frandom (make_number (999999))); + enum { bug_52711 = true }; /* https://bugs.gnu.org/57211 */ + char number[bug_52711 ? INT_BUFSIZE_BOUND (int) + 1 : sizeof "-999999"]; + EMACS_INT r = get_random (); + eassume (0 <= r); + int i = r % 1000000; AUTO_STRING_WITH_LEN (lnumber, number, sprintf (number, "-%d", i)); genbase = concat2 (name, lnumber); if (NILP (Fget_buffer (genbase))) @@ -1158,7 +1236,7 @@ is the default binding of the variable. */) { register Lisp_Object result = buffer_local_value (variable, buffer); - if (EQ (result, Qunbound)) + if (BASE_EQ (result, Qunbound)) xsignal1 (Qvoid_variable, variable); return result; @@ -1181,7 +1259,7 @@ buffer_local_value (Lisp_Object variable, Lisp_Object buffer) sym = XSYMBOL (variable); start: - switch (sym->redirect) + switch (sym->u.s.redirect) { case SYMBOL_VARALIAS: sym = indirect_variable (sym); goto start; case SYMBOL_PLAINVAL: result = SYMBOL_VAL (sym); break; @@ -1189,10 +1267,10 @@ buffer_local_value (Lisp_Object variable, Lisp_Object buffer) { /* Look in local_var_alist. */ struct Lisp_Buffer_Local_Value *blv = SYMBOL_BLV (sym); XSETSYMBOL (variable, sym); /* Update In case of aliasing. */ - result = Fassoc (variable, BVAR (buf, local_var_alist), Qnil); + result = assq_no_quit (variable, BVAR (buf, local_var_alist)); if (!NILP (result)) { - if (blv->fwd) + if (blv->fwd.fwdptr) { /* What binding is loaded right now? */ Lisp_Object current_alist_element = blv->valcell; @@ -1213,7 +1291,7 @@ buffer_local_value (Lisp_Object variable, Lisp_Object buffer) } case SYMBOL_FORWARDED: { - union Lisp_Fwd *fwd = SYMBOL_FWD (sym); + lispfwd fwd = SYMBOL_FWD (sym); if (BUFFER_OBJFWDP (fwd)) result = per_buffer_value (buf, XBUFFER_OBJFWD (fwd)->offset); else @@ -1253,7 +1331,7 @@ buffer_lisp_local_variables (struct buffer *buf, bool clone) if (buf != current_buffer) val = XCDR (elt); - result = Fcons (!clone && EQ (val, Qunbound) + result = Fcons (!clone && BASE_EQ (val, Qunbound) ? XCAR (elt) : Fcons (XCAR (elt), val), result); @@ -1262,6 +1340,25 @@ buffer_lisp_local_variables (struct buffer *buf, bool clone) return result; } + +/* If the variable at position index OFFSET in buffer BUF has a + buffer-local value, return (name . value). If SYM is non-nil, + it replaces name. */ + +static Lisp_Object +buffer_local_variables_1 (struct buffer *buf, int offset, Lisp_Object sym) +{ + int idx = PER_BUFFER_IDX (offset); + if ((idx == -1 || PER_BUFFER_VALUE_P (buf, idx)) + && SYMBOLP (PER_BUFFER_SYMBOL (offset))) + { + sym = NILP (sym) ? PER_BUFFER_SYMBOL (offset) : sym; + Lisp_Object val = per_buffer_value (buf, offset); + return BASE_EQ (val, Qunbound) ? sym : Fcons (sym, val); + } + return Qnil; +} + DEFUN ("buffer-local-variables", Fbuffer_local_variables, Sbuffer_local_variables, 0, 1, 0, doc: /* Return an alist of variables that are buffer-local in BUFFER. @@ -1273,42 +1370,53 @@ No argument or nil as argument means use current buffer as BUFFER. */) { struct buffer *buf = decode_buffer (buffer); Lisp_Object result = buffer_lisp_local_variables (buf, 0); + Lisp_Object tem; /* Add on all the variables stored in special slots. */ { - int offset, idx; + int offset; FOR_EACH_PER_BUFFER_OBJECT_AT (offset) { - idx = PER_BUFFER_IDX (offset); - if ((idx == -1 || PER_BUFFER_VALUE_P (buf, idx)) - && SYMBOLP (PER_BUFFER_SYMBOL (offset))) - { - Lisp_Object sym = PER_BUFFER_SYMBOL (offset); - Lisp_Object val = per_buffer_value (buf, offset); - result = Fcons (EQ (val, Qunbound) ? sym : Fcons (sym, val), - result); - } + tem = buffer_local_variables_1 (buf, offset, Qnil); + if (!NILP (tem)) + result = Fcons (tem, result); } } + tem = buffer_local_variables_1 (buf, PER_BUFFER_VAR_OFFSET (undo_list), + intern ("buffer-undo-list")); + if (!NILP (tem)) + result = Fcons (tem, result); + return result; } DEFUN ("buffer-modified-p", Fbuffer_modified_p, Sbuffer_modified_p, 0, 1, 0, - doc: /* Return t if BUFFER was modified since its file was last read or saved. -No argument or nil as argument means use current buffer as BUFFER. */) + doc: /* Return non-nil if BUFFER was modified since its file was last read or saved. +No argument or nil as argument means use current buffer as BUFFER. + +If BUFFER was autosaved since it was last modified, this function +returns the symbol `autosaved'. */) (Lisp_Object buffer) { struct buffer *buf = decode_buffer (buffer); - return BUF_SAVE_MODIFF (buf) < BUF_MODIFF (buf) ? Qt : Qnil; + if (BUF_SAVE_MODIFF (buf) < BUF_MODIFF (buf)) + { + if (BUF_AUTOSAVE_MODIFF (buf) == BUF_MODIFF (buf)) + return Qautosaved; + else + return Qt; + } + else + return Qnil; } DEFUN ("force-mode-line-update", Fforce_mode_line_update, Sforce_mode_line_update, 0, 1, 0, doc: /* Force redisplay of the current buffer's mode line and header line. -With optional non-nil ALL, force redisplay of all mode lines and +With optional non-nil ALL, force redisplay of all mode lines, tab lines and header lines. This function also forces recomputation of the menu bar menus and the frame title. */) (Lisp_Object all) @@ -1330,7 +1438,12 @@ menu bar menus and the frame title. */) DEFUN ("set-buffer-modified-p", Fset_buffer_modified_p, Sset_buffer_modified_p, 1, 1, 0, doc: /* Mark current buffer as modified or unmodified according to FLAG. -A non-nil FLAG means mark the buffer modified. */) +A non-nil FLAG means mark the buffer modified. +In addition, this function unconditionally forces redisplay of the +mode lines of the windows that display the current buffer, and also +locks or unlocks the file visited by the buffer, depending on whether +the function's argument is non-nil, but only if both `buffer-file-name' +and `buffer-file-truename' are non-nil. */) (Lisp_Object flag) { Frestore_buffer_modified_p (flag); @@ -1351,12 +1464,19 @@ A non-nil FLAG means mark the buffer modified. */) DEFUN ("restore-buffer-modified-p", Frestore_buffer_modified_p, Srestore_buffer_modified_p, 1, 1, 0, - doc: /* Like `set-buffer-modified-p', with a difference concerning redisplay. + doc: /* Like `set-buffer-modified-p', but doesn't redisplay buffer's mode line. +A nil FLAG means to mark the buffer as unmodified. A non-nil FLAG +means mark the buffer as modified. A special value of `autosaved' +will mark the buffer as modified and also as autosaved since it was +last modified. + +This function also locks or unlocks the file visited by the buffer, +if both `buffer-file-truename' and `buffer-file-name' are non-nil. + It is not ensured that mode lines will be updated to show the modified state of the current buffer. Use with care. */) (Lisp_Object flag) { - Lisp_Object fn; /* If buffer becoming modified, lock the file. If buffer becoming unmodified, unlock the file. */ @@ -1365,15 +1485,18 @@ state of the current buffer. Use with care. */) ? current_buffer->base_buffer : current_buffer; - fn = BVAR (b, file_truename); - /* Test buffer-file-name so that binding it to nil is effective. */ - if (!NILP (fn) && ! NILP (BVAR (b, filename))) + if (!inhibit_modification_hooks) { - bool already = SAVE_MODIFF < MODIFF; - if (!already && !NILP (flag)) - lock_file (fn); - else if (already && NILP (flag)) - unlock_file (fn); + Lisp_Object fn = BVAR (b, file_truename); + /* Test buffer-file-name so that binding it to nil is effective. */ + if (!NILP (fn) && ! NILP (BVAR (b, filename))) + { + bool already = SAVE_MODIFF < MODIFF; + if (!already && !NILP (flag)) + Flock_file (fn); + else if (already && NILP (flag)) + Funlock_file (fn); + } } /* Here we have a problem. SAVE_MODIFF is used here to encode @@ -1386,16 +1509,19 @@ state of the current buffer. Use with care. */) recent-auto-save-p from t to nil. Vice versa, if FLAG is non-nil and SAVE_MODIFF>=auto_save_modified we risk changing recent-auto-save-p from nil to t. */ - SAVE_MODIFF = (NILP (flag) - /* FIXME: This unavoidably sets recent-auto-save-p to nil. */ - ? MODIFF - /* Let's try to preserve recent-auto-save-p. */ - : SAVE_MODIFF < MODIFF ? SAVE_MODIFF - /* If SAVE_MODIFF == auto_save_modified == MODIFF, - we can either decrease SAVE_MODIFF and auto_save_modified - or increase MODIFF. */ - : MODIFF++); - + if (NILP (flag)) + /* This unavoidably sets recent-auto-save-p to nil. */ + SAVE_MODIFF = MODIFF; + else + { + /* If SAVE_MODIFF == auto_save_modified == MODIFF, we can either + decrease SAVE_MODIFF and auto_save_modified or increase + MODIFF. */ + if (SAVE_MODIFF >= MODIFF) + SAVE_MODIFF = modiff_incr (&MODIFF, 1); + if (EQ (flag, Qautosaved)) + BUF_AUTOSAVE_MODIFF (b) = MODIFF; + } return flag; } @@ -1403,11 +1529,23 @@ DEFUN ("buffer-modified-tick", Fbuffer_modified_tick, Sbuffer_modified_tick, 0, 1, 0, doc: /* Return BUFFER's tick counter, incremented for each change in text. Each buffer has a tick counter which is incremented each time the -text in that buffer is changed. It wraps around occasionally. +text in that buffer is changed. No argument or nil as argument means +use current buffer as BUFFER. */) + (Lisp_Object buffer) +{ + return modiff_to_integer (BUF_MODIFF (decode_buffer (buffer))); +} + +DEFUN ("internal--set-buffer-modified-tick", + Finternal__set_buffer_modified_tick, Sinternal__set_buffer_modified_tick, + 1, 2, 0, + doc: /* Set BUFFER's tick counter to TICK. No argument or nil as argument means use current buffer as BUFFER. */) - (register Lisp_Object buffer) + (Lisp_Object tick, Lisp_Object buffer) { - return make_number (BUF_MODIFF (decode_buffer (buffer))); + CHECK_FIXNUM (tick); + BUF_MODIFF (decode_buffer (buffer)) = XFIXNUM (tick); + return Qnil; } DEFUN ("buffer-chars-modified-tick", Fbuffer_chars_modified_tick, @@ -1420,9 +1558,9 @@ values returned by two individual calls of `buffer-chars-modified-tick', you can tell whether a character change occurred in that buffer in between these calls. No argument or nil as argument means use current buffer as BUFFER. */) - (register Lisp_Object buffer) + (Lisp_Object buffer) { - return make_number (BUF_CHARS_MODIFF (decode_buffer (buffer))); + return modiff_to_integer (BUF_CHARS_MODIFF (decode_buffer (buffer))); } DEFUN ("rename-buffer", Frename_buffer, Srename_buffer, 1, 2, @@ -1440,6 +1578,7 @@ This does not change the name of the visited file (if any). */) (register Lisp_Object newname, Lisp_Object unique) { register Lisp_Object tem, buf; + Lisp_Object requestedname = newname; CHECK_STRING (newname); @@ -1456,7 +1595,8 @@ This does not change the name of the visited file (if any). */) if (NILP (unique) && XBUFFER (tem) == current_buffer) return BVAR (current_buffer, name); if (!NILP (unique)) - newname = Fgenerate_new_buffer_name (newname, BVAR (current_buffer, name)); + newname = Fgenerate_new_buffer_name (newname, + BVAR (current_buffer, name)); else error ("Buffer name `%s' is in use", SDATA (newname)); } @@ -1465,7 +1605,7 @@ This does not change the name of the visited file (if any). */) /* Catch redisplay's attention. Unless we do this, the mode lines for any windows displaying current_buffer will stay unchanged. */ - update_mode_lines = 11; + bset_update_mode_line (current_buffer); XSETBUFFER (buf, current_buffer); Fsetcar (Frassq (buf, Vbuffer_alist), newname); @@ -1473,9 +1613,10 @@ This does not change the name of the visited file (if any). */) && !NILP (BVAR (current_buffer, auto_save_file_name))) call0 (intern ("rename-auto-save-file")); - /* Run buffer-list-update-hook. */ - if (!NILP (Vrun_hooks)) - call1 (Vrun_hooks, Qbuffer_list_update_hook); + run_buffer_list_update_hook (current_buffer); + + call2 (intern ("uniquify--rename-buffer-advice"), + requestedname, unique); /* Refetch since that last call may have done GC. */ return BVAR (current_buffer, name); @@ -1486,7 +1627,7 @@ This does not change the name of the visited file (if any). */) static bool candidate_buffer (Lisp_Object b, Lisp_Object buffer) { - return (BUFFERP (b) && !EQ (b, buffer) + return (BUFFERP (b) && !BASE_EQ (b, buffer) && BUFFER_LIVE_P (XBUFFER (b)) && !BUFFER_HIDDEN_P (XBUFFER (b))); } @@ -1544,16 +1685,7 @@ exists, return the buffer `*scratch*' (creating it if necessary). */) if (!NILP (notsogood)) return notsogood; else - { - AUTO_STRING (scratch, "*scratch*"); - buf = Fget_buffer (scratch); - if (NILP (buf)) - { - buf = Fget_buffer_create (scratch); - Fset_buffer_major_mode (buf); - } - return buf; - } + return safe_call (1, Qget_scratch_buffer_create); } /* The following function is a safe variant of Fother_buffer: It doesn't @@ -1569,15 +1701,7 @@ other_buffer_safely (Lisp_Object buffer) if (candidate_buffer (buf, buffer)) return buf; - AUTO_STRING (scratch, "*scratch*"); - buf = Fget_buffer (scratch); - if (NILP (buf)) - { - buf = Fget_buffer_create (scratch); - Fset_buffer_major_mode (buf); - } - - return buf; + return safe_call (1, Qget_scratch_buffer_create); } DEFUN ("buffer-enable-undo", Fbuffer_enable_undo, Sbuffer_enable_undo, @@ -1650,7 +1774,9 @@ buffer to be killed as the current buffer. If any of them returns nil, the buffer is not killed. The hook `kill-buffer-hook' is run before the buffer is actually killed. The buffer being killed will be current while the hook is running. Functions called by any of these hooks are -supposed to not change the current buffer. +supposed to not change the current buffer. Neither hook is run for +internal or temporary buffers created by `get-buffer-create' or +`generate-new-buffer' with argument INHIBIT-BUFFER-HOOKS non-nil. Any processes that have this buffer as the `process-buffer' are killed with SIGHUP. This function calls `replace-buffer-in-windows' for @@ -1678,28 +1804,54 @@ cleaning up all windows currently displaying the buffer to be killed. */) if (thread_check_current_buffer (b)) return Qnil; - /* Run hooks with the buffer to be killed the current buffer. */ + /* Run hooks with the buffer to be killed as the current buffer. */ { - ptrdiff_t count = SPECPDL_INDEX (); + specpdl_ref count = SPECPDL_INDEX (); + bool modified; - record_unwind_protect (save_excursion_restore, save_excursion_save ()); + record_unwind_protect_excursion (); set_buffer_internal (b); /* First run the query functions; if any query is answered no, don't kill the buffer. */ - tem = CALLN (Frun_hook_with_args_until_failure, - Qkill_buffer_query_functions); - if (NILP (tem)) - return unbind_to (count, Qnil); + if (!b->inhibit_buffer_hooks) + { + tem = CALLN (Frun_hook_with_args_until_failure, + Qkill_buffer_query_functions); + if (NILP (tem)) + return unbind_to (count, Qnil); + } + + /* Is this a modified buffer that's visiting a file? */ + modified = !NILP (BVAR (b, filename)) + && BUF_MODIFF (b) > BUF_SAVE_MODIFF (b); /* Query if the buffer is still modified. */ - if (INTERACTIVE && !NILP (BVAR (b, filename)) - && BUF_MODIFF (b) > BUF_SAVE_MODIFF (b)) + if (INTERACTIVE && modified) { - AUTO_STRING (format, "Buffer %s modified; kill anyway? "); - tem = do_yes_or_no_p (CALLN (Fformat, format, BVAR (b, name))); - if (NILP (tem)) + /* Ask whether to kill the buffer, and exit if the user says + "no". */ + if (NILP (call1 (Qkill_buffer__possibly_save, buffer))) return unbind_to (count, Qnil); + /* Recheck modified. */ + modified = BUF_MODIFF (b) > BUF_SAVE_MODIFF (b); + } + + /* Delete the autosave file, if requested. */ + if (modified + && kill_buffer_delete_auto_save_files + && delete_auto_save_files + && !NILP (Frecent_auto_save_p ()) + && STRINGP (BVAR (b, auto_save_file_name)) + && !NILP (Ffile_exists_p (BVAR (b, auto_save_file_name))) + /* If `auto-save-visited-mode' is on, then we're auto-saving + to the visited file -- don't delete it.. */ + && NILP (Fstring_equal (BVAR (b, auto_save_file_name), + BVAR (b, filename)))) + { + tem = do_yes_or_no_p (build_string ("Delete auto-save file? ")); + if (!NILP (tem)) + call0 (intern ("delete-auto-save-file-if-necessary")); } /* If the hooks have killed the buffer, exit now. */ @@ -1707,7 +1859,8 @@ cleaning up all windows currently displaying the buffer to be killed. */) return unbind_to (count, Qt); /* Then run the hooks. */ - run_hook (Qkill_buffer_hook); + if (!b->inhibit_buffer_hooks) + run_hook (Qkill_buffer_hook); unbind_to (count, Qnil); } @@ -1720,7 +1873,7 @@ cleaning up all windows currently displaying the buffer to be killed. */) since anything can happen within do_yes_or_no_p. */ /* Don't kill the minibuffer now current. */ - if (EQ (buffer, XWINDOW (minibuf_window)->contents)) + if (BASE_EQ (buffer, XWINDOW (minibuf_window)->contents)) return Qnil; /* When we kill an ordinary buffer which shares its buffer text @@ -1729,15 +1882,11 @@ cleaning up all windows currently displaying the buffer to be killed. */) ask questions or their hooks get errors. */ if (!b->base_buffer && b->indirections > 0) { - struct buffer *other; + Lisp_Object tail, other; - FOR_EACH_BUFFER (other) - if (other->base_buffer == b) - { - Lisp_Object buf; - XSETBUFFER (buf, other); - Fkill_buffer (buf); - } + FOR_EACH_LIVE_BUFFER (tail, other) + if (XBUFFER (other)->base_buffer == b) + Fkill_buffer (other); /* Exit if we now have killed the base buffer (Bug#11665). */ if (!BUFFER_LIVE_P (b)) @@ -1768,7 +1917,7 @@ cleaning up all windows currently displaying the buffer to be killed. */) is the sole other buffer give up. */ XSETBUFFER (tem, current_buffer); if (EQ (tem, XWINDOW (minibuf_window)->contents) - && EQ (buffer, Fother_buffer (buffer, Qnil, Qnil))) + && BASE_EQ (buffer, Fother_buffer (buffer, Qnil, Qnil))) return Qnil; /* Now there is no question: we can kill the buffer. */ @@ -1792,30 +1941,15 @@ cleaning up all windows currently displaying the buffer to be killed. */) tem = Vinhibit_quit; Vinhibit_quit = Qt; + /* Once the buffer is removed from Vbuffer_alist, its undo_list field is + not traced by the GC in the same way. So set it to nil early. */ + bset_undo_list (b, Qnil); /* Remove the buffer from the list of all buffers. */ Vbuffer_alist = Fdelq (Frassq (buffer, Vbuffer_alist), Vbuffer_alist); /* If replace_buffer_in_windows didn't do its job fix that now. */ replace_buffer_in_windows_safely (buffer); Vinhibit_quit = tem; - /* Delete any auto-save file, if we saved it in this session. - But not if the buffer is modified. */ - if (STRINGP (BVAR (b, auto_save_file_name)) - && BUF_AUTOSAVE_MODIFF (b) != 0 - && BUF_SAVE_MODIFF (b) < BUF_AUTOSAVE_MODIFF (b) - && BUF_SAVE_MODIFF (b) < BUF_MODIFF (b) - && NILP (Fsymbol_value (intern ("auto-save-visited-file-name")))) - { - Lisp_Object delete; - delete = Fsymbol_value (intern ("delete-auto-save-files")); - if (! NILP (delete)) - internal_delete_file (BVAR (b, auto_save_file_name)); - } - - /* Deleting an auto-save file could have killed our buffer. */ - if (!BUFFER_LIVE_P (b)) - return Qt; - if (b->base_buffer) { INTERVAL i; @@ -1865,7 +1999,6 @@ cleaning up all windows currently displaying the buffer to be killed. */) won't be protected from GC. They would be protected if they happened to remain cached in their symbols. This gets rid of them for certain. */ - swap_out_buffer_local_variables (b); reset_buffer_local_variables (b, 1); bset_name (b, Qnil); @@ -1905,11 +2038,8 @@ cleaning up all windows currently displaying the buffer to be killed. */) } bset_width_table (b, Qnil); unblock_input (); - bset_undo_list (b, Qnil); - /* Run buffer-list-update-hook. */ - if (!NILP (Vrun_hooks)) - call1 (Vrun_hooks, Qbuffer_list_update_hook); + run_buffer_list_update_hook (b); return Qt; } @@ -1949,9 +2079,7 @@ record_buffer (Lisp_Object buffer) fset_buffer_list (f, Fcons (buffer, Fdelq (buffer, f->buffer_list))); fset_buried_buffer_list (f, Fdelq (buffer, f->buried_buffer_list)); - /* Run buffer-list-update-hook. */ - if (!NILP (Vrun_hooks)) - call1 (Vrun_hooks, Qbuffer_list_update_hook); + run_buffer_list_update_hook (XBUFFER (buffer)); } @@ -1988,9 +2116,7 @@ DEFUN ("bury-buffer-internal", Fbury_buffer_internal, Sbury_buffer_internal, fset_buried_buffer_list (f, Fcons (buffer, Fdelq (buffer, f->buried_buffer_list))); - /* Run buffer-list-update-hook. */ - if (!NILP (Vrun_hooks)) - call1 (Vrun_hooks, Qbuffer_list_update_hook); + run_buffer_list_update_hook (XBUFFER (buffer)); return Qnil; } @@ -2003,7 +2129,6 @@ Use this function before selecting the buffer, since it may need to inspect the current buffer's major mode. */) (Lisp_Object buffer) { - ptrdiff_t count; Lisp_Object function; CHECK_BUFFER (buffer); @@ -2026,7 +2151,7 @@ the current buffer's major mode. */) `hack-local-variables' get run. */ return Qnil; - count = SPECPDL_INDEX (); + specpdl_ref count = SPECPDL_INDEX (); /* To select a nonfundamental mode, select the buffer temporarily and then call the mode function. */ @@ -2109,8 +2234,8 @@ void set_buffer_internal_2 (register struct buffer *b) { Lisp_Object var = XCAR (XCAR (tail)); struct Lisp_Symbol *sym = XSYMBOL (var); - if (sym->redirect == SYMBOL_LOCALIZED /* Just to be sure. */ - && SYMBOL_BLV (sym)->fwd) + if (sym->u.s.redirect == SYMBOL_LOCALIZED /* Just to be sure. */ + && SYMBOL_BLV (sym)->fwd.fwdptr) /* Just reference the variable to cause it to become set for this buffer. */ Fsymbol_value (var); @@ -2188,7 +2313,7 @@ If the text under POSITION (which defaults to point) has the if (NILP (position)) XSETFASTINT (position, PT); else - CHECK_NUMBER (position); + CHECK_FIXNUM (position); if (!NILP (BVAR (current_buffer, read_only)) && NILP (Vinhibit_read_only) @@ -2216,25 +2341,26 @@ so the buffer is truly empty after this. */) } void -validate_region (register Lisp_Object *b, register Lisp_Object *e) +validate_region (Lisp_Object *b, Lisp_Object *e) { - CHECK_NUMBER_COERCE_MARKER (*b); - CHECK_NUMBER_COERCE_MARKER (*e); + EMACS_INT beg = fix_position (*b), end = fix_position (*e); - if (XINT (*b) > XINT (*e)) + if (end < beg) { - Lisp_Object tem; - tem = *b; *b = *e; *e = tem; + EMACS_INT tem = beg; beg = end; end = tem; } - if (! (BEGV <= XINT (*b) && XINT (*e) <= ZV)) + if (! (BEGV <= beg && end <= ZV)) args_out_of_range_3 (Fcurrent_buffer (), *b, *e); + + *b = make_fixnum (beg); + *e = make_fixnum (end); } /* Advance BYTE_POS up to a character boundary and return the adjusted position. */ -static ptrdiff_t +ptrdiff_t advance_to_char_boundary (ptrdiff_t byte_pos) { int c; @@ -2256,7 +2382,7 @@ advance_to_char_boundary (ptrdiff_t byte_pos) c = FETCH_BYTE (byte_pos); } while (! CHAR_HEAD_P (c) && byte_pos > BEG); - INC_POS (byte_pos); + byte_pos += next_char_len (byte_pos); if (byte_pos < orig_byte_pos) byte_pos = orig_byte_pos; /* If C is a constituent of a multibyte sequence, BYTE_POS was @@ -2313,10 +2439,10 @@ results, see Info node `(elisp)Swapping Text'. */) error ("Cannot swap indirect buffers's text"); { /* This is probably harder to make work. */ - struct buffer *other; - FOR_EACH_BUFFER (other) - if (other->base_buffer == other_buffer - || other->base_buffer == current_buffer) + Lisp_Object tail, other; + FOR_EACH_LIVE_BUFFER (tail, other) + if (XBUFFER (other)->base_buffer == other_buffer + || XBUFFER (other)->base_buffer == current_buffer) error ("One of the buffers to swap has indirect buffers"); } @@ -2358,8 +2484,10 @@ results, see Info node `(elisp)Swapping Text'. */) swapfield (bidi_paragraph_cache, struct region_cache *); current_buffer->prevent_redisplay_optimizations_p = 1; other_buffer->prevent_redisplay_optimizations_p = 1; + swapfield (long_line_optimizations_p, bool_bf); swapfield_ (undo_list, Lisp_Object); swapfield_ (mark, Lisp_Object); + swapfield_ (mark_active, Lisp_Object); /* Belongs with the `mark'. */ swapfield_ (enable_multibyte_characters, Lisp_Object); swapfield_ (bidi_display_reordering, Lisp_Object); swapfield_ (bidi_paragraph_direction, Lisp_Object); @@ -2373,9 +2501,12 @@ results, see Info node `(elisp)Swapping Text'. */) bset_point_before_scroll (current_buffer, Qnil); bset_point_before_scroll (other_buffer, Qnil); - current_buffer->text->modiff++; other_buffer->text->modiff++; - current_buffer->text->chars_modiff++; other_buffer->text->chars_modiff++; - current_buffer->text->overlay_modiff++; other_buffer->text->overlay_modiff++; + modiff_incr (¤t_buffer->text->modiff, 1); + modiff_incr (&other_buffer->text->modiff, 1); + modiff_incr (¤t_buffer->text->chars_modiff, 1); + modiff_incr (&other_buffer->text->chars_modiff, 1); + modiff_incr (¤t_buffer->text->overlay_modiff, 1); + modiff_incr (&other_buffer->text->overlay_modiff, 1); current_buffer->text->beg_unchanged = current_buffer->text->gpt; current_buffer->text->end_unchanged = current_buffer->text->gpt; other_buffer->text->beg_unchanged = other_buffer->text->gpt; @@ -2410,25 +2541,25 @@ results, see Info node `(elisp)Swapping Text'. */) { ws = Fcons (w, ws); if (MARKERP (XWINDOW (w)->pointm) - && (EQ (XWINDOW (w)->contents, buf1) - || EQ (XWINDOW (w)->contents, buf2))) + && (BASE_EQ (XWINDOW (w)->contents, buf1) + || BASE_EQ (XWINDOW (w)->contents, buf2))) Fset_marker (XWINDOW (w)->pointm, - make_number + make_fixnum (BUF_BEGV (XBUFFER (XWINDOW (w)->contents))), XWINDOW (w)->contents); /* Blindly copied from pointm part. */ if (MARKERP (XWINDOW (w)->old_pointm) - && (EQ (XWINDOW (w)->contents, buf1) - || EQ (XWINDOW (w)->contents, buf2))) + && (BASE_EQ (XWINDOW (w)->contents, buf1) + || BASE_EQ (XWINDOW (w)->contents, buf2))) Fset_marker (XWINDOW (w)->old_pointm, - make_number + make_fixnum (BUF_BEGV (XBUFFER (XWINDOW (w)->contents))), XWINDOW (w)->contents); if (MARKERP (XWINDOW (w)->start) - && (EQ (XWINDOW (w)->contents, buf1) - || EQ (XWINDOW (w)->contents, buf2))) + && (BASE_EQ (XWINDOW (w)->contents, buf1) + || BASE_EQ (XWINDOW (w)->contents, buf2))) Fset_marker (XWINDOW (w)->start, - make_number + make_fixnum (XBUFFER (XWINDOW (w)->contents)->last_window_start), XWINDOW (w)->contents); w = Fnext_window (w, Qt, Qt); @@ -2436,10 +2567,11 @@ results, see Info node `(elisp)Swapping Text'. */) } if (current_buffer->text->intervals) - (eassert (EQ (current_buffer->text->intervals->up.obj, buffer)), + (eassert (BASE_EQ (current_buffer->text->intervals->up.obj, buffer)), XSETBUFFER (current_buffer->text->intervals->up.obj, current_buffer)); if (other_buffer->text->intervals) - (eassert (EQ (other_buffer->text->intervals->up.obj, Fcurrent_buffer ())), + (eassert (BASE_EQ (other_buffer->text->intervals->up.obj, + Fcurrent_buffer ())), XSETBUFFER (other_buffer->text->intervals->up.obj, other_buffer)); return Qnil; @@ -2459,7 +2591,7 @@ current buffer is cleared. */) (Lisp_Object flag) { struct Lisp_Marker *tail, *markers; - struct buffer *other; + Lisp_Object btail, other; ptrdiff_t begv, zv; bool narrowed = (BEG != BEGV || Z != ZV); bool modified_p = !NILP (Fbuffer_modified_p (Qnil)); @@ -2517,8 +2649,6 @@ current buffer is cleared. */) p = BEG_ADDR; while (1) { - int c, bytes; - if (pos == stop) { if (pos == Z) @@ -2530,7 +2660,7 @@ current buffer is cleared. */) p++, pos++; else if (CHAR_BYTE8_HEAD_P (*p)) { - c = STRING_CHAR_AND_LENGTH (p, bytes); + int bytes, c = string_char_and_length (p, &bytes); /* Delete all bytes for this 8-bit character but the last one, and change the last one to the character code. */ @@ -2547,12 +2677,10 @@ current buffer is cleared. */) } else { - bytes = BYTES_BY_CHAR_HEAD (*p); + int bytes = BYTES_BY_CHAR_HEAD (*p); p += bytes, pos += bytes; } } - if (narrowed) - Fnarrow_to_region (make_number (begv), make_number (zv)); } else { @@ -2601,8 +2729,7 @@ current buffer is cleared. */) if (ASCII_CHAR_P (*p)) p++, pos++; else if (EQ (flag, Qt) - && ! CHAR_BYTE8_HEAD_P (*p) - && (bytes = MULTIBYTE_LENGTH (p, pend)) > 0) + && 0 < (bytes = multibyte_length (p, pend, true, false))) p += bytes, pos += bytes; else { @@ -2632,9 +2759,6 @@ current buffer is cleared. */) if (pt != PT) TEMP_SET_PT (pt); - if (narrowed) - Fnarrow_to_region (make_number (begv), make_number (zv)); - /* Do this first, so that chars_in_text asks the right question. set_intervals_multibyte needs it too. */ bset_enable_multibyte_characters (current_buffer, Qt); @@ -2689,6 +2813,9 @@ current buffer is cleared. */) /* Do this last, so it can calculate the new correspondences between chars and bytes. */ + /* FIXME: Is it worth the trouble, really? Couldn't we just throw + away all the text-properties instead of trying to guess how + to adjust them? AFAICT the result is not reliable anyway. */ set_intervals_multibyte (1); set_overlays_multibyte (1); } @@ -2711,13 +2838,16 @@ current buffer is cleared. */) /* Copy this buffer's new multibyte status into all of its indirect buffers. */ - FOR_EACH_BUFFER (other) - if (other->base_buffer == current_buffer && BUFFER_LIVE_P (other)) - { - BVAR (other, enable_multibyte_characters) - = BVAR (current_buffer, enable_multibyte_characters); - other->prevent_redisplay_optimizations_p = 1; - } + FOR_EACH_LIVE_BUFFER (btail, other) + { + struct buffer *o = XBUFFER (other); + if (o->base_buffer == current_buffer && BUFFER_LIVE_P (o)) + { + BVAR (o, enable_multibyte_characters) + = BVAR (current_buffer, enable_multibyte_characters); + o->prevent_redisplay_optimizations_p = true; + } + } /* Restore the modifiedness of the buffer. */ if (!modified_p && !NILP (Fbuffer_modified_p (Qnil))) @@ -2736,7 +2866,7 @@ current buffer is cleared. */) } DEFUN ("kill-all-local-variables", Fkill_all_local_variables, - Skill_all_local_variables, 0, 0, 0, + Skill_all_local_variables, 0, 1, 0, doc: /* Switch to Fundamental mode by killing current buffer's local variables. Most local variable bindings are eliminated so that the default values become effective once more. Also, the syntax table is set from @@ -2747,57 +2877,28 @@ This function also forces redisplay of the mode line. Every function to select a new major mode starts by calling this function. -As a special exception, local variables whose names have -a non-nil `permanent-local' property are not eliminated by this function. +As a special exception, local variables whose names have a non-nil +`permanent-local' property are not eliminated by this function. If +the optional KILL-PERMANENT argument is non-nil, clear out these local +variables, too. The first thing this function does is run the normal hook `change-major-mode-hook'. */) - (void) + (Lisp_Object kill_permanent) { run_hook (Qchange_major_mode_hook); - /* Make sure none of the bindings in local_var_alist - remain swapped in, in their symbols. */ - - swap_out_buffer_local_variables (current_buffer); - /* Actually eliminate all local bindings of this buffer. */ - reset_buffer_local_variables (current_buffer, 0); + reset_buffer_local_variables (current_buffer, !NILP (kill_permanent)); /* Force mode-line redisplay. Useful here because all major mode commands call this function. */ - update_mode_lines = 12; + bset_update_mode_line (current_buffer); return Qnil; } -/* Make sure no local variables remain set up with buffer B - for their current values. */ - -static void -swap_out_buffer_local_variables (struct buffer *b) -{ - Lisp_Object oalist, alist, buffer; - - XSETBUFFER (buffer, b); - oalist = BVAR (b, local_var_alist); - - for (alist = oalist; CONSP (alist); alist = XCDR (alist)) - { - Lisp_Object sym = XCAR (XCAR (alist)); - eassert (XSYMBOL (sym)->redirect == SYMBOL_LOCALIZED); - /* Need not do anything if some other buffer's binding is - now cached. */ - if (EQ (SYMBOL_BLV (XSYMBOL (sym))->where, buffer)) - { - /* Symbol is set up for this buffer's old local value: - swap it out! */ - swap_in_global_binding (XSYMBOL (sym)); - } - } -} - /* Find all the overlays in the current buffer that overlap the range [BEG, END). @@ -3061,17 +3162,17 @@ make_sortvec_item (struct sortvec *item, Lisp_Object overlay) item->priority = 0; item->spriority = 0; } - else if (INTEGERP (tem)) + else if (FIXNUMP (tem)) { - item->priority = XINT (tem); + item->priority = XFIXNUM (tem); item->spriority = 0; } else if (CONSP (tem)) { Lisp_Object car = XCAR (tem); Lisp_Object cdr = XCDR (tem); - item->priority = INTEGERP (car) ? XINT (car) : 0; - item->spriority = INTEGERP (cdr) ? XINT (cdr) : 0; + item->priority = FIXNUMP (car) ? XFIXNUM (car) : 0; + item->spriority = FIXNUMP (cdr) ? XFIXNUM (cdr) : 0; } } /* Sort an array of overlays by priority. The array is modified in place. @@ -3168,7 +3269,7 @@ record_overlay_string (struct sortstrlist *ssl, Lisp_Object str, ssl->buf[ssl->used].string = str; ssl->buf[ssl->used].string2 = str2; ssl->buf[ssl->used].size = size; - ssl->buf[ssl->used].priority = (INTEGERP (pri) ? XINT (pri) : 0); + ssl->buf[ssl->used].priority = (FIXNUMP (pri) ? XFIXNUM (pri) : 0); ssl->used++; if (NILP (BVAR (current_buffer, enable_multibyte_characters))) @@ -3215,8 +3316,6 @@ record_overlay_string (struct sortstrlist *ssl, Lisp_Object str, ptrdiff_t overlay_strings (ptrdiff_t pos, struct window *w, unsigned char **pstr) { - Lisp_Object overlay, window, str; - ptrdiff_t obegin, oend; bool multibyte = ! NILP (BVAR (current_buffer, enable_multibyte_characters)); struct interval_node *node; @@ -3227,30 +3326,31 @@ overlay_strings (ptrdiff_t pos, struct window *w, unsigned char **pstr) pos - 1, pos + 1, ITREE_DESCENDING); while ((node = buffer_overlay_iter_next (current_buffer))) { - overlay = node->data; + Lisp_Object overlay = node->data; eassert (OVERLAYP (overlay)); - obegin = node->begin; - oend = node->end; + ptrdiff_t startpos = node->begin; + ptrdiff_t endpos = node->end; - if (oend != pos && obegin != pos) + if (endpos != pos && startpos != pos) continue; - window = Foverlay_get (overlay, Qwindow); + Lisp_Object window = Foverlay_get (overlay, Qwindow); if (WINDOWP (window) && XWINDOW (window) != w) continue; - if (obegin == pos + Lisp_Object str; + if (startpos == pos && (str = Foverlay_get (overlay, Qbefore_string), STRINGP (str))) record_overlay_string (&overlay_heads, str, - (obegin == oend + (startpos == endpos ? Foverlay_get (overlay, Qafter_string) : Qnil), Foverlay_get (overlay, Qpriority), - oend - obegin); - else if (oend == pos + endpos - startpos); + else if (endpos == pos && (str = Foverlay_get (overlay, Qafter_string), STRINGP (str))) record_overlay_string (&overlay_tails, str, Qnil, Foverlay_get (overlay, Qpriority), - oend - obegin); + endpos - startpos); } buffer_overlay_iter_finish (current_buffer); @@ -3346,11 +3446,10 @@ for the front of the overlay advance when text is inserted there The fifth arg REAR-ADVANCE, if non-nil, makes the marker for the rear of the overlay advance when text is inserted there \(which means the text *is* included in the overlay). */) - (Lisp_Object begin, Lisp_Object end, Lisp_Object buffer, + (Lisp_Object beg, Lisp_Object end, Lisp_Object buffer, Lisp_Object front_advance, Lisp_Object rear_advance) { Lisp_Object ov; - ptrdiff_t obegin, oend; struct buffer *b; if (NILP (buffer)) @@ -3362,23 +3461,23 @@ for the rear of the overlay advance when text is inserted there if (! BUFFER_LIVE_P (b)) error ("Attempt to create overlay in a dead buffer"); - if (MARKERP (begin) && !EQ (Fmarker_buffer (begin), buffer)) - signal_error ("Marker points into wrong buffer", begin); - if (MARKERP (end) && !EQ (Fmarker_buffer (end), buffer)) + if (MARKERP (beg) && !BASE_EQ (Fmarker_buffer (beg), buffer)) + signal_error ("Marker points into wrong buffer", beg); + if (MARKERP (end) && !BASE_EQ (Fmarker_buffer (end), buffer)) signal_error ("Marker points into wrong buffer", end); - CHECK_NUMBER_COERCE_MARKER (begin); - CHECK_NUMBER_COERCE_MARKER (end); + CHECK_FIXNUM_COERCE_MARKER (beg); + CHECK_FIXNUM_COERCE_MARKER (end); - if (XINT (begin) > XINT (end)) + if (XFIXNUM (beg) > XFIXNUM (end)) { Lisp_Object temp; - temp = begin; begin = end; end = temp; + temp = beg; beg = end; end = temp; } - obegin = clip_to_bounds (BEG, XINT (begin), b->text->z); - oend = clip_to_bounds (obegin, XINT (end), b->text->z); - ov = build_overlay (obegin, oend, + ptrdiff_t obeg = clip_to_bounds (BEG, XFIXNUM (beg), b->text->z); + ptrdiff_t oend = clip_to_bounds (obeg, XFIXNUM (end), b->text->z); + ov = build_overlay (obeg, oend, ! NILP (front_advance), ! NILP (rear_advance), Qnil); add_buffer_overlay (b, XOVERLAY (ov)); @@ -3405,7 +3504,7 @@ modify_overlay (struct buffer *buf, ptrdiff_t start, ptrdiff_t end) bset_redisplay (buf); - ++BUF_OVERLAY_MODIFF (buf); + modiff_incr (&BUF_OVERLAY_MODIFF (buf), 1); } DEFUN ("move-overlay", Fmove_overlay, Smove_overlay, 3, 4, 0, @@ -3417,7 +3516,7 @@ buffer. */) { struct buffer *b, *ob = 0; Lisp_Object obuffer; - ptrdiff_t count = SPECPDL_INDEX (); + specpdl_ref count = SPECPDL_INDEX (); ptrdiff_t n_beg, n_end; ptrdiff_t o_beg UNINIT, o_end UNINIT; @@ -3431,15 +3530,15 @@ buffer. */) if (NILP (Fbuffer_live_p (buffer))) error ("Attempt to move overlay to a dead buffer"); - if (MARKERP (beg) && !EQ (Fmarker_buffer (beg), buffer)) + if (MARKERP (beg) && !BASE_EQ (Fmarker_buffer (beg), buffer)) signal_error ("Marker points into wrong buffer", beg); - if (MARKERP (end) && !EQ (Fmarker_buffer (end), buffer)) + if (MARKERP (end) && !BASE_EQ (Fmarker_buffer (end), buffer)) signal_error ("Marker points into wrong buffer", end); - CHECK_NUMBER_COERCE_MARKER (beg); - CHECK_NUMBER_COERCE_MARKER (end); + CHECK_FIXNUM_COERCE_MARKER (beg); + CHECK_FIXNUM_COERCE_MARKER (end); - if (XINT (beg) > XINT (end)) + if (XFIXNUM (beg) > XFIXNUM (end)) { Lisp_Object temp; temp = beg; beg = end; end = temp; @@ -3465,13 +3564,13 @@ buffer. */) add_buffer_overlay (XBUFFER (buffer), XOVERLAY (overlay)); } /* Set the overlay boundaries, which may clip them. */ - set_overlay_region (XOVERLAY (overlay), XINT (beg), XINT (end)); + set_overlay_region (XOVERLAY (overlay), XFIXNUM (beg), XFIXNUM (end)); n_beg = OVERLAY_START (overlay); n_end = OVERLAY_END (overlay); /* If the overlay has changed buffers, do a thorough redisplay. */ - if (!EQ (buffer, obuffer)) + if (!BASE_EQ (buffer, obuffer)) { /* Redisplay where the overlay was. */ if (ob) @@ -3494,7 +3593,15 @@ buffer. */) /* Delete the overlay if it is empty after clipping and has the evaporate property. */ if (n_beg == n_end && !NILP (Foverlay_get (overlay, Qevaporate))) - return unbind_to (count, Fdelete_overlay (overlay)); + { /* We used to call `Fdelete_overlay' here, but it causes problems: + - At this stage, `overlay' is not included in its buffer's lists + of overlays (the data-structure is in an inconsistent state), + contrary to `Fdelete_overlay's assumptions. + - Most of the work done by Fdelete_overlay has already been done + here for other reasons. */ + drop_overlay (XOVERLAY (overlay)); + return unbind_to (count, overlay); + } return unbind_to (count, overlay); } @@ -3504,7 +3611,7 @@ DEFUN ("delete-overlay", Fdelete_overlay, Sdelete_overlay, 1, 1, 0, (Lisp_Object overlay) { struct buffer *b; - ptrdiff_t count = SPECPDL_INDEX (); + specpdl_ref count = SPECPDL_INDEX (); CHECK_OVERLAY (overlay); @@ -3548,7 +3655,7 @@ DEFUN ("overlay-start", Foverlay_start, Soverlay_start, 1, 1, 0, if (! OVERLAY_BUFFER (overlay)) return Qnil; - return make_number (OVERLAY_START (overlay)); + return make_fixnum (OVERLAY_START (overlay)); } DEFUN ("overlay-end", Foverlay_end, Soverlay_end, 1, 1, 0, @@ -3559,7 +3666,7 @@ DEFUN ("overlay-end", Foverlay_end, Soverlay_end, 1, 1, 0, if (! OVERLAY_BUFFER (overlay)) return Qnil; - return make_number (OVERLAY_END (overlay)); + return make_fixnum (OVERLAY_END (overlay)); } DEFUN ("overlay-buffer", Foverlay_buffer, Soverlay_buffer, 1, 1, 0, @@ -3593,14 +3700,18 @@ OVERLAY. */) DEFUN ("overlays-at", Foverlays_at, Soverlays_at, 1, 2, 0, doc: /* Return a list of the overlays that contain the character at POS. -If SORTED is non-nil, then sort them by decreasing priority. */) +If SORTED is non-nil, then sort them by decreasing priority. + +Zero-length overlays that start and stop at POS are not included in +the return value. Instead use `overlays-in' if those overlays are of +interest. */) (Lisp_Object pos, Lisp_Object sorted) { ptrdiff_t len, noverlays; Lisp_Object *overlay_vec; Lisp_Object result; - CHECK_NUMBER_COERCE_MARKER (pos); + CHECK_FIXNUM_COERCE_MARKER (pos); if (!buffer_has_overlays ()) return Qnil; @@ -3611,7 +3722,7 @@ If SORTED is non-nil, then sort them by decreasing priority. */) /* Put all the overlays we want in a vector in overlay_vec. Store the length in len. */ - noverlays = overlays_at (XINT (pos), 1, &overlay_vec, &len, NULL); + noverlays = overlays_at (XFIXNUM (pos), true, &overlay_vec, &len, NULL); if (!NILP (sorted)) noverlays = sort_overlays (overlay_vec, noverlays, @@ -3634,17 +3745,18 @@ DEFUN ("overlays-in", Foverlays_in, Soverlays_in, 2, 2, 0, doc: /* Return a list of the overlays that overlap the region BEG ... END. Overlap means that at least one character is contained within the overlay and also contained within the specified region. + Empty overlays are included in the result if they are located at BEG, between BEG and END, or at END provided END denotes the position at the -end of the buffer. */) +end of the accessible part of the buffer. */) (Lisp_Object beg, Lisp_Object end) { ptrdiff_t len, noverlays; Lisp_Object *overlay_vec; Lisp_Object result; - CHECK_NUMBER_COERCE_MARKER (beg); - CHECK_NUMBER_COERCE_MARKER (end); + CHECK_FIXNUM_COERCE_MARKER (beg); + CHECK_FIXNUM_COERCE_MARKER (end); if (!buffer_has_overlays ()) return Qnil; @@ -3654,7 +3766,8 @@ end of the buffer. */) /* Put all the overlays we want in a vector in overlay_vec. Store the length in len. */ - noverlays = overlays_in (XINT (beg), XINT (end), 1, &overlay_vec, &len, true, NULL); + noverlays = overlays_in (XFIXNUM (beg), XFIXNUM (end), 1, &overlay_vec, &len, + true, NULL); /* Make a list of them all. */ result = Flist (noverlays, overlay_vec); @@ -3670,12 +3783,12 @@ If there are no overlay boundaries from POS to (point-max), the value is (point-max). */) (Lisp_Object pos) { - CHECK_NUMBER_COERCE_MARKER (pos); + CHECK_FIXNUM_COERCE_MARKER (pos); if (!buffer_has_overlays ()) - return make_number (ZV); + return make_fixnum (ZV); - return make_number (next_overlay_change (XINT (pos))); + return make_fixnum (next_overlay_change (XFIXNUM (pos))); } DEFUN ("previous-overlay-change", Fprevious_overlay_change, @@ -3686,12 +3799,12 @@ the value is (point-min). */) (Lisp_Object pos) { - CHECK_NUMBER_COERCE_MARKER (pos); + CHECK_FIXNUM_COERCE_MARKER (pos); if (!buffer_has_overlays ()) - return make_number (BEGV); + return make_fixnum (BEGV); - return make_number (previous_overlay_change (XINT (pos))); + return make_fixnum (previous_overlay_change (XFIXNUM (pos))); } @@ -3723,7 +3836,7 @@ That makes overlay lookup faster for positions near POS (but perhaps slower for positions far away from POS). */) (Lisp_Object pos) { - CHECK_NUMBER_COERCE_MARKER (pos); + CHECK_FIXNUM_COERCE_MARKER (pos); /* Noop */ return Qnil; } @@ -3829,7 +3942,7 @@ report_overlay_modification (Lisp_Object start, Lisp_Object end, bool after, Lisp_Object arg1, Lisp_Object arg2, Lisp_Object arg3) { /* True if this change is an insertion. */ - bool insertion = (after ? XFASTINT (arg3) == 0 : EQ (start, end)); + bool insertion = (after ? XFIXNAT (arg3) == 0 : EQ (start, end)); /* We used to run the functions as soon as we found them and only register them in last_overlay_modification_hooks for the purpose of the `after' @@ -3842,8 +3955,8 @@ report_overlay_modification (Lisp_Object start, Lisp_Object end, bool after, if (!after) { struct interval_node *node; - EMACS_INT begin_arg = XFASTINT (start); - EMACS_INT end_arg = XFASTINT (end); + EMACS_INT begin_arg = XFIXNUM (start); + EMACS_INT end_arg = XFIXNUM (end); /* We are being called before a change. Scan the overlays to find the functions to call. */ last_overlay_modification_hooks_used = 0; @@ -3859,19 +3972,18 @@ report_overlay_modification (Lisp_Object start, Lisp_Object end, bool after, Lisp_Object overlay = node->data; ptrdiff_t obegin = OVERLAY_START (overlay); ptrdiff_t oend = OVERLAY_END (overlay); - Lisp_Object prop; if (insertion && (begin_arg == obegin || end_arg == obegin)) { - prop = Foverlay_get (overlay, Qinsert_in_front_hooks); + Lisp_Object prop = Foverlay_get (overlay, Qinsert_in_front_hooks); if (!NILP (prop)) add_overlay_mod_hooklist (prop, overlay); } if (insertion && (begin_arg == oend || end_arg == oend)) { - prop = Foverlay_get (overlay, Qinsert_behind_hooks); + Lisp_Object prop = Foverlay_get (overlay, Qinsert_behind_hooks); if (!NILP (prop)) add_overlay_mod_hooklist (prop, overlay); } @@ -3879,7 +3991,7 @@ report_overlay_modification (Lisp_Object start, Lisp_Object end, bool after, for both insertion and deletion. */ if (! insertion || (end_arg > obegin && begin_arg < oend)) { - prop = Foverlay_get (overlay, Qmodification_hooks); + Lisp_Object prop = Foverlay_get (overlay, Qmodification_hooks); if (!NILP (prop)) add_overlay_mod_hooklist (prop, overlay); } @@ -3894,23 +4006,6 @@ report_overlay_modification (Lisp_Object start, Lisp_Object end, bool after, Lisp_Object *copy; ptrdiff_t i; - if (size) - { - Lisp_Object ovl - = XVECTOR (last_overlay_modification_hooks)->contents[1]; - - /* If the buffer of the first overlay in the array doesn't - match the current buffer, then these modification hooks - should not be run in this buffer. This could happen when - some code calls some insdel functions, such as del_range_1, - with the PREPARE argument false -- in that case this - function is never called to record the overlay modification - hook functions in the last_overlay_modification_hooks - array, so anything we find there is not ours. */ - if (OVERLAY_BUFFER (ovl) != current_buffer) - return; - } - USE_SAFE_ALLOCA; SAFE_ALLOCA_LISP (copy, size); memcpy (copy, XVECTOR (last_overlay_modification_hooks)->contents, @@ -3921,7 +4016,12 @@ report_overlay_modification (Lisp_Object start, Lisp_Object end, bool after, Lisp_Object prop_i, overlay_i; prop_i = copy[i++]; overlay_i = copy[i++]; - call_overlay_mod_hooks (prop_i, overlay_i, after, arg1, arg2, arg3); + /* It is possible that the recorded overlay has been deleted + (which makes its markers' buffers be nil), or that (due to + some bug) it belongs to a different buffer. Only run this + hook if the overlay belongs to the current buffer. */ + if (OVERLAY_BUFFER (overlay_i) == current_buffer) + call_overlay_mod_hooks (prop_i, overlay_i, after, arg1, arg2, arg3); } SAFE_FREE (); @@ -4086,7 +4186,7 @@ mmap_init (void) if (mmap_fd <= 0) { /* No anonymous mmap -- we need the file descriptor. */ - mmap_fd = emacs_open ("/dev/zero", O_RDONLY, 0); + mmap_fd = emacs_open_noquit ("/dev/zero", O_RDONLY, 0); if (mmap_fd == -1) fatal ("Cannot open /dev/zero: %s", emacs_strerror (errno)); } @@ -4358,24 +4458,38 @@ alloc_buffer_text (struct buffer *b, ptrdiff_t nbytes) void enlarge_buffer_text (struct buffer *b, ptrdiff_t delta) { - void *p; - ptrdiff_t nbytes = (BUF_Z_BYTE (b) - BUF_BEG_BYTE (b) + BUF_GAP_SIZE (b) + 1 - + delta); block_input (); + void *p; + unsigned char *old_beg = b->text->beg; + ptrdiff_t old_nbytes = + BUF_Z_BYTE (b) - BUF_BEG_BYTE (b) + BUF_GAP_SIZE (b) + 1; + ptrdiff_t new_nbytes = old_nbytes + delta; + + if (pdumper_object_p (old_beg)) + b->text->beg = NULL; + else + old_beg = NULL; + #if defined USE_MMAP_FOR_BUFFERS - p = mmap_realloc ((void **) &b->text->beg, nbytes); + p = mmap_realloc ((void **) &b->text->beg, new_nbytes); #elif defined REL_ALLOC - p = r_re_alloc ((void **) &b->text->beg, nbytes); + p = r_re_alloc ((void **) &b->text->beg, new_nbytes); #else - p = xrealloc (b->text->beg, nbytes); + p = xrealloc (b->text->beg, new_nbytes); #endif + __lsan_ignore_object (p); if (p == NULL) { + if (old_beg) + b->text->beg = old_beg; unblock_input (); - memory_full (nbytes); + memory_full (new_nbytes); } + if (old_beg) + memcpy (p, old_beg, min (old_nbytes, new_nbytes)); + BUF_BEG_ADDR (b) = p; unblock_input (); } @@ -4388,13 +4502,16 @@ free_buffer_text (struct buffer *b) { block_input (); + if (!pdumper_object_p (b->text->beg)) + { #if defined USE_MMAP_FOR_BUFFERS - mmap_free ((void **) &b->text->beg); + mmap_free ((void **) &b->text->beg); #elif defined REL_ALLOC - r_alloc_free ((void **) &b->text->beg); + r_alloc_free ((void **) &b->text->beg); #else - xfree (b->text->beg); + xfree (b->text->beg); #endif + } BUF_BEG_ADDR (b) = NULL; unblock_input (); @@ -4405,51 +4522,64 @@ free_buffer_text (struct buffer *b) /*********************************************************************** Initialization ***********************************************************************/ - void init_buffer_once (void) { + /* TODO: clean up the buffer-local machinery. Right now, + we have: + + buffer_defaults: default values of buffer-locals + buffer_local_flags: metadata + buffer_permanent_local_flags: metadata + buffer_local_symbols: metadata + + There must be a simpler way to store the metadata. + */ + int idx; + /* Items flagged permanent get an explicit permanent-local property + added in bindings.el, for clarity. */ + PDUMPER_REMEMBER_SCALAR (buffer_permanent_local_flags); memset (buffer_permanent_local_flags, 0, sizeof buffer_permanent_local_flags); /* 0 means not a lisp var, -1 means always local, else mask. */ memset (&buffer_local_flags, 0, sizeof buffer_local_flags); - bset_filename (&buffer_local_flags, make_number (-1)); - bset_directory (&buffer_local_flags, make_number (-1)); - bset_backed_up (&buffer_local_flags, make_number (-1)); - bset_save_length (&buffer_local_flags, make_number (-1)); - bset_auto_save_file_name (&buffer_local_flags, make_number (-1)); - bset_read_only (&buffer_local_flags, make_number (-1)); - bset_major_mode (&buffer_local_flags, make_number (-1)); - bset_mode_name (&buffer_local_flags, make_number (-1)); - bset_undo_list (&buffer_local_flags, make_number (-1)); - bset_mark_active (&buffer_local_flags, make_number (-1)); - bset_point_before_scroll (&buffer_local_flags, make_number (-1)); - bset_file_truename (&buffer_local_flags, make_number (-1)); - bset_invisibility_spec (&buffer_local_flags, make_number (-1)); - bset_file_format (&buffer_local_flags, make_number (-1)); - bset_auto_save_file_format (&buffer_local_flags, make_number (-1)); - bset_display_count (&buffer_local_flags, make_number (-1)); - bset_display_time (&buffer_local_flags, make_number (-1)); - bset_enable_multibyte_characters (&buffer_local_flags, make_number (-1)); + bset_filename (&buffer_local_flags, make_fixnum (-1)); + bset_directory (&buffer_local_flags, make_fixnum (-1)); + bset_backed_up (&buffer_local_flags, make_fixnum (-1)); + bset_save_length (&buffer_local_flags, make_fixnum (-1)); + bset_auto_save_file_name (&buffer_local_flags, make_fixnum (-1)); + bset_read_only (&buffer_local_flags, make_fixnum (-1)); + bset_major_mode (&buffer_local_flags, make_fixnum (-1)); + bset_local_minor_modes (&buffer_local_flags, make_fixnum (-1)); + bset_mode_name (&buffer_local_flags, make_fixnum (-1)); + bset_undo_list (&buffer_local_flags, make_fixnum (-1)); + bset_mark_active (&buffer_local_flags, make_fixnum (-1)); + bset_point_before_scroll (&buffer_local_flags, make_fixnum (-1)); + bset_file_truename (&buffer_local_flags, make_fixnum (-1)); + bset_invisibility_spec (&buffer_local_flags, make_fixnum (-1)); + bset_file_format (&buffer_local_flags, make_fixnum (-1)); + bset_auto_save_file_format (&buffer_local_flags, make_fixnum (-1)); + bset_display_count (&buffer_local_flags, make_fixnum (-1)); + bset_display_time (&buffer_local_flags, make_fixnum (-1)); + bset_enable_multibyte_characters (&buffer_local_flags, make_fixnum (-1)); /* These used to be stuck at 0 by default, but now that the all-zero value means Qnil, we have to initialize them explicitly. */ - bset_name (&buffer_local_flags, make_number (0)); - bset_mark (&buffer_local_flags, make_number (0)); - bset_local_var_alist (&buffer_local_flags, make_number (0)); - bset_keymap (&buffer_local_flags, make_number (0)); - bset_downcase_table (&buffer_local_flags, make_number (0)); - bset_upcase_table (&buffer_local_flags, make_number (0)); - bset_case_canon_table (&buffer_local_flags, make_number (0)); - bset_case_eqv_table (&buffer_local_flags, make_number (0)); - bset_minor_modes (&buffer_local_flags, make_number (0)); - bset_width_table (&buffer_local_flags, make_number (0)); - bset_pt_marker (&buffer_local_flags, make_number (0)); - bset_begv_marker (&buffer_local_flags, make_number (0)); - bset_zv_marker (&buffer_local_flags, make_number (0)); - bset_last_selected_window (&buffer_local_flags, make_number (0)); + bset_name (&buffer_local_flags, make_fixnum (0)); + bset_mark (&buffer_local_flags, make_fixnum (0)); + bset_local_var_alist (&buffer_local_flags, make_fixnum (0)); + bset_keymap (&buffer_local_flags, make_fixnum (0)); + bset_downcase_table (&buffer_local_flags, make_fixnum (0)); + bset_upcase_table (&buffer_local_flags, make_fixnum (0)); + bset_case_canon_table (&buffer_local_flags, make_fixnum (0)); + bset_case_eqv_table (&buffer_local_flags, make_fixnum (0)); + bset_width_table (&buffer_local_flags, make_fixnum (0)); + bset_pt_marker (&buffer_local_flags, make_fixnum (0)); + bset_begv_marker (&buffer_local_flags, make_fixnum (0)); + bset_zv_marker (&buffer_local_flags, make_fixnum (0)); + bset_last_selected_window (&buffer_local_flags, make_fixnum (0)); idx = 1; XSETFASTINT (BVAR (&buffer_local_flags, mode_line_format), idx); ++idx; @@ -4460,7 +4590,9 @@ init_buffer_once (void) XSETFASTINT (BVAR (&buffer_local_flags, selective_display), idx); ++idx; XSETFASTINT (BVAR (&buffer_local_flags, selective_display_ellipses), idx); ++idx; XSETFASTINT (BVAR (&buffer_local_flags, tab_width), idx); ++idx; - XSETFASTINT (BVAR (&buffer_local_flags, truncate_lines), idx); ++idx; + XSETFASTINT (BVAR (&buffer_local_flags, truncate_lines), idx); + /* Make this one a permanent local. */ + buffer_permanent_local_flags[idx++] = 1; XSETFASTINT (BVAR (&buffer_local_flags, word_wrap), idx); ++idx; XSETFASTINT (BVAR (&buffer_local_flags, ctl_arrow), idx); ++idx; XSETFASTINT (BVAR (&buffer_local_flags, fill_column), idx); ++idx; @@ -4493,14 +4625,20 @@ init_buffer_once (void) XSETFASTINT (BVAR (&buffer_local_flags, scroll_up_aggressively), idx); ++idx; XSETFASTINT (BVAR (&buffer_local_flags, scroll_down_aggressively), idx); ++idx; XSETFASTINT (BVAR (&buffer_local_flags, header_line_format), idx); ++idx; + XSETFASTINT (BVAR (&buffer_local_flags, tab_line_format), idx); ++idx; XSETFASTINT (BVAR (&buffer_local_flags, cursor_type), idx); ++idx; XSETFASTINT (BVAR (&buffer_local_flags, extra_line_spacing), idx); ++idx; XSETFASTINT (BVAR (&buffer_local_flags, cursor_in_non_selected_windows), idx); ++idx; + /* buffer_local_flags contains no pointers, so it's safe to treat it + as a blob for pdumper. */ + PDUMPER_REMEMBER_SCALAR (buffer_local_flags); + /* Need more room? */ if (idx >= MAX_PER_BUFFER_VARS) emacs_abort (); last_per_buffer_idx = idx; + PDUMPER_REMEMBER_SCALAR (last_per_buffer_idx); /* Make sure all markable slots in buffer_defaults are initialized reasonably, so mark_buffer won't choke. */ @@ -4533,6 +4671,7 @@ init_buffer_once (void) /* real setup is done in bindings.el */ bset_mode_line_format (&buffer_defaults, build_pure_c_string ("%-")); bset_header_line_format (&buffer_defaults, Qnil); + bset_tab_line_format (&buffer_defaults, Qnil); bset_abbrev_mode (&buffer_defaults, Qnil); bset_overwrite_mode (&buffer_defaults, Qnil); bset_case_fold_search (&buffer_defaults, Qt); @@ -4593,7 +4732,7 @@ init_buffer_once (void) Vbuffer_alist = Qnil; current_buffer = 0; - all_buffers = 0; + pdumper_remember_lv_ptr_raw (¤t_buffer, Lisp_Vectorlike); QSFundamental = build_pure_c_string ("Fundamental"); @@ -4608,25 +4747,24 @@ init_buffer_once (void) Fput (Qkill_buffer_hook, Qpermanent_local, Qt); /* Super-magic invisible buffer. */ - Vprin1_to_string_buffer = Fget_buffer_create (build_pure_c_string (" prin1")); + Vprin1_to_string_buffer = + Fget_buffer_create (build_pure_c_string (" prin1"), Qt); Vbuffer_alist = Qnil; - Fset_buffer (Fget_buffer_create (build_pure_c_string ("*scratch*"))); + Fset_buffer (Fget_buffer_create (build_pure_c_string ("*scratch*"), Qnil)); inhibit_modification_hooks = 0; } void -init_buffer (int initialized) +init_buffer (void) { - char *pwd; Lisp_Object temp; - ptrdiff_t len; #ifdef USE_MMAP_FOR_BUFFERS - if (initialized) + if (dumped_with_unexec_p ()) { - struct buffer *b; + Lisp_Object tail, buffer; #ifndef WINDOWSNT /* These must be reset in the dumped Emacs, to avoid stale @@ -4643,39 +4781,33 @@ init_buffer (int initialized) recorded by temacs, that cannot be used by the dumped Emacs. We map new memory for their text here. - Implementation note: the buffers we carry from temacs are: + Implementation notes: the buffers we carry from temacs are: " prin1", "*scratch*", " *Minibuf-0*", "*Messages*", and " *code-conversion-work*". They are created by init_buffer_once and init_window_once (which are not called - in the dumped Emacs), and by the first call to coding.c routines. */ - FOR_EACH_BUFFER (b) + in the dumped Emacs), and by the first call to coding.c + routines. Since FOR_EACH_LIVE_BUFFER only walks the buffers + in Vbuffer_alist, any buffer we carry from temacs that is + not in the alist (a.k.a. "magic invisible buffers") should + be handled here explicitly. */ + FOR_EACH_LIVE_BUFFER (tail, buffer) { + struct buffer *b = XBUFFER (buffer); b->text->beg = NULL; enlarge_buffer_text (b, 0); } + /* The " prin1" buffer is not in Vbuffer_alist. */ + XBUFFER (Vprin1_to_string_buffer)->text->beg = NULL; + enlarge_buffer_text (XBUFFER (Vprin1_to_string_buffer), 0); } - else - { - struct buffer *b; - - /* Only buffers with allocated buffer text should be present at - this point in temacs. */ - FOR_EACH_BUFFER (b) - { - eassert (b->text->beg != NULL); - } - } -#else /* not USE_MMAP_FOR_BUFFERS */ - /* Avoid compiler warnings. */ - (void) initialized; #endif /* USE_MMAP_FOR_BUFFERS */ AUTO_STRING (scratch, "*scratch*"); - Fset_buffer (Fget_buffer_create (scratch)); + Fset_buffer (Fget_buffer_create (scratch, Qnil)); if (NILP (BVAR (&buffer_defaults, enable_multibyte_characters))) Fset_buffer_multibyte (Qnil); - pwd = emacs_get_current_dir_name (); + char const *pwd = emacs_wd; if (!pwd) { @@ -4687,22 +4819,16 @@ init_buffer (int initialized) { /* Maybe this should really use some standard subroutine whose definition is filename syntax dependent. */ - len = strlen (pwd); - if (!(IS_DIRECTORY_SEP (pwd[len - 1]))) - { - /* Grow buffer to add directory separator and '\0'. */ - pwd = realloc (pwd, len + 2); - if (!pwd) - fatal ("get_current_dir_name: %s\n", strerror (errno)); - pwd[len] = DIRECTORY_SEP; - pwd[len + 1] = '\0'; - len++; - } + ptrdiff_t len = strlen (pwd); + bool add_slash = ! IS_DIRECTORY_SEP (pwd[len - 1]); /* At this moment, we still don't know how to decode the directory name. So, we keep the bytes in unibyte form so that file I/O routines correctly get the original bytes. */ - bset_directory (current_buffer, make_unibyte_string (pwd, len)); + Lisp_Object dirname = make_unibyte_string (pwd, len + add_slash); + if (add_slash) + SSET (dirname, len, DIRECTORY_SEP); + bset_directory (current_buffer, dirname); /* Add /: to the front of the name if it would otherwise be treated as magic. */ @@ -4723,8 +4849,6 @@ init_buffer (int initialized) temp = get_minibuffer (0); bset_directory (XBUFFER (temp), BVAR (current_buffer, directory)); - - free (pwd); } /* Similar to defvar_lisp but define a variable whose value is the @@ -4754,9 +4878,9 @@ defvar_per_buffer (struct Lisp_Buffer_Objfwd *bo_fwd, const char *namestring, bo_fwd->type = Lisp_Fwd_Buffer_Obj; bo_fwd->offset = offset; bo_fwd->predicate = predicate; - sym->declared_special = 1; - sym->redirect = SYMBOL_FORWARDED; - SET_SYMBOL_FWD (sym, (union Lisp_Fwd *) bo_fwd); + sym->u.s.declared_special = true; + sym->u.s.redirect = SYMBOL_FORWARDED; + SET_SYMBOL_FWD (sym, bo_fwd); XSETSYMBOL (PER_BUFFER_SYMBOL (offset), sym); if (PER_BUFFER_IDX (offset) == 0) @@ -4813,8 +4937,7 @@ void syms_of_buffer (void) { staticpro (&last_overlay_modification_hooks); - last_overlay_modification_hooks - = Fmake_vector (make_number (10), Qnil); + last_overlay_modification_hooks = make_nil_vector (10); staticpro (&QSFundamental); staticpro (&Vbuffer_alist); @@ -4838,6 +4961,7 @@ syms_of_buffer (void) DEFSYM (Qbefore_change_functions, "before-change-functions"); DEFSYM (Qafter_change_functions, "after-change-functions"); DEFSYM (Qkill_buffer_query_functions, "kill-buffer-query-functions"); + DEFSYM (Qget_scratch_buffer_create, "get-scratch-buffer-create"); DEFSYM (Qvertical_scroll_bar, "vertical-scroll-bar"); Fput (Qvertical_scroll_bar, Qchoice, list4 (Qnil, Qt, Qleft, Qright)); @@ -4852,20 +4976,32 @@ syms_of_buffer (void) Qoverwrite_mode_binary)); Fput (Qprotected_field, Qerror_conditions, - listn (CONSTYPE_PURE, 2, Qprotected_field, Qerror)); + pure_list (Qprotected_field, Qerror)); Fput (Qprotected_field, Qerror_message, build_pure_c_string ("Attempt to modify a protected field")); + DEFSYM (Qclone_indirect_buffer_hook, "clone-indirect-buffer-hook"); + + DEFVAR_PER_BUFFER ("tab-line-format", + &BVAR (current_buffer, tab_line_format), + Qnil, + doc: /* Analogous to `mode-line-format', but controls the tab line. +The tab line appears, optionally, at the top of a window; +the mode line appears at the bottom. */); + DEFVAR_PER_BUFFER ("header-line-format", &BVAR (current_buffer, header_line_format), Qnil, doc: /* Analogous to `mode-line-format', but controls the header line. -The header line appears, optionally, at the top of a window; -the mode line appears at the bottom. */); +The header line appears, optionally, at the top of a window; the mode +line appears at the bottom. + +Also see `header-line-indent-mode' if `display-line-number-mode' is +used. */); DEFVAR_PER_BUFFER ("mode-line-format", &BVAR (current_buffer, mode_line_format), Qnil, - doc: /* Template for displaying mode line for current buffer. + doc: /* Template for displaying mode line for a window's buffer. The value may be nil, a string, a symbol or a list. @@ -4878,6 +5014,9 @@ For any symbol other than t or nil, the symbol's value is processed as `risky-local-variable' property, all properties in any strings, as well as all :eval and :propertize forms in the value, are ignored. +When the value is processed, the window's buffer is temporarily the +current buffer. + A list whose car is a string or list is processed by processing each of the list elements recursively, as separate mode line constructs, and concatenating the results. @@ -4936,6 +5075,12 @@ The default value (normally `fundamental-mode') affects new buffers. A value of nil means to use the current buffer's major mode, provided it is not marked as "special". */); + DEFVAR_PER_BUFFER ("local-minor-modes", + &BVAR (current_buffer, local_minor_modes), + Qnil, + doc: /* Minor modes currently active in the current buffer. +This is a list of symbols, or nil if there are no minor modes active. */); + DEFVAR_PER_BUFFER ("mode-name", &BVAR (current_buffer, mode_name), Qnil, doc: /* Pretty name of current buffer's major mode. @@ -4957,6 +5102,9 @@ Use the command `abbrev-mode' to change this variable. */); DEFVAR_PER_BUFFER ("fill-column", &BVAR (current_buffer, fill_column), Qintegerp, doc: /* Column beyond which automatic line-wrapping should happen. +It is used by filling commands, such as `fill-region' and `fill-paragraph', +and by `auto-fill-mode', which see. +See also `current-fill-column'. Interactively, you can set the buffer local value using \\[set-fill-column]. */); DEFVAR_PER_BUFFER ("left-margin", &BVAR (current_buffer, left_margin), @@ -4967,15 +5115,18 @@ Linefeed indents to this column in Fundamental mode. */); DEFVAR_PER_BUFFER ("tab-width", &BVAR (current_buffer, tab_width), Qintegerp, doc: /* Distance between tab stops (for display of tab characters), in columns. -NOTE: This controls the display width of a TAB character, and not -the size of an indentation step. -This should be an integer greater than zero. */); +This controls the width of a TAB character on display. +The value should be a positive integer. +Note that this variable doesn't necessarily affect the size of the +indentation step. However, if the major mode's indentation facility +inserts one or more TAB characters, this variable will affect the +indentation step as well, even if `indent-tabs-mode' is non-nil. */); DEFVAR_PER_BUFFER ("ctl-arrow", &BVAR (current_buffer, ctl_arrow), Qnil, - doc: /* Non-nil means display control chars with uparrow. -A value of nil means use backslash and octal digits. -This variable does not apply to characters whose display is specified -in the current display table (if there is one). */); + doc: /* Non-nil means display control chars with uparrow `^'. +A value of nil means use backslash `\\' and octal digits. +This variable does not apply to characters whose display is specified in +the current display table (if there is one; see `standard-display-table'). */); DEFVAR_PER_BUFFER ("enable-multibyte-characters", &BVAR (current_buffer, enable_multibyte_characters), @@ -4986,6 +5137,8 @@ file I/O and the behavior of various editing commands. This variable is buffer-local but you cannot set it directly; use the function `set-buffer-multibyte' to change a buffer's representation. +To prevent any attempts to set it or make it buffer-local, Emacs will +signal an error in those cases. See also Info node `(elisp)Text Representations'. */); make_symbol_constant (intern_c_string ("enable-multibyte-characters")); @@ -5009,7 +5162,11 @@ This variable is never applied to a way of decoding a file while reading it. */ DEFVAR_PER_BUFFER ("bidi-display-reordering", &BVAR (current_buffer, bidi_display_reordering), Qnil, - doc: /* Non-nil means reorder bidirectional text for display in the visual order. */); + doc: /* Non-nil means reorder bidirectional text for display in the visual order. +Setting this to nil is intended for use in debugging the display code. +Don't set to nil in normal sessions, as that is not supported. +See also `bidi-paragraph-direction'; setting that non-nil might +speed up redisplay. */); DEFVAR_PER_BUFFER ("bidi-paragraph-start-re", &BVAR (current_buffer, bidi_paragraph_start_re), Qnil, @@ -5074,7 +5231,10 @@ Note that this is overridden by the variable `truncate-partial-width-windows' if that variable is non-nil and this buffer is not full-frame width. -Minibuffers set this variable to nil. */); +Minibuffers set this variable to nil. + +Don't set this to a non-nil value when `visual-line-mode' is +turned on, as it could produce confusing results. */); DEFVAR_PER_BUFFER ("word-wrap", &BVAR (current_buffer, word_wrap), Qnil, doc: /* Non-nil means to use word-wrapping for continuation lines. @@ -5089,7 +5249,7 @@ word-wrapping, you might want to reduce the value of in narrower windows. Instead of setting this variable directly, most users should use -Visual Line mode . Visual Line mode, when enabled, sets `word-wrap' +Visual Line mode. Visual Line mode, when enabled, sets `word-wrap' to t, and additionally redefines simple editing commands to act on visual lines rather than logical lines. See the documentation of `visual-line-mode'. */); @@ -5097,8 +5257,8 @@ visual lines rather than logical lines. See the documentation of DEFVAR_PER_BUFFER ("default-directory", &BVAR (current_buffer, directory), Qstringp, doc: /* Name of default directory of current buffer. -It should be a directory name (as opposed to a directory file-name). -On GNU and Unix systems, directory names end in a slash `/'. +It should be an absolute directory name; on GNU and Unix systems, +these names start with `/' or `~' and end with `/'. To interactively change the default directory, use command `cd'. */); DEFVAR_PER_BUFFER ("auto-fill-function", &BVAR (current_buffer, auto_fill_function), @@ -5282,15 +5442,16 @@ specifies. */); DEFVAR_PER_BUFFER ("indicate-empty-lines", &BVAR (current_buffer, indicate_empty_lines), Qnil, - doc: /* Visually indicate empty lines after the buffer end. -If non-nil, a bitmap is displayed in the left fringe of a window on -window-systems. */); + doc: /* Visually indicate unused ("empty") screen lines after the buffer end. +If non-nil, a bitmap is displayed in the left fringe of a window +on graphical displays for each screen line that doesn't correspond +to any buffer text. */); DEFVAR_PER_BUFFER ("indicate-buffer-boundaries", &BVAR (current_buffer, indicate_buffer_boundaries), Qnil, doc: /* Visually indicate buffer boundaries and scrolling. If non-nil, the first and last line of the buffer are marked in the fringe -of a window on window-systems with angle bitmaps, or if the window can be +of a window on graphical displays with angle bitmaps, or if the window can be scrolled, the top and bottom line of the window are marked with up and down arrow bitmaps. @@ -5421,13 +5582,13 @@ An entry (TEXT . POSITION) represents the deletion of the string TEXT from (abs POSITION). If POSITION is positive, point was at the front of the text being deleted; if negative, point was at the end. -An entry (t HIGH LOW USEC PSEC) indicates that the buffer was previously -unmodified; (HIGH LOW USEC PSEC) is in the same style as (current-time) -and is the visited file's modification time, as of that time. If the -modification time of the most recent save is different, this entry is -obsolete. +An entry (t . TIMESTAMP), where TIMESTAMP is in the style of +`current-time', indicates that the buffer was previously unmodified; +TIMESTAMP is the visited file's modification time, as of that time. +If the modification time of the most recent save is different, this +entry is obsolete. -An entry (t . 0) means means the buffer was previously unmodified but +An entry (t . 0) means the buffer was previously unmodified but its time stamp was unknown because it was not associated with a file. An entry (t . -1) is similar, except that it means the buffer's visited file did not exist. @@ -5560,10 +5721,10 @@ Lisp programs may give this variable certain special values: DEFVAR_LISP ("inhibit-read-only", Vinhibit_read_only, doc: /* Non-nil means disregard read-only status of buffers or characters. -If the value is t, disregard `buffer-read-only' and all `read-only' -text properties. If the value is a list, disregard `buffer-read-only' -and disregard a `read-only' text property if the property value -is a member of the list. */); +A non-nil value that is a list means disregard `buffer-read-only' status, +and disregard a `read-only' text property if the property value is a +member of the list. Any other non-nil value means disregard `buffer-read-only' +and all `read-only' text properties. */); Vinhibit_read_only = Qnil; DEFVAR_PER_BUFFER ("cursor-type", &BVAR (current_buffer, cursor_type), Qnil, @@ -5573,6 +5734,9 @@ Values are interpreted as follows: t use the cursor specified for the frame nil don't display a cursor box display a filled box cursor + (box . SIZE) display a filled box cursor, but make it + hollow if cursor is under masked image larger than + SIZE pixels in either dimension. hollow display a hollow box cursor bar display a vertical bar cursor with default width (bar . WIDTH) display a vertical bar cursor with width WIDTH @@ -5606,9 +5770,14 @@ Use Custom to set this variable and update the display. */); DEFVAR_LISP ("kill-buffer-query-functions", Vkill_buffer_query_functions, doc: /* List of functions called with no args to query before killing a buffer. The buffer being killed will be current while the functions are running. +See `kill-buffer'. If any of them returns nil, the buffer is not killed. Functions run by -this hook are supposed to not change the current buffer. */); +this hook are supposed to not change the current buffer. + +This hook is not run for internal or temporary buffers created by +`get-buffer-create' or `generate-new-buffer' with argument +INHIBIT-BUFFER-HOOKS non-nil. */); Vkill_buffer_query_functions = Qnil; DEFVAR_LISP ("change-major-mode-hook", Vchange_major_mode_hook, @@ -5619,12 +5788,67 @@ The function `kill-all-local-variables' runs this before doing anything else. * DEFVAR_LISP ("buffer-list-update-hook", Vbuffer_list_update_hook, doc: /* Hook run when the buffer list changes. -Functions running this hook are, `get-buffer-create', -`make-indirect-buffer', `rename-buffer', `kill-buffer', -`bury-buffer-internal' and `select-window'. */); +Functions (implicitly) running this hook are `get-buffer-create', +`make-indirect-buffer', `rename-buffer', `kill-buffer', `bury-buffer' +and `select-window'. This hook is not run for internal or temporary +buffers created by `get-buffer-create' or `generate-new-buffer' with +argument INHIBIT-BUFFER-HOOKS non-nil. + +Functions run by this hook should avoid calling `select-window' with a +nil NORECORD argument since it may lead to infinite recursion. */); Vbuffer_list_update_hook = Qnil; DEFSYM (Qbuffer_list_update_hook, "buffer-list-update-hook"); + DEFVAR_BOOL ("kill-buffer-delete-auto-save-files", + kill_buffer_delete_auto_save_files, + doc: /* If non-nil, offer to delete any autosave file when killing a buffer. + +If `delete-auto-save-files' is nil, any autosave deletion is inhibited. */); + kill_buffer_delete_auto_save_files = 0; + + DEFVAR_BOOL ("delete-auto-save-files", delete_auto_save_files, + doc: /* Non-nil means delete auto-save file when a buffer is saved. +This is the default. If nil, auto-save file deletion is inhibited. */); + delete_auto_save_files = 1; + + DEFVAR_LISP ("clone-indirect-buffer-hook", Vclone_indirect_buffer_hook, + doc: /* Normal hook to run in the new buffer at the end of `make-indirect-buffer'. + +Since `clone-indirect-buffer' calls `make-indirect-buffer', this hook +will run for `clone-indirect-buffer' calls as well. */); + Vclone_indirect_buffer_hook = Qnil; + + DEFVAR_LISP ("long-line-threshold", Vlong_line_threshold, + doc: /* Line length above which to use redisplay shortcuts. + +The value should be a positive integer or nil. +If the value is an integer, shortcuts in the display code intended +to speed up redisplay for long lines will automatically be enabled +in buffers which contain one or more lines whose length is above +this threshold. +If nil, these display shortcuts will always remain disabled. + +There is no reason to change that value except for debugging purposes. */); + XSETFASTINT (Vlong_line_threshold, 10000); + + DEFVAR_INT ("large-hscroll-threshold", large_hscroll_threshold, + doc: /* Horizontal scroll of truncated lines above which to use redisplay shortcuts. + +The value should be a positive integer. + +Shortcuts in the display code intended to speed up redisplay for long +and truncated lines will automatically be enabled when a line's +horizontal scroll amount is or about to become larger than the value +of this variable. + +This variable has effect only in buffers which contain one or more +lines whose length is above `long-line-threshold', which see. +To disable redisplay shortcuts for long truncated line, set this +variable to `most-positive-fixnum'. + +There is no reason to change that value except for debugging purposes. */); + large_hscroll_threshold = 10000; + defsubr (&Sbuffer_live_p); defsubr (&Sbuffer_list); defsubr (&Sget_buffer); @@ -5641,6 +5865,7 @@ Functions running this hook are, `get-buffer-create', defsubr (&Sforce_mode_line_update); defsubr (&Sset_buffer_modified_p); defsubr (&Sbuffer_modified_tick); + defsubr (&Sinternal__set_buffer_modified_tick); defsubr (&Sbuffer_chars_modified_tick); defsubr (&Srename_buffer); defsubr (&Sother_buffer); @@ -5675,16 +5900,15 @@ Functions running this hook are, `get-buffer-create', defsubr (&Soverlay_put); defsubr (&Srestore_buffer_modified_p); - Fput (intern_c_string ("erase-buffer"), Qdisabled, Qt); + DEFSYM (Qautosaved, "autosaved"); #ifdef ITREE_DEBUG defsubr (&Soverlay_tree); #endif -} -void -keys_of_buffer (void) -{ - initial_define_key (control_x_map, 'b', "switch-to-buffer"); - initial_define_key (control_x_map, 'k', "kill-buffer"); + DEFSYM (Qkill_buffer__possibly_save, "kill-buffer--possibly-save"); + + DEFSYM (Qbuffer_stale_function, "buffer-stale-function"); + + Fput (intern_c_string ("erase-buffer"), Qdisabled, Qt); } |