Skip to content

Commit b699f0b

Browse files
committed
Support wcwidth_l with xlocale_wrapper.
1 parent e80410e commit b699f0b

File tree

5 files changed

+77
-1
lines changed

5 files changed

+77
-1
lines changed

Package.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,14 @@ let _: Package =
2020
],
2121
targets: [
2222
.target(name: "libunistring"),
23+
.target(name: "xlocale_wrapper"),
2324
.target(name: "Geometry"),
2425
.target(name: "Primitives"),
2526
.target(name: "VirtualTerminal", dependencies: [
2627
.target(name: "Geometry"),
2728
.target(name: "Primitives"),
2829
.target(name: "libunistring", condition: .when(traits: ["GNU"])),
30+
.target(name: "xlocale_wrapper"),
2931
.product(name: "POSIXCore", package: "swift-platform-core", condition: .when(platforms: [.macOS, .linux])),
3032
.product(name: "WindowsCore", package: "swift-platform-core", condition: .when(platforms: [.windows])),
3133
]),

Sources/VirtualTerminal/Buffer/TextMetrics.swift

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,22 @@
44
#if os(Windows)
55
import WindowsCore
66
#else
7+
import POSIXCore
8+
import Synchronization
9+
#if canImport(Darwin)
10+
import Darwin
11+
import xlocale_wrapper
12+
#elseif canImport(Glibc)
13+
import Glibc
14+
#endif
715
#if GNU
816
import libunistring
917
#endif
1018
import POSIXCore
1119
import Synchronization
20+
#endif
1221

22+
#if canImport(Glibc)
1323
private enum Locale {
1424
private static let utf8: Mutex<locale_t?> = Mutex(nil)
1525

@@ -21,7 +31,18 @@ private enum Locale {
2131
}
2232
}
2333
}
34+
#elseif canImport(Darwin)
35+
private enum Locale {
36+
private static let utf8: Mutex<UnsafeMutableRawPointer?> = Mutex(nil)
2437

38+
static var ID_UTF8: UnsafeMutableRawPointer? {
39+
return utf8.withLock { locale in
40+
if let locale { return locale }
41+
locale = vt_newlocale(LC_CTYPE_MASK, "en_US.UTF-8", nil)
42+
return locale
43+
}
44+
}
45+
}
2546
#endif
2647

2748
extension UnicodeScalar {
@@ -87,12 +108,14 @@ extension UnicodeScalar {
87108
// Normal width character -> 1
88109
// Wide character (CJK, etc.) -> 2
89110
return max(1, Int(uc_width(UInt32(value), "C.UTF-8")))
90-
#else
111+
#elseif canImport(Glibc)
91112
// Control character or invalid - zero width -> -1
92113
// Zero-width character (combining marks, etc.) -> 0
93114
// Normal width character -> 1
94115
// Wide character (CJK, etc.) -> 2
95116
return max(1, Int(wcwidth_l(wchar_t(value), Locale.ID_UTF8)))
117+
#else
118+
return max(1, Int(vt_wcwidth_l(wchar_t(value), Locale.ID_UTF8)))
96119
#endif
97120
}
98121
}

Sources/VirtualTerminal/Platform/POSIXTerminal.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@
66
import Geometry
77
import POSIXCore
88
import Synchronization
9+
#if !GNU
10+
import unistd
11+
#endif
912

1013
/// POSIX/Unix terminal implementation using standard file descriptors.
1114
///
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/* Copyright © 2025 Saleem Abdulrasool <compnerd@compnerd.org> */
2+
/* SPDX-License-Identifier: BSD-3-Clause */
3+
4+
#ifndef xlocale_wrapper_h
5+
#define xlocale_wrapper_h
6+
7+
#include <wchar.h>
8+
9+
#ifdef __cplusplus
10+
extern "C" {
11+
#endif
12+
13+
// Wrapper functions for xlocale functionality
14+
int vt_wcwidth_l(wchar_t wc, void *locale);
15+
void *vt_newlocale(int mask, const char *locale, void *base);
16+
void vt_freelocale(void *locale);
17+
18+
// Constants
19+
#if __APPLE__
20+
#define LC_CTYPE_MASK (1 << 1)
21+
#endif
22+
23+
#ifdef __cplusplus
24+
}
25+
#endif
26+
27+
#endif /* xlocale_wrapper_h */
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
/* Copyright © 2025 Saleem Abdulrasool <compnerd@compnerd.org> */
2+
/* SPDX-License-Identifier: BSD-3-Clause */
3+
4+
#include <wchar.h>
5+
#include <xlocale.h>
6+
7+
int vt_wcwidth_l(wchar_t wc, void *locale) {
8+
return wcwidth_l(wc, (locale_t)locale);
9+
}
10+
11+
void *vt_newlocale(int mask, const char *locale, void *base) {
12+
return newlocale(mask, locale, (locale_t)base);
13+
}
14+
15+
void vt_freelocale(void *locale) {
16+
freelocale((locale_t)locale);
17+
}
18+
19+
#if __APPLE__
20+
#define LC_CTYPE_MASK (1 << 1)
21+
#endif

0 commit comments

Comments
 (0)