# HG changeset patch # User Richard M. Stallman # Date 789083428 0 # Node ID b5260fe3dfdd90147eb76c4648896f8c9e64d9c6 # Parent 55ce83f36b30a50037ce22eadc9d8c2d862803d8 (Fmake_indirect_buffer): New function. (Fbuffer_base_buffer): New function. (syms_of_buffer): defsubr them. (reset_buffer): Don't alter intervals here. (Fget_buffer_create): Use BUF_MARKERS. Init BUF_INTERVALS here. (Fkill_buffer): Use BUF_MARKERS; but don't touch it in indir buf. Likewise BUF_INTERVALS. (init_buffer_once): Set up .text and BUF_INTERVALS in buffer_local_symbols and buffer_defaults. (Fkill_buffer): Don't free the text in indirect buffer. When killing a base buffer, kill its indirect buffers first. (set_buffer_temp): New function. (reset_buffer_local_variables): Initialize buffer_file_type field. (Fget_buffer_create): Initialize pt_marker, begv/zv_marker. (set_buffer_internal): Use and update these markers. Copy undo_list in and out of the base buffer. (Fget_buffer_create): Init save_modiff field here. (reset_buffer): Not here. (Fbuffer_modified_p): Use BUF_SAVE_MODIFF. (Fset_buffer_modified_p): Use SAVE_MODIFF. (Fkill_buffer, list_buffers_1): Use BUF_SAVE_MODIFF. (Fget_buffer_create): Initialize the size and text fields. diff -r 55ce83f36b30 -r b5260fe3dfdd src/buffer.c --- a/src/buffer.c Mon Jan 02 21:38:22 1995 +0000 +++ b/src/buffer.c Mon Jan 02 21:50:28 1995 +0000 @@ -255,6 +255,12 @@ b = (struct buffer *) xmalloc (sizeof (struct buffer)); + b->size = sizeof (struct buffer) / sizeof (EMACS_INT); + + /* An ordinary buffer uses its own struct buffer_text. */ + b->text = &b->own_text; + b->base_buffer = 0; + BUF_GAP_SIZE (b) = 20; BLOCK_INPUT; BUFFER_ALLOC (BUF_BEG_ADDR (b), BUF_GAP_SIZE (b)); @@ -268,6 +274,8 @@ BUF_ZV (b) = 1; BUF_Z (b) = 1; BUF_MODIFF (b) = 1; + BUF_SAVE_MODIFF (b) = 1; + BUF_INTERVALS (b) = 0; b->newline_cache = 0; b->width_run_cache = 0; @@ -277,8 +285,11 @@ b->next = all_buffers; all_buffers = b; - b->mark = Fmake_marker (); - /*b->number = make_number (++buffer_count);*/ + /* An ordinary buffer normally doesn't need markers + to handle BEGV and ZV. */ + b->pt_marker = Qnil; + b->begv_marker = Qnil; + b->zv_marker = Qnil; name = Fcopy_sequence (name); INITIALIZE_INTERVAL (XSTRING (name), NULL_INTERVAL); @@ -297,11 +308,100 @@ Vbuffer_alist = nconc2 (Vbuffer_alist, Fcons (Fcons (name, buf), Qnil)); b->mark = Fmake_marker (); - b->markers = Qnil; + BUF_MARKERS (b) = Qnil; b->name = name; return buf; } +DEFUN ("make-indirect-buffer", + Fmake_indirect_buffer, Smake_indirect_buffer, 2, 2, + "BMake indirect buffer: \nbIndirect to base buffer: ", + "Create and return an indirect buffer named NAME, with base buffer BASE.\n\ +BASE should be an existing buffer (or buffer name).") + (name, base_buffer) + register Lisp_Object name, base_buffer; +{ + register Lisp_Object buf; + register struct buffer *b; + + buf = Fget_buffer (name); + if (!NILP (buf)) + error ("Buffer name `%s' is in use", XSTRING (name)->data); + + base_buffer = Fget_buffer (base_buffer); + if (NILP (base_buffer)) + error ("No such buffer: `%s'", + XSTRING (XBUFFER (base_buffer)->name)->data); + + if (XSTRING (name)->size == 0) + error ("Empty string for buffer name is not allowed"); + + b = (struct buffer *) xmalloc (sizeof (struct buffer)); + + b->size = sizeof (struct buffer) / sizeof (EMACS_INT); + + if (XBUFFER (base_buffer)->base_buffer) + b->base_buffer = XBUFFER (base_buffer)->base_buffer; + else + b->base_buffer = XBUFFER (base_buffer); + + /* Use the base buffer's text object. */ + b->text = b->base_buffer->text; + + BUF_BEGV (b) = BUF_BEGV (b->base_buffer); + BUF_ZV (b) = BUF_ZV (b->base_buffer); + BUF_PT (b) = BUF_PT (b->base_buffer); + + b->newline_cache = 0; + b->width_run_cache = 0; + b->width_table = Qnil; + + /* Put this on the chain of all buffers including killed ones. */ + b->next = all_buffers; + all_buffers = b; + + name = Fcopy_sequence (name); + INITIALIZE_INTERVAL (XSTRING (name), NULL_INTERVAL); + b->name = name; + + reset_buffer (b); + reset_buffer_local_variables (b); + + /* Put this in the alist of all live buffers. */ + XSETBUFFER (buf, b); + Vbuffer_alist = nconc2 (Vbuffer_alist, Fcons (Fcons (name, buf), Qnil)); + + b->mark = Fmake_marker (); + b->name = name; + + /* Make sure the base buffer has markers for its narrowing. */ + if (NILP (b->base_buffer->pt_marker)) + { + b->base_buffer->pt_marker = Fmake_marker (); + Fset_marker (b->base_buffer->pt_marker, + make_number (BUF_PT (b->base_buffer)), base_buffer); + } + if (NILP (b->base_buffer->begv_marker)) + { + b->base_buffer->begv_marker = Fmake_marker (); + Fset_marker (b->base_buffer->begv_marker, + make_number (BUF_BEGV (b->base_buffer)), base_buffer); + } + if (NILP (b->base_buffer->zv_marker)) + { + b->base_buffer->zv_marker = Fmake_marker (); + Fset_marker (b->base_buffer->zv_marker, + make_number (BUF_ZV (b->base_buffer)), base_buffer); + } + + /* Give the indirect buffer markers for its narrowing. */ + b->pt_marker = Fpoint_marker (); + b->begv_marker = Fpoint_min_marker (); + b->zv_marker = Fpoint_max_marker (); + + return buf; +} + /* Reinitialize everything about a buffer except its name and contents and local variables. */ @@ -312,7 +412,6 @@ b->filename = Qnil; b->directory = (current_buffer) ? current_buffer->directory : Qnil; b->modtime = 0; - b->save_modified = 1; XSETFASTINT (b->save_length, 0); b->last_window_start = 1; b->backed_up = Qnil; @@ -324,9 +423,6 @@ b->overlays_after = Qnil; XSETFASTINT (b->overlay_center, 1); b->mark_active = Qnil; - - /* Only defined if Emacs is compiled with USE_TEXT_PROPERTIES */ - INITIALIZE_INTERVAL (b, NULL_INTERVAL); } /* Reset buffer B's local variables info. @@ -352,6 +448,7 @@ b->upcase_table = Vascii_upcase_table; b->case_canon_table = Vascii_canon_table; b->case_eqv_table = Vascii_eqv_table; + b->buffer_file_type = Qnil; #if 0 b->sort_table = XSTRING (Vascii_sort_table); b->folding_sort_table = XSTRING (Vascii_folding_sort_table); @@ -440,6 +537,30 @@ return XBUFFER (buffer)->filename; } +DEFUN ("buffer-base-buffer", Fbuffer_base_buffer, Sbuffer_base_buffer, + 0, 1, 0, + "Return the base buffer of indirect buffer BUFFER.\n\ +If BUFFER is not indirect, return nil.") + (buffer) + register Lisp_Object buffer; +{ + struct buffer *base; + Lisp_Object base_buffer; + + if (NILP (buffer)) + base = current_buffer->base_buffer; + else + { + CHECK_BUFFER (buffer, 0); + base = XBUFFER (buffer)->base_buffer; + } + + if (! base) + return Qnil; + XSETBUFFER (base_buffer, base); + return base_buffer; +} + DEFUN ("buffer-local-variables", Fbuffer_local_variables, Sbuffer_local_variables, 0, 1, 0, "Return an alist of variables that are buffer-local in BUFFER.\n\ @@ -529,7 +650,7 @@ buf = XBUFFER (buffer); } - return buf->save_modified < BUF_MODIFF (buf) ? Qt : Qnil; + return BUF_SAVE_MODIFF (buf) < BUF_MODIFF (buf) ? Qt : Qnil; } DEFUN ("set-buffer-modified-p", Fset_buffer_modified_p, Sset_buffer_modified_p, @@ -549,7 +670,7 @@ fn = current_buffer->filename; if (!NILP (fn)) { - already = current_buffer->save_modified < MODIFF; + already = SAVE_MODIFF < MODIFF; if (!already && !NILP (flag)) lock_file (fn); else if (already && NILP (flag)) @@ -557,7 +678,7 @@ } #endif /* CLASH_DETECTION */ - current_buffer->save_modified = NILP (flag) ? MODIFF : 0; + SAVE_MODIFF = NILP (flag) ? MODIFF : 0; update_mode_lines++; return flag; } @@ -762,7 +883,7 @@ /* Query if the buffer is still modified. */ if (INTERACTIVE && !NILP (b->filename) - && BUF_MODIFF (b) > b->save_modified) + && BUF_MODIFF (b) > BUF_SAVE_MODIFF (b)) { GCPRO2 (buf, bufname); tem = do_yes_or_no_p (format1 ("Buffer %s modified; kill anyway? ", @@ -807,6 +928,26 @@ if (NILP (b->name)) return Qnil; + /* When we kill a base buffer, kill all its indirect buffers. + We do it at this stage so nothing terrible happens if they + ask questions or their hooks get errors. */ + if (! b->base_buffer) + { + struct buffer *other; + + GCPRO1 (buf); + + for (other = all_buffers; other; other = other->next) + if (other->base_buffer == b) + { + Lisp_Object buf; + XSETBUFFER (buf, other); + Fkill_buffer (buf); + } + + UNGCPRO; + } + /* Make this buffer not be current. In the process, notice if this is the sole visible buffer and give up if so. */ @@ -843,24 +984,32 @@ internal_delete_file (b->auto_save_file_name); } - /* Unchain all markers of this buffer - and leave them pointing nowhere. */ - for (tem = b->markers; !EQ (tem, Qnil); ) + if (! b->base_buffer) { - m = XMARKER (tem); - m->buffer = 0; - tem = m->chain; - m->chain = Qnil; + /* Unchain all markers of this buffer + and leave them pointing nowhere. */ + for (tem = BUF_MARKERS (b); !EQ (tem, Qnil); ) + { + m = XMARKER (tem); + m->buffer = 0; + tem = m->chain; + m->chain = Qnil; + } + BUF_MARKERS (b) = Qnil; + +#ifdef USE_TEXT_PROPERTIES + BUF_INTERVALS (b) = NULL_INTERVAL; +#endif + + /* Perhaps we should explicitly free the interval tree here... */ } - b->markers = Qnil; - - /* Only defined if Emacs is compiled with USE_TEXT_PROPERTIES */ - INITIALIZE_INTERVAL (b, NULL_INTERVAL); - /* Perhaps we should explicitly free the interval tree here... */ b->name = Qnil; + BLOCK_INPUT; - BUFFER_FREE (BUF_BEG_ADDR (b)); + if (! b->base_buffer) + BUFFER_FREE (BUF_BEG_ADDR (b)); + if (b->newline_cache) { free_region_cache (b->newline_cache); @@ -1029,6 +1178,49 @@ current_buffer = b; last_known_column_point = -1; /* invalidate indentation cache */ + if (old_buf) + { + /* Put the undo list back in the base buffer, so that it appears + that an indirect buffer shares the undo list of its base. */ + if (old_buf->base_buffer) + old_buf->base_buffer->undo_list = old_buf->undo_list; + + /* If the old current buffer has markers to record PT, BEGV and ZV + when it is not current, update them now. */ + if (! NILP (old_buf->pt_marker)) + { + Lisp_Object obuf; + XSETBUFFER (obuf, old_buf); + Fset_marker (old_buf->pt_marker, BUF_PT (old_buf), obuf); + } + if (! NILP (old_buf->begv_marker)) + { + Lisp_Object obuf; + XSETBUFFER (obuf, old_buf); + Fset_marker (old_buf->begv_marker, BUF_BEGV (old_buf), obuf); + } + if (! NILP (old_buf->zv_marker)) + { + Lisp_Object obuf; + XSETBUFFER (obuf, old_buf); + Fset_marker (old_buf->zv_marker, BUF_ZV (old_buf), obuf); + } + } + + /* Get the undo list from the base buffer, so that it appears + that an indirect buffer shares the undo list of its base. */ + if (b->base_buffer) + b->undo_list = b->base_buffer->undo_list; + + /* If the new current buffer has markers to record PT, BEGV and ZV + when it is not current, fetch them now. */ + if (! NILP (b->pt_marker)) + BUF_PT (b) = marker_position (b->pt_marker); + if (! NILP (b->begv_marker)) + BUF_BEGV (b) = marker_position (b->begv_marker); + if (! NILP (b->zv_marker)) + BUF_ZV (b) = marker_position (b->zv_marker); + /* Look down buffer's list of local Lisp variables to find and update any that forward into C variables. */ @@ -1060,6 +1252,55 @@ } } +/* Switch to buffer B temporarily for redisplay purposes. + This avoids certain things thatdon't need to be done within redisplay. */ + +void +set_buffer_temp (b) + struct buffer *b; +{ + register struct buffer *old_buf; + + if (current_buffer == b) + return; + + old_buf = current_buffer; + current_buffer = b; + + if (old_buf) + { + /* If the old current buffer has markers to record PT, BEGV and ZV + when it is not current, update them now. */ + if (! NILP (old_buf->pt_marker)) + { + Lisp_Object obuf; + XSETBUFFER (obuf, old_buf); + Fset_marker (old_buf->pt_marker, BUF_PT (old_buf), obuf); + } + if (! NILP (old_buf->begv_marker)) + { + Lisp_Object obuf; + XSETBUFFER (obuf, old_buf); + Fset_marker (old_buf->begv_marker, BUF_BEGV (old_buf), obuf); + } + if (! NILP (old_buf->zv_marker)) + { + Lisp_Object obuf; + XSETBUFFER (obuf, old_buf); + Fset_marker (old_buf->zv_marker, BUF_ZV (old_buf), obuf); + } + } + + /* If the new current buffer has markers to record PT, BEGV and ZV + when it is not current, fetch them now. */ + if (! NILP (b->pt_marker)) + BUF_PT (b) = marker_position (b->pt_marker); + if (! NILP (b->begv_marker)) + BUF_BEGV (b) = marker_position (b->begv_marker); + if (! NILP (b->zv_marker)) + BUF_ZV (b) = marker_position (b->zv_marker); +} + DEFUN ("set-buffer", Fset_buffer, Sset_buffer, 1, 1, 0, "Make the buffer BUFFER current for editing operations.\n\ BUFFER may be a buffer or the name of an existing buffer.\n\ @@ -1207,7 +1448,7 @@ XSETFASTINT (desired_point, PT); write_string (b == old ? "." : " ", -1); /* Identify modified buffers */ - write_string (BUF_MODIFF (b) > b->save_modified ? "*" : " ", -1); + write_string (BUF_MODIFF (b) > BUF_SAVE_MODIFF (b) ? "*" : " ", -1); /* The current buffer is special-cased to be marked read-only. It is actually made read-only by the call to Buffer-menu-mode, below. */ @@ -2540,6 +2781,13 @@ reset_buffer_local_variables (&buffer_defaults); reset_buffer (&buffer_local_symbols); reset_buffer_local_variables (&buffer_local_symbols); + /* Prevent GC from getting confused. */ + buffer_defaults.text = &buffer_defaults.own_text; + buffer_local_symbols.text = &buffer_local_symbols.own_text; +#ifdef USE_TEXT_PROPERTIES + BUF_INTERVALS (&buffer_defaults) = 0; + BUF_INTERVALS (&buffer_local_symbols) = 0; +#endif XSETBUFFER (Vbuffer_defaults, &buffer_defaults); XSETBUFFER (Vbuffer_local_symbols, &buffer_local_symbols); @@ -3124,10 +3372,12 @@ defsubr (&Sget_buffer); defsubr (&Sget_file_buffer); defsubr (&Sget_buffer_create); + defsubr (&Smake_indirect_buffer); defsubr (&Sgenerate_new_buffer_name); defsubr (&Sbuffer_name); /*defsubr (&Sbuffer_number);*/ defsubr (&Sbuffer_file_name); + defsubr (&Sbuffer_base_buffer); defsubr (&Sbuffer_local_variables); defsubr (&Sbuffer_modified_p); defsubr (&Sset_buffer_modified_p);