aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorEli Zaretskii2021-04-14 11:47:55 +0300
committerEli Zaretskii2021-04-14 11:47:55 +0300
commitd1559ede54684513b79025ade2b4677447c7a487 (patch)
tree5bbb4c12e05a3ea4f260d204f3f8e9b854d5a22d /src
parent844b8949a71f180d395a237c768b22d91cf91ded (diff)
downloademacs-d1559ede54684513b79025ade2b4677447c7a487.tar.gz
emacs-d1559ede54684513b79025ade2b4677447c7a487.zip
Add two optional arguments to 'string-width'
* src/character.c (Fstring_width, lisp_string_width): Accept two optional arguments FROM and TO, to indicate the substring to be considered. (Fstring_width): Add caveats in the doc string about display features ignored by the function. (Bug#47712) * src/character.h (lisp_string_width): Update prototype. * src/editfns.c (styled_format): Adjust call of lisp_string_width to its changed signature. * test/src/character-tests.el (character-test-string-width): New file with tests for 'string-width'. * doc/lispref/display.texi (Size of Displayed Text): Document caveats of using 'string-width'. * etc/NEWS: Announce the change.
Diffstat (limited to 'src')
-rw-r--r--src/character.c56
-rw-r--r--src/character.h4
-rw-r--r--src/editfns.c9
3 files changed, 41 insertions, 28 deletions
diff --git a/src/character.c b/src/character.c
index a599a0355f4..41abb83a48b 100644
--- a/src/character.c
+++ b/src/character.c
@@ -321,28 +321,32 @@ strwidth (const char *str, ptrdiff_t len)
321 return c_string_width ((const unsigned char *) str, len, -1, NULL, NULL); 321 return c_string_width ((const unsigned char *) str, len, -1, NULL, NULL);
322} 322}
323 323
324/* Return width of Lisp string STRING when displayed in the current 324/* Return width of a (substring of a) Lisp string STRING when
325 buffer. The width is measured by how many columns it occupies on 325 displayed in the current buffer. The width is measured by how many
326 the screen while paying attention to compositions. If PRECISION > 326 columns it occupies on the screen while paying attention to
327 0, return the width of longest substring that doesn't exceed 327 compositions. If PRECISION > 0, return the width of longest
328 PRECISION, and set number of characters and bytes of the substring 328 substring that doesn't exceed PRECISION, and set number of
329 in *NCHARS and *NBYTES respectively. */ 329 characters and bytes of the substring in *NCHARS and *NBYTES
330 respectively. FROM and TO are zero-based character indices
331 that define the substring of STRING to consider. */
330 332
331ptrdiff_t 333ptrdiff_t
332lisp_string_width (Lisp_Object string, ptrdiff_t precision, 334lisp_string_width (Lisp_Object string, ptrdiff_t from, ptrdiff_t to,
333 ptrdiff_t *nchars, ptrdiff_t *nbytes) 335 ptrdiff_t precision, ptrdiff_t *nchars, ptrdiff_t *nbytes)
334{ 336{
335 ptrdiff_t len = SCHARS (string);
336 /* This set multibyte to 0 even if STRING is multibyte when it 337 /* This set multibyte to 0 even if STRING is multibyte when it
337 contains only ascii and eight-bit-graphic, but that's 338 contains only ascii and eight-bit-graphic, but that's
338 intentional. */ 339 intentional. */
339 bool multibyte = len < SBYTES (string); 340 bool multibyte = SCHARS (string) < SBYTES (string);
340 unsigned char *str = SDATA (string); 341 unsigned char *str = SDATA (string);
341 ptrdiff_t i = 0, i_byte = 0; 342 ptrdiff_t i = from, i_byte = from ? string_char_to_byte (string, from) : 0;
343 ptrdiff_t from_byte = i_byte;
342 ptrdiff_t width = 0; 344 ptrdiff_t width = 0;
343 struct Lisp_Char_Table *dp = buffer_display_table (); 345 struct Lisp_Char_Table *dp = buffer_display_table ();
344 346
345 while (i < len) 347 eassert (precision <= 0 || (nchars && nbytes));
348
349 while (i < to)
346 { 350 {
347 ptrdiff_t chars, bytes, thiswidth; 351 ptrdiff_t chars, bytes, thiswidth;
348 Lisp_Object val; 352 Lisp_Object val;
@@ -375,8 +379,8 @@ lisp_string_width (Lisp_Object string, ptrdiff_t precision,
375 379
376 if (0 < precision && precision - width < thiswidth) 380 if (0 < precision && precision - width < thiswidth)
377 { 381 {
378 *nchars = i; 382 *nchars = i - from;
379 *nbytes = i_byte; 383 *nbytes = i_byte - from_byte;
380 return width; 384 return width;
381 } 385 }
382 if (INT_ADD_WRAPV (thiswidth, width, &width)) 386 if (INT_ADD_WRAPV (thiswidth, width, &width))
@@ -387,27 +391,37 @@ lisp_string_width (Lisp_Object string, ptrdiff_t precision,
387 391
388 if (precision > 0) 392 if (precision > 0)
389 { 393 {
390 *nchars = i; 394 *nchars = i - from;
391 *nbytes = i_byte; 395 *nbytes = i_byte - from_byte;
392 } 396 }
393 397
394 return width; 398 return width;
395} 399}
396 400
397DEFUN ("string-width", Fstring_width, Sstring_width, 1, 1, 0, 401DEFUN ("string-width", Fstring_width, Sstring_width, 1, 3, 0,
398 doc: /* Return width of STRING when displayed in the current buffer. 402 doc: /* Return width of STRING when displayed in the current buffer.
399Width is measured by how many columns it occupies on the screen. 403Width is measured by how many columns it occupies on the screen.
404Optional arguments FROM and TO specify the substring of STRING to
405consider, and are interpreted as in `substring'.
406
400When calculating width of a multibyte character in STRING, 407When calculating width of a multibyte character in STRING,
401only the base leading-code is considered; the validity of 408only the base leading-code is considered; the validity of
402the following bytes is not checked. Tabs in STRING are always 409the following bytes is not checked. Tabs in STRING are always
403taken to occupy `tab-width' columns. 410taken to occupy `tab-width' columns. The effect of faces and fonts
404usage: (string-width STRING) */) 411used for non-Latin and other unusual characters (such as emoji) is
405 (Lisp_Object str) 412ignored as well, as are display properties and invisible text.
413For these reasons, the results are not generally reliable;
414for accurate dimensions of text as it will be displayed,
415use `window-text-pixel-size' instead.
416usage: (string-width STRING &optional FROM TO) */)
417 (Lisp_Object str, Lisp_Object from, Lisp_Object to)
406{ 418{
407 Lisp_Object val; 419 Lisp_Object val;
420 ptrdiff_t ifrom, ito;
408 421
409 CHECK_STRING (str); 422 CHECK_STRING (str);
410 XSETFASTINT (val, lisp_string_width (str, -1, NULL, NULL)); 423 validate_subarray (str, from, to, SCHARS (str), &ifrom, &ito);
424 XSETFASTINT (val, lisp_string_width (str, ifrom, ito, -1, NULL, NULL));
411 return val; 425 return val;
412} 426}
413 427
diff --git a/src/character.h b/src/character.h
index cbf43097ae2..d19e1e2604c 100644
--- a/src/character.h
+++ b/src/character.h
@@ -572,8 +572,8 @@ extern ptrdiff_t str_to_unibyte (const unsigned char *, unsigned char *,
572extern ptrdiff_t strwidth (const char *, ptrdiff_t); 572extern ptrdiff_t strwidth (const char *, ptrdiff_t);
573extern ptrdiff_t c_string_width (const unsigned char *, ptrdiff_t, int, 573extern ptrdiff_t c_string_width (const unsigned char *, ptrdiff_t, int,
574 ptrdiff_t *, ptrdiff_t *); 574 ptrdiff_t *, ptrdiff_t *);
575extern ptrdiff_t lisp_string_width (Lisp_Object, ptrdiff_t, 575extern ptrdiff_t lisp_string_width (Lisp_Object, ptrdiff_t, ptrdiff_t,
576 ptrdiff_t *, ptrdiff_t *); 576 ptrdiff_t, ptrdiff_t *, ptrdiff_t *);
577 577
578extern Lisp_Object Vchar_unify_table; 578extern Lisp_Object Vchar_unify_table;
579extern Lisp_Object string_escape_byte8 (Lisp_Object); 579extern Lisp_Object string_escape_byte8 (Lisp_Object);
diff --git a/src/editfns.c b/src/editfns.c
index 87e743afc31..bc73c1e2c5b 100644
--- a/src/editfns.c
+++ b/src/editfns.c
@@ -3386,12 +3386,11 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message)
3386 else 3386 else
3387 { 3387 {
3388 ptrdiff_t nch, nby; 3388 ptrdiff_t nch, nby;
3389 width = lisp_string_width (arg, prec, &nch, &nby); 3389 nchars_string = SCHARS (arg);
3390 width = lisp_string_width (arg, 0, nchars_string, prec,
3391 &nch, &nby);
3390 if (prec < 0) 3392 if (prec < 0)
3391 { 3393 nbytes = SBYTES (arg);
3392 nchars_string = SCHARS (arg);
3393 nbytes = SBYTES (arg);
3394 }
3395 else 3394 else
3396 { 3395 {
3397 nchars_string = nch; 3396 nchars_string = nch;