| 
167 | 167 | 
 
  | 
168 | 168 |                     this.cursorPosition = 0;  | 
169 | 169 |                     this.history = [];  | 
 | 170 | +                    this.historyBuffer = [];  | 
170 | 171 |                     this.historyIndex = -1;  | 
171 | 172 |                     this.beforeHistoryNav = "";  | 
172 | 173 |                 }  | 
 | 
219 | 220 |                                 this.cursorLeft();  | 
220 | 221 |                                 break;  | 
221 | 222 |                             case '[H': // home key  | 
222 |  | -                                this.cursorHome();  | 
 | 223 | +                                this.cursorHome(true);  | 
223 | 224 |                                 break;  | 
224 | 225 |                             case '[F': // end key  | 
225 |  | -                                this.cursorEnd();  | 
 | 226 | +                                this.cursorEnd(true);  | 
226 | 227 |                                 break;  | 
227 | 228 |                             case '[3~': // delete key  | 
228 | 229 |                                 this.deleteAtCursor();  | 
 | 
248 | 249 |                             case "\x03": // CTRL+C  | 
249 | 250 |                                 this.input = "";  | 
250 | 251 |                                 this.xterm.write("\n")  | 
251 |  | -                                // this is a real hack.  the hard-coded 4... :\  | 
252 | 252 |                                 this.xterm.write('\x1b[' + (this.cursorPosition + 4) + 'D');  | 
253 | 253 |                                 this.cursorPosition = 0;  | 
254 | 254 |                                 this.resolveInput("" + '\n');  | 
 | 
270 | 270 |                         }  | 
271 | 271 |                     } else {  | 
272 | 272 |                         this.handleCursorInsert(data);  | 
 | 273 | +                        this.updateHistory();  | 
273 | 274 |                     }  | 
274 | 275 |                 };  | 
275 | 276 | 
 
  | 
 | 277 | +                clearLine(){  | 
 | 278 | +                    this.xterm.write('\x1b[K')  | 
 | 279 | +                }  | 
 | 280 | + | 
276 | 281 |                 writeLine(line) {  | 
277 | 282 |                     this.xterm.write(line.slice(0, -1));  | 
278 | 283 |                     this.xterm.write("\r\n");  | 
 | 
288 | 293 |                         this.xterm.write(trailing);  | 
289 | 294 |                         this.xterm.write('\x1b[' + trailing.length + 'D');  | 
290 | 295 |                     }  | 
 | 296 | +                    this.updateHistory();  | 
 | 297 | +                }  | 
 | 298 | + | 
 | 299 | +                handleTab() {  | 
 | 300 | +                    // handle tabs: from the current position, add spaces until  | 
 | 301 | +                    // this.cursorPosition is a multiple of 4.  | 
 | 302 | +                    const prefix = this.input.slice(0, this.cursorPosition);  | 
 | 303 | +                    const suffix = this.input.slice(this.cursorPosition);  | 
 | 304 | +                    const count = 4 - (this.cursorPosition % 4);  | 
 | 305 | +                    const toAdd = " ".repeat(count);  | 
 | 306 | +                    this.input = prefix + toAdd + suffix  | 
 | 307 | +                    this.cursorHome(false);  | 
 | 308 | +                    this.clearLine();  | 
 | 309 | +                    this.xterm.write(this.input);  | 
 | 310 | +                    if (suffix){  | 
 | 311 | +                        this.xterm.write('\x1b[' + suffix.length + 'D');  | 
 | 312 | +                    }  | 
 | 313 | +                    this.cursorPosition += count;  | 
 | 314 | +                    this.updateHistory(false);  | 
291 | 315 |                 }  | 
292 | 316 | 
 
  | 
293 | 317 |                 handleCursorErase() {  | 
 | 
300 | 324 |                     }  | 
301 | 325 |                     const trailing = this.input.slice(this.cursorPosition);  | 
302 | 326 |                     this.input = this.input.slice(0, this.cursorPosition - 1) + trailing;  | 
303 |  | -                    this.cursorPosition -= 1;  | 
304 |  | -                    this.xterm.write("\x1B[D");  | 
305 |  | -                    this.xterm.write("\x1B[K");  | 
306 |  | -                    if (trailing){  | 
 | 327 | +                    this.cursorLeft();  | 
 | 328 | +                    this.clearLine();  | 
 | 329 | +                    if (trailing.length !== 0){  | 
307 | 330 |                         this.xterm.write(trailing);  | 
308 | 331 |                         this.xterm.write('\x1b[' + trailing.length + 'D');  | 
309 | 332 |                     }  | 
 | 333 | +                    this.updateHistory();  | 
310 | 334 |                 }  | 
311 | 335 | 
 
  | 
