From a6764f2d8fd02a7cdf6683e8d240017b64c10f82 Mon Sep 17 00:00:00 2001 From: Dominique Fournier Date: Wed, 13 Jun 2018 10:17:16 +0000 Subject: [PATCH] console : manage correctely the window size console : Add support to Ctrl+L git-svn-id: https://svn.fournier38.fr/svn/ProgSVN/trunk@4237 bf3deb0d-5f1a-0410-827f-c0cc1f45334c --- console.php | 114 +++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 99 insertions(+), 15 deletions(-) diff --git a/console.php b/console.php index 0f3719a..2a21c3a 100644 --- a/console.php +++ b/console.php @@ -13,6 +13,7 @@ class console { // PROPERTIES // {{{ +private $usleep = 0; /** Save the initial stty value */ private $initSttyState; @@ -46,6 +47,14 @@ class console /** Set the function called when the completion char is called */ private $completionFunction = array (); + + /** Set the width of the terminal in chars + */ + private $termWidth; + + /** Store the last cursor position in the last readline + */ + private $cursorPos = 1; // }}} /** The constructor init the console. @@ -61,6 +70,17 @@ class console // Do not display anything, so we don't see the characters when the user is // deleting. exec ("stty -echo -icanon min 1 time 0"); + $termSize = exec ("stty size", $null, $rc); + if ($rc === 0) + { + list ($termHeight, $termWidth) = explode (" ", $termSize); + if (is_null ($termWidth) || is_bool ($termWidth)) + $this->termWidth = 80; + else + $this->termWidth = intval ($termWidth); + } + else + $this->termWidth = 80; } // }}} @@ -210,7 +230,7 @@ class console { // Gets can not delete chars before the call. Keep the prompt (if exists) $prompt = $this->lineContent; - $minLength = mb_strlen ($this->lineContent); + $minLength = mb_strlen ($this->lineContent) + 1; // The cursor position from first char of line. $cursorPos = $minLength; // Manage the history and a temporary buffer if the user has already type @@ -285,7 +305,7 @@ class console echo "\n".implode ("\n", $completeArr)."\n"; } } - $cursorPos = mb_strlen ($prompt.$string); + $cursorPos = mb_strlen ($prompt.$string) + 1; $this->rewriteLine ($prompt.$string); $this->moveCursor ($cursorPos); } @@ -299,6 +319,16 @@ class console return $string; } // }}} + elseif (ord($char) === 12) + // Refresh page (Ctrl+L) + // {{{ + { + echo "\033[2J\033[;H"; + $cursorPos = mb_strlen ($prompt.$string) + 1; + $this->rewriteLine ($prompt.$string); + $this->moveCursor ($cursorPos); + } + // }}} elseif (ord($char) === 21) // Empty line from prompt to cursor (Ctrl+U) // {{{ @@ -329,11 +359,11 @@ class console // Remove the previous char (Backspace) // {{{ { - if ($cursorPos <= $minLength) + if ($cursorPos -1 <= $minLength) continue; - $cursorPos--; $strArr = $this->mb_str_split ($string); - unset ($strArr[$cursorPos - $minLength]); + $cursorPos--; + unset ($strArr[$cursorPos - $minLength - 1]); $string = implode ($strArr); $this->rewriteLine ($prompt.$string); $this->moveCursor ($cursorPos); @@ -356,7 +386,7 @@ class console if ($pos !== false) $cursorPos += $pos +1 ; else - $cursorPos = mb_strlen ($prompt.$string); + $cursorPos = mb_strlen ($prompt.$string) + 1; $this->moveCursor ($cursorPos); } // }}} @@ -384,7 +414,7 @@ class console { $historyPos--; $string = $this->history[$historyPos]; - $cursorPos = mb_strlen ($prompt.$string); + $cursorPos = mb_strlen ($prompt.$string) + 1; $this->rewriteLine ($prompt.$string); $this->moveCursor ($cursorPos); } @@ -403,7 +433,7 @@ class console { $string = $historyTmp; } - $cursorPos = mb_strlen ($prompt.$string); + $cursorPos = mb_strlen ($prompt.$string) + 1; $this->rewriteLine ($prompt.$string); $this->moveCursor ($cursorPos); } @@ -412,7 +442,7 @@ class console // Cursor right // {{{ { - if ($cursorPos < mb_strlen ($this->lineContent)) + if ($cursorPos <= mb_strlen ($this->lineContent)) { $cursorPos++; $this->moveCursor ($cursorPos); @@ -494,23 +524,64 @@ class console // {{{ { if ($this->echoMode) + { + // Based on https://stackoverflow.com/a/27850902/158716 + $oldLength = mb_strlen ($this->lineContent); + // 1. Calculate on which line the cursor is positionned + $cursorLine = 1 + floor ((-1+$this->cursorPos) / $this->termWidth); + $lastLines = 1 + floor ((1+$oldLength) / $this->termWidth); + for ($i = $cursorLine ; $i < $lastLines ; $i++) + echo "\033[1B"; + // 3. Remove the lines from lastLines to line 1 + if ($lastLines > 1) + { + for ($i = $lastLines ; $i > 1 ; $i--) + echo "\r\033[K\033[1A\r"; + } + // 4. Clean the line 1 + echo "\r\033[K"; + $this->lineContent = $text; + echo $this->lineContent; + $this->cursorPos = mb_strlen ($this->lineContent); + } +/* if ($this->echoMode) { echo "\r".str_repeat (" ", mb_strlen ($this->lineContent))."\r"; $this->lineContent = $text; echo $this->lineContent; - } + }*/ } // }}} - /** Move the cursor on position $position + /** Move the cursor on position $position. The first column is $cursorPos=1 * @param integer $cursorPos The new position on line */ private function moveCursor ($cursorPos) // {{{ { + if ($cursorPos < 1) + $this->consoleException ("MoveCursor lesser than one : $cursorPos"); if ($this->echoMode) { - echo "\r".str_repeat (chr (27).chr (91).chr (67), $cursorPos); + $oldLength = mb_strlen ($this->lineContent); + // 1. Calculate on which line the cursor is positionned + $cursorLine = 1 + floor ((-1+$this->cursorPos) / $this->termWidth); + // 2. Return the cursor to the first line + for ($i = $cursorLine ; $i > 1 ; $i--) + echo chr (27).chr (91).chr (49).chr (65)."\r"; + // 3. Down the cursor to the wanted line + $wantedLine = ceil ($cursorPos / $this->termWidth); + if ($wantedLine > 1) + { + for ($i = 1 ; $i < $wantedLine ; $i++) + echo "\r".chr (27).chr (91).chr (49).chr (66)."\r"; + } + // 4. Move the cursor on the last line + $needMovePos = -1 + $cursorPos - ($wantedLine - 1) * $this->termWidth; + echo "\r".str_repeat (chr (27).chr (91).chr (67), $needMovePos); + $this->cursorPos = $cursorPos; + // On unique line : + //echo "\r".str_repeat (chr (27).chr (91).chr (67), $cursorPos); } } // }}} @@ -674,15 +745,28 @@ class console /** This function return an array with each char, but supports UTF-8 * @param string $string The string to explode + * @param integer $split_length The number of chars in each split * @return array */ - private function mb_str_split ($string) + private function mb_str_split ($string, $split_length = 1) // {{{ { $res = array(); - for ($i = 0; $i < mb_strlen ($string); $i++) - $res[] = mb_substr ($string, $i, 1); + for ($i = 0; $i < mb_strlen ($string); $i += $split_length) + $res[] = mb_substr ($string, $i, $split_length); return $res; } // }}} + + /** This function debug the data + * @param mixed $data The data to store + */ + private function debug ($data) + // {{{ + { + if (is_array ($data) || is_bool ($data)) + $data = var_export ($data, true); + file_put_contents ("/tmp/debug", date ("H:i:s")." $data\n", FILE_APPEND); + } + // }}} }