|
35 | 35 | ['term-accent', ' │ │'], |
36 | 36 | ['term-accent', ' ╰──────────────────────────────────────────╯'], |
37 | 37 | ['term-info', ' 欢迎来到 TY 的博客终端。输入 help 查看可用命令。'], |
38 | | - ['term-muted', ' 提示:Tab 可补全命令,↑↓ 翻历史,输入 random 随机读一篇。'] |
| 38 | + ['term-muted', ' 提示:Tab 补全,↑↓ 翻历史;试试 cowsay、matrix、coin、fish。'] |
39 | 39 | ]; |
40 | 40 |
|
41 | 41 | var FORTUNES = [ |
|
92 | 92 | ['random', '随机打开一篇文章'], |
93 | 93 | ['neofetch', '显示博客系统信息'], |
94 | 94 | ['fortune', '来一句程序员语录'], |
| 95 | + ['cowsay <文本>', '让奶牛替你说话'], |
| 96 | + ['matrix [行数]', '看一场数字雨'], |
| 97 | + ['coin', '抛一枚硬币'], |
| 98 | + ['dice', '掷一颗骰子'], |
| 99 | + ['fish', '养一条 ASCII 小鱼'], |
95 | 100 | ['whoami', '我是谁'], |
96 | 101 | ['date', '当前时间'], |
97 | 102 | ['echo <文本>', '复读机'], |
98 | 103 | ['search <关键词>', '跳到站内搜索'], |
99 | 104 | ['theme <dark|light>', '切换主题'], |
100 | 105 | ['clear', '清屏'], |
| 106 | + ['sl', '(打错 ls 的彩蛋)'], |
| 107 | + ['vim', '(退出难的梗)'], |
101 | 108 | ['sudo', '你以为呢'], |
102 | 109 | ['exit', '关闭终端'] |
103 | 110 | ]; |
|
175 | 182 | print(FORTUNES[Math.floor(Math.random() * FORTUNES.length)], 'term-accent'); |
176 | 183 | } |
177 | 184 |
|
| 185 | + function cowsay(text) { |
| 186 | + var msg = String(text || '').trim(); |
| 187 | + if (!msg) { msg = '哞~ 你好呀!'; } |
| 188 | + // 控制气泡宽度,避免太长撑破布局 |
| 189 | + var MAX = 28; |
| 190 | + var lines = []; |
| 191 | + var cur = ''; |
| 192 | + // 按字符简单折行(中文/英文都按单字符切) |
| 193 | + Array.prototype.forEach.call(msg, function (ch) { |
| 194 | + if (cur.length >= MAX) { lines.push(cur); cur = ''; } |
| 195 | + cur += ch; |
| 196 | + }); |
| 197 | + if (cur) { lines.push(cur); } |
| 198 | + var width = Math.max(3, lines.reduce(function (m, l) { return Math.max(m, l.length); }, 0)); |
| 199 | + |
| 200 | + var top = ' ' + repeat('_', width + 2); |
| 201 | + var bottom = ' ' + repeat('-', width + 2); |
| 202 | + lines.forEach(function (l, i) { |
| 203 | + var pad = repeat(' ', width - l.length); |
| 204 | + if (lines.length === 1) { |
| 205 | + print(' < ' + esc(l) + ' >', 'term-info'); |
| 206 | + } else if (i === 0) { |
| 207 | + print(' / ' + esc(l) + pad + ' \\', 'term-info'); |
| 208 | + } else if (i === lines.length - 1) { |
| 209 | + print(' \\ ' + esc(l) + pad + ' /', 'term-info'); |
| 210 | + } else { |
| 211 | + print(' | ' + esc(l) + pad + ' |', 'term-info'); |
| 212 | + } |
| 213 | + }); |
| 214 | + print(top, 'term-muted'); |
| 215 | + print(' \\ ^__^', 'term-ascii'); |
| 216 | + print(' \\ (oo)\\_______', 'term-ascii'); |
| 217 | + print(' (__)\\ )\\/\\', 'term-ascii'); |
| 218 | + print(' ||----w |', 'term-ascii'); |
| 219 | + print(' || ||', 'term-ascii'); |
| 220 | + print(bottom, 'term-muted'); |
| 221 | + } |
| 222 | + |
| 223 | + function repeat(ch, n) { |
| 224 | + return new Array(n + 1).join(ch); |
| 225 | + } |
| 226 | + |
| 227 | + function matrix(arg) { |
| 228 | + var rows = parseInt(arg, 10); |
| 229 | + if (!rows || rows < 1) { rows = 8; } |
| 230 | + if (rows > 30) { rows = 30; } |
| 231 | + var glyphs = '01あいうえおカキクケコサシスセソ¥$#@%&*'; |
| 232 | + for (var i = 0; i < rows; i++) { |
| 233 | + var s = ''; |
| 234 | + var len = 18 + Math.floor(Math.random() * 24); |
| 235 | + for (var j = 0; j < len; j++) { |
| 236 | + s += Math.random() < 0.12 ? ' ' : glyphs[Math.floor(Math.random() * glyphs.length)]; |
| 237 | + } |
| 238 | + print('<span class="term-ascii">' + esc(s) + '</span>', null); |
| 239 | + } |
| 240 | + print('(Matrix 彩蛋。输入 clear 结束这场雨。)', 'term-muted'); |
| 241 | + } |
| 242 | + |
| 243 | + function coin() { |
| 244 | + var face = Math.random() < 0.5; |
| 245 | + print('🪙 ' + (face ? '正面' : '反面') + '(' + (face ? 'heads' : 'tails') + ')', 'term-ok'); |
| 246 | + } |
| 247 | + |
| 248 | + function dice() { |
| 249 | + var n = 1 + Math.floor(Math.random() * 6); |
| 250 | + var faces = ['', '⚀', '⚁', '⚂', '⚃', '⚄', '⚅']; |
| 251 | + print('🎲 掷出了 ' + n + ' 点 ' + faces[n], 'term-ok'); |
| 252 | + } |
| 253 | + |
| 254 | + function fish() { |
| 255 | + var art = [ |
| 256 | + ['term-info', ' /`·.¸'], |
| 257 | + ['term-info', ' /¸...¸`:·'], |
| 258 | + ['term-info', ' ¸.·´ ¸ `·.¸.·´)'], |
| 259 | + ['term-ascii', ': © ):´; ¸ {'], |
| 260 | + ['term-info', ' `·.¸ `· ¸.·´\\`·¸)'], |
| 261 | + ['term-info', ' `\\\\´´\\¸.·´'] |
| 262 | + ]; |
| 263 | + print('你的小鱼:', 'term-ok'); |
| 264 | + art.forEach(function (row) { print(row[1], row[0]); }); |
| 265 | + print('(它正游过你的终端。输入 clear 放它回大海。)', 'term-muted'); |
| 266 | + } |
| 267 | + |
| 268 | + function sl() { |
| 269 | + var art = [ |
| 270 | + ['term-warn', ' ==== ________'], |
| 271 | + ['term-warn', ' _D _| |_______/ \\__I_I_____===__|_________|'], |
| 272 | + ['term-warn', ' |(_)--- | H\\________/ | | =|___ ___|'], |
| 273 | + ['term-warn', ' / | | H | | | | ||_| |_||'], |
| 274 | + ['term-warn', ' | | | H |__--------------------| [___] |'], |
| 275 | + ['term-warn', ' | ________|___H__/__|_____/[][]~\\_______| |'], |
| 276 | + ['term-warn', ' |/ | |-----------I_____I [][] [] D |=======|__'] |
| 277 | + ]; |
| 278 | + print('你输的是 sl,不是 ls 😄 不过没关系,火车来了:', 'term-warn'); |
| 279 | + art.forEach(function (row) { print(row[1], row[0]); }); |
| 280 | + print('—— 这列小火车开走了。下次记得 ls。', 'term-muted'); |
| 281 | + } |
| 282 | + |
| 283 | + function vim() { |
| 284 | + var msgs = [ |
| 285 | + '你想退出 vim?先试试 :q! 吧。哦对,这里连 vim 都没有,你自由了。', |
| 286 | + '退出 vim 的正确姿势:<Esc> :q! <Enter>。或者直接拔电源。', |
| 287 | + '你不是第一个卡在 vim 里的人。放心,这里真的没有 vim。', |
| 288 | + 'vim 不可怕,可怕的是以为自己在 vim 里却退不出来。你安全了。' |
| 289 | + ]; |
| 290 | + print(msgs[Math.floor(Math.random() * msgs.length)], 'term-accent'); |
| 291 | + } |
| 292 | + |
178 | 293 | function whoami() { |
179 | 294 | print('TY —— 程序员 / 折腾爱好者 / 博客主', null); |
180 | 295 | print('GitHub: <a href="https://github.com/tyuecode" target="_blank" rel="noopener">github.com/tyuecode</a>', null); |
|
257 | 372 | case 'random': random(); break; |
258 | 373 | case 'neofetch': case 'fetch': neofetch(); break; |
259 | 374 | case 'fortune': case 'quote': fortune(); break; |
| 375 | + case 'cowsay': cowsay(args.join(' ')); break; |
| 376 | + case 'matrix': matrix(args[0]); break; |
| 377 | + case 'coin': coin(); break; |
| 378 | + case 'dice': dice(); break; |
| 379 | + case 'fish': fish(); break; |
| 380 | + case 'sl': sl(); break; |
| 381 | + case 'vim': case 'vi': vim(); break; |
260 | 382 | case 'whoami': whoami(); break; |
261 | 383 | case 'date': dateCmd(); break; |
262 | 384 | case 'echo': echoCmd(args); break; |
|
277 | 399 | var historyIndex = -1; |
278 | 400 |
|
279 | 401 | var COMMANDS = ['help', 'ls', 'cat', 'random', 'neofetch', 'fortune', |
280 | | - 'whoami', 'date', 'echo', 'search', 'theme dark', 'theme light', 'clear', 'sudo', 'exit']; |
| 402 | + 'cowsay', 'matrix', 'coin', 'dice', 'fish', 'whoami', 'date', 'echo', |
| 403 | + 'search', 'theme dark', 'theme light', 'clear', 'sl', 'vim', 'sudo', 'exit']; |
281 | 404 |
|
282 | 405 | input.addEventListener('keydown', function (e) { |
283 | 406 | if (e.key === 'Enter') { |
|
0 commit comments