Skip to content

Commit 1f28571

Browse files
vfs
1 parent 4da52da commit 1f28571

File tree

6 files changed

+192
-11
lines changed

6 files changed

+192
-11
lines changed

README.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# MiaoShell
2+
Simple terminal emulator with basic commands and features.
3+
4+
Install dependencies:
5+
```bash
6+
npm install
7+
```
8+
Debug:
9+
```bash
10+
npm run dev
11+
```
12+
Build for production:
13+
```bash
14+
npm run build
15+
```

package-lock.json

Lines changed: 20 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@
88
},
99
"dependencies": {
1010
"@xterm/addon-fit": "^0.10.0",
11-
"@xterm/xterm": "^5.3.0"
11+
"@xterm/xterm": "^5.3.0",
12+
"xterm-addon-web-links": "^0.9.0"
1213
},
1314
"devDependencies": {
1415
"vite": "^7.0.6"

src/assets/miao.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
__ ____ _____ __ ____
2+
/ |/ (_)___ _____ / ___// /_ ___ / / /
3+
/ /|_/ / / __ `/ __ \\__ \/ __ \/ _ \/ / /
4+
/ / / / / /_/ / /_/ /__/ / / / / __/ / /
5+
/_/ /_/_/\__,_/\____/____/_/ /_/\___/_/_/
6+

src/script.js

Lines changed: 148 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,162 @@
11
//script.js
22
import { Terminal } from '@xterm/xterm';
33
import { FitAddon } from '@xterm/addon-fit';
4+
import { WebLinksAddon } from 'xterm-addon-web-links';
45
import '@xterm/xterm/css/xterm.css';
56

7+
// Custom beep function using Web Audio API
8+
function squareBeep(freq = 440, duration = 0.1) {
9+
const audioCtx = new (window.AudioContext || window.webkitAudioContext)();
10+
const oscillator = audioCtx.createOscillator();
11+
const gainNode = audioCtx.createGain();
12+
13+
oscillator.type = 'square';
14+
oscillator.frequency.value = freq; // in Hz
15+
16+
oscillator.connect(gainNode);
17+
gainNode.connect(audioCtx.destination);
18+
19+
oscillator.start();
20+
oscillator.stop(audioCtx.currentTime + duration);
21+
}
22+
23+
// ANSI color codes for terminal formatting
24+
const colors = {
25+
reset: '\x1B[0m',
26+
bold: '\x1B[1m',
27+
italic: '\x1B[3m',
28+
green: '\x1B[1;32m',
29+
blue: '\x1B[1;34m',
30+
yellow: '\x1B[1;33m',
31+
red: '\x1B[1;3;31m'
32+
};
33+
634
var term = new Terminal();
735
term.open(document.getElementById('terminal'));
836

37+
// Fit terminal to container
938
let fitAddon = new FitAddon();
1039
term.loadAddon(fitAddon);
1140
fitAddon.fit();
12-
13-
// Resize the terminal when the window resizes
1441
window.addEventListener('resize', () => {
1542
fitAddon.fit();
1643
});
1744

45+
term.open(document.getElementById('terminal'));
46+
term.loadAddon(new WebLinksAddon());
47+
48+
49+
1850
let currentInput = '';
1951
let currentLine = '';
2052
let cursorPosition = 0;
2153

2254
// Available commands
55+
56+
// --- Virtual File System ---
57+
let vfs = {};
58+
const VFS_KEY = 'miaoshell-vfs';
59+
60+
function loadVFS() {
61+
try {
62+
const data = localStorage.getItem(VFS_KEY);
63+
if (data) vfs = JSON.parse(data);
64+
else vfs = {};
65+
} catch (e) {
66+
vfs = {};
67+
}
68+
}
69+
70+
function saveVFS() {
71+
localStorage.setItem(VFS_KEY, JSON.stringify(vfs));
72+
}
73+
74+
// Load VFS on startup
75+
loadVFS();
76+
2377
const commands = {
2478
help: () => {
2579
term.writeln('\r\nAvailable commands:');
2680
term.writeln(' help - Show this help message');
2781
term.writeln(' clear - Clear the terminal');
2882
term.writeln(' echo - Echo back your message');
29-
term.writeln(' date - Show current date and time')
83+
term.writeln(' date - Show current date and time');
84+
term.writeln(' beep - Make a beep sound');
85+
term.writeln(' ls - List files in the virtual file system');
86+
term.writeln(' cat - Show file contents: cat filename');
87+
term.writeln(' write - Write to a file: write filename content');
88+
term.writeln(' rm - Remove a file: rm filename');
89+
term.writeln(' save - Save VFS to browser storage');
90+
term.writeln(' load - Load VFS from browser storage');
91+
term.writeln(' about - About this terminal');
3092
},
3193
clear: () => {
32-
term.clear();
94+
setTimeout(() => {
95+
term.clear();
96+
}, 0);
3397
},
3498
echo: (args) => {
3599
term.writeln('\r\n' + args.join(' '));
36100
},
37101
date: () => {
38102
term.writeln('\r\n' + new Date().toString());
103+
},
104+
beep: () => {
105+
squareBeep();
106+
term.writeln('\r\n🔊 Beep!');
107+
},
108+
ls: () => {
109+
const files = Object.keys(vfs);
110+
if (files.length === 0) term.writeln('\r\n(no files)');
111+
else term.writeln('\r\n' + files.join(' '));
112+
},
113+
cat: (args) => {
114+
if (!args[0]) {
115+
term.writeln('\r\nUsage: cat filename');
116+
return;
117+
}
118+
const file = args[0];
119+
if (vfs[file] !== undefined) {
120+
term.writeln('\r\n' + vfs[file]);
121+
} else {
122+
term.writeln(`\r\nFile not found: ${file}`);
123+
}
124+
},
125+
write: (args) => {
126+
if (!args[0]) {
127+
term.writeln('\r\nUsage: write filename content');
128+
return;
129+
}
130+
const file = args[0];
131+
const content = args.slice(1).join(' ');
132+
vfs[file] = content;
133+
term.writeln(`\r\nWrote to ${file}`);
134+
},
135+
rm: (args) => {
136+
if (!args[0]) {
137+
term.writeln('\r\nUsage: rm filename');
138+
return;
139+
}
140+
const file = args[0];
141+
if (vfs[file] !== undefined) {
142+
delete vfs[file];
143+
term.writeln(`\r\nDeleted ${file}`);
144+
} else {
145+
term.writeln(`\r\nFile not found: ${file}`);
146+
}
147+
},
148+
save: () => {
149+
saveVFS();
150+
term.writeln('\r\nVFS saved to browser storage.');
151+
},
152+
load: () => {
153+
loadVFS();
154+
term.writeln('\r\nVFS loaded from browser storage.');
155+
},
156+
about: () => {
157+
term.writeln('\r\n' + colors.bold + 'MiaoShell' + colors.reset + ' - A Useless Terminal');
158+
term.writeln('Version: 1.0.0');
159+
term.writeln('https://github.com/daniel4-scratch/xtermtest');
39160
}
40161
};
41162

@@ -57,7 +178,7 @@ function executeCommand(input) {
57178
}
58179

59180
function prompt() {
60-
term.write('\r\n\x1B[1;32muser@xterm-demo\x1B[0m:\x1B[1;34m~\x1B[0m$ ');
181+
term.write(`\r\n${colors.green}user@miaoshell${colors.reset}:${colors.blue}~${colors.reset}$ `);
61182
}
62183

63184
// Handle user input
@@ -76,10 +197,28 @@ term.onData(data => {
76197
} else if (code >= 32) { // Printable characters
77198
currentInput += data;
78199
term.write(data);
200+
} else if (code === 27) { // Escape key
201+
// Handle escape sequences if needed
79202
}
80203
});
81204

82-
// Initialize terminal
83-
term.writeln('Welcome to \x1B[1;3;31mXterm.js\x1B[0m Terminal Demo!');
84-
term.writeln('Type \x1B[1;33mhelp\x1B[0m to see available commands.');
85-
prompt();
205+
async function init() {
206+
// Initialize terminal
207+
//print ./assets/miao.txt
208+
await fetch('./assets/miao.txt')
209+
.then(response => response.text())
210+
.then(text => {
211+
text.split(/\r?\n/).forEach(line => term.writeln(line));
212+
})
213+
.catch(error => {
214+
term.writeln('Error loading file: ' + error);
215+
});
216+
term.writeln(`Welcome to ${colors.red}MiaoShell${colors.reset} - A Useless Terminal!`);
217+
term.writeln(`Type ${colors.yellow}help${colors.reset} to see available commands.`);
218+
prompt();
219+
};
220+
221+
init().catch(err => {
222+
console.error('Error initializing terminal:', err);
223+
term.writeln('Error initializing terminal. Check console for details.');
224+
});

src/style.css

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ body{
66
display: flex;
77
justify-content: center;
88
align-items: center;
9+
background-color: black;
910
}
1011

1112
#terminal {

0 commit comments

Comments
 (0)