Using saved parent location: http://bzr.savannah.gnu.org/r/emacs/trunk/ Now on revision 104383. ------------------------------------------------------------ revno: 104383 committer: Glenn Morris branch nick: trunk timestamp: Thu 2011-05-26 21:58:50 -0400 message: * lisp/mail/emacsbug.el: Don't require url-util. diff: === modified file 'lisp/ChangeLog' --- lisp/ChangeLog 2011-05-27 01:54:56 +0000 +++ lisp/ChangeLog 2011-05-27 01:58:50 +0000 @@ -1,5 +1,7 @@ 2011-05-27 Glenn Morris + * mail/emacsbug.el: Don't require url-util. + * shell.el (shell-directory-tracker): Case matters. (Bug#8735) * files.el (set-auto-mode): === modified file 'lisp/mail/emacsbug.el' --- lisp/mail/emacsbug.el 2011-05-26 16:14:53 +0000 +++ lisp/mail/emacsbug.el 2011-05-27 01:58:50 +0000 @@ -32,8 +32,6 @@ ;;; Code: -(require 'url-util) - (defgroup emacsbug nil "Sending Emacs bug reports." :group 'maint ------------------------------------------------------------ revno: 104382 committer: Glenn Morris branch nick: trunk timestamp: Thu 2011-05-26 21:54:56 -0400 message: * lisp/shell.el (shell-directory-tracker): Case matters. (Bug#8735) diff: === modified file 'lisp/ChangeLog' --- lisp/ChangeLog 2011-05-27 01:00:53 +0000 +++ lisp/ChangeLog 2011-05-27 01:54:56 +0000 @@ -1,5 +1,7 @@ 2011-05-27 Glenn Morris + * shell.el (shell-directory-tracker): Case matters. (Bug#8735) + * files.el (set-auto-mode): Also respect mode: entries at the end of the file. (Bug#8586) === modified file 'lisp/shell.el' --- lisp/shell.el 2011-05-24 02:45:50 +0000 +++ lisp/shell.el 2011-05-27 01:54:56 +0000 @@ -704,6 +704,7 @@ (concat "^" shell-command-separator-regexp) str) ; skip whitespace (match-end 0))) + (case-fold-search) end cmd arg1) (while (string-match shell-command-regexp str start) (setq end (match-end 0) ------------------------------------------------------------ revno: 104381 committer: Glenn Morris branch nick: trunk timestamp: Thu 2011-05-26 21:43:15 -0400 message: Tweak previous modes.texi change. diff: === modified file 'doc/lispref/modes.texi' --- doc/lispref/modes.texi 2011-05-27 01:00:53 +0000 +++ doc/lispref/modes.texi 2011-05-27 01:43:15 +0000 @@ -583,7 +583,7 @@ @var{find-file} is normally @code{nil}. In this case, @code{normal-mode} unconditionally processes any file local variables. -The function calls @code{set-auto-mode} to choose a major mode. If it +The function calls @code{set-auto-mode} to choose a major mode. If this does not specify a mode, the buffer stays in the major mode determined by the default value of @code{major-mode} (see below). ------------------------------------------------------------ revno: 104380 committer: Glenn Morris branch nick: trunk timestamp: Thu 2011-05-26 21:00:53 -0400 message: Make set-auto-mode respect mode: entries at the end of the file (bug#8586) * lisp/files.el (set-auto-mode): Also respect mode: entries at the end of the file. * doc/lispref/modes.texi (Auto Major Mode): Update for set-auto-mode changes. * doc/emacs/custom.texi (Specifying File Variables): Major modes no longer need come first. * etc/NEWS: Mention this. diff: === modified file 'doc/emacs/ChangeLog' --- doc/emacs/ChangeLog 2011-05-22 19:05:14 +0000 +++ doc/emacs/ChangeLog 2011-05-27 01:00:53 +0000 @@ -1,3 +1,8 @@ +2011-05-27 Glenn Morris + + * custom.texi (Specifying File Variables): + Major modes no longer need come first. + 2011-05-22 Chong Yidong * mule.texi (Specify Coding, Text Coding, Communication Coding): === modified file 'doc/emacs/custom.texi' --- doc/emacs/custom.texi 2011-05-17 02:26:56 +0000 +++ doc/emacs/custom.texi 2011-05-27 01:00:53 +0000 @@ -1130,7 +1130,10 @@ If a file has both a local variables list and a @samp{-*-} line, Emacs processes @emph{everything} in the @samp{-*-} line first, and -@emph{everything} in the local variables list afterward. +@emph{everything} in the local variables list afterward. The exception +to this is a major mode specification. Emacs applies this first, +wherever it appears, since most major modes kill all local variables as +part of their initialization. A local variables list starts with a line containing the string @samp{Local Variables:}, and ends with a line containing the string @@ -1205,11 +1208,6 @@ These four ``variables'' are not really variables; setting them in any other context has no special meaning. - @emph{If @code{mode} is used to set a major mode, it should be the -first ``variable'' in the list.} Otherwise, the entries that precede -it will usually have no effect, since most major modes kill all local -variables as part of their initialization. - You can use the @code{mode} ``variable'' to enable minor modes as well as the major modes; in fact, you can use it more than once, first to set the major mode and then to enable minor modes which are === modified file 'doc/lispref/ChangeLog' --- doc/lispref/ChangeLog 2011-05-26 16:20:21 +0000 +++ doc/lispref/ChangeLog 2011-05-27 01:00:53 +0000 @@ -1,3 +1,7 @@ +2011-05-27 Glenn Morris + + * modes.texi (Auto Major Mode): Update for set-auto-mode changes. + 2011-05-26 Glenn Morris * variables.texi (File Local Variables): === modified file 'doc/lispref/modes.texi' --- doc/lispref/modes.texi 2011-05-19 06:54:27 +0000 +++ doc/lispref/modes.texi 2011-05-27 01:00:53 +0000 @@ -583,12 +583,9 @@ @var{find-file} is normally @code{nil}. In this case, @code{normal-mode} unconditionally processes any file local variables. -If @code{normal-mode} processes the local variables list and this list -specifies a major mode, that mode overrides any mode chosen by -@code{set-auto-mode}. If neither @code{set-auto-mode} nor -@code{hack-local-variables} specify a major mode, the buffer stays in -the major mode determined by the default value of @code{major-mode} -(see below). +The function calls @code{set-auto-mode} to choose a major mode. If it +does not specify a mode, the buffer stays in the major mode determined +by the default value of @code{major-mode} (see below). @cindex file mode specification error @code{normal-mode} uses @code{condition-case} around the call to the @@ -600,15 +597,15 @@ @cindex visited file mode This function selects the major mode that is appropriate for the current buffer. It bases its decision (in order of precedence) on -the @w{@samp{-*-}} line, on the @w{@samp{#!}} line (using +the @w{@samp{-*-}} line, on any @samp{mode:} local variable near the +end of a file, on the @w{@samp{#!}} line (using @code{interpreter-mode-alist}), on the text at the beginning of the buffer (using @code{magic-mode-alist}), and finally on the visited file name (using @code{auto-mode-alist}). @xref{Choosing Modes, , How -Major Modes are Chosen, emacs, The GNU Emacs Manual}. However, this -function does not look for the @samp{mode:} local variable near the -end of a file; the @code{hack-local-variables} function does that. +Major Modes are Chosen, emacs, The GNU Emacs Manual}. If @code{enable-local-variables} is @code{nil}, @code{set-auto-mode} -does not check the @w{@samp{-*-}} line for a mode tag either. +does not check the @w{@samp{-*-}} line, or near the end of the file, +for any mode tag. If @var{keep-mode-if-same} is non-@code{nil}, this function does not call the mode command if the buffer is already in the proper major === modified file 'etc/NEWS' --- etc/NEWS 2011-05-24 14:22:44 +0000 +++ etc/NEWS 2011-05-27 01:00:53 +0000 @@ -993,6 +993,10 @@ ** New variables `delayed-warnings-list' and `delayed-warnings-hook' allow deferring warnings until the main command loop is executed. ++++ +** `set-auto-mode' now respects mode: local variables at the end of files, +as well as those in the -*- line. + * Changes in Emacs 24.1 on non-free operating systems === modified file 'lisp/ChangeLog' --- lisp/ChangeLog 2011-05-26 07:35:47 +0000 +++ lisp/ChangeLog 2011-05-27 01:00:53 +0000 @@ -1,3 +1,8 @@ +2011-05-27 Glenn Morris + + * files.el (set-auto-mode): + Also respect mode: entries at the end of the file. (Bug#8586) + 2011-05-26 Glenn Morris * files.el (hack-local-variables-prop-line, hack-local-variables): === modified file 'lisp/files.el' --- lisp/files.el 2011-05-26 07:35:47 +0000 +++ lisp/files.el 2011-05-27 01:00:53 +0000 @@ -2241,6 +2241,8 @@ (interactive) (funcall (or (default-value 'major-mode) 'fundamental-mode)) (let ((enable-local-variables (or (not find-file) enable-local-variables))) + ;; FIXME this is less efficient than it could be, since both + ;; s-a-m and h-l-v may parse the same regions, looking for "mode:". (report-errors "File mode specification error: %s" (set-auto-mode)) (report-errors "File local-variables error: %s" @@ -2616,23 +2618,24 @@ "Select major mode appropriate for current buffer. To find the right major mode, this function checks for a -*- mode tag, +checks for a `mode:' entry in the Local Variables section of the file, checks if it uses an interpreter listed in `interpreter-mode-alist', matches the buffer beginning against `magic-mode-alist', compares the filename against the entries in `auto-mode-alist', then matches the buffer beginning against `magic-fallback-mode-alist'. -It does not check for the `mode:' local variable in the -Local Variables section of the file; for that, use `hack-local-variables'. - -If `enable-local-variables' is nil, this function does not check for a --*- mode tag. +If `enable-local-variables' is nil, this function does not check for +any mode: tag anywhere in the file. If the optional argument KEEP-MODE-IF-SAME is non-nil, then we set the major mode only if that would change it. In other words we don't actually set it to the same mode the buffer already has." ;; Look for -*-MODENAME-*- or -*- ... mode: MODENAME; ... -*- (let (end done mode modes) - ;; Find a -*- mode tag + ;; Once we drop the deprecated feature where mode: is also allowed to + ;; specify minor-modes (ie, there can be more than one "mode:), we can + ;; remove this section and just let (hack-local-variables t) handle it. + ;; Find a -*- mode tag. (save-excursion (goto-char (point-min)) (skip-chars-forward " \t\n") @@ -2667,6 +2670,14 @@ (or (set-auto-mode-0 mode keep-mode-if-same) ;; continuing would call minor modes again, toggling them off (throw 'nop nil)))))) + (and (not done) + enable-local-variables + (setq mode (hack-local-variables t)) + (not (memq mode modes)) ; already tried and failed + (if (not (functionp mode)) + (message "Ignoring unknown mode `%s'" mode) + (setq done t) + (set-auto-mode-0 mode keep-mode-if-same))) ;; If we didn't, look for an interpreter specified in the first line. ;; As a special case, allow for things like "#!/bin/env perl", which ;; finds the interpreter anywhere in $PATH. ------------------------------------------------------------ revno: 104379 committer: Glenn Morris branch nick: trunk timestamp: Thu 2011-05-26 20:55:07 -0400 message: Repeat previous gnus-group.el change for bugs.debian.org. * lisp/gnus/gnus-group.el (gnus-bug-group-download-format-alist): Use the "maintainer" version of debian reports as well. diff: === modified file 'lisp/gnus/ChangeLog' --- lisp/gnus/ChangeLog 2011-05-26 00:49:54 +0000 +++ lisp/gnus/ChangeLog 2011-05-27 00:55:07 +0000 @@ -1,3 +1,8 @@ +2011-05-27 Glenn Morris + + * gnus-group.el (gnus-bug-group-download-format-alist): + Use the "maintainer" version of debian reports as well. + 2011-05-26 Glenn Morris * gnus-group.el (gnus-bug-group-download-format-alist): === modified file 'lisp/gnus/gnus-group.el' --- lisp/gnus/gnus-group.el 2011-05-26 00:49:54 +0000 +++ lisp/gnus/gnus-group.el 2011-05-27 00:55:07 +0000 @@ -2412,13 +2412,13 @@ (defcustom gnus-bug-group-download-format-alist '((emacs . "http://debbugs.gnu.org/%s;mbox=yes;mboxmaint=yes") (debian - . "http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=%s&mbox=yes")) + . "http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=%s&mbox=yes;mboxmaint=yes")) "Alist of symbols for bug trackers and the corresponding URL format string. The URL format string must contain a single \"%s\", specifying the bug number, and browsing the URL must return mbox output." :group 'gnus-group-foreign - ;; Added mboxmaint=yes for Emacs. This gets the version with the - ;; messages as they went out, not as they came in. + ;; Added mboxmaint=yes. This gets the version with the messages as + ;; they went out, not as they came in. ;; Eg bug-gnu-emacs is replaced by ###@debbugs. :version "24.1" :type '(repeat (cons (symbol) (string :tag "URL format string")))) ------------------------------------------------------------ revno: 104378 committer: Chong Yidong branch nick: trunk timestamp: Thu 2011-05-26 15:20:59 -0400 message: src/xselect.c (x_handle_selection_request): Fix typo in last change. diff: === modified file 'src/xselect.c' --- src/xselect.c 2011-05-26 17:42:32 +0000 +++ src/xselect.c 2011-05-26 19:20:59 +0000 @@ -811,10 +811,6 @@ int success = 0; int count = SPECPDL_INDEX (); - TRACE2 ("x_handle_selection_request, from=0x%08lx time=%lu", - (unsigned long) SELECTION_EVENT_REQUESTOR (event), - (unsigned long) SELECTION_EVENT_TIME (event)); - GCPRO2 (local_selection_data, target_symbol); /* Decline if we don't own any selections. */ @@ -836,6 +832,10 @@ x_start_queuing_selection_requests (); record_unwind_protect (queue_selection_requests_unwind, Qnil); + TRACE2 ("x_handle_selection_request: selection=%s, target=%s", + SDATA (SYMBOL_NAME (selection_symbol)), + SDATA (SYMBOL_NAME (target_symbol))); + if (EQ (target_symbol, QMULTIPLE)) { /* For MULTIPLE targets, the event property names a list of atom @@ -849,7 +849,7 @@ multprop = x_get_window_property_as_lisp_data (display, requestor, property, QMULTIPLE, selection); - if (!VECTORP (multprop) || !(ASIZE (multprop) % 2)) + if (!VECTORP (multprop) || ASIZE (multprop) % 2) goto DONE; nselections = ASIZE (multprop) / 2; ------------------------------------------------------------ revno: 104377 committer: Chong Yidong branch nick: trunk timestamp: Thu 2011-05-26 13:42:32 -0400 message: * src/xselect.c: ICCCM-compliant handling of MULTIPLE targets. (converted_selections, conversion_fail_tag): New global variables. (x_selection_request_lisp_error): Free the above. (x_get_local_selection): Remove unnecessary code. (x_reply_selection_request): Args changed; handle arbitrary array of converted selections stored in converted_selections. Separate the XChangeProperty and SelectionNotify steps. (x_handle_selection_request): Rewrite to handle MULTIPLE target. (x_convert_selection): New function. (x_handle_selection_event): Simplify. (x_get_foreign_selection): Don't ignore incoming requests while waiting for an answer; this will fail when we implement SAVE_TARGETS, and seems unnecessary anyway. (selection_data_to_lisp_data): Recognize ATOM_PAIR type. (Vx_sent_selection_functions): Doc fix. diff: === modified file 'src/ChangeLog' --- src/ChangeLog 2011-05-26 05:36:55 +0000 +++ src/ChangeLog 2011-05-26 17:42:32 +0000 @@ -1,3 +1,21 @@ +2011-05-26 Chong Yidong + + * xselect.c: ICCCM-compliant handling of MULTIPLE targets. + (converted_selections, conversion_fail_tag): New global variables. + (x_selection_request_lisp_error): Free the above. + (x_get_local_selection): Remove unnecessary code. + (x_reply_selection_request): Args changed; handle arbitrary array + of converted selections stored in converted_selections. Separate + the XChangeProperty and SelectionNotify steps. + (x_handle_selection_request): Rewrite to handle MULTIPLE target. + (x_convert_selection): New function. + (x_handle_selection_event): Simplify. + (x_get_foreign_selection): Don't ignore incoming requests while + waiting for an answer; this will fail when we implement + SAVE_TARGETS, and seems unnecessary anyway. + (selection_data_to_lisp_data): Recognize ATOM_PAIR type. + (Vx_sent_selection_functions): Doc fix. + 2011-05-26 Leo Liu * editfns.c (Ftranspose_regions): Allow empty regions. (Bug#8699) === modified file 'src/xselect.c' --- src/xselect.c 2011-05-22 21:57:43 +0000 +++ src/xselect.c 2011-05-26 17:42:32 +0000 @@ -43,6 +43,7 @@ #include struct prop_location; +struct selection_data; static Lisp_Object x_atom_to_symbol (Display *dpy, Atom atom); static Atom symbol_to_x_atom (struct x_display_info *, Display *, @@ -54,8 +55,9 @@ static Lisp_Object queue_selection_requests_unwind (Lisp_Object); static Lisp_Object some_frame_on_display (struct x_display_info *); static Lisp_Object x_catch_errors_unwind (Lisp_Object); -static void x_reply_selection_request (struct input_event *, int, - unsigned char *, int, Atom); +static void x_reply_selection_request (struct input_event *, struct x_display_info *); +static int x_convert_selection (struct input_event *, Lisp_Object, Lisp_Object, + Atom, int); static int waiting_for_other_props_on_window (Display *, Window); static struct prop_location *expect_property_change (Display *, Window, Atom, int); @@ -401,32 +403,6 @@ handler_fn = Qnil; value = XCAR (XCDR (XCDR (local_value))); } -#if 0 /* #### MULTIPLE doesn't work yet */ - else if (CONSP (target_type) - && XCAR (target_type) == QMULTIPLE) - { - Lisp_Object pairs; - int size; - int i; - pairs = XCDR (target_type); - size = ASIZE (pairs); - /* If the target is MULTIPLE, then target_type looks like - (MULTIPLE . [[SELECTION1 TARGET1] [SELECTION2 TARGET2] ... ]) - We modify the second element of each pair in the vector and - return it as [[SELECTION1 ] [SELECTION2 ] ... ] - */ - for (i = 0; i < size; i++) - { - Lisp_Object pair; - pair = XVECTOR (pairs)->contents [i]; - XVECTOR (pair)->contents [1] - = x_get_local_selection (XVECTOR (pair)->contents [0], - XVECTOR (pair)->contents [1], - local_request); - } - return pairs; - } -#endif else { /* Don't allow a quit within the converter. @@ -514,6 +490,30 @@ static struct x_display_info *selection_request_dpyinfo; +/* Raw selection data, for sending to a requestor window. */ + +struct selection_data +{ + unsigned char *data; + unsigned int size; + int format; + Atom type; + int nofree; + Atom property; + /* This can be set to non-NULL during x_reply_selection_request, if + the selection is waiting for an INCR transfer to complete. Don't + free these; that's done by unexpect_property_change. */ + struct prop_location *wait_object; + struct selection_data *next; +}; + +/* Linked list of the above (in support of MULTIPLE targets). */ + +struct selection_data *converted_selections; + +/* "Data" to send a requestor for a failed MULTIPLE subtarget. */ +Atom conversion_fail_tag; + /* Used as an unwind-protect clause so that, if a selection-converter signals an error, we tell the requester that we were unable to do what they wanted before we throw to top-level or go into the debugger or whatever. */ @@ -521,6 +521,17 @@ static Lisp_Object x_selection_request_lisp_error (Lisp_Object ignore) { + struct selection_data *cs, *next; + + for (cs = converted_selections; cs; cs = next) + { + next = cs->next; + if (cs->nofree == 0 && cs->data) + xfree (cs->data); + xfree (cs); + } + converted_selections = NULL; + if (x_selection_current_request != 0 && selection_request_dpyinfo->display) x_decline_selection_request (x_selection_current_request); @@ -592,27 +603,23 @@ return Qnil; } -/* Send the reply to a selection request event EVENT. - TYPE is the type of selection data requested. - DATA and SIZE describe the data to send, already converted. - FORMAT is the unit-size (in bits) of the data to be transmitted. */ +/* Send the reply to a selection request event EVENT. */ #ifdef TRACE_SELECTION static int x_reply_selection_request_cnt; #endif /* TRACE_SELECTION */ static void -x_reply_selection_request (struct input_event *event, int format, unsigned char *data, int size, Atom type) +x_reply_selection_request (struct input_event *event, struct x_display_info *dpyinfo) { XEvent reply_base; XSelectionEvent *reply = &(reply_base.xselection); Display *display = SELECTION_EVENT_DISPLAY (event); Window window = SELECTION_EVENT_REQUESTOR (event); int bytes_remaining; - int format_bytes = format/8; int max_bytes = SELECTION_QUANTUM (display); - struct x_display_info *dpyinfo = x_display_info_for_display (display); int count = SPECPDL_INDEX (); + struct selection_data *cs; if (max_bytes > MAX_SELECTION_QUANTUM) max_bytes = MAX_SELECTION_QUANTUM; @@ -634,143 +641,133 @@ record_unwind_protect (x_catch_errors_unwind, Qnil); x_catch_errors (display); + /* Loop over converted selections, storing them in the requested + properties. If data is large, only store the first N bytes + (section 2.7.2 of ICCCM). Note that we store the data for a + MULTIPLE request in the opposite order; the ICCM says only that + the conversion itself must be done in the same order. */ + for (cs = converted_selections; cs; cs = cs->next) + { + if (cs->property != None) + { + bytes_remaining = cs->size * (cs->format / 8); + if (bytes_remaining <= max_bytes) + { + /* Send all the data at once, with minimal handshaking. */ + TRACE1 ("Sending all %d bytes", bytes_remaining); + XChangeProperty (display, window, cs->property, + cs->type, cs->format, PropModeReplace, + cs->data, cs->size); + } + else + { + /* Send an INCR tag to initiate incremental transfer. */ + long value[1]; + + TRACE2 ("Start sending %d bytes incrementally (%s)", + bytes_remaining, XGetAtomName (display, cs->property)); + cs->wait_object + = expect_property_change (display, window, cs->property, + PropertyDelete); + + /* XChangeProperty expects an array of long even if long + is more than 32 bits. */ + value[0] = bytes_remaining; + XChangeProperty (display, window, cs->property, + dpyinfo->Xatom_INCR, 32, PropModeReplace, + (unsigned char *) value, 1); + XSelectInput (display, window, PropertyChangeMask); + } + } + } + + /* Now issue the SelectionNotify event. */ + XSendEvent (display, window, False, 0L, &reply_base); + XFlush (display); + #ifdef TRACE_SELECTION { char *sel = XGetAtomName (display, reply->selection); char *tgt = XGetAtomName (display, reply->target); - TRACE3 ("%s, target %s (%d)", sel, tgt, ++x_reply_selection_request_cnt); + TRACE3 ("Sent SelectionNotify: %s, target %s (%d)", + sel, tgt, ++x_reply_selection_request_cnt); if (sel) XFree (sel); if (tgt) XFree (tgt); } #endif /* TRACE_SELECTION */ - /* Store the data on the requested property. - If the selection is large, only store the first N bytes of it. - */ - bytes_remaining = size * format_bytes; - if (bytes_remaining <= max_bytes) - { - /* Send all the data at once, with minimal handshaking. */ - TRACE1 ("Sending all %d bytes", bytes_remaining); - XChangeProperty (display, window, reply->property, type, format, - PropModeReplace, data, size); - /* At this point, the selection was successfully stored; ack it. */ - XSendEvent (display, window, False, 0L, &reply_base); - } - else - { - /* Send an INCR selection. */ - struct prop_location *wait_object; - int had_errors; - Lisp_Object frame; - - frame = some_frame_on_display (dpyinfo); - - /* If the display no longer has frames, we can't expect - to get many more selection requests from it, so don't - bother trying to queue them. */ - if (!NILP (frame)) - { - x_start_queuing_selection_requests (); - - record_unwind_protect (queue_selection_requests_unwind, - Qnil); - } - - if (x_window_to_frame (dpyinfo, window)) /* #### debug */ - error ("Attempt to transfer an INCR to ourself!"); - - TRACE2 ("Start sending %d bytes incrementally (%s)", - bytes_remaining, XGetAtomName (display, reply->property)); - wait_object = expect_property_change (display, window, reply->property, - PropertyDelete); - - TRACE1 ("Set %s to number of bytes to send", - XGetAtomName (display, reply->property)); + /* Finish sending the rest of each of the INCR values. This should + be improved; there's a chance of deadlock if more than one + subtarget in a MULTIPLE selection requires an INCR transfer, and + the requestor and Emacs loop waiting on different transfers. */ + for (cs = converted_selections; cs; cs = cs->next) + if (cs->wait_object) { - /* XChangeProperty expects an array of long even if long is more than - 32 bits. */ - long value[1]; - - value[0] = bytes_remaining; - XChangeProperty (display, window, reply->property, dpyinfo->Xatom_INCR, - 32, PropModeReplace, - (unsigned char *) value, 1); + int format_bytes = cs->format / 8; + int had_errors = x_had_errors_p (display); + UNBLOCK_INPUT; + + bytes_remaining = cs->size * format_bytes; + + /* Wait for the requester to ack by deleting the property. + This can run Lisp code (process handlers) or signal. */ + if (! had_errors) + { + TRACE1 ("Waiting for ACK (deletion of %s)", + XGetAtomName (display, cs->property)); + wait_for_property_change (cs->wait_object); + } + else + unexpect_property_change (cs->wait_object); + + while (bytes_remaining) + { + int i = ((bytes_remaining < max_bytes) + ? bytes_remaining + : max_bytes) / format_bytes; + BLOCK_INPUT; + + cs->wait_object + = expect_property_change (display, window, cs->property, + PropertyDelete); + + TRACE1 ("Sending increment of %d elements", i); + TRACE1 ("Set %s to increment data", + XGetAtomName (display, cs->property)); + + /* Append the next chunk of data to the property. */ + XChangeProperty (display, window, cs->property, + cs->type, cs->format, PropModeAppend, + cs->data, i); + bytes_remaining -= i * format_bytes; + cs->data += i * ((cs->format == 32) ? sizeof (long) : format_bytes); + XFlush (display); + had_errors = x_had_errors_p (display); + UNBLOCK_INPUT; + + if (had_errors) break; + + /* Wait for the requester to ack this chunk by deleting + the property. This can run Lisp code or signal. */ + TRACE1 ("Waiting for increment ACK (deletion of %s)", + XGetAtomName (display, cs->property)); + wait_for_property_change (cs->wait_object); + } + + /* Now write a zero-length chunk to the property to tell the + requester that we're done. */ + BLOCK_INPUT; + if (! waiting_for_other_props_on_window (display, window)) + XSelectInput (display, window, 0L); + + TRACE1 ("Set %s to a 0-length chunk to indicate EOF", + XGetAtomName (display, cs->property)); + XChangeProperty (display, window, cs->property, + cs->type, cs->format, PropModeReplace, + cs->data, 0); + TRACE0 ("Done sending incrementally"); } - XSelectInput (display, window, PropertyChangeMask); - - /* Tell 'em the INCR data is there... */ - TRACE0 ("Send SelectionNotify event"); - XSendEvent (display, window, False, 0L, &reply_base); - XFlush (display); - - had_errors = x_had_errors_p (display); - UNBLOCK_INPUT; - - /* First, wait for the requester to ack by deleting the property. - This can run random lisp code (process handlers) or signal. */ - if (! had_errors) - { - TRACE1 ("Waiting for ACK (deletion of %s)", - XGetAtomName (display, reply->property)); - wait_for_property_change (wait_object); - } - else - unexpect_property_change (wait_object); - - TRACE0 ("Got ACK"); - while (bytes_remaining) - { - int i = ((bytes_remaining < max_bytes) - ? bytes_remaining - : max_bytes) / format_bytes; - - BLOCK_INPUT; - - wait_object - = expect_property_change (display, window, reply->property, - PropertyDelete); - - TRACE1 ("Sending increment of %d elements", i); - TRACE1 ("Set %s to increment data", - XGetAtomName (display, reply->property)); - - /* Append the next chunk of data to the property. */ - XChangeProperty (display, window, reply->property, type, format, - PropModeAppend, data, i); - bytes_remaining -= i * format_bytes; - if (format == 32) - data += i * sizeof (long); - else - data += i * format_bytes; - XFlush (display); - had_errors = x_had_errors_p (display); - UNBLOCK_INPUT; - - if (had_errors) - break; - - /* Now wait for the requester to ack this chunk by deleting the - property. This can run random lisp code or signal. */ - TRACE1 ("Waiting for increment ACK (deletion of %s)", - XGetAtomName (display, reply->property)); - wait_for_property_change (wait_object); - } - - /* Now write a zero-length chunk to the property to tell the - requester that we're done. */ - BLOCK_INPUT; - if (! waiting_for_other_props_on_window (display, window)) - XSelectInput (display, window, 0L); - - TRACE1 ("Set %s to a 0-length chunk to indicate EOF", - XGetAtomName (display, reply->property)); - XChangeProperty (display, window, reply->property, type, format, - PropModeReplace, data, 0); - TRACE0 ("Done sending incrementally"); - } - /* rms, 2003-01-03: I think I have fixed this bug. */ /* The window we're communicating with may have been deleted in the meantime (that's a real situation from a bug report). @@ -798,118 +795,166 @@ static void x_handle_selection_request (struct input_event *event) { - struct gcpro gcpro1, gcpro2, gcpro3; - Lisp_Object local_selection_data; - Lisp_Object selection_symbol; - Lisp_Object target_symbol; - Lisp_Object converted_selection; + struct gcpro gcpro1, gcpro2; Time local_selection_time; - Lisp_Object successful_p; - int count; - struct x_display_info *dpyinfo - = x_display_info_for_display (SELECTION_EVENT_DISPLAY (event)); + + Display *display = SELECTION_EVENT_DISPLAY (event); + struct x_display_info *dpyinfo = x_display_info_for_display (display); + + Atom selection = SELECTION_EVENT_SELECTION (event); + Lisp_Object selection_symbol = x_atom_to_symbol (display, selection); + Atom target = SELECTION_EVENT_TARGET (event); + Lisp_Object target_symbol = x_atom_to_symbol (display, target); + Atom property = SELECTION_EVENT_PROPERTY (event); + Lisp_Object local_selection_data + = assq_no_quit (selection_symbol, Vselection_alist); + int success = 0; + int count = SPECPDL_INDEX (); TRACE2 ("x_handle_selection_request, from=0x%08lx time=%lu", (unsigned long) SELECTION_EVENT_REQUESTOR (event), (unsigned long) SELECTION_EVENT_TIME (event)); - local_selection_data = Qnil; - target_symbol = Qnil; - converted_selection = Qnil; - successful_p = Qnil; - - GCPRO3 (local_selection_data, converted_selection, target_symbol); - - selection_symbol = x_atom_to_symbol (SELECTION_EVENT_DISPLAY (event), - SELECTION_EVENT_SELECTION (event)); - - local_selection_data = assq_no_quit (selection_symbol, Vselection_alist); - - if (NILP (local_selection_data)) - { - /* Someone asked for the selection, but we don't have it any more. - */ - x_decline_selection_request (event); - goto DONE; - } - - local_selection_time = (Time) - cons_to_long (XCAR (XCDR (XCDR (local_selection_data)))); - + GCPRO2 (local_selection_data, target_symbol); + + /* Decline if we don't own any selections. */ + if (NILP (local_selection_data)) goto DONE; + + /* Decline requests issued prior to our acquiring the selection. */ + local_selection_time + = (Time) cons_to_long (XCAR (XCDR (XCDR (local_selection_data)))); if (SELECTION_EVENT_TIME (event) != CurrentTime && local_selection_time > SELECTION_EVENT_TIME (event)) - { - /* Someone asked for the selection, and we have one, but not the one - they're looking for. - */ - x_decline_selection_request (event); - goto DONE; - } + goto DONE; x_selection_current_request = event; - count = SPECPDL_INDEX (); selection_request_dpyinfo = dpyinfo; record_unwind_protect (x_selection_request_lisp_error, Qnil); - target_symbol = x_atom_to_symbol (SELECTION_EVENT_DISPLAY (event), - SELECTION_EVENT_TARGET (event)); + /* We might be able to handle nested x_handle_selection_requests, + but this is difficult to test, and seems unimportant. */ + x_start_queuing_selection_requests (); + record_unwind_protect (queue_selection_requests_unwind, Qnil); -#if 0 /* #### MULTIPLE doesn't work yet */ if (EQ (target_symbol, QMULTIPLE)) - target_symbol = fetch_multiple_target (event); -#endif - - /* Convert lisp objects back into binary data */ - - converted_selection - = x_get_local_selection (selection_symbol, target_symbol, 0); - - if (! NILP (converted_selection)) - { - unsigned char *data; - unsigned int size; - int format; - Atom type; - int nofree; - - if (CONSP (converted_selection) && NILP (XCDR (converted_selection))) - { - x_decline_selection_request (event); - goto DONE2; - } - - lisp_data_to_selection_data (SELECTION_EVENT_DISPLAY (event), - converted_selection, - &data, &type, &size, &format, &nofree); - - x_reply_selection_request (event, format, data, size, type); - successful_p = Qt; - - /* Indicate we have successfully processed this event. */ - x_selection_current_request = 0; - - /* Use xfree, not XFree, because lisp_data_to_selection_data - calls xmalloc itself. */ - if (!nofree) - xfree (data); - } - - DONE2: - unbind_to (count, Qnil); + { + /* For MULTIPLE targets, the event property names a list of atom + pairs; the first atom names a target and the second names a + non-None property. */ + Window requestor = SELECTION_EVENT_REQUESTOR (event); + Lisp_Object multprop; + int j, nselections; + + if (property == None) goto DONE; + multprop = x_get_window_property_as_lisp_data (display, requestor, property, + QMULTIPLE, selection); + + if (!VECTORP (multprop) || !(ASIZE (multprop) % 2)) + goto DONE; + + nselections = ASIZE (multprop) / 2; + /* Perform conversions. This can signal. */ + for (j = 0; j < nselections; j++) + { + struct selection_data *cs = converted_selections + j; + Lisp_Object subtarget = AREF (multprop, 2*j); + Atom subproperty = symbol_to_x_atom (dpyinfo, display, + AREF (multprop, 2*j+1)); + + if (subproperty != None) + x_convert_selection (event, selection_symbol, subtarget, + subproperty, 1); + } + success = 1; + } + else + { + if (property == None) + property = SELECTION_EVENT_TARGET (event); + success = x_convert_selection (event, selection_symbol, + target_symbol, property, 0); + } DONE: - /* Let random lisp code notice that the selection has been asked for. */ - { - Lisp_Object rest; - rest = Vx_sent_selection_functions; - if (!EQ (rest, Qunbound)) - for (; CONSP (rest); rest = Fcdr (rest)) - call3 (Fcar (rest), selection_symbol, target_symbol, successful_p); - } - + if (success) + x_reply_selection_request (event, dpyinfo); + else + x_decline_selection_request (event); + x_selection_current_request = 0; + + /* Run the `x-sent-selection-functions' abnormal hook. */ + if (!NILP (Vx_sent_selection_functions) + && !EQ (Vx_sent_selection_functions, Qunbound)) + { + Lisp_Object args[4]; + args[0] = Vx_sent_selection_functions; + args[1] = selection_symbol; + args[2] = target_symbol; + args[3] = success ? Qt : Qnil; + Frun_hook_with_args (4, args); + } + + unbind_to (count, Qnil); UNGCPRO; } + +/* Perform the requested selection conversion, and write the data to + the converted_selections linked list, where it can be accessed by + x_reply_selection_request. If FOR_MULTIPLE is non-zero, write out + the data even if conversion fails, using conversion_fail_tag. + + Return 0 if the selection failed to convert, 1 otherwise. */ + +static int +x_convert_selection (struct input_event *event, + Lisp_Object selection_symbol, + Lisp_Object target_symbol, + Atom property, int for_multiple) +{ + struct gcpro gcpro1; + Lisp_Object lisp_selection; + struct selection_data *cs; + GCPRO1 (lisp_selection); + + lisp_selection + = x_get_local_selection (selection_symbol, target_symbol, 0); + + /* A nil return value means we can't perform the conversion. */ + if (NILP (lisp_selection) + || (CONSP (lisp_selection) && NILP (XCDR (lisp_selection)))) + { + if (for_multiple) + { + cs = xmalloc (sizeof (struct selection_data)); + cs->data = (unsigned char *) &conversion_fail_tag; + cs->size = 1; + cs->format = 32; + cs->type = XA_ATOM; + cs->nofree = 1; + cs->property = property; + cs->wait_object = NULL; + cs->next = converted_selections; + converted_selections = cs; + } + + RETURN_UNGCPRO (0); + } + + /* Otherwise, record the converted selection to binary. */ + cs = xmalloc (sizeof (struct selection_data)); + cs->nofree = 1; + cs->property = property; + cs->wait_object = NULL; + cs->next = converted_selections; + converted_selections = cs; + lisp_data_to_selection_data (SELECTION_EVENT_DISPLAY (event), + lisp_selection, + &(cs->data), &(cs->type), + &(cs->size), &(cs->format), + &(cs->nofree)); + RETURN_UNGCPRO (1); +} /* Handle a SelectionClear event EVENT, which indicates that some client cleared out our previously asserted selection. @@ -1001,16 +1046,12 @@ x_handle_selection_event (struct input_event *event) { TRACE0 ("x_handle_selection_event"); - - if (event->kind == SELECTION_REQUEST_EVENT) - { - if (x_queue_selection_requests) - x_queue_event (event); - else - x_handle_selection_request (event); - } - else + if (event->kind != SELECTION_REQUEST_EVENT) x_handle_selection_clear (event); + else if (x_queue_selection_requests) + x_queue_event (event); + else + x_handle_selection_request (event); } @@ -1218,55 +1259,6 @@ -#if 0 /* #### MULTIPLE doesn't work yet */ - -static Lisp_Object -fetch_multiple_target (event) - XSelectionRequestEvent *event; -{ - Display *display = event->display; - Window window = event->requestor; - Atom target = event->target; - Atom selection_atom = event->selection; - int result; - - return - Fcons (QMULTIPLE, - x_get_window_property_as_lisp_data (display, window, target, - QMULTIPLE, selection_atom)); -} - -static Lisp_Object -copy_multiple_data (obj) - Lisp_Object obj; -{ - Lisp_Object vec; - int i; - int size; - if (CONSP (obj)) - return Fcons (XCAR (obj), copy_multiple_data (XCDR (obj))); - - CHECK_VECTOR (obj); - vec = Fmake_vector (size = ASIZE (obj), Qnil); - for (i = 0; i < size; i++) - { - Lisp_Object vec2 = XVECTOR (obj)->contents [i]; - CHECK_VECTOR (vec2); - if (ASIZE (vec2) != 2) - /* ??? Confusing error message */ - signal_error ("Vectors must be of length 2", vec2); - XVECTOR (vec)->contents [i] = Fmake_vector (2, Qnil); - XVECTOR (XVECTOR (vec)->contents [i])->contents [0] - = XVECTOR (vec2)->contents [0]; - XVECTOR (XVECTOR (vec)->contents [i])->contents [1] - = XVECTOR (vec2)->contents [1]; - } - return vec; -} - -#endif - - /* Variables for communication with x_handle_selection_notify. */ static Atom reading_which_selection; static Lisp_Object reading_selection_reply; @@ -1339,16 +1331,18 @@ frame = some_frame_on_display (dpyinfo); - /* If the display no longer has frames, we can't expect - to get many more selection requests from it, so don't - bother trying to queue them. */ + /* It should not be necessary to stop handling selection requests + during this time. In fact, the SAVE_TARGETS mechanism requires + us to handle a clipboard manager's requests before it returns + SelectionNotify. */ +#if 0 if (!NILP (frame)) { x_start_queuing_selection_requests (); - - record_unwind_protect (queue_selection_requests_unwind, - Qnil); + record_unwind_protect (queue_selection_requests_unwind, Qnil); } +#endif + UNBLOCK_INPUT; /* This allows quits. Also, don't wait forever. */ @@ -1583,9 +1577,9 @@ } -/* Once a requested selection is "ready" (we got a SelectionNotify event), - fetch value from property PROPERTY of X window WINDOW on display DISPLAY. - TARGET_TYPE and SELECTION_ATOM are used in error message if this fails. */ +/* Fetch a value from property PROPERTY of X window WINDOW on display + DISPLAY. TARGET_TYPE and SELECTION_ATOM are used in error message + if this fails. */ static Lisp_Object x_get_window_property_as_lisp_data (Display *display, Window window, @@ -1717,9 +1711,10 @@ return str; } /* Convert a single atom to a Lisp_Symbol. Convert a set of atoms to - a vector of symbols. - */ - else if (type == XA_ATOM) + a vector of symbols. */ + else if (type == XA_ATOM + /* Treat ATOM_PAIR type similar to list of atoms. */ + || type == dpyinfo->Xatom_ATOM_PAIR) { int i; /* On a 64 bit machine sizeof(Atom) == sizeof(long) == 8. @@ -1866,45 +1861,15 @@ if (NILP (type)) type = QATOM; *size_ret = ASIZE (obj); *format_ret = 32; + for (i = 0; i < *size_ret; i++) + if (!SYMBOLP (XVECTOR (obj)->contents [i])) + signal_error ("All elements of selection vector must have same type", obj); + *data_ret = (unsigned char *) xmalloc ((*size_ret) * sizeof (Atom)); for (i = 0; i < *size_ret; i++) - if (SYMBOLP (XVECTOR (obj)->contents [i])) - (*(Atom **) data_ret) [i] - = symbol_to_x_atom (dpyinfo, display, XVECTOR (obj)->contents [i]); - else - signal_error ("All elements of selection vector must have same type", obj); - } -#if 0 /* #### MULTIPLE doesn't work yet */ - else if (VECTORP (XVECTOR (obj)->contents [0])) - /* This vector is an ATOM_PAIR set */ - { - if (NILP (type)) type = QATOM_PAIR; - *size_ret = ASIZE (obj); - *format_ret = 32; - *data_ret = (unsigned char *) - xmalloc ((*size_ret) * sizeof (Atom) * 2); - for (i = 0; i < *size_ret; i++) - if (VECTORP (XVECTOR (obj)->contents [i])) - { - Lisp_Object pair = XVECTOR (obj)->contents [i]; - if (ASIZE (pair) != 2) - signal_error ( - "Elements of the vector must be vectors of exactly two elements", - pair); - - (*(Atom **) data_ret) [i * 2] - = symbol_to_x_atom (dpyinfo, display, - XVECTOR (pair)->contents [0]); - (*(Atom **) data_ret) [(i * 2) + 1] - = symbol_to_x_atom (dpyinfo, display, - XVECTOR (pair)->contents [1]); - } - else - signal_error ("All elements of the vector must be of the same type", - obj); - - } -#endif + (*(Atom **) data_ret) [i] + = symbol_to_x_atom (dpyinfo, display, XVECTOR (obj)->contents [i]); + } else /* This vector is an INTEGER set, or something like it */ { @@ -2590,6 +2555,9 @@ Vselection_alist = Qnil; staticpro (&Vselection_alist); + converted_selections = NULL; + conversion_fail_tag = None; + DEFVAR_LISP ("selection-converter-alist", Vselection_converter_alist, doc: /* An alist associating X Windows selection-types with functions. These functions are called to convert the selection, with three args: @@ -2615,7 +2583,7 @@ DEFVAR_LISP ("x-sent-selection-functions", Vx_sent_selection_functions, doc: /* A list of functions to be called when Emacs answers a selection request. -The functions are called with four arguments: +The functions are called with three arguments: - the selection name (typically `PRIMARY', `SECONDARY', or `CLIPBOARD'); - the selection-type which Emacs was asked to convert the selection into before sending (for example, `STRING' or `LENGTH'); ------------------------------------------------------------ revno: 104376 committer: Glenn Morris branch nick: trunk timestamp: Thu 2011-05-26 09:20:21 -0700 message: * variables.texi (File Local Variables): More hack-local-variables details. diff: === modified file 'doc/lispref/ChangeLog' --- doc/lispref/ChangeLog 2011-05-26 00:54:27 +0000 +++ doc/lispref/ChangeLog 2011-05-26 16:20:21 +0000 @@ -2,6 +2,7 @@ * variables.texi (File Local Variables): Update hack-local-variables `mode-only' return value. + Add some more details on what this function does in the other case. 2011-05-19 Glenn Morris === modified file 'doc/lispref/variables.texi' --- doc/lispref/variables.texi 2011-05-26 00:54:27 +0000 +++ doc/lispref/variables.texi 2011-05-26 16:20:21 +0000 @@ -1670,7 +1670,10 @@ @code{file-local-variables-alist} and applying each local variable in turn. It calls @code{before-hack-local-variables-hook} and @code{hack-local-variables-hook} before and after applying the -variables, respectively. +variables, respectively. It only calls the before-hook if the alist +is non-@code{nil}; it always calls the other hook. This +function ignores a @samp{mode} element if it specifies the same major +mode as the buffer already has. If the optional argument @var{mode-only} is non-@code{nil}, then all this function does is return a symbol specifying the major mode, ------------------------------------------------------------ revno: 104375 committer: Glenn Morris branch nick: trunk timestamp: Thu 2011-05-26 09:14:53 -0700 message: Restrict regexp match in previous emacsbug.el change. diff: === modified file 'lisp/mail/emacsbug.el' --- lisp/mail/emacsbug.el 2011-05-26 02:57:08 +0000 +++ lisp/mail/emacsbug.el 2011-05-26 16:14:53 +0000 @@ -352,8 +352,9 @@ ;; This is the default user-mail-address. On today's ;; systems, it seems more likely to be wrong than right, ;; since most people don't run their own mail server. - (string-match (format "\\<%s@%s\\>" (user-login-name) - (system-name)) + (string-match (format "\\<%s@%s\\>" + (regexp-quote (user-login-name)) + (regexp-quote (system-name))) from)) (not (yes-or-no-p (format "Is `%s' really your email address? " from))) ------------------------------------------------------------ revno: 104374 committer: Glenn Morris branch nick: trunk timestamp: Thu 2011-05-26 00:35:47 -0700 message: * lisp/files.el (hack-local-variables, hack-local-variables-apply): Doc fixes. diff: === modified file 'lisp/ChangeLog' --- lisp/ChangeLog 2011-05-26 07:23:11 +0000 +++ lisp/ChangeLog 2011-05-26 07:35:47 +0000 @@ -2,6 +2,7 @@ * files.el (hack-local-variables-prop-line, hack-local-variables): Downcase mode names, as seems to be traditional. + (hack-local-variables, hack-local-variables-apply): Doc fixes. * mail/emacsbug.el (report-emacs-bug): Mention checking From address. (report-emacs-bug-hook): Try to validate the From address. (Bug#8038) === modified file 'lisp/files.el' --- lisp/files.el 2011-05-26 07:23:11 +0000 +++ lisp/files.el 2011-05-26 07:35:47 +0000 @@ -3147,6 +3147,8 @@ (defun hack-local-variables (&optional mode-only) "Parse and put into effect this buffer's local variables spec. +Uses `hack-local-variables-apply' to apply the variables. + If MODE-ONLY is non-nil, all we do is check whether a \"mode:\" is specified, and return the corresponding mode symbol, or nil. In this case, we try to ignore minor-modes, and only return a @@ -3260,6 +3262,14 @@ (hack-local-variables-apply))))) (defun hack-local-variables-apply () + "Apply the elements of `file-local-variables-alist'. +If there are any elements, runs `before-hack-local-variables-hook', +then calls `hack-one-local-variable' to apply the alist elements one by one. +Finishes by running `hack-local-variables-hook', regardless of whether +the alist is empty or not. + +Note that this function ignores a `mode' entry if it specifies the same +major mode as the buffer already has." (when file-local-variables-alist ;; Any 'evals must run in the Right sequence. (setq file-local-variables-alist ------------------------------------------------------------ revno: 104373 committer: Glenn Morris branch nick: trunk timestamp: Thu 2011-05-26 00:23:11 -0700 message: Downcase mode names in recent files.el changes. * lisp/files.el (hack-local-variables-prop-line, hack-local-variables): Downcase mode names, as seems to be traditional. diff: === modified file 'lisp/ChangeLog' --- lisp/ChangeLog 2011-05-26 00:52:33 +0000 +++ lisp/ChangeLog 2011-05-26 07:23:11 +0000 @@ -1,5 +1,8 @@ 2011-05-26 Glenn Morris + * files.el (hack-local-variables-prop-line, hack-local-variables): + Downcase mode names, as seems to be traditional. + * mail/emacsbug.el (report-emacs-bug): Mention checking From address. (report-emacs-bug-hook): Try to validate the From address. (Bug#8038) === modified file 'lisp/files.el' --- lisp/files.el 2011-05-23 17:57:17 +0000 +++ lisp/files.el 2011-05-26 07:23:11 +0000 @@ -3078,7 +3078,8 @@ (if mode-only (and (equal keyname "mode") (setq result - (intern (concat (symbol-name val) "-mode")))) + (intern (concat (downcase (symbol-name val)) + "-mode")))) (or (equal keyname "coding") (condition-case nil (push (cons (if (eq key 'eval) @@ -3240,7 +3241,7 @@ ;; deprecated, but try to reject them anyway. (not (string-match "-minor\\'" - (setq val2 (symbol-name val)))) + (setq val2 (downcase (symbol-name val))))) (setq result (intern (concat val2 "-mode")))) (unless (eq var 'coding) (condition-case nil ------------------------------------------------------------ revno: 104372 committer: Leo Liu branch nick: trunk timestamp: Thu 2011-05-26 13:36:55 +0800 message: Allow empty regions in transpose-regions See http://debbugs.gnu.org/cgi/bugreport.cgi?bug=8699. diff: === modified file 'src/ChangeLog' --- src/ChangeLog 2011-05-25 03:45:04 +0000 +++ src/ChangeLog 2011-05-26 05:36:55 +0000 @@ -1,3 +1,7 @@ +2011-05-26 Leo Liu + + * editfns.c (Ftranspose_regions): Allow empty regions. (Bug#8699) + 2011-05-25 YAMAMOTO Mitsuharu * dispextern.h (struct glyph_row): New member fringe_bitmap_periodic_p. === modified file 'src/editfns.c' --- src/editfns.c 2011-05-15 17:17:44 +0000 +++ src/editfns.c 2011-05-26 05:36:55 +0000 @@ -4353,8 +4353,9 @@ if (start2 < end1) error ("Transposed regions overlap"); - else if (start1 == end1 || start2 == end2) - error ("Transposed region has length 0"); + /* Nothing to change for adjacent regions with one being empty */ + else if ((start1 == end1 || start2 == end2) && end1 == start2) + return Qnil; /* The possibilities are: 1. Adjacent (contiguous) regions, or separate but equal regions