312 | 336 |                 deleteAtCursor(){  | 
313 | 337 |                     if (this.cursorPosition < this.input.length){  | 
314 | 338 |                         const trailing = this.input.slice(this.cursorPosition + 1);  | 
315 | 339 |                         this.input = this.input.slice(0, this.cursorPosition) + trailing;  | 
316 |  | -                        this.xterm.write("\x1B[K");  | 
317 |  | -                        if (trailing){  | 
 | 340 | +                        this.clearLine();  | 
 | 341 | +                        if (trailing.length !== 0){  | 
318 | 342 |                             this.xterm.write(trailing);  | 
319 | 343 |                             this.xterm.write('\x1b[' + trailing.length + 'D');  | 
320 | 344 |                         }  | 
 | 345 | +                        this.updateHistory();  | 
 | 346 | +                    }  | 
 | 347 | +                }  | 
 | 348 | + | 
 | 349 | +                cursorRight(){  | 
 | 350 | +                     if (this.cursorPosition < this.input.length){  | 
 | 351 | +                         this.cursorPosition += 1;  | 
 | 352 | +                         this.xterm.write('\x1b[C');  | 
 | 353 | +                     }  | 
 | 354 | +                }  | 
 | 355 | + | 
 | 356 | +                cursorLeft(){  | 
 | 357 | +                    if (this.cursorPosition > 0){  | 
 | 358 | +                        this.cursorPosition -= 1;  | 
 | 359 | +                        this.xterm.write('\x1b[D');  | 
 | 360 | +                    }  | 
 | 361 | +                }  | 
 | 362 | + | 
 | 363 | +                cursorHome(updatePosition) {  | 
 | 364 | +                    if (this.cursorPosition > 0){  | 
 | 365 | +                        this.xterm.write('\x1b[' + this.cursorPosition + 'D');  | 
 | 366 | +                        if (updatePosition) {  | 
 | 367 | +                            this.cursorPosition = 0;  | 
 | 368 | +                        }  | 
 | 369 | +                    }  | 
 | 370 | +                }  | 
 | 371 | + | 
 | 372 | +                cursorEnd() {  | 
 | 373 | +                    if (this.cursorPosition < this.input.length){  | 
 | 374 | +                        this.xterm.write('\x1b[' + (this.input.length - this.cursorPosition) + 'C');  | 
 | 375 | +                        this.cursorPosition = this.input.length;  | 
 | 376 | +                    }  | 
 | 377 | +                }  | 
 | 378 | + | 
 | 379 | +                updateHistory(){  | 
 | 380 | +                    if (this.historyIndex !== -1){  | 
 | 381 | +                        this.historyBuffer[this.historyIndex] = this.input;  | 
 | 382 | +                    }else{  | 
 | 383 | +                        this.beforeHistoryNav = this.input;  | 
321 | 384 |                     }  | 
322 | 385 |                 }  | 
323 | 386 | 
 
  | 
 | 
333 | 396 |                     }else if (this.historyIndex > 0){  | 
334 | 397 |                         this.historyIndex -= 1;  | 
335 | 398 |                     }  | 
336 |  | -                    this.input = this.history[this.historyIndex];  | 
337 |  | -                    // jump back to the start of the line  | 
338 |  | -                    if (this.cursorPosition > 0){  | 
339 |  | -                        this.xterm.write('\x1b[' + (this.cursorPosition) + 'D');  | 
340 |  | -                    }  | 
341 |  | -                    // clear the line  | 
342 |  | -                    this.xterm.write('\x1b[K')  | 
 | 399 | +                    this.input = this.historyBuffer[this.historyIndex];  | 
 | 400 | +                    this.cursorHome(false);  | 
 | 401 | +                    this.clearLine();  | 
343 | 402 |                     this.xterm.write(this.input);  | 
344 | 403 |                     this.cursorPosition = this.input.length;  | 
345 | 404 |                 }  | 
 | 
