regex-dungeon 0.1.0 → 0.1.1

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.
Files changed (2) hide show
  1. package/index.js +34 -3
  2. package/package.json +1 -1
package/index.js CHANGED
@@ -204,10 +204,41 @@ function banner() {
204
204
  console.log(magenta(`╚${line}╝`));
205
205
  }
206
206
 
207
+ // Terminal display width: CJK/Hangul and most emoji occupy two columns,
208
+ // variation selectors / combining marks / ZWJ occupy zero. Counting code
209
+ // points (or .length) miscounts these and breaks fixed-width box alignment.
210
+ function charWidth(cp) {
211
+ if (cp === 0x200d) return 0; // zero-width joiner
212
+ if (cp >= 0xfe00 && cp <= 0xfe0f) return 0; // variation selectors
213
+ if (cp >= 0x0300 && cp <= 0x036f) return 0; // combining diacritics
214
+ if (
215
+ (cp >= 0x1100 && cp <= 0x115f) || // Hangul Jamo
216
+ (cp >= 0x2e80 && cp <= 0x303e) || // CJK radicals .. symbols
217
+ (cp >= 0x3041 && cp <= 0x33ff) || // Kana .. CJK compat
218
+ (cp >= 0x3400 && cp <= 0x4dbf) || // CJK Ext A
219
+ (cp >= 0x4e00 && cp <= 0x9fff) || // CJK Unified
220
+ (cp >= 0xa000 && cp <= 0xa4cf) || // Yi
221
+ (cp >= 0xac00 && cp <= 0xd7a3) || // Hangul syllables
222
+ (cp >= 0xf900 && cp <= 0xfaff) || // CJK compat ideographs
223
+ (cp >= 0xfe30 && cp <= 0xfe4f) || // CJK compat forms
224
+ (cp >= 0xff00 && cp <= 0xff60) || // Fullwidth forms
225
+ (cp >= 0xffe0 && cp <= 0xffe6) ||
226
+ (cp >= 0x1f000 && cp <= 0x1faff) || // emoji & symbols
227
+ (cp >= 0x2600 && cp <= 0x27bf) || // Misc symbols, Dingbats
228
+ (cp >= 0x2b00 && cp <= 0x2bff)
229
+ )
230
+ return 2;
231
+ return 1;
232
+ }
233
+
234
+ function displayWidth(s) {
235
+ let w = 0;
236
+ for (const ch of s) w += charWidth(ch.codePointAt(0));
237
+ return w;
238
+ }
239
+
207
240
  function center(s, w) {
208
- // width-aware enough for our ASCII-ish content
209
- const len = [...s].length + (s.match(/🗡️/g) || []).length; // emojis ~2 cols
210
- const pad = Math.max(0, w - len);
241
+ const pad = Math.max(0, w - displayWidth(s));
211
242
  const left = Math.floor(pad / 2);
212
243
  return ' '.repeat(left) + s + ' '.repeat(pad - left);
213
244
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "regex-dungeon",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "A zero-dependency terminal roguelike that teaches regex — slay the monsters that must die, spare the rest, with one regular expression per floor.",
5
5
  "bin": {
6
6
  "regex-dungeon": "index.js"