diff --git a/guix/build/syscalls.scm b/guix/build/syscalls.scm index b845b8aab9..b29b6f78b6 100644 --- a/guix/build/syscalls.scm +++ b/guix/build/syscalls.scm @@ -192,6 +192,7 @@ terminal-window-size terminal-columns terminal-rows + terminal-string-width openpty login-tty @@ -2336,6 +2337,20 @@ PORT, trying to guess a reasonable value if all else fails. The result is always a positive integer." (terminal-dimension window-size-rows port (const 25))) +(define terminal-string-width + (let ((mbstowcs (syscall->procedure int "mbstowcs" (list '* '* size_t))) + (wcswidth (syscall->procedure int "wcswidth" (list '* size_t)))) + (lambda (str) + "Return the width of a string as it would be printed on the terminal. +This procedure accounts for characters that have a different width than 1, such +as CJK double-width characters." + (let ((wchar (make-bytevector (* (+ (string-length str) 1) 4)))) + (mbstowcs (bytevector->pointer wchar) + (string->pointer str) + (string-length str)) + (wcswidth (bytevector->pointer wchar) + (string-length str)))))) + (define openpty (let ((proc (syscall->procedure int "openpty" '(* * * * *) #:library "libutil"))) diff --git a/tests/syscalls.scm b/tests/syscalls.scm index c9e011f453..eb85b358c4 100644 --- a/tests/syscalls.scm +++ b/tests/syscalls.scm @@ -583,6 +583,12 @@ (test-assert "terminal-rows" (> (terminal-rows) 0)) +(test-assert "terminal-string-width English" + (= (terminal-string-width "hello") 5)) + +(test-assert "terminal-string-width Japanese" + (= (terminal-string-width "今日は") 6)) + (test-assert "openpty" (let ((head inferior (openpty))) (and (integer? head) (integer? inferior)