# HG changeset patch # User Martin Rudalics # Date 1186489320 0 # Node ID b9c61edbe743491b422e8ae1e8fcb1a799fd1404 # Parent d004a08e940250b57b53c13f5d0e39a464bda7d2 (Finsert_file_contents): Run format-decode and after_insert_file_functions on entire buffer when REPLACE is non-nil and inhibit modification_hooks and point_motion_hooks. For consistency, run after_insert_file_functions iff something got inserted. Move signal_after_change and update_compositions after code running after_insert_file_functions. Make sure that undo_list doesn't record intermediate steps of the decoding process. diff -r d004a08e9402 -r b9c61edbe743 src/fileio.c --- a/src/fileio.c Tue Aug 07 08:56:08 2007 +0000 +++ b/src/fileio.c Tue Aug 07 12:22:00 2007 +0000 @@ -3690,27 +3690,25 @@ 1, 5, 0, doc: /* Insert contents of file FILENAME after point. Returns list of absolute file name and number of characters inserted. -If second argument VISIT is non-nil, the buffer's visited filename -and last save file modtime are set, and it is marked unmodified. -If visiting and the file does not exist, visiting is completed -before the error is signaled. -The optional third and fourth arguments BEG and END -specify what portion of the file to insert. -These arguments count bytes in the file, not characters in the buffer. -If VISIT is non-nil, BEG and END must be nil. - -If optional fifth argument REPLACE is non-nil, -it means replace the current buffer contents (in the accessible portion) -with the file contents. This is better than simply deleting and inserting -the whole thing because (1) it preserves some marker positions -and (2) it puts less data in the undo list. -When REPLACE is non-nil, the value is the number of characters actually read, -which is often less than the number of characters to be read. - -This does code conversion according to the value of -`coding-system-for-read' or `file-coding-system-alist', -and sets the variable `last-coding-system-used' to the coding system -actually used. */) +If second argument VISIT is non-nil, the buffer's visited filename and +last save file modtime are set, and it is marked unmodified. If +visiting and the file does not exist, visiting is completed before the +error is signaled. + +The optional third and fourth arguments BEG and END specify what portion +of the file to insert. These arguments count bytes in the file, not +characters in the buffer. If VISIT is non-nil, BEG and END must be nil. + +If optional fifth argument REPLACE is non-nil, replace the current +buffer contents (in the accessible portion) with the file contents. +This is better than simply deleting and inserting the whole thing +because (1) it preserves some marker positions and (2) it puts less data +in the undo list. When REPLACE is non-nil, the second return value is +the number of characters that replace previous buffer contents. + +This function does code conversion according to the value of +`coding-system-for-read' or `file-coding-system-alist', and sets the +variable `last-coding-system-used' to the coding system actually used. */) (filename, visit, beg, end, replace) Lisp_Object filename, visit, beg, end, replace; { @@ -3720,8 +3718,8 @@ register int how_much; register int unprocessed; int count = SPECPDL_INDEX (); - struct gcpro gcpro1, gcpro2, gcpro3, gcpro4; - Lisp_Object handler, val, insval, orig_filename; + struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5; + Lisp_Object handler, val, insval, orig_filename, old_undo; Lisp_Object p; int total = 0; int not_regular = 0; @@ -3744,8 +3742,9 @@ val = Qnil; p = Qnil; orig_filename = Qnil; - - GCPRO4 (filename, val, p, orig_filename); + old_undo = Qnil; + + GCPRO5 (filename, val, p, orig_filename, old_undo); CHECK_STRING (filename); filename = Fexpand_file_name (filename, Qnil); @@ -4704,24 +4703,105 @@ /* Decode file format */ if (inserted > 0) { - int empty_undo_list_p = 0; - - /* If we're anyway going to discard undo information, don't - record it in the first place. The buffer's undo list at this - point is either nil or t when visiting a file. */ - if (!NILP (visit)) + /* Don't run point motion or modification hooks when decoding. */ + int count = SPECPDL_INDEX (); + specbind (Qinhibit_point_motion_hooks, Qt); + specbind (Qinhibit_modification_hooks, Qt); + + /* Save old undo list and don't record undo for decoding. */ + old_undo = current_buffer->undo_list; + current_buffer->undo_list = Qt; + + if (NILP (replace)) + { + insval = call3 (Qformat_decode, + Qnil, make_number (inserted), visit); + CHECK_NUMBER (insval); + inserted = XFASTINT (insval); + } + else + { + /* If REPLACE is non-nil and we succeeded in not replacing the + beginning or end of the buffer text with the file's contents, + call format-decode with `point' positioned at the beginning of + the buffer and `inserted' equalling the number of characters + in the buffer. Otherwise, format-decode might fail to + correctly analyze the beginning or end of the buffer. Hence + we temporarily save `point' and `inserted' here and restore + `point' iff format-decode did not insert or delete any text. + Otherwise we leave `point' at point-min. */ + int opoint = PT; + int opoint_byte = PT_BYTE; + int oinserted = ZV - BEGV; + + TEMP_SET_PT_BOTH (BEGV, BEGV_BYTE); + insval = call3 (Qformat_decode, + Qnil, make_number (oinserted), visit); + CHECK_NUMBER (insval); + if (insval = oinserted) + SET_PT_BOTH (opoint, opoint_byte); + inserted = XFASTINT (insval); + } + + /* For consistency with format-decode call these now iff inserted > 0 + (martin 2007-06-28) */ + p = Vafter_insert_file_functions; + while (CONSP (p)) { - empty_undo_list_p = NILP (current_buffer->undo_list); - current_buffer->undo_list = Qt; + if (NILP (replace)) + { + insval = call1 (XCAR (p), make_number (inserted)); + if (!NILP (insval)) + { + CHECK_NUMBER (insval); + inserted = XFASTINT (insval); + } + } + else + { + /* For the rationale of this see the comment on format-decode above. */ + int opoint = PT; + int opoint_byte = PT_BYTE; + int oinserted = ZV - BEGV; + + TEMP_SET_PT_BOTH (BEGV, BEGV_BYTE); + insval = call1 (XCAR (p), make_number (oinserted)); + if (!NILP (insval)) + { + CHECK_NUMBER (insval); + if (insval = oinserted) + SET_PT_BOTH (opoint, opoint_byte); + inserted = XFASTINT (insval); + } + } + + QUIT; + p = XCDR (p); } - insval = call3 (Qformat_decode, - Qnil, make_number (inserted), visit); - CHECK_NUMBER (insval); - inserted = XFASTINT (insval); - - if (!NILP (visit)) - current_buffer->undo_list = empty_undo_list_p ? Qnil : Qt; + if (NILP (visit)) + { + Lisp_Object lbeg, lend; + XSETINT (lbeg, PT); + XSETINT (lend, PT + inserted); + if (CONSP (old_undo)) + { + Lisp_Object tem = XCAR (old_undo); + if (CONSP (tem) && INTEGERP (XCAR (tem)) && + INTEGERP (XCDR (tem)) && (XCAR (tem)) == lbeg) + /* In the non-visiting case record only the final insertion. */ + current_buffer->undo_list = + Fcons (Fcons (lbeg, lend), Fcdr (old_undo)); + } + } + else if (old_undo == Qt) + /* If undo_list was Qt before, keep it that way. */ + current_buffer->undo_list = Qt; + else + /* Otherwise start with an empty undo_list. */ + current_buffer->undo_list = Qnil; + + unbind_to (count, Qnil); } /* Call after-change hooks for the inserted text, aside from the case @@ -4734,19 +4814,6 @@ update_compositions (PT, PT, CHECK_BORDER); } - p = Vafter_insert_file_functions; - while (CONSP (p)) - { - insval = call1 (XCAR (p), make_number (inserted)); - if (!NILP (insval)) - { - CHECK_NUMBER (insval); - inserted = XFASTINT (insval); - } - QUIT; - p = XCDR (p); - } - if (!NILP (visit) && current_buffer->modtime == -1) {