commit e2913dc880b9843bf69cf885270551bafeb46120 (HEAD, refs/remotes/origin/master) Author: Stefan Monnier Date: Mon Oct 3 09:47:46 2016 -0400 * src/fileio.c (Finsert_file_contents): Fix hook handling (bug#24340) * src/fileio.c (Finsert_file_contents): Run before-change-hooks before deleting the old buffer content. * src/lisp.h (del_range_byte): * src/insdel.c (del_range_byte): Drop the last argument. * src/fns.c (Fbase64_encode_region): Adjust accordingly. diff --git a/src/fileio.c b/src/fileio.c index 5fe0411..8f16d1e 100644 --- a/src/fileio.c +++ b/src/fileio.c @@ -3858,6 +3858,7 @@ by calling `format-decode', which see. */) if (! giveup_match_end) { ptrdiff_t temp; + ptrdiff_t this_count = SPECPDL_INDEX (); /* We win! We can handle REPLACE the optimized way. */ @@ -3887,13 +3888,19 @@ by calling `format-decode', which see. */) beg_offset += same_at_start - BEGV_BYTE; end_offset -= ZV_BYTE - same_at_end; - invalidate_buffer_caches (current_buffer, - BYTE_TO_CHAR (same_at_start), - same_at_end_charpos); - del_range_byte (same_at_start, same_at_end, 0); + /* This binding is to avoid ask-user-about-supersession-threat + being called in insert_from_buffer or del_range_bytes (via + prepare_to_modify_buffer). + AFAICT we could avoid ask-user-about-supersession-threat by setting + current_buffer->modtime earlier, but we could still end up calling + ask-user-about-supersession-threat if the file is modified while + we read it, so we bind buffer-file-name instead. */ + specbind (intern ("buffer-file-name"), Qnil); + del_range_byte (same_at_start, same_at_end); /* Insert from the file at the proper position. */ temp = BYTE_TO_CHAR (same_at_start); SET_PT_BOTH (temp, same_at_start); + unbind_to (this_count, Qnil); /* If display currently starts at beginning of line, keep it that way. */ @@ -3998,10 +4005,9 @@ by calling `format-decode', which see. */) /* Truncate the buffer to the size of the file. */ if (same_at_start != same_at_end) { - invalidate_buffer_caches (current_buffer, - BYTE_TO_CHAR (same_at_start), - BYTE_TO_CHAR (same_at_end)); - del_range_byte (same_at_start, same_at_end, 0); + /* See previous specbind for the reason behind this. */ + specbind (intern ("buffer-file-name"), Qnil); + del_range_byte (same_at_start, same_at_end); } inserted = 0; @@ -4049,12 +4055,11 @@ by calling `format-decode', which see. */) we are taking from the decoded string. */ inserted -= (ZV_BYTE - same_at_end) + (same_at_start - BEGV_BYTE); + /* See previous specbind for the reason behind this. */ + specbind (intern ("buffer-file-name"), Qnil); if (same_at_end != same_at_start) { - invalidate_buffer_caches (current_buffer, - BYTE_TO_CHAR (same_at_start), - same_at_end_charpos); - del_range_byte (same_at_start, same_at_end, 0); + del_range_byte (same_at_start, same_at_end); temp = GPT; eassert (same_at_start == GPT_BYTE); same_at_start = GPT_BYTE; @@ -4075,10 +4080,6 @@ by calling `format-decode', which see. */) same_at_start + inserted - BEGV_BYTE + BUF_BEG_BYTE (XBUFFER (conversion_buffer))) - same_at_start_charpos); - /* This binding is to avoid ask-user-about-supersession-threat - being called in insert_from_buffer (via in - prepare_to_modify_buffer). */ - specbind (intern ("buffer-file-name"), Qnil); insert_from_buffer (XBUFFER (conversion_buffer), same_at_start_charpos, inserted_chars, 0); /* Set `inserted' to the number of inserted characters. */ diff --git a/src/fns.c b/src/fns.c index 4f12dd5..dfc7842 100644 --- a/src/fns.c +++ b/src/fns.c @@ -3193,7 +3193,7 @@ into shorter lines. */) SET_PT_BOTH (XFASTINT (beg), ibeg); insert (encoded, encoded_length); SAFE_FREE (); - del_range_byte (ibeg + encoded_length, iend + encoded_length, 1); + del_range_byte (ibeg + encoded_length, iend + encoded_length); /* If point was outside of the region, restore it exactly; else just move to the beginning of the region. */ diff --git a/src/insdel.c b/src/insdel.c index 5d3884b..ed914ec 100644 --- a/src/insdel.c +++ b/src/insdel.c @@ -1690,7 +1690,7 @@ del_range_1 (ptrdiff_t from, ptrdiff_t to, bool prepare, bool ret_string) /* Like del_range_1 but args are byte positions, not char positions. */ void -del_range_byte (ptrdiff_t from_byte, ptrdiff_t to_byte, bool prepare) +del_range_byte (ptrdiff_t from_byte, ptrdiff_t to_byte) { ptrdiff_t from, to; @@ -1706,23 +1706,22 @@ del_range_byte (ptrdiff_t from_byte, ptrdiff_t to_byte, bool prepare) from = BYTE_TO_CHAR (from_byte); to = BYTE_TO_CHAR (to_byte); - if (prepare) - { - ptrdiff_t old_from = from, old_to = Z - to; - ptrdiff_t range_length = to - from; - prepare_to_modify_buffer (from, to, &from); - to = from + range_length; - - if (old_from != from) - from_byte = CHAR_TO_BYTE (from); - if (to > ZV) - { - to = ZV; - to_byte = ZV_BYTE; - } - else if (old_to == Z - to) - to_byte = CHAR_TO_BYTE (to); - } + { + ptrdiff_t old_from = from, old_to = Z - to; + ptrdiff_t range_length = to - from; + prepare_to_modify_buffer (from, to, &from); + to = from + range_length; + + if (old_from != from) + from_byte = CHAR_TO_BYTE (from); + if (to > ZV) + { + to = ZV; + to_byte = ZV_BYTE; + } + else if (old_to == Z - to) + to_byte = CHAR_TO_BYTE (to); + } del_range_2 (from, from_byte, to, to_byte, 0); signal_after_change (from, to - from, 0); diff --git a/src/lisp.h b/src/lisp.h index 7430898..2e46592 100644 --- a/src/lisp.h +++ b/src/lisp.h @@ -3505,7 +3505,7 @@ extern void insert_from_string_before_markers (Lisp_Object, ptrdiff_t, ptrdiff_t, bool); extern void del_range (ptrdiff_t, ptrdiff_t); extern Lisp_Object del_range_1 (ptrdiff_t, ptrdiff_t, bool, bool); -extern void del_range_byte (ptrdiff_t, ptrdiff_t, bool); +extern void del_range_byte (ptrdiff_t, ptrdiff_t); extern void del_range_both (ptrdiff_t, ptrdiff_t, ptrdiff_t, ptrdiff_t, bool); extern Lisp_Object del_range_2 (ptrdiff_t, ptrdiff_t, ptrdiff_t, ptrdiff_t, bool); commit a7e9d1cce3f935dbe9f242f0bf2dbf34f5919952 Author: Tino Calancha Date: Mon Oct 3 21:16:00 2016 +0900 Ibuffer: 'w' and 'B' default to buffer at current line See discussion in: https://lists.gnu.org/archive/html/emacs-devel/2016-09/msg00384.html * lisp/ibuffer.el (ibuffer--near-buffers): New defun; return buffers near current line. * lisp/ibuf-ext.el (ibuffer-copy-buffername-as-kill): Use it. Add argument ARG; if a non-zero integer, return next ARG buffers. Otherwise return the marked buffers. If there are not marked buffers, return buffer at current line without prompting the user. Use ibuffer-get-marked-buffers instead of ibuffer-map-marked-lines. Append to kill ring when last command was a kill-region. (ibuffer-copy-filename-as-kill): Idem. Simplify the code. Use ibuffer-buffer-file-name instead of buffer-file-name to include buffers in Dired mode. diff --git a/lisp/ibuf-ext.el b/lisp/ibuf-ext.el index f93957e..1918ce8 100644 --- a/lisp/ibuf-ext.el +++ b/lisp/ibuf-ext.el @@ -1420,7 +1420,7 @@ This requires the external program \"diff\" to be in your `exec-path'." ;;;###autoload (defun ibuffer-copy-filename-as-kill (&optional arg) - "Copy filenames of marked buffers into the kill ring. + "Copy filenames of marked (or next ARG) buffers into the kill ring. The names are separated by a space. If a buffer has no filename, it is ignored. @@ -1431,55 +1431,51 @@ With \\[universal-argument], use the filename of each marked file relative to `ibuffer-default-directory' if non-nil, otherwise `default-directory'. You can then feed the file name(s) to other commands with \\[yank]." - (interactive "p") - (if (zerop (ibuffer-count-marked-lines)) - (message "No buffers marked; use 'm' to mark a buffer") - (let ((result "") - (type (cond ((or (null arg) (zerop arg)) - 'full) - ((= arg 4) - 'relative) - (t - 'name)))) - (ibuffer-map-marked-lines - #'(lambda (buf _mark) - (setq result - (concat result - (let ((name (buffer-file-name buf))) - (cond (name - (concat - (pcase type - (`full - name) - (`relative - (file-relative-name - name (or ibuffer-default-directory - default-directory))) - (_ - (file-name-nondirectory name))) " ")) - (t ""))))))) - (when (not (zerop (length result))) - (setq result - (substring result 0 -1))) - (kill-new result) - (message "%s" result)))) + (interactive "P") + (let* ((buffers (cond ((and (integerp arg) (not (zerop arg))) + (ibuffer--near-buffers arg)) + (t + (or (ibuffer-get-marked-buffers) + (list (ibuffer-current-buffer)))))) + (file-names + (mapcar + (lambda (buf) + (let ((name (with-current-buffer buf + (ibuffer-buffer-file-name)))) + (if (null name) + "" + (cond ((and (integerp arg) (zerop arg)) name) + ((consp arg) + (file-relative-name + name (or ibuffer-default-directory + default-directory))) + (t (file-name-nondirectory name)))))) + buffers)) + (string + (mapconcat 'identity (delete "" file-names) " "))) + (unless (string= string "") + (if (eq last-command 'kill-region) + (kill-append string nil) + (kill-new string)) + (message "%s" string)))) ;;;###autoload -(defun ibuffer-copy-buffername-as-kill () - "Copy buffer names of marked buffers into the kill ring. +(defun ibuffer-copy-buffername-as-kill (&optional arg) + "Copy buffer names of marked (or next ARG) buffers into the kill ring. The names are separated by a space. You can then feed the file name(s) to other commands with \\[yank]." - (interactive) - (if (zerop (ibuffer-count-marked-lines)) - (message "No buffers marked; use 'm' to mark a buffer") - (let ((res "")) - (ibuffer-map-marked-lines - #'(lambda (buf _mark) - (setq res (concat res (buffer-name buf) " ")))) - (when (not (zerop (length res))) - (setq res (substring res 0 -1))) - (kill-new res) - (message res)))) + (interactive "P") + (let* ((buffers (cond ((and (integerp arg) (not (zerop arg))) + (ibuffer--near-buffers arg)) + (t + (or (ibuffer-get-marked-buffers) + (list (ibuffer-current-buffer)))))) + (string (mapconcat #'buffer-name buffers " "))) + (unless (string= string "") + (if (eq last-command 'kill-region) + (kill-append string nil) + (kill-new string)) + (message "%s" string)))) (defun ibuffer-mark-on-buffer (func &optional ibuffer-mark-on-buffer-mark group) (let ((count diff --git a/lisp/ibuffer.el b/lisp/ibuffer.el index e965535..9becfc9 100644 --- a/lisp/ibuffer.el +++ b/lisp/ibuffer.el @@ -2022,6 +2022,16 @@ the buffer object itself and the current mark symbol." (ibuffer-forward-line 0) (ibuffer-forward-line (1- target-line-offset)))))) +;; Return buffers around current line. +(defun ibuffer--near-buffers (n) + (delq nil + (mapcar + (lambda (x) + (car (get-text-property + (line-beginning-position (if (natnump n) x (- (1- x)))) + 'ibuffer-properties))) + (number-sequence 1 (abs n))))) + (defun ibuffer-get-marked-buffers () "Return a list of buffer objects currently marked." (delq nil commit 3b6eb9489d03e5ecc60e487e8eb340e34942825c Author: Tino Calancha Date: Mon Oct 3 20:02:54 2016 +0900 dired-mark-extension: Unmark if called with C-u prefix See discussion in #Bug2518 and: https://lists.gnu.org/archive/html/emacs-devel/2016-09/msg00711.html * lisp/dired-x.el (dired-mark-extension): Update interactive calls: a prefix arg C-u unmark files; a prefix C-u C-u prompt for MARKER-CHAR and mark files with it. (dired-mark-sexp): Show in the prompt that we are unmarking if called with a prefix argument. * doc/misc/dired-x.texi (Advanced Mark Commands): Update documentation for 'dired-mark-extension'. diff --git a/doc/misc/dired-x.texi b/doc/misc/dired-x.texi index 2391852..db01896 100644 --- a/doc/misc/dired-x.texi +++ b/doc/misc/dired-x.texi @@ -710,8 +710,10 @@ variable @code{window-min-height}. @findex dired-mark-extension Mark all files with a certain extension for use in later commands. A @samp{.} is not automatically prepended to the string entered, you must type it -explicitly. If invoked with a prefix argument, this command asks for -a character to use as the marker. +explicitly. +If invoked with prefix argument @kbd{C-u}, this command unmark files instead. +If called with the @kbd{C-u C-u} prefix, asks for a character to use +as the marker, and marks files with it. When called from Lisp, @var{extension} may also be a list of extensions and an optional argument @var{marker-char} specifies the marker used. diff --git a/lisp/dired-x.el b/lisp/dired-x.el index 7d73c42..8313905 100644 --- a/lisp/dired-x.el +++ b/lisp/dired-x.el @@ -334,17 +334,27 @@ See also the functions: A `.' is *not* automatically prepended to the string entered. EXTENSION may also be a list of extensions instead of a single one. Optional MARKER-CHAR is marker to use. -Interactively, ask for EXTENSION, and if invoked with a prefix -argument, for MARKER-CHAR as well." +Interactively, ask for EXTENSION. +Prefixed with one C-u, unmark files instead. +Prefixed with two C-u's, prompt for MARKER-CHAR and mark files with it." (interactive - (list (read-string "Marking extension: ") - (and current-prefix-arg - (let* ((dflt (char-to-string dired-marker-char)) - (input (read-string - (format - "Marker character to use (default %s): " dflt) - nil nil dflt))) - (aref input 0))))) + (let ((suffix + (read-string (format "%s extension: " + (if (equal current-prefix-arg '(4)) + "UNmarking" + "Marking")))) + (marker + (pcase current-prefix-arg + ('(4) ?\s) + ('(16) + (let* ((dflt (char-to-string dired-marker-char)) + (input (read-string + (format + "Marker character to use (default %s): " dflt) + nil nil dflt))) + (aref input 0))) + (_ dired-marker-char)))) + (list suffix marker))) (or (listp extension) (setq extension (list extension))) (dired-mark-files-regexp @@ -1470,7 +1480,13 @@ refer at all to the underlying file system. Contrast this with ;; (string-match "foo" sym) into which a user would soon fall. ;; Give `equal' instead of `=' in the example, as this works on ;; integers and strings. - (interactive "xMark if (lisp expr): \nP") + (interactive + (list (read--expression + (format "%s if (lisp expr): " + (if current-prefix-arg + "UNmark" + "Mark"))) + current-prefix-arg)) (message "%s" predicate) (let ((dired-marker-char (if unflag-p ?\040 dired-marker-char)) inode s mode nlink uid gid size time name sym)