@meebs/meeb 1.0.0
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.
- package/README.md +158 -0
- package/animals/alien.js +34 -0
- package/animals/axolotl.js +38 -0
- package/animals/bat.js +34 -0
- package/animals/bear.js +41 -0
- package/animals/bee.js +32 -0
- package/animals/bunny.js +45 -0
- package/animals/butterfly.js +36 -0
- package/animals/capybara.js +36 -0
- package/animals/cat.js +44 -0
- package/animals/chameleon.js +44 -0
- package/animals/chick.js +27 -0
- package/animals/cookie.js +30 -0
- package/animals/crab.js +32 -0
- package/animals/crocodile.js +32 -0
- package/animals/deer.js +35 -0
- package/animals/dino.js +37 -0
- package/animals/dog.js +44 -0
- package/animals/dragon.js +44 -0
- package/animals/duck.js +45 -0
- package/animals/eagle.js +37 -0
- package/animals/elephant.js +33 -0
- package/animals/firefly.js +37 -0
- package/animals/fish.js +32 -0
- package/animals/flamingo.js +36 -0
- package/animals/fox.js +43 -0
- package/animals/frog.js +46 -0
- package/animals/ghost.js +32 -0
- package/animals/giraffe.js +37 -0
- package/animals/gorilla.js +37 -0
- package/animals/hamster.js +35 -0
- package/animals/hedgehog.js +32 -0
- package/animals/hippo.js +34 -0
- package/animals/index.js +87 -0
- package/animals/jellyfish.js +34 -0
- package/animals/koala.js +34 -0
- package/animals/ladybug.js +34 -0
- package/animals/lion.js +36 -0
- package/animals/mantisshrimp.js +49 -0
- package/animals/monkey.js +35 -0
- package/animals/moth.js +41 -0
- package/animals/mouse.js +33 -0
- package/animals/narwhal.js +38 -0
- package/animals/octopus.js +31 -0
- package/animals/otter.js +43 -0
- package/animals/owl.js +38 -0
- package/animals/panda.js +42 -0
- package/animals/parrot.js +39 -0
- package/animals/peacock.js +42 -0
- package/animals/penguin.js +47 -0
- package/animals/penguin2.js +38 -0
- package/animals/pig.js +33 -0
- package/animals/raccoon.js +35 -0
- package/animals/redpanda.js +39 -0
- package/animals/robot.js +37 -0
- package/animals/scorpion.js +33 -0
- package/animals/seahorse.js +39 -0
- package/animals/shark.js +33 -0
- package/animals/shit.js +33 -0
- package/animals/sloth.js +34 -0
- package/animals/snail.js +34 -0
- package/animals/snake.js +36 -0
- package/animals/spider.js +33 -0
- package/animals/squid.js +33 -0
- package/animals/starfish.js +32 -0
- package/animals/stingray.js +41 -0
- package/animals/swan.js +34 -0
- package/animals/toucan.js +41 -0
- package/animals/turtle.js +35 -0
- package/animals/unicorn.js +40 -0
- package/animals/walrus.js +35 -0
- package/animals/whale.js +42 -0
- package/animals/wolf.js +36 -0
- package/animals/yak.js +36 -0
- package/animals/zebra.js +34 -0
- package/color.js +9 -0
- package/completions/_meeb +41 -0
- package/completions/meeb.bash +16 -0
- package/emoji.js +30 -0
- package/fortune.js +41 -0
- package/gif.js +435 -0
- package/index.js +915 -0
- package/info.js +80 -0
- package/package.json +39 -0
- package/png.js +88 -0
- package/svg.js +43 -0
- package/theme.js +80 -0
- package/tui.js +76 -0
- package/util.js +313 -0
package/util.js
ADDED
|
@@ -0,0 +1,313 @@
|
|
|
1
|
+
const { rgb, fgBg } = require('./color')
|
|
2
|
+
|
|
3
|
+
const ANSI_RE = /\x1b\[[0-9;]*m/g
|
|
4
|
+
|
|
5
|
+
function stripAnsi(str) {
|
|
6
|
+
return str.replace(ANSI_RE, '')
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
function visLen(str) {
|
|
10
|
+
return stripAnsi(str).length
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function wrapText(text, maxWidth) {
|
|
14
|
+
const words = text.replace(/\n/g, ' ').split(/\s+/).filter(Boolean)
|
|
15
|
+
const lines = []
|
|
16
|
+
let current = ''
|
|
17
|
+
for (const word of words) {
|
|
18
|
+
if (current && (current.length + 1 + word.length) > maxWidth) {
|
|
19
|
+
lines.push(current)
|
|
20
|
+
current = word
|
|
21
|
+
} else {
|
|
22
|
+
current = current ? current + ' ' + word : word
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
if (current) lines.push(current)
|
|
26
|
+
return lines.length ? lines : ['']
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function addSay(art, msg) {
|
|
30
|
+
const artLines = art.split('\n')
|
|
31
|
+
const artWidth = Math.max(...artLines.map(l => visLen(l)))
|
|
32
|
+
const maxBubble = 60
|
|
33
|
+
const msgLines = wrapText(msg, maxBubble)
|
|
34
|
+
const innerWidth = Math.max(...msgLines.map(l => l.length), 8)
|
|
35
|
+
const bubbleWidth = innerWidth + 2
|
|
36
|
+
const pad = Math.max(0, Math.floor((artWidth - bubbleWidth - 2) / 2))
|
|
37
|
+
const sp = ' '.repeat(pad)
|
|
38
|
+
|
|
39
|
+
const top = `${sp} ${'_'.repeat(bubbleWidth)}`
|
|
40
|
+
const mid = msgLines.map(l =>
|
|
41
|
+
`${sp}| ${l}${' '.repeat(innerWidth - l.length)} |`
|
|
42
|
+
)
|
|
43
|
+
if (mid.length === 1) {
|
|
44
|
+
mid[0] = `${sp}< ${msgLines[0]}${' '.repeat(innerWidth - msgLines[0].length)} >`
|
|
45
|
+
}
|
|
46
|
+
const bot = `${sp} ${'‾'.repeat(bubbleWidth)}`
|
|
47
|
+
const ptr = `${sp}${' '.repeat(Math.floor(bubbleWidth / 2))}${mid.length === 1 ? '|' : '╱'}`
|
|
48
|
+
|
|
49
|
+
return [top, ...mid, bot, ptr, ...artLines].join('\n')
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function addHat(art) {
|
|
53
|
+
const month = new Date().getMonth() // 0-indexed
|
|
54
|
+
const lines = art.split('\n')
|
|
55
|
+
|
|
56
|
+
// find the first non-empty line
|
|
57
|
+
let firstIdx = lines.findIndex(l => l.trim().length > 0)
|
|
58
|
+
if (firstIdx < 0) firstIdx = 0
|
|
59
|
+
const firstLine = lines[firstIdx]
|
|
60
|
+
const contentStart = visLen(firstLine) - visLen(firstLine.trimStart())
|
|
61
|
+
|
|
62
|
+
let hat
|
|
63
|
+
if (month === 11 || month === 0) {
|
|
64
|
+
// Dec-Jan: santa hat
|
|
65
|
+
hat = [
|
|
66
|
+
' '.repeat(contentStart) + rgb(220, 50, 40, ' ▄') + rgb(240, 240, 240, '●'),
|
|
67
|
+
' '.repeat(contentStart) + rgb(220, 50, 40, ' ▄██▀'),
|
|
68
|
+
' '.repeat(contentStart) + rgb(240, 240, 240, '▀████▀'),
|
|
69
|
+
]
|
|
70
|
+
} else if (month === 1) {
|
|
71
|
+
// Feb: heart
|
|
72
|
+
hat = [
|
|
73
|
+
' '.repeat(contentStart) + rgb(220, 50, 80, ' ▄▀▄ ▄▀▄'),
|
|
74
|
+
' '.repeat(contentStart) + rgb(220, 50, 80, ' ▀▄███▄▀'),
|
|
75
|
+
' '.repeat(contentStart) + rgb(220, 50, 80, ' ▀█▀'),
|
|
76
|
+
]
|
|
77
|
+
} else if (month === 2) {
|
|
78
|
+
// Mar: shamrock
|
|
79
|
+
hat = [
|
|
80
|
+
' '.repeat(contentStart) + rgb(40, 180, 60, ' ▄█▄█▄'),
|
|
81
|
+
' '.repeat(contentStart) + rgb(40, 180, 60, ' ▀███▀'),
|
|
82
|
+
' '.repeat(contentStart) + rgb(40, 180, 60, ' █'),
|
|
83
|
+
]
|
|
84
|
+
} else if (month === 3) {
|
|
85
|
+
// Apr: rain cloud
|
|
86
|
+
hat = [
|
|
87
|
+
' '.repeat(contentStart) + rgb(180, 180, 190, ' ▄███▄'),
|
|
88
|
+
' '.repeat(contentStart) + rgb(180, 180, 190, ' ▀█████▀'),
|
|
89
|
+
' '.repeat(contentStart) + rgb(100, 160, 240, ' ░ ░ ░'),
|
|
90
|
+
]
|
|
91
|
+
} else if (month === 4) {
|
|
92
|
+
// May: flower
|
|
93
|
+
hat = [
|
|
94
|
+
' '.repeat(contentStart) + rgb(240, 100, 150, ' ▄█▄'),
|
|
95
|
+
' '.repeat(contentStart) + rgb(240, 100, 150, ' █') + rgb(240, 220, 60, '▀█▀') + rgb(240, 100, 150, '█'),
|
|
96
|
+
' '.repeat(contentStart) + rgb(240, 100, 150, ' ▀█▀'),
|
|
97
|
+
]
|
|
98
|
+
} else if (month === 5) {
|
|
99
|
+
// Jun: sun
|
|
100
|
+
hat = [
|
|
101
|
+
' '.repeat(contentStart) + rgb(240, 200, 50, ' ╲ ▄▄ ╱'),
|
|
102
|
+
' '.repeat(contentStart) + rgb(240, 200, 50, ' ─████─'),
|
|
103
|
+
' '.repeat(contentStart) + rgb(240, 200, 50, ' ╱ ▀▀ ╲'),
|
|
104
|
+
]
|
|
105
|
+
} else if (month === 6) {
|
|
106
|
+
// Jul: firework
|
|
107
|
+
hat = [
|
|
108
|
+
' '.repeat(contentStart) + rgb(220, 50, 40, ' ·') + rgb(240, 240, 240, '✦') + rgb(50, 80, 220, '· '),
|
|
109
|
+
' '.repeat(contentStart) + rgb(50, 80, 220, ' · ') + rgb(220, 50, 40, '✦') + rgb(240, 240, 240, ' ·'),
|
|
110
|
+
' '.repeat(contentStart) + rgb(240, 240, 240, ' · ') + rgb(50, 80, 220, '·'),
|
|
111
|
+
]
|
|
112
|
+
} else if (month === 7) {
|
|
113
|
+
// Aug: sunglasses
|
|
114
|
+
hat = [
|
|
115
|
+
' '.repeat(contentStart) + rgb(30, 30, 30, ' ▄████████▄'),
|
|
116
|
+
' '.repeat(contentStart) + rgb(30, 30, 30, ' █▀▀██▀▀██▀'),
|
|
117
|
+
]
|
|
118
|
+
} else if (month === 8) {
|
|
119
|
+
// Sep: falling leaf
|
|
120
|
+
hat = [
|
|
121
|
+
' '.repeat(contentStart) + rgb(220, 140, 40, ' ▄▖'),
|
|
122
|
+
' '.repeat(contentStart) + rgb(220, 140, 40, ' ▄██▘'),
|
|
123
|
+
' '.repeat(contentStart) + rgb(220, 140, 40, ' ▀▀'),
|
|
124
|
+
]
|
|
125
|
+
} else if (month === 9) {
|
|
126
|
+
// Oct: jack-o-lantern
|
|
127
|
+
hat = [
|
|
128
|
+
' '.repeat(contentStart) + rgb(40, 140, 40, ' █'),
|
|
129
|
+
' '.repeat(contentStart) + rgb(230, 150, 30, ' ▄███▄'),
|
|
130
|
+
' '.repeat(contentStart) + rgb(230, 150, 30, ' █') + rgb(30, 30, 30, '▀█▀') + rgb(230, 150, 30, '█'),
|
|
131
|
+
' '.repeat(contentStart) + rgb(230, 150, 30, ' ▀███▀'),
|
|
132
|
+
]
|
|
133
|
+
} else if (month === 10) {
|
|
134
|
+
// Nov: pilgrim hat
|
|
135
|
+
hat = [
|
|
136
|
+
' '.repeat(contentStart) + rgb(40, 40, 40, ' ▄██▄'),
|
|
137
|
+
' '.repeat(contentStart) + rgb(40, 40, 40, ' ▐') + rgb(220, 180, 50, '█') + rgb(40, 40, 40, '██') + rgb(220, 180, 50, '█') + rgb(40, 40, 40, '▌'),
|
|
138
|
+
' '.repeat(contentStart) + rgb(40, 40, 40, ' ▀██████▀'),
|
|
139
|
+
]
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
if (hat) {
|
|
143
|
+
lines.splice(firstIdx, 0, ...hat)
|
|
144
|
+
}
|
|
145
|
+
return lines.join('\n')
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
const FLIP_MAP = {
|
|
149
|
+
'▐': '▌', '▌': '▐', '▛': '▜', '▜': '▛', '▙': '▟', '▟': '▙',
|
|
150
|
+
'▗': '▖', '▖': '▗', '▝': '▘', '▘': '▝', '▄': '▄', '▀': '▀',
|
|
151
|
+
'█': '█', '░': '░', '▓': '▓', '◉': '◉', '●': '●', '◆': '◆',
|
|
152
|
+
'▼': '▼', '▽': '▽', '▶': '◀', '◀': '▶', '▬': '▬',
|
|
153
|
+
'═': '═', '─': '─', '╲': '╱', '╱': '╲',
|
|
154
|
+
'▀▄': '▄▀', '(': ')', ')': '(',
|
|
155
|
+
'/': '\\', '\\': '/', '<': '>', '>': '<',
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
function flipLine(line) {
|
|
159
|
+
// Parse into styled characters, tracking cumulative ANSI state
|
|
160
|
+
const cells = [] // { style: string, char: string }
|
|
161
|
+
let currentStyle = '' // accumulated ANSI codes that define current style
|
|
162
|
+
let i = 0
|
|
163
|
+
while (i < line.length) {
|
|
164
|
+
if (line[i] === '\x1b' && i + 1 < line.length && line[i + 1] === '[') {
|
|
165
|
+
let j = i + 2
|
|
166
|
+
while (j < line.length && line[j] !== 'm') j++
|
|
167
|
+
const code = line.slice(i, j + 1)
|
|
168
|
+
// reset clears accumulated style, otherwise append
|
|
169
|
+
if (code === '\x1b[0m') {
|
|
170
|
+
currentStyle = ''
|
|
171
|
+
} else {
|
|
172
|
+
currentStyle += code
|
|
173
|
+
}
|
|
174
|
+
i = j + 1
|
|
175
|
+
} else {
|
|
176
|
+
cells.push({ style: currentStyle, char: line[i] })
|
|
177
|
+
i++
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// Reverse cell order, flip characters, and re-emit styles
|
|
182
|
+
cells.reverse()
|
|
183
|
+
const reset = '\x1b[0m'
|
|
184
|
+
let result = ''
|
|
185
|
+
let lastStyle = null
|
|
186
|
+
for (const cell of cells) {
|
|
187
|
+
if (cell.style !== lastStyle) {
|
|
188
|
+
result += reset + cell.style
|
|
189
|
+
lastStyle = cell.style
|
|
190
|
+
}
|
|
191
|
+
result += FLIP_MAP[cell.char] || cell.char
|
|
192
|
+
}
|
|
193
|
+
result += reset
|
|
194
|
+
return result
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
function flipArt(art) {
|
|
198
|
+
const lines = art.split('\n')
|
|
199
|
+
// find max visible width for padding
|
|
200
|
+
const maxW = Math.max(...lines.map(l => visLen(l)))
|
|
201
|
+
return lines.map(line => {
|
|
202
|
+
const flipped = flipLine(line)
|
|
203
|
+
// pad to right-align (since flip reverses alignment)
|
|
204
|
+
const pad = maxW - visLen(flipped)
|
|
205
|
+
return ' '.repeat(Math.max(0, pad)) + flipped
|
|
206
|
+
}).join('\n')
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
function sideBySide(art1, art2, gap = 4) {
|
|
210
|
+
const lines1 = art1.split('\n')
|
|
211
|
+
const lines2 = art2.split('\n')
|
|
212
|
+
const maxLines = Math.max(lines1.length, lines2.length)
|
|
213
|
+
const maxWidth1 = Math.max(...lines1.map(l => visLen(l)), 0)
|
|
214
|
+
const spacer = ' '.repeat(gap)
|
|
215
|
+
const result = []
|
|
216
|
+
|
|
217
|
+
for (let i = 0; i < maxLines; i++) {
|
|
218
|
+
const l1 = lines1[i] || ''
|
|
219
|
+
const l2 = lines2[i] || ''
|
|
220
|
+
const pad = maxWidth1 - visLen(l1)
|
|
221
|
+
result.push(l1 + ' '.repeat(Math.max(0, pad)) + spacer + l2)
|
|
222
|
+
}
|
|
223
|
+
return result.join('\n')
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
function addLabel(art, text) {
|
|
227
|
+
const artLines = art.split('\n')
|
|
228
|
+
const artWidth = Math.max(...artLines.map(l => visLen(l)))
|
|
229
|
+
const labelLines = wrapText(text, 60)
|
|
230
|
+
const result = [...artLines, '']
|
|
231
|
+
for (const line of labelLines) {
|
|
232
|
+
const pad = Math.max(0, Math.floor((artWidth - line.length) / 2))
|
|
233
|
+
result.push(' '.repeat(pad) + line)
|
|
234
|
+
}
|
|
235
|
+
return result.join('\n')
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
// Parse a line into styled cells (reused by stretch/squish/flip)
|
|
239
|
+
function parseCells(line) {
|
|
240
|
+
const cells = []
|
|
241
|
+
let currentStyle = ''
|
|
242
|
+
let i = 0
|
|
243
|
+
while (i < line.length) {
|
|
244
|
+
if (line[i] === '\x1b' && i + 1 < line.length && line[i + 1] === '[') {
|
|
245
|
+
let j = i + 2
|
|
246
|
+
while (j < line.length && line[j] !== 'm') j++
|
|
247
|
+
const code = line.slice(i, j + 1)
|
|
248
|
+
if (code === '\x1b[0m') currentStyle = ''
|
|
249
|
+
else currentStyle += code
|
|
250
|
+
i = j + 1
|
|
251
|
+
} else {
|
|
252
|
+
cells.push({ style: currentStyle, char: line[i] })
|
|
253
|
+
i++
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
return cells
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
function cellsToString(cells) {
|
|
260
|
+
const reset = '\x1b[0m'
|
|
261
|
+
let result = ''
|
|
262
|
+
let lastStyle = null
|
|
263
|
+
for (const cell of cells) {
|
|
264
|
+
if (cell.style !== lastStyle) {
|
|
265
|
+
result += reset + cell.style
|
|
266
|
+
lastStyle = cell.style
|
|
267
|
+
}
|
|
268
|
+
result += cell.char
|
|
269
|
+
}
|
|
270
|
+
if (cells.length) result += reset
|
|
271
|
+
return result
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
function stretchLine(line) {
|
|
275
|
+
const cells = parseCells(line)
|
|
276
|
+
const stretched = []
|
|
277
|
+
for (const cell of cells) {
|
|
278
|
+
stretched.push(cell)
|
|
279
|
+
stretched.push({ style: cell.style, char: cell.char })
|
|
280
|
+
}
|
|
281
|
+
return cellsToString(stretched)
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
function stretchArt(art) {
|
|
285
|
+
return art.split('\n').map(stretchLine).join('\n')
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
function squishLine(line) {
|
|
289
|
+
const cells = parseCells(line)
|
|
290
|
+
const squished = cells.filter((_, i) => i % 2 === 0)
|
|
291
|
+
return cellsToString(squished)
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
function squishArt(art) {
|
|
295
|
+
return art.split('\n').map(squishLine).join('\n')
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
function stretchVArt(art) {
|
|
299
|
+
const lines = art.split('\n')
|
|
300
|
+
const result = []
|
|
301
|
+
for (const line of lines) {
|
|
302
|
+
result.push(line)
|
|
303
|
+
result.push(line)
|
|
304
|
+
}
|
|
305
|
+
return result.join('\n')
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
function squishVArt(art) {
|
|
309
|
+
const lines = art.split('\n')
|
|
310
|
+
return lines.filter((_, i) => i % 2 === 0).join('\n')
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
module.exports = { addSay, addHat, addLabel, stripAnsi, flipArt, stretchArt, squishArt, stretchVArt, squishVArt, sideBySide }
|