350 | 409 |                         return;  | 
351 | 410 |                     }else if (this.historyIndex < this.history.length - 1){  | 
352 | 411 |                         this.historyIndex += 1;  | 
353 |  | -                        this.input = this.history[this.historyIndex];  | 
 | 412 | +                        this.input = this.historyBuffer[this.historyIndex];  | 
354 | 413 |                     }else if (this.historyIndex == this.history.length - 1){  | 
355 | 414 |                         // we're coming back from the last history value; reset  | 
356 | 415 |                         // the input to whatever it was when we started going  | 
357 | 416 |                         // through the history  | 
358 | 417 |                         this.input = this.beforeHistoryNav;  | 
359 | 418 |                         this.historyIndex = -1;  | 
360 | 419 |                     }  | 
361 |  | -                    // jump back to the start of the line  | 
362 |  | -                    if (this.cursorPosition > 0){  | 
363 |  | -                        this.xterm.write('\x1b[' + (this.cursorPosition) + 'D');  | 
364 |  | -                    }  | 
365 |  | -                    // clear the line  | 
366 |  | -                    this.xterm.write('\x1b[K')  | 
 | 420 | +                    this.cursorHome(false);  | 
 | 421 | +                    this.clearLine();  | 
367 | 422 |                     this.xterm.write(this.input);  | 
368 | 423 |                     this.cursorPosition = this.input.length;  | 
369 | 424 |                 }  | 
370 | 425 | 
 
  | 
371 |  | -                cursorRight(){  | 
372 |  | -                     if (this.cursorPosition < this.input.length){  | 
373 |  | -                         this.cursorPosition += 1;  | 
374 |  | -                         this.xterm.write('\x1b[C');  | 
375 |  | -                     }  | 
376 |  | -                }  | 
377 |  | - | 
378 |  | -                cursorLeft(){  | 
379 |  | -                    if (this.cursorPosition > 0){  | 
380 |  | -                        this.cursorPosition -= 1;  | 
381 |  | -                        this.xterm.write('\x1b[D');  | 
382 |  | -                    }  | 
383 |  | -                }  | 
384 |  | - | 
385 |  | -                cursorHome() {  | 
386 |  | -                    if (this.cursorPosition > 0){  | 
387 |  | -                        this.xterm.write('\x1b[' + this.cursorPosition + 'D');  | 
388 |  | -                        this.cursorPosition = 0;  | 
389 |  | -                    }  | 
390 |  | -                }  | 
391 |  | - | 
392 |  | -                cursorEnd() {  | 
393 |  | -                    if (this.cursorPosition < this.input.length){  | 
394 |  | -                        this.xterm.write('\x1b[' + (this.input.length - this.cursorPosition) + 'C');  | 
395 |  | -                        this.cursorPosition = this.input.length;  | 
396 |  | -                    }  | 
397 |  | -                }  | 
398 |  | - | 
399 |  | -                handleTab() {  | 
400 |  | -                    // handle tabs: from the current position, add spaces until  | 
401 |  | -                    // this.cursorPosition is a multiple of 4.  | 
402 |  | -                    const prefix = this.input.slice(0, this.cursorPosition);  | 
403 |  | -                    const suffix = this.input.slice(this.cursorPosition);  | 
404 |  | -                    const count = 4 - (this.cursorPosition % 4);  | 
405 |  | -                    const toAdd = " ".repeat(count);  | 
406 |  | -                    this.input = prefix + toAdd + suffix;  | 
407 |  | -                    if (this.cursorPosition > 0){  | 
408 |  | -                        this.xterm.write('\x1b[' + (this.cursorPosition) + 'D');  | 
409 |  | -                    }  | 
410 |  | -                    // clear the line  | 
411 |  | -                    this.xterm.write('\x1b[K')  | 
412 |  | -                    this.xterm.write(this.input);  | 
413 |  | -                    if (suffix){  | 
414 |  | -                        this.xterm.write('\x1b[' + suffix.length + 'D');  | 
415 |  | -                    }  | 
416 |  | -                    this.cursorPosition += count;  | 
417 |  | -                }  | 
418 |  | - | 
419 | 426 |                 prompt = async () => {  | 
420 | 427 |                     this.activeInput = true;  | 
421 | 428 |                     // Hack to allow stdout/stderr to finish before we figure out where input starts  | 
 | 
442 | 449 |                     }  | 
443 | 450 |                     return new Promise((resolve, reject) => {  | 
444 | 451 |                         this.resolveInput = (value) => {  | 
445 |  | -                            if (value !== ""){  | 
 | 452 | +                            if (value.replace(/\s/g, '').length != 0){  | 
 | 453 | +                                if (this.historyIndex !== -1){  | 
 | 454 | +                                    this.historyBuffer[this.historyIndex] = this.history[this.historyIndex];  | 
 | 455 | +                                }  | 
446 | 456 |                                 this.history.push(value.slice(0, -1));  | 
 | 457 | +                                this.historyBuffer.push(value.slice(0, -1));  | 
447 | 458 |                                 this.historyIndex = -1;  | 
448 | 459 |                                 this.cursorPosition = 0;  | 
449 | 460 |                             }  | 
 | 
0 commit comments