diff options
| author | Eli Zaretskii | 2021-04-14 11:47:55 +0300 |
|---|---|---|
| committer | Eli Zaretskii | 2021-04-14 11:47:55 +0300 |
| commit | d1559ede54684513b79025ade2b4677447c7a487 (patch) | |
| tree | 5bbb4c12e05a3ea4f260d204f3f8e9b854d5a22d /src | |
| parent | 844b8949a71f180d395a237c768b22d91cf91ded (diff) | |
| download | emacs-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.c | 56 | ||||
| -rw-r--r-- | src/character.h | 4 | ||||
| -rw-r--r-- | src/editfns.c | 9 |
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 | ||
| 331 | ptrdiff_t | 333 | ptrdiff_t |
| 332 | lisp_string_width (Lisp_Object string, ptrdiff_t precision, | 334 | lisp_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 | ||
| 397 | DEFUN ("string-width", Fstring_width, Sstring_width, 1, 1, 0, | 401 | DEFUN ("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. |
| 399 | Width is measured by how many columns it occupies on the screen. | 403 | Width is measured by how many columns it occupies on the screen. |
| 404 | Optional arguments FROM and TO specify the substring of STRING to | ||
| 405 | consider, and are interpreted as in `substring'. | ||
| 406 | |||
| 400 | When calculating width of a multibyte character in STRING, | 407 | When calculating width of a multibyte character in STRING, |
| 401 | only the base leading-code is considered; the validity of | 408 | only the base leading-code is considered; the validity of |
| 402 | the following bytes is not checked. Tabs in STRING are always | 409 | the following bytes is not checked. Tabs in STRING are always |
| 403 | taken to occupy `tab-width' columns. | 410 | taken to occupy `tab-width' columns. The effect of faces and fonts |
| 404 | usage: (string-width STRING) */) | 411 | used for non-Latin and other unusual characters (such as emoji) is |
| 405 | (Lisp_Object str) | 412 | ignored as well, as are display properties and invisible text. |
| 413 | For these reasons, the results are not generally reliable; | ||
| 414 | for accurate dimensions of text as it will be displayed, | ||
| 415 | use `window-text-pixel-size' instead. | ||
| 416 | usage: (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 *, | |||
| 572 | extern ptrdiff_t strwidth (const char *, ptrdiff_t); | 572 | extern ptrdiff_t strwidth (const char *, ptrdiff_t); |
| 573 | extern ptrdiff_t c_string_width (const unsigned char *, ptrdiff_t, int, | 573 | extern ptrdiff_t c_string_width (const unsigned char *, ptrdiff_t, int, |
| 574 | ptrdiff_t *, ptrdiff_t *); | 574 | ptrdiff_t *, ptrdiff_t *); |
| 575 | extern ptrdiff_t lisp_string_width (Lisp_Object, ptrdiff_t, | 575 | extern 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 | ||
| 578 | extern Lisp_Object Vchar_unify_table; | 578 | extern Lisp_Object Vchar_unify_table; |
| 579 | extern Lisp_Object string_escape_byte8 (Lisp_Object); | 579 | extern 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; |