diff options
| author | Stefan Monnier | 2014-12-11 16:07:23 -0500 |
|---|---|---|
| committer | Stefan Monnier | 2014-12-11 16:07:23 -0500 |
| commit | aeeaf082e69ec088d6bbb140ddf0ce8119580a67 (patch) | |
| tree | 433810d5e49b5a9b7f110bffc7a6659ca43f7c59 /src/fileio.c | |
| parent | c6f03ed03d68e52e8b18011d2c57959532b45fb5 (diff) | |
| download | emacs-aeeaf082e69ec088d6bbb140ddf0ce8119580a67.tar.gz emacs-aeeaf082e69ec088d6bbb140ddf0ce8119580a67.zip | |
Fixes: debbugs:19161
* src/fileio.c: Better preserve window-points during revert.
(Qget_buffer_window_list): New var.
(get_window_points_and_markers, restore_window_points): New functions.
(Finsert_file_contents): Use them to save and restore window-points.
Diffstat (limited to 'src/fileio.c')
| -rw-r--r-- | src/fileio.c | 115 |
1 files changed, 87 insertions, 28 deletions
diff --git a/src/fileio.c b/src/fileio.c index b8dec3a2041..83b4954b745 100644 --- a/src/fileio.c +++ b/src/fileio.c | |||
| @@ -148,6 +148,7 @@ static Lisp_Object Qcopy_directory; | |||
| 148 | static Lisp_Object Qdelete_directory; | 148 | static Lisp_Object Qdelete_directory; |
| 149 | 149 | ||
| 150 | static Lisp_Object Qsubstitute_env_in_file_name; | 150 | static Lisp_Object Qsubstitute_env_in_file_name; |
| 151 | static Lisp_Object Qget_buffer_window_list; | ||
| 151 | 152 | ||
| 152 | Lisp_Object Qfile_error, Qfile_notify_error; | 153 | Lisp_Object Qfile_error, Qfile_notify_error; |
| 153 | static Lisp_Object Qfile_already_exists, Qfile_date_error; | 154 | static Lisp_Object Qfile_already_exists, Qfile_date_error; |
| @@ -197,7 +198,7 @@ check_writable (const char *filename, int amode) | |||
| 197 | bool res = faccessat (AT_FDCWD, filename, amode, AT_EACCESS) == 0; | 198 | bool res = faccessat (AT_FDCWD, filename, amode, AT_EACCESS) == 0; |
| 198 | #ifdef CYGWIN | 199 | #ifdef CYGWIN |
| 199 | /* faccessat may have returned failure because Cygwin couldn't | 200 | /* faccessat may have returned failure because Cygwin couldn't |
| 200 | determine the file's UID or GID; if so, we return success. */ | 201 | determine the file's UID or GID; if so, we return success. */ |
| 201 | if (!res) | 202 | if (!res) |
| 202 | { | 203 | { |
| 203 | int faccessat_errno = errno; | 204 | int faccessat_errno = errno; |
| @@ -3410,6 +3411,56 @@ time_error_value (int errnum) | |||
| 3410 | return make_timespec (0, ns); | 3411 | return make_timespec (0, ns); |
| 3411 | } | 3412 | } |
| 3412 | 3413 | ||
| 3414 | static Lisp_Object | ||
| 3415 | get_window_points_and_markers (void) | ||
| 3416 | { | ||
| 3417 | Lisp_Object pt_marker = Fpoint_marker (); | ||
| 3418 | Lisp_Object windows | ||
| 3419 | = call3 (Qget_buffer_window_list, Fcurrent_buffer (), Qnil, Qt); | ||
| 3420 | Lisp_Object window_markers = windows; | ||
| 3421 | /* Window markers (and point) are handled specially: rather than move to | ||
| 3422 | just before or just after the modified text, we try to keep the | ||
| 3423 | markers at the same distance (bug#19161). | ||
| 3424 | In general, this is wrong, but for window-markers, this should be harmless | ||
| 3425 | and is convenient for the end user when most of the file is unmodified, | ||
| 3426 | except for a few minor details near the beginning and near the end. */ | ||
| 3427 | for (; CONSP (windows); windows = XCDR (windows)) | ||
| 3428 | if (WINDOWP (XCAR (windows))) | ||
| 3429 | { | ||
| 3430 | Lisp_Object window_marker = XWINDOW (XCAR (windows))->pointm; | ||
| 3431 | XSETCAR (windows, | ||
| 3432 | Fcons (window_marker, Fmarker_position (window_marker))); | ||
| 3433 | } | ||
| 3434 | return Fcons (Fcons (pt_marker, Fpoint ()), window_markers); | ||
| 3435 | } | ||
| 3436 | |||
| 3437 | static void | ||
| 3438 | restore_window_points (Lisp_Object window_markers, ptrdiff_t inserted, | ||
| 3439 | ptrdiff_t same_at_start, ptrdiff_t same_at_end) | ||
| 3440 | { | ||
| 3441 | for (; CONSP (window_markers); window_markers = XCDR (window_markers)) | ||
| 3442 | if (CONSP (XCAR (window_markers))) | ||
| 3443 | { | ||
| 3444 | Lisp_Object car = XCAR (window_markers); | ||
| 3445 | Lisp_Object marker = XCAR (car); | ||
| 3446 | Lisp_Object oldpos = XCDR (car); | ||
| 3447 | if (MARKERP (marker) && INTEGERP (oldpos) | ||
| 3448 | && XINT (oldpos) > same_at_start | ||
| 3449 | && XINT (oldpos) < same_at_end) | ||
| 3450 | { | ||
| 3451 | ptrdiff_t oldsize = same_at_end - same_at_start; | ||
| 3452 | ptrdiff_t newsize = inserted; | ||
| 3453 | double growth = newsize / (double)oldsize; | ||
| 3454 | ptrdiff_t newpos | ||
| 3455 | = same_at_start + growth * (XINT (oldpos) - same_at_start); | ||
| 3456 | Fset_marker (marker, make_number (newpos), Qnil); | ||
| 3457 | } | ||
| 3458 | } | ||
| 3459 | } | ||
| 3460 | |||
| 3461 | /* FIXME: insert-file-contents should be split with the top-level moved to | ||
| 3462 | Elisp and only the core kept in C. */ | ||
| 3463 | |||
| 3413 | DEFUN ("insert-file-contents", Finsert_file_contents, Sinsert_file_contents, | 3464 | DEFUN ("insert-file-contents", Finsert_file_contents, Sinsert_file_contents, |
| 3414 | 1, 5, 0, | 3465 | 1, 5, 0, |
| 3415 | doc: /* Insert contents of file FILENAME after point. | 3466 | doc: /* Insert contents of file FILENAME after point. |
| @@ -3454,18 +3505,23 @@ by calling `format-decode', which see. */) | |||
| 3454 | int save_errno = 0; | 3505 | int save_errno = 0; |
| 3455 | char read_buf[READ_BUF_SIZE]; | 3506 | char read_buf[READ_BUF_SIZE]; |
| 3456 | struct coding_system coding; | 3507 | struct coding_system coding; |
| 3457 | bool replace_handled = 0; | 3508 | bool replace_handled = false; |
| 3458 | bool set_coding_system = 0; | 3509 | bool set_coding_system = false; |
| 3459 | Lisp_Object coding_system; | 3510 | Lisp_Object coding_system; |
| 3460 | bool read_quit = 0; | 3511 | bool read_quit = false; |
| 3461 | /* If the undo log only contains the insertion, there's no point | 3512 | /* If the undo log only contains the insertion, there's no point |
| 3462 | keeping it. It's typically when we first fill a file-buffer. */ | 3513 | keeping it. It's typically when we first fill a file-buffer. */ |
| 3463 | bool empty_undo_list_p | 3514 | bool empty_undo_list_p |
| 3464 | = (!NILP (visit) && NILP (BVAR (current_buffer, undo_list)) | 3515 | = (!NILP (visit) && NILP (BVAR (current_buffer, undo_list)) |
| 3465 | && BEG == Z); | 3516 | && BEG == Z); |
| 3466 | Lisp_Object old_Vdeactivate_mark = Vdeactivate_mark; | 3517 | Lisp_Object old_Vdeactivate_mark = Vdeactivate_mark; |
| 3467 | bool we_locked_file = 0; | 3518 | bool we_locked_file = false; |
| 3468 | ptrdiff_t fd_index; | 3519 | ptrdiff_t fd_index; |
| 3520 | Lisp_Object window_markers = Qnil; | ||
| 3521 | /* same_at_start and same_at_end count bytes, because file access counts | ||
| 3522 | bytes and BEG and END count bytes. */ | ||
| 3523 | ptrdiff_t same_at_start = BEGV_BYTE; | ||
| 3524 | ptrdiff_t same_at_end = ZV_BYTE; | ||
| 3469 | 3525 | ||
| 3470 | if (current_buffer->base_buffer && ! NILP (visit)) | 3526 | if (current_buffer->base_buffer && ! NILP (visit)) |
| 3471 | error ("Cannot do file visiting in an indirect buffer"); | 3527 | error ("Cannot do file visiting in an indirect buffer"); |
| @@ -3521,7 +3577,11 @@ by calling `format-decode', which see. */) | |||
| 3521 | 3577 | ||
| 3522 | /* Replacement should preserve point as it preserves markers. */ | 3578 | /* Replacement should preserve point as it preserves markers. */ |
| 3523 | if (!NILP (replace)) | 3579 | if (!NILP (replace)) |
| 3524 | record_unwind_protect (restore_point_unwind, Fpoint_marker ()); | 3580 | { |
| 3581 | window_markers = get_window_points_and_markers (); | ||
| 3582 | record_unwind_protect (restore_point_unwind, | ||
| 3583 | XCAR (XCAR (window_markers))); | ||
| 3584 | } | ||
| 3525 | 3585 | ||
| 3526 | if (fstat (fd, &st) != 0) | 3586 | if (fstat (fd, &st) != 0) |
| 3527 | report_file_error ("Input file status", orig_filename); | 3587 | report_file_error ("Input file status", orig_filename); |
| @@ -3599,14 +3659,14 @@ by calling `format-decode', which see. */) | |||
| 3599 | } | 3659 | } |
| 3600 | 3660 | ||
| 3601 | /* Prevent redisplay optimizations. */ | 3661 | /* Prevent redisplay optimizations. */ |
| 3602 | current_buffer->clip_changed = 1; | 3662 | current_buffer->clip_changed = true; |
| 3603 | 3663 | ||
| 3604 | if (EQ (Vcoding_system_for_read, Qauto_save_coding)) | 3664 | if (EQ (Vcoding_system_for_read, Qauto_save_coding)) |
| 3605 | { | 3665 | { |
| 3606 | coding_system = coding_inherit_eol_type (Qutf_8_emacs, Qunix); | 3666 | coding_system = coding_inherit_eol_type (Qutf_8_emacs, Qunix); |
| 3607 | setup_coding_system (coding_system, &coding); | 3667 | setup_coding_system (coding_system, &coding); |
| 3608 | /* Ensure we set Vlast_coding_system_used. */ | 3668 | /* Ensure we set Vlast_coding_system_used. */ |
| 3609 | set_coding_system = 1; | 3669 | set_coding_system = true; |
| 3610 | } | 3670 | } |
| 3611 | else if (BEG < Z) | 3671 | else if (BEG < Z) |
| 3612 | { | 3672 | { |
| @@ -3712,7 +3772,7 @@ by calling `format-decode', which see. */) | |||
| 3712 | 3772 | ||
| 3713 | setup_coding_system (coding_system, &coding); | 3773 | setup_coding_system (coding_system, &coding); |
| 3714 | /* Ensure we set Vlast_coding_system_used. */ | 3774 | /* Ensure we set Vlast_coding_system_used. */ |
| 3715 | set_coding_system = 1; | 3775 | set_coding_system = true; |
| 3716 | } | 3776 | } |
| 3717 | 3777 | ||
| 3718 | /* If requested, replace the accessible part of the buffer | 3778 | /* If requested, replace the accessible part of the buffer |
| @@ -3734,16 +3794,11 @@ by calling `format-decode', which see. */) | |||
| 3734 | && (NILP (coding_system) | 3794 | && (NILP (coding_system) |
| 3735 | || ! CODING_REQUIRE_DECODING (&coding))) | 3795 | || ! CODING_REQUIRE_DECODING (&coding))) |
| 3736 | { | 3796 | { |
| 3737 | /* same_at_start and same_at_end count bytes, | ||
| 3738 | because file access counts bytes | ||
| 3739 | and BEG and END count bytes. */ | ||
| 3740 | ptrdiff_t same_at_start = BEGV_BYTE; | ||
| 3741 | ptrdiff_t same_at_end = ZV_BYTE; | ||
| 3742 | ptrdiff_t overlap; | 3797 | ptrdiff_t overlap; |
| 3743 | /* There is still a possibility we will find the need to do code | 3798 | /* There is still a possibility we will find the need to do code |
| 3744 | conversion. If that happens, set this variable to | 3799 | conversion. If that happens, set this variable to |
| 3745 | give up on handling REPLACE in the optimized way. */ | 3800 | give up on handling REPLACE in the optimized way. */ |
| 3746 | bool giveup_match_end = 0; | 3801 | bool giveup_match_end = false; |
| 3747 | 3802 | ||
| 3748 | if (beg_offset != 0) | 3803 | if (beg_offset != 0) |
| 3749 | { | 3804 | { |
| @@ -3777,7 +3832,7 @@ by calling `format-decode', which see. */) | |||
| 3777 | /* We found that the file should be decoded somehow. | 3832 | /* We found that the file should be decoded somehow. |
| 3778 | Let's give up here. */ | 3833 | Let's give up here. */ |
| 3779 | { | 3834 | { |
| 3780 | giveup_match_end = 1; | 3835 | giveup_match_end = true; |
| 3781 | break; | 3836 | break; |
| 3782 | } | 3837 | } |
| 3783 | 3838 | ||
| @@ -3790,7 +3845,7 @@ by calling `format-decode', which see. */) | |||
| 3790 | if (bufpos != nread) | 3845 | if (bufpos != nread) |
| 3791 | break; | 3846 | break; |
| 3792 | } | 3847 | } |
| 3793 | immediate_quit = 0; | 3848 | immediate_quit = false; |
| 3794 | /* If the file matches the buffer completely, | 3849 | /* If the file matches the buffer completely, |
| 3795 | there's no need to replace anything. */ | 3850 | there's no need to replace anything. */ |
| 3796 | if (same_at_start - BEGV_BYTE == end_offset - beg_offset) | 3851 | if (same_at_start - BEGV_BYTE == end_offset - beg_offset) |
| @@ -3802,7 +3857,7 @@ by calling `format-decode', which see. */) | |||
| 3802 | del_range_1 (same_at_start, same_at_end, 0, 0); | 3857 | del_range_1 (same_at_start, same_at_end, 0, 0); |
| 3803 | goto handled; | 3858 | goto handled; |
| 3804 | } | 3859 | } |
| 3805 | immediate_quit = 1; | 3860 | immediate_quit = true; |
| 3806 | QUIT; | 3861 | QUIT; |
| 3807 | /* Count how many chars at the end of the file | 3862 | /* Count how many chars at the end of the file |
| 3808 | match the text at the end of the buffer. But, if we have | 3863 | match the text at the end of the buffer. But, if we have |
| @@ -3853,7 +3908,7 @@ by calling `format-decode', which see. */) | |||
| 3853 | && FETCH_BYTE (same_at_end - 1) >= 0200 | 3908 | && FETCH_BYTE (same_at_end - 1) >= 0200 |
| 3854 | && ! NILP (BVAR (current_buffer, enable_multibyte_characters)) | 3909 | && ! NILP (BVAR (current_buffer, enable_multibyte_characters)) |
| 3855 | && (CODING_MAY_REQUIRE_DECODING (&coding))) | 3910 | && (CODING_MAY_REQUIRE_DECODING (&coding))) |
| 3856 | giveup_match_end = 1; | 3911 | giveup_match_end = true; |
| 3857 | break; | 3912 | break; |
| 3858 | } | 3913 | } |
| 3859 | 3914 | ||
| @@ -3906,7 +3961,7 @@ by calling `format-decode', which see. */) | |||
| 3906 | if (XBUFFER (XWINDOW (selected_window)->contents) == current_buffer) | 3961 | if (XBUFFER (XWINDOW (selected_window)->contents) == current_buffer) |
| 3907 | XWINDOW (selected_window)->start_at_line_beg = !NILP (Fbolp ()); | 3962 | XWINDOW (selected_window)->start_at_line_beg = !NILP (Fbolp ()); |
| 3908 | 3963 | ||
| 3909 | replace_handled = 1; | 3964 | replace_handled = true; |
| 3910 | } | 3965 | } |
| 3911 | } | 3966 | } |
| 3912 | 3967 | ||
| @@ -3921,8 +3976,6 @@ by calling `format-decode', which see. */) | |||
| 3921 | in a more optimized way. */ | 3976 | in a more optimized way. */ |
| 3922 | if (!NILP (replace) && ! replace_handled && BEGV < ZV) | 3977 | if (!NILP (replace) && ! replace_handled && BEGV < ZV) |
| 3923 | { | 3978 | { |
| 3924 | ptrdiff_t same_at_start = BEGV_BYTE; | ||
| 3925 | ptrdiff_t same_at_end = ZV_BYTE; | ||
| 3926 | ptrdiff_t same_at_start_charpos; | 3979 | ptrdiff_t same_at_start_charpos; |
| 3927 | ptrdiff_t inserted_chars; | 3980 | ptrdiff_t inserted_chars; |
| 3928 | ptrdiff_t overlap; | 3981 | ptrdiff_t overlap; |
| @@ -3986,7 +4039,7 @@ by calling `format-decode', which see. */) | |||
| 3986 | } | 4039 | } |
| 3987 | 4040 | ||
| 3988 | coding_system = CODING_ID_NAME (coding.id); | 4041 | coding_system = CODING_ID_NAME (coding.id); |
| 3989 | set_coding_system = 1; | 4042 | set_coding_system = true; |
| 3990 | decoded = BUF_BEG_ADDR (XBUFFER (conversion_buffer)); | 4043 | decoded = BUF_BEG_ADDR (XBUFFER (conversion_buffer)); |
| 3991 | inserted = (BUF_Z_BYTE (XBUFFER (conversion_buffer)) | 4044 | inserted = (BUF_Z_BYTE (XBUFFER (conversion_buffer)) |
| 3992 | - BUF_BEG_BYTE (XBUFFER (conversion_buffer))); | 4045 | - BUF_BEG_BYTE (XBUFFER (conversion_buffer))); |
| @@ -4111,7 +4164,7 @@ by calling `format-decode', which see. */) | |||
| 4111 | /* Make binding buffer-file-name to nil effective. */ | 4164 | /* Make binding buffer-file-name to nil effective. */ |
| 4112 | && !NILP (BVAR (current_buffer, filename)) | 4165 | && !NILP (BVAR (current_buffer, filename)) |
| 4113 | && SAVE_MODIFF >= MODIFF) | 4166 | && SAVE_MODIFF >= MODIFF) |
| 4114 | we_locked_file = 1; | 4167 | we_locked_file = true; |
| 4115 | prepare_to_modify_buffer (PT, PT, NULL); | 4168 | prepare_to_modify_buffer (PT, PT, NULL); |
| 4116 | } | 4169 | } |
| 4117 | 4170 | ||
| @@ -4141,7 +4194,7 @@ by calling `format-decode', which see. */) | |||
| 4141 | 4194 | ||
| 4142 | while (how_much < total) | 4195 | while (how_much < total) |
| 4143 | { | 4196 | { |
| 4144 | /* try is reserved in some compilers (Microsoft C) */ | 4197 | /* `try' is reserved in some compilers (Microsoft C). */ |
| 4145 | ptrdiff_t trytry = min (total - how_much, READ_BUF_SIZE); | 4198 | ptrdiff_t trytry = min (total - how_much, READ_BUF_SIZE); |
| 4146 | ptrdiff_t this; | 4199 | ptrdiff_t this; |
| 4147 | 4200 | ||
| @@ -4166,7 +4219,7 @@ by calling `format-decode', which see. */) | |||
| 4166 | 4219 | ||
| 4167 | if (NILP (nbytes)) | 4220 | if (NILP (nbytes)) |
| 4168 | { | 4221 | { |
| 4169 | read_quit = 1; | 4222 | read_quit = true; |
| 4170 | break; | 4223 | break; |
| 4171 | } | 4224 | } |
| 4172 | 4225 | ||
| @@ -4299,7 +4352,7 @@ by calling `format-decode', which see. */) | |||
| 4299 | coding_system = raw_text_coding_system (coding_system); | 4352 | coding_system = raw_text_coding_system (coding_system); |
| 4300 | setup_coding_system (coding_system, &coding); | 4353 | setup_coding_system (coding_system, &coding); |
| 4301 | /* Ensure we set Vlast_coding_system_used. */ | 4354 | /* Ensure we set Vlast_coding_system_used. */ |
| 4302 | set_coding_system = 1; | 4355 | set_coding_system = true; |
| 4303 | } | 4356 | } |
| 4304 | 4357 | ||
| 4305 | if (!NILP (visit)) | 4358 | if (!NILP (visit)) |
| @@ -4310,7 +4363,7 @@ by calling `format-decode', which see. */) | |||
| 4310 | /* Can't do this if part of the buffer might be preserved. */ | 4363 | /* Can't do this if part of the buffer might be preserved. */ |
| 4311 | && NILP (replace)) | 4364 | && NILP (replace)) |
| 4312 | /* Visiting a file with these coding system makes the buffer | 4365 | /* Visiting a file with these coding system makes the buffer |
| 4313 | unibyte. */ | 4366 | unibyte. */ |
| 4314 | bset_enable_multibyte_characters (current_buffer, Qnil); | 4367 | bset_enable_multibyte_characters (current_buffer, Qnil); |
| 4315 | } | 4368 | } |
| 4316 | 4369 | ||
| @@ -4349,6 +4402,11 @@ by calling `format-decode', which see. */) | |||
| 4349 | 4402 | ||
| 4350 | handled: | 4403 | handled: |
| 4351 | 4404 | ||
| 4405 | if (inserted > 0) | ||
| 4406 | restore_window_points (window_markers, inserted, | ||
| 4407 | BYTE_TO_CHAR (same_at_start), | ||
| 4408 | BYTE_TO_CHAR (same_at_end)); | ||
| 4409 | |||
| 4352 | if (!NILP (visit)) | 4410 | if (!NILP (visit)) |
| 4353 | { | 4411 | { |
| 4354 | if (empty_undo_list_p) | 4412 | if (empty_undo_list_p) |
| @@ -6037,6 +6095,7 @@ This includes interactive calls to `delete-file' and | |||
| 6037 | DEFSYM (Qcopy_directory, "copy-directory"); | 6095 | DEFSYM (Qcopy_directory, "copy-directory"); |
| 6038 | DEFSYM (Qdelete_directory, "delete-directory"); | 6096 | DEFSYM (Qdelete_directory, "delete-directory"); |
| 6039 | DEFSYM (Qsubstitute_env_in_file_name, "substitute-env-in-file-name"); | 6097 | DEFSYM (Qsubstitute_env_in_file_name, "substitute-env-in-file-name"); |
| 6098 | DEFSYM (Qget_buffer_window_list, "get-buffer-window-list"); | ||
| 6040 | 6099 | ||
| 6041 | defsubr (&Sfind_file_name_handler); | 6100 | defsubr (&Sfind_file_name_handler); |
| 6042 | defsubr (&Sfile_name_directory); | 6101 | defsubr (&Sfile_name_directory); |