]> git.eshelyaron.com Git - emacs.git/commitdiff
substitute-command-keys now curves quotes
authorPaul Eggert <eggert@cs.ucla.edu>
Thu, 28 May 2015 07:06:13 +0000 (00:06 -0700)
committerPaul Eggert <eggert@cs.ucla.edu>
Thu, 28 May 2015 07:22:01 +0000 (00:22 -0700)
So, for example, it turns "`abc'" into "‘abc’" (Bug#20385).
* doc/lispref/help.texi (Keys in Documentation):
* etc/NEWS: Document this.
* src/doc.c (Fsubstitute_command_keys): Implement it.

doc/lispref/help.texi
etc/NEWS
src/doc.c

index 868d284356906f267c5d92f861e8d6d539214bac..ce29f3f5bc31dc0a6ed9be7467c48bd09b85c817 100644 (file)
@@ -318,10 +318,18 @@ stands for no text itself.  It is used only for a side effect: it
 specifies @var{mapvar}'s value as the keymap for any following
 @samp{\[@var{command}]} sequences in this documentation string.
 
+@item `
+(grave accent) stands for a left single quotation mark (@samp{‘}).
+
+@item '
+(apostrophe) stands for a right single quotation mark (@samp{’}) if
+preceded by grave accent and there are no intervening apostrophes.
+Otherwise, apostrophe stands for itself.
+
 @item \=
-quotes the following character and is discarded; thus, @samp{\=\[} puts
-@samp{\[} into the output, and @samp{\=\=} puts @samp{\=} into the
-output.
+quotes the following character and is discarded; thus, @samp{\=`} puts
+@samp{`} into the output, @samp{\=\[} puts @samp{\[} into the output,
+and @samp{\=\=} puts @samp{\=} into the output.
 @end table
 
 @strong{Please note:} Each @samp{\} must be doubled when written in a
@@ -354,8 +362,8 @@ specifies a key binding that the command does not actually have.
 @smallexample
 @group
 (substitute-command-keys
-   "To abort recursive edit, type: \\[abort-recursive-edit]")
-@result{} "To abort recursive edit, type: C-]"
+   "To abort recursive edit, type ‘\\[abort-recursive-edit]’.")
+@result{} "To abort recursive edit, type ‘C-]’."
 @end group
 
 @group
@@ -376,8 +384,8 @@ C-g             abort-recursive-edit
 @group
 (substitute-command-keys
    "To abort a recursive edit from the minibuffer, type\
-\\<minibuffer-local-must-match-map>\\[abort-recursive-edit].")
-@result{} "To abort a recursive edit from the minibuffer, type C-g."
+`\\<minibuffer-local-must-match-map>\\[abort-recursive-edit]'.")
+@result{} "To abort a recursive edit from the minibuffer, type ‘C-g’."
 @end group
 @end smallexample
 
index a220330ebbff1e844216d1deafb9271886d0d2f8..5afd40e6727014ace9229641a1b59960225990b5 100644 (file)
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -805,6 +805,12 @@ when signaling a file error.  For example, it now reports "Permission
 denied" instead of "permission denied".  The old behavior was problematic
 in languages like German where downcasing rules depend on grammar.
 
+** (substitute-command-keys "`foo'") now returns "‘foo’".
+That is, it replaces grave accents by left single quotation marks, and
+apostrophes that match grave accents by right single quotation marks.
+As before, isolated apostrophes and characters preceded by \= are
+output as-is.
+
 +++
 ** The character classes [:alpha:] and [:alnum:] in regular expressions
 now match multibyte characters using Unicode character properties.
index 8b18fb0a5a2d4e542921d5d7263646e307b7392c..32d65563fd93c85a3eb7a57a3aa58fcca56fce15 100644 (file)
--- a/src/doc.c
+++ b/src/doc.c
@@ -693,15 +693,21 @@ summary).
 
 Each substring of the form \\=\\<MAPVAR> specifies the use of MAPVAR
 as the keymap for future \\=\\[COMMAND] substrings.
-\\=\\= quotes the following character and is discarded;
-thus, \\=\\=\\=\\= puts \\=\\= into the output, and \\=\\=\\=\\[ puts \\=\\[ into the output.
+
+Each \\=` is replaced by ‘.  Each ' preceded by \\=` and without
+intervening ' is replaced by ’.
+
+\\=\\= quotes the following character and is discarded; thus,
+\\=\\=\\=\\= puts \\=\\= into the output, \\=\\=\\=\\[ puts \\=\\[ into the output, and
+\\=\\=\\=` puts \\=` into the output.
 
 Return the original STRING if no substitutions are made.
 Otherwise, return a new string.  */)
   (Lisp_Object string)
 {
   char *buf;
-  bool changed = 0;
+  bool changed = false;
+  bool in_quote = false;
   unsigned char *strp;
   char *bufp;
   ptrdiff_t idx;
@@ -734,6 +740,12 @@ Otherwise, return a new string.  */)
   keymap = Voverriding_local_map;
 
   bsize = SBYTES (string);
+
+  /* Add some room for expansion due to quote replacement.  */
+  enum { EXTRA_ROOM = 20 };
+  if (bsize <= STRING_BYTES_BOUND - EXTRA_ROOM)
+    bsize += EXTRA_ROOM;
+
   bufp = buf = xmalloc (bsize);
 
   strp = SDATA (string);
@@ -743,7 +755,7 @@ Otherwise, return a new string.  */)
        {
          /* \= quotes the next character;
             thus, to put in \[ without its special meaning, use \=\[.  */
-         changed = 1;
+         changed = true;
          strp += 2;
          if (multibyte)
            {
@@ -766,7 +778,6 @@ Otherwise, return a new string.  */)
          ptrdiff_t start_idx;
          bool follow_remap = 1;
 
-         changed = 1;
          strp += 2;            /* skip \[ */
          start = strp;
          start_idx = start - SDATA (string);
@@ -833,7 +844,6 @@ Otherwise, return a new string.  */)
          Lisp_Object earlier_maps;
          ptrdiff_t count = SPECPDL_INDEX ();
 
-         changed = 1;
          strp += 2;            /* skip \{ or \< */
          start = strp;
          start_idx = start - SDATA (string);
@@ -903,6 +913,7 @@ Otherwise, return a new string.  */)
          length = SCHARS (tem);
          length_byte = SBYTES (tem);
        subst:
+         changed = true;
          {
            ptrdiff_t offset = bufp - buf;
            if (STRING_BYTES_BOUND - length_byte < bsize)
@@ -916,6 +927,22 @@ Otherwise, return a new string.  */)
            strp = SDATA (string) + idx;
          }
        }
+      else if (strp[0] == '`')
+       {
+         in_quote = true;
+         start = (unsigned char *) "\xE2\x80\x98"; /* ‘ */
+       subst_quote:
+         length = 1;
+         length_byte = 3;
+         idx = strp - SDATA (string) + 1;
+         goto subst;
+       }
+      else if (strp[0] == '\'' && in_quote)
+       {
+         in_quote = false;
+         start = (unsigned char *) "\xE2\x80\x99"; /* ’ */
+         goto subst_quote;
+       }
       else if (! multibyte)            /* just copy other chars */
        *bufp++ = *strp++, nchars++;
       else