pi-tui-status-beautifier 1.1.2 → 1.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -247,75 +247,88 @@ export function beautifyStatus(
|
|
|
247
247
|
|
|
248
248
|
/**
|
|
249
249
|
* Calculates the visual column cell width of a string (Finding 5), taking into account
|
|
250
|
-
* full-width Unicode characters, East Asian
|
|
250
|
+
* full-width Unicode characters, East Asian ideographs, Kana, Hangul, emojis, and zero-width joiners.
|
|
251
251
|
*/
|
|
252
252
|
export function getStringWidth(str: string): number {
|
|
253
253
|
if (!str) return 0;
|
|
254
|
-
// Strip ANSI escape sequences & control codes before counting visual width
|
|
255
254
|
const clean = str.replace(ANSI_STRIP_REGEX, "");
|
|
256
255
|
let width = 0;
|
|
257
|
-
|
|
258
|
-
|
|
256
|
+
|
|
257
|
+
for (const char of clean) {
|
|
258
|
+
const code = char.codePointAt(0) || 0;
|
|
259
|
+
|
|
260
|
+
// Zero-width characters (ZWJ, variation selectors, combining marks)
|
|
261
|
+
if (
|
|
262
|
+
code === 0x200d ||
|
|
263
|
+
code === 0xfe0f ||
|
|
264
|
+
code === 0xfe0e ||
|
|
265
|
+
(code >= 0x0300 && code <= 0x036f) ||
|
|
266
|
+
(code >= 0x200b && code <= 0x200f)
|
|
267
|
+
) {
|
|
268
|
+
continue;
|
|
269
|
+
}
|
|
270
|
+
|
|
259
271
|
if (isFullWidth(code)) {
|
|
260
272
|
width += 2;
|
|
261
273
|
} else {
|
|
262
274
|
width += 1;
|
|
263
275
|
}
|
|
264
276
|
}
|
|
277
|
+
|
|
265
278
|
return width;
|
|
266
279
|
}
|
|
267
280
|
|
|
268
281
|
/**
|
|
269
282
|
* Checks if a character unicode code point is full-width (East Asian Width).
|
|
270
283
|
*/
|
|
271
|
-
function isFullWidth(code: number): boolean {
|
|
284
|
+
export function isFullWidth(code: number): boolean {
|
|
272
285
|
if (isNaN(code)) return false;
|
|
273
286
|
return (
|
|
274
|
-
code >= 0x1100 &&
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
(code >= 0xff01 && code <= 0xff60) ||
|
|
296
|
-
(code >= 0xffe0 && code <= 0xffe6) ||
|
|
297
|
-
// East Asian Wide characters beyond BMP
|
|
298
|
-
(code >= 0x1b000 && code <= 0x1b001) ||
|
|
299
|
-
(code >= 0x1f200 && code <= 0x1f251) ||
|
|
300
|
-
(code >= 0x20000 && code <= 0x3fffd))
|
|
287
|
+
(code >= 0x1100 && code <= 0x115f) || // Hangul Jamo
|
|
288
|
+
code === 0x2329 ||
|
|
289
|
+
code === 0x232a ||
|
|
290
|
+
(code >= 0x2e80 && code <= 0x3247 && code !== 0x303f) || // CJK Radicals
|
|
291
|
+
(code >= 0x3040 && code <= 0x309f) || // Hiragana
|
|
292
|
+
(code >= 0x30a0 && code <= 0x30ff) || // Katakana
|
|
293
|
+
(code >= 0x3250 && code <= 0x4dbf) || // CJK Extension A
|
|
294
|
+
(code >= 0x4e00 && code <= 0xa4c6) || // CJK Unified Ideographs .. Yi
|
|
295
|
+
(code >= 0xa960 && code <= 0xa97c) || // Hangul Jamo Extended-A
|
|
296
|
+
(code >= 0xac00 && code <= 0xd7af) || // Hangul Syllables
|
|
297
|
+
(code >= 0xf900 && code <= 0xfaff) || // CJK Compatibility Ideographs
|
|
298
|
+
(code >= 0xfe10 && code <= 0xfe19) || // Vertical Forms
|
|
299
|
+
(code >= 0xfe30 && code <= 0xfe6b) || // CJK Compatibility Forms
|
|
300
|
+
(code >= 0xff01 && code <= 0xff60) || // Fullwidth Forms
|
|
301
|
+
(code >= 0xffe0 && code <= 0xffe6) || // Fullwidth Symbols
|
|
302
|
+
(code >= 0x1f300 && code <= 0x1f9ff) || // Emojis & Pictographs
|
|
303
|
+
(code >= 0x1f600 && code <= 0x1f64f) || // Emoticons
|
|
304
|
+
(code >= 0x1f680 && code <= 0x1f6ff) || // Transport & Map
|
|
305
|
+
(code >= 0x2600 && code <= 0x27bf) || // Dingbats & Misc
|
|
306
|
+
(code >= 0x1fa70 && code <= 0x1faff) || // Symbols Extended-A
|
|
307
|
+
(code >= 0x20000 && code <= 0x3fffd) // CJK Extensions B/C/D
|
|
301
308
|
);
|
|
302
309
|
}
|
|
303
310
|
|
|
304
311
|
/**
|
|
305
|
-
* Slices a string to a maximum visual cell width.
|
|
312
|
+
* Slices a string to a maximum visual cell width without cutting surrogate pairs in half.
|
|
306
313
|
*/
|
|
307
314
|
export function sliceToVisualWidth(str: string, maxWidth: number): string {
|
|
308
315
|
let width = 0;
|
|
309
316
|
let sliced = "";
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
const
|
|
317
|
+
|
|
318
|
+
for (const char of str) {
|
|
319
|
+
const code = char.codePointAt(0) || 0;
|
|
320
|
+
const charWidth = (
|
|
321
|
+
code === 0x200d || code === 0xfe0f || code === 0xfe0e ||
|
|
322
|
+
(code >= 0x0300 && code <= 0x036f) || (code >= 0x200b && code <= 0x200f)
|
|
323
|
+
) ? 0 : (isFullWidth(code) ? 2 : 1);
|
|
324
|
+
|
|
313
325
|
if (width + charWidth > maxWidth) {
|
|
314
326
|
break;
|
|
315
327
|
}
|
|
316
328
|
width += charWidth;
|
|
317
|
-
sliced +=
|
|
329
|
+
sliced += char;
|
|
318
330
|
}
|
|
331
|
+
|
|
319
332
|
return sliced;
|
|
320
333
|
}
|
|
321
334
|
|
|
@@ -412,14 +425,16 @@ export default function (pi: ExtensionAPI) {
|
|
|
412
425
|
ctx.ui.setStatus(key, val);
|
|
413
426
|
}
|
|
414
427
|
|
|
415
|
-
// 3. Command-Driven Disk I/O: Persist settings to disk
|
|
428
|
+
// 3. Command-Driven Disk I/O: Persist settings to disk atomically outside core paint loop
|
|
416
429
|
try {
|
|
417
430
|
if (fs.existsSync(settingsPath)) {
|
|
418
431
|
const data = fs.readFileSync(settingsPath, "utf-8");
|
|
419
432
|
const config = JSON.parse(data);
|
|
420
433
|
if (!config.beautifier) config.beautifier = {};
|
|
421
434
|
config.beautifier.style = styleKey;
|
|
422
|
-
|
|
435
|
+
const tempSettings = `${settingsPath}.tmp.${process.pid}.${Date.now()}`;
|
|
436
|
+
fs.writeFileSync(tempSettings, JSON.stringify(config, null, 2), "utf-8");
|
|
437
|
+
fs.renameSync(tempSettings, settingsPath);
|
|
423
438
|
}
|
|
424
439
|
} catch (e) {
|
|
425
440
|
// Silently fail disk write to avoid crashing active user sessions
|