Skip to content

Commit 9fab1da

Browse files
committed
demo improvements
1 parent 3a9fe5c commit 9fab1da

File tree

5 files changed

+197
-150
lines changed

5 files changed

+197
-150
lines changed

README.md

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,49 @@ function handleCommand(inputText) {
202202
}
203203
```
204204

205+
## Integration Tips
206+
207+
### Managing the Command Prompt
208+
209+
When building a terminal UI, you'll need to display a prompt that shows the current user and directory. The prompt typically needs to update after commands like `cd` or `su` that change the current path or user.
210+
211+
**Pattern for updating the prompt:**
212+
213+
```javascript
214+
function updatePrompt() {
215+
const user = shell.getCurrentUser();
216+
let path = shell.getCurrentPath();
217+
const home = shell.environment.HOME;
218+
219+
// Replace home directory with ~
220+
if (path === home) {
221+
path = '~';
222+
} else if (path.startsWith(home + '/')) {
223+
path = '~' + path.substring(home.length);
224+
}
225+
226+
// Use # for root, $ for regular users
227+
const promptChar = user === 'root' ? '#' : '$';
228+
229+
// Update your prompt element
230+
promptElement.textContent = `${user}@hostname:${path}${promptChar}`;
231+
}
232+
```
233+
234+
**Typical command execution flow:**
235+
236+
1. User enters a command
237+
2. Capture the current prompt text (for display in command history)
238+
3. Execute the command: `const output = shell.execute(command)`
239+
4. Display the command with its original prompt in history
240+
5. Display the command output
241+
6. Update the active prompt to reflect any changes (new path, new user, etc.)
242+
7. Clear the input field for the next command
243+
244+
**Key point:** When displaying command history, preserve the prompt as it was when the command was entered. Only update the active input prompt after command execution.
245+
246+
See the [live demo source code](https://github.com/hypexr/unix-shell-js/blob/main/docs/index.html) for a complete working example.
247+
205248
## API Reference
206249

207250
### UnixShell Constructor

docs/index.html

Lines changed: 23 additions & 144 deletions
Original file line numberDiff line numberDiff line change
@@ -4,140 +4,7 @@
44
<meta charset="UTF-8">
55
<meta name="viewport" content="width=device-width, initial-scale=1.0">
66
<title>Unix Shell JS - Live Demo</title>
7-
<style>
8-
* {
9-
margin: 0;
10-
padding: 0;
11-
box-sizing: border-box;
12-
}
13-
14-
body {
15-
font-family: 'Courier New', monospace;
16-
background: #000;
17-
color: #0f0;
18-
padding: 20px;
19-
line-height: 1.6;
20-
}
21-
22-
.container {
23-
max-width: 1000px;
24-
margin: 0 auto;
25-
}
26-
27-
h1 {
28-
color: #0f0;
29-
margin-bottom: 10px;
30-
font-size: 2em;
31-
}
32-
33-
.description {
34-
margin-bottom: 20px;
35-
color: #0a0;
36-
}
37-
38-
.terminal {
39-
background: #111;
40-
border: 2px solid #0f0;
41-
border-radius: 5px;
42-
padding: 20px;
43-
min-height: 400px;
44-
box-shadow: 0 0 20px rgba(0, 255, 0, 0.3);
45-
}
46-
47-
.terminal-line {
48-
margin: 5px 0;
49-
display: flex;
50-
align-items: baseline;
51-
}
52-
53-
.prompt {
54-
color: #0f0;
55-
margin-right: 5px;
56-
}
57-
58-
.terminal-input {
59-
color: #0f0;
60-
background: transparent;
61-
border: none;
62-
outline: none;
63-
font-family: 'Courier New', monospace;
64-
font-size: 14px;
65-
flex: 1;
66-
}
67-
68-
.terminal-output {
69-
color: #0f0;
70-
white-space: pre-wrap;
71-
margin: 5px 0;
72-
}
73-
74-
.cursor {
75-
display: inline-block;
76-
width: 8px;
77-
height: 16px;
78-
background: #0f0;
79-
animation: blink 1s infinite;
80-
margin-left: 2px;
81-
}
82-
83-
@keyframes blink {
84-
0%, 49% { opacity: 1; }
85-
50%, 100% { opacity: 0; }
86-
}
87-
88-
.info {
89-
margin-top: 20px;
90-
padding: 15px;
91-
background: #112;
92-
border: 1px solid #0f0;
93-
border-radius: 5px;
94-
}
95-
96-
.info h2 {
97-
color: #0f0;
98-
margin-bottom: 10px;
99-
font-size: 1.2em;
100-
}
101-
102-
.info ul {
103-
list-style: none;
104-
margin-left: 20px;
105-
}
106-
107-
.info li:before {
108-
content: "▸ ";
109-
color: #0f0;
110-
}
111-
112-
a {
113-
color: #0f0;
114-
text-decoration: none;
115-
}
116-
117-
a:hover {
118-
text-decoration: underline;
119-
}
120-
121-
.links {
122-
margin-top: 20px;
123-
text-align: center;
124-
}
125-
126-
.links a {
127-
margin: 0 10px;
128-
padding: 10px 20px;
129-
border: 1px solid #0f0;
130-
border-radius: 3px;
131-
display: inline-block;
132-
transition: all 0.3s;
133-
}
134-
135-
.links a:hover {
136-
background: #0f0;
137-
color: #000;
138-
text-decoration: none;
139-
}
140-
</style>
7+
<link rel="stylesheet" href="style.css">
1418
</head>
1429
<body>
14310
<div class="container">
@@ -147,13 +14,10 @@ <h1>Unix Shell JS - Live Demo</h1>
14714
<div class="terminal" id="terminal">
14815
<div class="terminal-output">Unix Shell JS v1.0.0
14916
Type 'help' to see available commands, 'ls' to list files, or 'vim README.md' to edit a file.
150-
151-
👉 Click anywhere in this terminal to start typing commands!
15217
</div>
15318
<div class="terminal-line">
15419
<span class="prompt">user@demo:~$</span>
15520
<input type="text" class="terminal-input" id="input" autocomplete="off" autofocus>
156-
<span class="cursor"></span>
15721
</div>
15822
</div>
15923

@@ -181,6 +45,8 @@ <h2>Try These Commands:</h2>
18145
<script src="vi-editor.js"></script>
18246
<script src="example-files.js"></script>
18347
<script>
48+
// Wait for scripts to load
49+
window.addEventListener('load', function() {
18450
// Initialize the shell
18551
const shell = new UnixShell({
18652
username: 'user',
@@ -202,7 +68,14 @@ <h2>Try These Commands:</h2>
20268
}
20369

20470
function updatePrompt() {
205-
const prompt = document.querySelector('.prompt');
71+
// Get the prompt in the last terminal-line (the active input line)
72+
// Specifically avoid history lines
73+
const activeLine = terminal.querySelector('.terminal-line:last-child');
74+
if (!activeLine || activeLine.classList.contains('terminal-history')) return;
75+
76+
const prompt = activeLine.querySelector('.prompt');
77+
if (!prompt) return;
78+
20679
const user = shell.getCurrentUser();
20780
let path = shell.getCurrentPath();
20881
const home = shell.environment.HOME;
@@ -217,6 +90,9 @@ <h2>Try These Commands:</h2>
21790
prompt.textContent = `${user}@demo:${path}$`;
21891
}
21992

93+
// Update prompt on load to reflect any restored state from localStorage
94+
updatePrompt();
95+
22096
input.addEventListener('keydown', (e) => {
22197
// Handle Tab for autocomplete
22298
if (e.key === 'Tab') {
@@ -252,7 +128,6 @@ <h2>Try These Commands:</h2>
252128
// Multiple matches - show them
253129
const matchList = completions.matches.join(' ');
254130
addOutput(matchList);
255-
window.scrollTo(0, document.body.scrollHeight);
256131
}
257132
return;
258133
}
@@ -261,10 +136,13 @@ <h2>Try These Commands:</h2>
261136
const command = input.value.trim();
262137

263138
if (command) {
264-
// Show command
139+
// Capture current prompt text before executing command
140+
const currentPromptText = terminal.querySelector('.terminal-line:last-child .prompt').textContent;
141+
142+
// Show command with the prompt as it was when command was entered
265143
const commandLine = document.createElement('div');
266-
commandLine.className = 'terminal-line';
267-
commandLine.innerHTML = `<span class="prompt">${document.querySelector('.prompt').textContent}</span> ${command}`;
144+
commandLine.className = 'terminal-line terminal-history';
145+
commandLine.innerHTML = `<span class="prompt">${currentPromptText}</span> ${command}`;
268146
terminal.insertBefore(commandLine, terminal.lastElementChild);
269147

270148
// Execute command
@@ -291,15 +169,16 @@ <h2>Try These Commands:</h2>
291169

292170
input.value = '';
293171

294-
// Scroll to bottom
295-
window.scrollTo(0, document.body.scrollHeight);
172+
// Scroll terminal to bottom to keep input visible
173+
terminal.scrollTop = terminal.scrollHeight;
296174
}
297175
});
298176

299177
// Focus input when clicking anywhere
300178
document.addEventListener('click', () => {
301179
input.focus();
302180
});
181+
}); // End of window.addEventListener('load')
303182
</script>
304183
</body>
305184
</html>

docs/index.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -276,7 +276,7 @@ class UnixShell {
276276
const path = targetPath || this.currentPath;
277277
const node = this.getNode(path);
278278

279-
if (!node) {
279+
if (node === null || node === undefined) {
280280
return `ls: cannot access '${targetPath || '.'}': No such file or directory`;
281281
}
282282

@@ -369,7 +369,7 @@ class UnixShell {
369369
const newPath = this.resolvePath(args[0]);
370370
const node = this.getNode(newPath);
371371

372-
if (!node) {
372+
if (node === null || node === undefined) {
373373
return `cd: ${args[0]}: No such file or directory`;
374374
}
375375

@@ -393,7 +393,7 @@ class UnixShell {
393393

394394
const node = this.getNode(args[0]);
395395

396-
if (!node) {
396+
if (node === null || node === undefined) {
397397
return `cat: ${args[0]}: No such file or directory`;
398398
}
399399

0 commit comments

Comments
 (0)