APPROVE COMMIT
NOTE: This patch has been committed
# HG changeset patch
# User Aidan Kehoe <kehoea(a)parhasard.net>
# Date 1492621216 -3600
# Wed Apr 19 18:00:16 2017 +0100
# Node ID 513b2ed98e3ea153c0e65bce5a93994c48d10b42
# Parent 74b4d4c11264e149d03d748b9c34f253a69801bf
Sync API of #'generate-new-buffer-name with GNU. Thank you GNU!
src/ChangeLog addition:
2017-04-19 Aidan Kehoe <kehoea(a)parhasard.net>
* buffer.c:
* buffer.c (get_buffer):
Vbuffer_alist is an internal list, no need to GCPRO and call
Fassoc.
* buffer.c (Fgenerate_new_buffer_name):
Update this to match GNU's current API; if NAME starts with a
space, generate the candidate new buffer names using get_random(),
start with suffixes of <2> rather than <1>.
Don't make new Lisp strings or call get_buffer() in the loop.
Copy string extent info to the new buffer name if NAME has extent
info.
man/ChangeLog addition:
2017-04-19 Aidan Kehoe <kehoea(a)parhasard.net>
* lispref/buffers.texi (Buffer Names):
Update documentation on #'generate-new-buffer-name to reflect
changes made to it today.
diff -r 74b4d4c11264 -r 513b2ed98e3e man/ChangeLog
--- a/man/ChangeLog Sun Mar 19 23:27:07 2017 +0000
+++ b/man/ChangeLog Wed Apr 19 18:00:16 2017 +0100
@@ -1,3 +1,9 @@
+2017-04-19 Aidan Kehoe <kehoea(a)parhasard.net>
+
+ * lispref/buffers.texi (Buffer Names):
+ Update documentation on #'generate-new-buffer-name to reflect
+ changes made to it today.
+
2017-03-09 Aidan Kehoe <kehoea(a)parhasard.net>
* widget.texi (Introduction):
diff -r 74b4d4c11264 -r 513b2ed98e3e man/lispref/buffers.texi
--- a/man/lispref/buffers.texi Sun Mar 19 23:27:07 2017 +0000
+++ b/man/lispref/buffers.texi Wed Apr 19 18:00:16 2017 +0100
@@ -293,10 +293,13 @@
This function returns a name that would be unique for a new buffer---but
does not create the buffer. It starts with @var{starting-name}, and
produces a name not currently in use for any buffer by appending a
-number inside of @samp{<@dots{}>}.
+number inside of @samp{<@dots{}>}. The numbers appended start at 2, or
+at a random value if @var{starting-name} begins with the space
+character, which indicates that a buffer is not visible to users.
-If @var{ignore} is given, it specifies a name that is okay to use (if it
-is in the sequence to be tried), even if a buffer with that name exists.
+If @var{ignore} is given, it should be a string. This means to consider
+@var{ignore} as an acceptable buffer name, even if a buffer of that name
+already exists.
See the related function @code{generate-new-buffer} in @ref{Creating
Buffers}.
diff -r 74b4d4c11264 -r 513b2ed98e3e src/ChangeLog
--- a/src/ChangeLog Sun Mar 19 23:27:07 2017 +0000
+++ b/src/ChangeLog Wed Apr 19 18:00:16 2017 +0100
@@ -1,3 +1,17 @@
+2017-04-19 Aidan Kehoe <kehoea(a)parhasard.net>
+
+ * buffer.c:
+ * buffer.c (get_buffer):
+ Vbuffer_alist is an internal list, no need to GCPRO and call
+ Fassoc.
+ * buffer.c (Fgenerate_new_buffer_name):
+ Update this to match GNU's current API; if NAME starts with a
+ space, generate the candidate new buffer names using get_random(),
+ start with suffixes of <2> rather than <1>.
+ Don't make new Lisp strings or call get_buffer() in the loop.
+ Copy string extent info to the new buffer name if NAME has extent
+ info.
+
2017-03-19 Aidan Kehoe <kehoea(a)parhasard.net>
* gc.c (GC_CONS_THRESHOLD):
diff -r 74b4d4c11264 -r 513b2ed98e3e src/buffer.c
--- a/src/buffer.c Sun Mar 19 23:27:07 2017 +0000
+++ b/src/buffer.c Wed Apr 19 18:00:16 2017 +0100
@@ -395,13 +395,11 @@
else
{
Lisp_Object buf;
- struct gcpro gcpro1;
CHECK_STRING (name);
name = LISP_GETTEXT (name);
- GCPRO1 (name);
- buf = Fcdr (Fassoc (name, Vbuffer_alist));
- UNGCPRO;
+ buf = Fcdr (assoc_no_quit (name, Vbuffer_alist));
+
if (NILP (buf) && error_if_deleted_or_does_not_exist)
nsberror (name);
return buf;
@@ -770,43 +768,98 @@
Return a string that is the name of no existing buffer based on NAME.
If there is no live buffer named NAME, then return NAME.
Otherwise modify name by appending `<NUMBER>', incrementing NUMBER
-until an unused name is found, and then return that name.
-Optional second argument IGNORE specifies a name that is okay to use
-\(if it is in the sequence to be tried)
-even if a buffer with that name exists.
+\(starting at 2) until an unused name is found, and then return that name.
+
+Optional second argument IGNORE specifies a name that is okay to use (if it
+is in the sequence to be tried) even if a buffer with that name exists.
+
+If NAME begins with a space (i.e., a buffer that is not normally
+visible to users), then if buffer NAME already exists a random number
+is first appended to NAME, to speed up finding a non-existent buffer.
*/
(name, ignore))
{
- REGISTER Lisp_Object gentemp, tem;
- int count;
- Ibyte number[10];
+ Ibyte *candidate;
+ Bytecount csize, clen, ignore_length = -1;
+ EMACS_INT count;
CHECK_STRING (name);
- name = LISP_GETTEXT (name);
#ifdef I18N3
/* #### Doc string should indicate that the buffer name will get
translated. */
#endif
-
- tem = Fget_buffer (name);
- if (NILP (tem))
- return name;
-
- count = 1;
+ name = LISP_GETTEXT (name);
+
+ if (!NILP (ignore))
+ {
+ CHECK_STRING (ignore);
+ ignore_length = XSTRING_LENGTH (ignore);
+
+ if (ignore_length == XSTRING_LENGTH (name)
+ && !qxememcmp (XSTRING_DATA (name), XSTRING_DATA (ignore),
+ ignore_length))
+ {
+ return name;
+ }
+ }
+
+ if (NILP (Fget_buffer (name))) /* XEmacs; don't #'string-equal on nil, see
+ above for the IGNORE handling. */
+ {
+ return name;
+ }
+
+ csize = XSTRING_LENGTH (name) + DECIMAL_PRINT_SIZE (EMACS_INT)
+ + sizeof ("<>");
+ candidate = alloca_ibytes (csize);
+
+ count = itext_ichar_eql (XSTRING_DATA (name), ' ') ? get_random () : 2;
while (1)
{
- qxesprintf (number, "<%d>", ++count);
- gentemp = concat2 (name, build_istring (number));
- if (!NILP (ignore))
+ /* XEmacs; GNU worry about the performance of this function, and then
+ allocate a full new Lisp string on the heap for every iteration of
+ the loop, and call a full Fget_buffer, too. If the performance of
+ #'generate-new-buffer-name really matters--and I've seen no real
+ evidence that is the case--the approach below with snprintf() and
+ ALIST_LOOP_3() is better. */
+ clen = emacs_snprintf (candidate, csize, "%s<%ld>", XSTRING_DATA
(name),
+ ++count);
+ if (clen == ignore_length &&
+ !qxememcmp (candidate, XSTRING_DATA (ignore), clen))
{
- tem = Fstring_equal (gentemp, ignore);
- if (!NILP (tem))
- return gentemp;
+ return ignore;
}
- tem = Fget_buffer (gentemp);
- if (NILP (tem))
- return gentemp;
+ else
+ {
+ Boolint seen = 0;
+ ALIST_LOOP_3 (bufname, bufobj, Vbuffer_alist)
+ {
+ if (XSTRING_LENGTH (bufname) == clen
+ && !qxememcmp (candidate, XSTRING_DATA (bufname), clen))
+ {
+ seen = 1;
+ break;
+ }
+ }
+
+ USED (bufobj); /* Silence warning for this. */
+
+ if (!seen)
+ {
+ Lisp_Object result = make_string (candidate, clen);
+
+ if (string_extent_info (name) != NULL)
+ {
+ /* Despite what other code thinks, stretch_string_extents()
+ doesn't call Lisp, this is OK from the GC perspective. */
+ stretch_string_extents (result, name, 0, 0,
+ XSTRING_LENGTH (name), clen);
+ }
+
+ return result;
+ }
+ }
}
}
--
‘As I sat looking up at the Guinness ad, I could never figure out /
How your man stayed up on the surfboard after forty pints of stout’
(C. Moore)