/** * Reads a single line from the user. * * @param string $prompt You may specify a string with which to prompt the user. * * @return Returns a single string from the user. */ public function readline($prompt = null) { $line = null; $this->_reset(); // Output prompt if ($prompt !== null) { $this->_prompt = $prompt; echo $prompt; } while (1) { $c = self::readKey(); switch ($c) { // Unrecognised character case null: Terminal::bell(); break; // TAB // TAB case chr(9): // If autocompletion is registered, then do it if ($this->_autocomplete_callback !== null) { $autocomplete_text = $this->_doAutocomplete($this->_buffer); if (!empty($autocomplete_text)) { $this->_insert($autocomplete_text); } else { Terminal::bell(); } // Otherwise, TAB will insert spaces } else { $this->_insert(" "); } break; // CTRL-A (Home) - move the cursor all the way to the left // CTRL-A (Home) - move the cursor all the way to the left case chr(1): $this->_cursorLeft($this->_buffer_position); break; // CTRL-E (End) - move cursor all the way to the end // CTRL-E (End) - move cursor all the way to the end case chr(5): $this->_cursorRight(mb_strlen($this->_buffer) - $this->_buffer_position); break; // Line-delete - backspace from current position to beginning of line // Line-delete - backspace from current position to beginning of line case chr(21): $this->_backspace($this->_buffer_position); break; // Word-delete (CTRL-W) // Word-delete (CTRL-W) case chr(23): // Get previous word position $prev_word_pos = $this->_buffer_position - $this->_getPreviousWordPos(); // Delete word, unless we're at the start of the line, then bell if ($prev_word_pos > 0) { $this->_backspace($this->_buffer_position - $this->_getPreviousWordPos()); } else { Terminal::bell(); } break; // CTRL-LEFT // CTRL-LEFT case chr(27) . chr(91) . chr(53) . chr(68): $this->_cursorLeft($this->_buffer_position - $this->_getPreviousWordPos()); break; // CTRL-RIGHT // CTRL-RIGHT case chr(27) . chr(91) . chr(53) . chr(67): $this->_cursorRight($this->_getNextWordPos() - $this->_buffer_position); break; // CTRL-C // CTRL-C case chr(3): $line = $this->_buffer . $c; break; // CTRL-D // CTRL-D case chr(4): // Return current line immediately on CTRL-D if (mb_strlen($this->_buffer) === 0) { $line = $this->_buffer . $c; } else { Terminal::bell(); } break; case UP: // Move backwards in the history if (!$this->_historyMovePosition(-1)) { Terminal::bell(); } break; case DOWN: // Move forward in the history if (!$this->_historyMovePosition(1)) { Terminal::bell(); } break; case LEFT: // Move left, or beep if we're already at the beginning if (!$this->_cursorLeft()) { Terminal::bell(); } break; case RIGHT: // Move right, or beep if we're already at the end if (!$this->_cursorRight()) { Terminal::bell(); } break; // Backspace key // Backspace key case chr(8): // Delete // Delete case chr(127): if (!$this->_backspace()) { Terminal::bell(); } break; // Enter key // Enter key case chr(10): // Set the $line variable so we return below $line = $this->_buffer; break; // Normal character key // Normal character key default: // Ignore unknown control characters if (ord($c[0]) === 27) { Terminal::bell(); continue; } // Insert this character into the buffer and move on $this->_insert($c); } // If line has been set, we're ready to do something with this command if ($line !== null) { // Firstly check for internal commands if ($this->_runInternalCommand(trim($line))) { // It it was an internal command, don't return, just reset and pretend // nothing happened... $this->addHistory($line); $line = null; $this->_reset(); } // Remove temp history item array_pop($this->_history_tmp); return $line; } } }