diff options
| author | Eli Zaretskii | 2025-10-09 12:07:57 +0300 |
|---|---|---|
| committer | Eli Zaretskii | 2025-10-09 12:07:57 +0300 |
| commit | 5a70f5096eafb9bf2ea5b2e798293def1a8cf404 (patch) | |
| tree | cae03524b0f46464ba2791b2802eaff16b6f0047 /src | |
| parent | 73423a1e0e98534512f63929e174a8578a1ac4f2 (diff) | |
| download | emacs-5a70f5096eafb9bf2ea5b2e798293def1a8cf404.tar.gz emacs-5a70f5096eafb9bf2ea5b2e798293def1a8cf404.zip | |
Fix text-terminal output with UTF-8 encoding on MS-Windows
* src/w32console.c (w32con_write_glyphs)
(w32con_write_glyphs_with_face): Support UTF-8 encoded text
better, by counting characters and using display columns, not
bytes, to move the cursor after writing the text. (Bug#79298)
Diffstat (limited to 'src')
| -rw-r--r-- | src/w32console.c | 38 |
1 files changed, 30 insertions, 8 deletions
diff --git a/src/w32console.c b/src/w32console.c index 1bca0cadff9..30f511d93f9 100644 --- a/src/w32console.c +++ b/src/w32console.c | |||
| @@ -351,10 +351,23 @@ w32con_write_glyphs (struct frame *f, register struct glyph *string, | |||
| 351 | conversion_buffer = (LPCSTR) encode_terminal_code (string, n, coding); | 351 | conversion_buffer = (LPCSTR) encode_terminal_code (string, n, coding); |
| 352 | if (coding->produced > 0) | 352 | if (coding->produced > 0) |
| 353 | { | 353 | { |
| 354 | /* By default, assume single-byte encoding and single-column | ||
| 355 | characters... */ | ||
| 356 | ptrdiff_t nchars = coding->produced; | ||
| 357 | ptrdiff_t ncols = nchars; | ||
| 358 | /* ...but if we are using UTF-8, correct that by computing | ||
| 359 | characters. Note: multibyte_chars_in_text and strwidth | ||
| 360 | handle the internal encoding of characters, which is a | ||
| 361 | superset of UTF-8. | ||
| 362 | FIXME: this doesn't handle character compositions. */ | ||
| 363 | if (coding->encoder == encode_coding_utf_8) | ||
| 364 | { | ||
| 365 | ncols = strwidth (conversion_buffer, nchars); | ||
| 366 | nchars = multibyte_chars_in_text (conversion_buffer, nchars); | ||
| 367 | } | ||
| 354 | /* Set the attribute for these characters. */ | 368 | /* Set the attribute for these characters. */ |
| 355 | if (!FillConsoleOutputAttribute (cur_screen, char_attr, | 369 | if (!FillConsoleOutputAttribute (cur_screen, char_attr, nchars, |
| 356 | coding->produced, cursor_coords, | 370 | cursor_coords, &r)) |
| 357 | &r)) | ||
| 358 | { | 371 | { |
| 359 | printf ("Failed writing console attributes: %lu\n", | 372 | printf ("Failed writing console attributes: %lu\n", |
| 360 | GetLastError ()); | 373 | GetLastError ()); |
| @@ -371,7 +384,7 @@ w32con_write_glyphs (struct frame *f, register struct glyph *string, | |||
| 371 | fflush (stdout); | 384 | fflush (stdout); |
| 372 | } | 385 | } |
| 373 | 386 | ||
| 374 | cursor_coords.X += coding->produced; | 387 | cursor_coords.X += ncols; |
| 375 | w32con_move_cursor (f, cursor_coords.Y, cursor_coords.X); | 388 | w32con_move_cursor (f, cursor_coords.Y, cursor_coords.X); |
| 376 | } | 389 | } |
| 377 | len -= n; | 390 | len -= n; |
| @@ -407,19 +420,28 @@ w32con_write_glyphs_with_face (struct frame *f, register int x, register int y, | |||
| 407 | /* Compute the character attributes corresponding to the face. */ | 420 | /* Compute the character attributes corresponding to the face. */ |
| 408 | DWORD char_attr = w32_face_attributes (f, face_id); | 421 | DWORD char_attr = w32_face_attributes (f, face_id); |
| 409 | COORD start_coords; | 422 | COORD start_coords; |
| 423 | /* By default, assume single-byte encoding... */ | ||
| 424 | ptrdiff_t nchars = coding->produced; | ||
| 425 | /* ...but if we are using UTF-8, correct that by counting | ||
| 426 | characters. Note: multibyte_chars_in_text handles the | ||
| 427 | internal encoding of characters, which is a superset of | ||
| 428 | UTF-8. | ||
| 429 | FIXME: this doesn't handle character compositions. */ | ||
| 430 | if (coding->encoder == encode_coding_utf_8) | ||
| 431 | nchars = multibyte_chars_in_text (conversion_buffer, nchars); | ||
| 410 | 432 | ||
| 411 | start_coords.X = x; | 433 | start_coords.X = x; |
| 412 | start_coords.Y = y; | 434 | start_coords.Y = y; |
| 413 | /* Set the attribute for these characters. */ | 435 | /* Set the attribute for these characters. */ |
| 414 | if (!FillConsoleOutputAttribute (cur_screen, char_attr, | 436 | if (!FillConsoleOutputAttribute (cur_screen, char_attr, nchars, |
| 415 | coding->produced, start_coords, | 437 | start_coords, &filled)) |
| 416 | &filled)) | ||
| 417 | DebPrint (("Failed writing console attributes: %d\n", GetLastError ())); | 438 | DebPrint (("Failed writing console attributes: %d\n", GetLastError ())); |
| 418 | else | 439 | else |
| 419 | { | 440 | { |
| 420 | /* Write the characters. */ | 441 | /* Write the characters. */ |
| 421 | if (!WriteConsoleOutputCharacter (cur_screen, conversion_buffer, | 442 | if (!WriteConsoleOutputCharacter (cur_screen, conversion_buffer, |
| 422 | filled, start_coords, &written)) | 443 | coding->produced, start_coords, |
| 444 | &written)) | ||
| 423 | DebPrint (("Failed writing console characters: %d\n", | 445 | DebPrint (("Failed writing console characters: %d\n", |
| 424 | GetLastError ())); | 446 | GetLastError ())); |
| 425 | } | 447 | } |