diff --git a/src/Document.php b/src/Document.php index b0c5167..3b5405d 100644 --- a/src/Document.php +++ b/src/Document.php @@ -230,6 +230,10 @@ class Document { // Add a new row with the contents of the previous row at the point of the split $this->insertRow($at->y + 1, substr($chars, $at->x)); + + // Highlight the two changed rows + $row->update(); + $this->rows[$at->y + 1]->update(); } $this->dirty = true; diff --git a/src/Editor.php b/src/Editor.php index 6689c1e..99f3817 100644 --- a/src/Editor.php +++ b/src/Editor.php @@ -56,6 +56,11 @@ class Editor { */ protected bool $shouldQuit = false; + /** + * @var int The amount to move the cursor off the left + */ + protected int $cursorLeftOffset = 0; + /** * @var int The number of times to confirm you wish to quit */ @@ -87,6 +92,8 @@ class Editor { { $this->statusMessage = StatusMessage::from('HELP: Ctrl-S = save | Ctrl-Q = quit | Ctrl-F = find'); $this->cursor = Point::new(); + $this->cursor->x += $this->cursorLeftOffset; + $this->offset = Point::new(); $this->terminalSize = Terminal::size(); @@ -385,13 +392,13 @@ class Editor { ($fileRow >= $this->document->numRows) ? $this->drawPlaceholderRow($y) - : $this->drawRow($fileRow); + : $this->drawRow($fileRow, true); $this->outputBuffer .= "\r\n"; } } - protected function drawRow(int $rowIdx): void + protected function drawRow(int $rowIdx, bool $lineNumbers): void { $row = $this->document->row($rowIdx); if ( ! $row->isValid()) @@ -409,8 +416,46 @@ class Editor { $len = $this->terminalSize->cols; } - $chars = substr($row->render, $this->offset->x, (int)$len); - $hl = array_slice($row->hl, $this->offset->x, (int)$len); + if ($lineNumbers) + { + $this->drawLineNumbers($rowIdx); + } + + $this->drawRowHighlighting($row, $len); + + $this->outputBuffer .= ANSI::RESET_TEXT; + $this->outputBuffer .= ANSI::color(Color::FG_WHITE); + } + + protected function drawLineNumbers(int $rowIdx): void + { + $rawColCount = match (true) { + $this->document->numRows > 50 => 3, + $this->document->numRows > 500 => 4, + $this->document->numRows > 5_000 => 5, + $this->document->numRows > 50_000 => 6, + $this->document->numRows > 500_000 => 7, + default => 2, + }; + + $rowNumber = $rowIdx + 1; + $digitLen = strlen("$rowNumber"); + $frontPadding = str_repeat(' ', $rawColCount - $digitLen); + $rearPadding = str_repeat(' ', 2); + + $output = sprintf("%s%d%s", $frontPadding, $rowNumber, $rearPadding); + + $this->outputBuffer .= ANSI::RESET_TEXT; + $this->outputBuffer .= ANSI::color(Color::FG_WHITE); + $this->outputBuffer .= $output; + + $this->cursorLeftOffset = strlen($output); + } + + protected function drawRowHighlighting(Row $row, int $len): void + { + $chars = substr($row->render, $this->offset->x, $len); + $hl = array_slice($row->hl, $this->offset->x, $len); $currentColor = -1; @@ -454,9 +499,6 @@ class Editor { $this->outputBuffer .= $ch; } } - - $this->outputBuffer .= ANSI::RESET_TEXT; - $this->outputBuffer .= ANSI::color(Color::FG_WHITE); } protected function drawPlaceholderRow(int $y): void @@ -548,9 +590,10 @@ class Editor { $this->drawMessageBar(); // Specify the current cursor position + // The current 'x' position takes into account the length of the line number column $this->outputBuffer .= ANSI::moveCursor( $this->cursor->y - $this->offset->y, - $this->renderX - $this->offset->x + $this->renderX - $this->offset->x + $this->cursorLeftOffset, ); $this->outputBuffer .= ANSI::SHOW_CURSOR; @@ -666,7 +709,7 @@ class Editor { protected function moveCursor(string $key): void { - $x = $this->cursor->x; + $x = saturating_sub($this->cursor->x, $this->cursorLeftOffset); $y = $this->cursor->y; $row = $this->document->row($y); if ( ! $row->isValid()) @@ -685,7 +728,7 @@ class Editor { { // Beginning of a line, go to end of previous line $y--; - $x = $row->size - 1; + $x = $this->document->row($y)->size - 1; } break; @@ -766,7 +809,7 @@ class Editor { $this->document->delete($this->cursor); } - if ($ch === KeyType::BACKSPACE && ($this->cursor->x > 0 || $this->cursor->y > 0)) + if ($ch === KeyType::BACKSPACE && ($this->cursor->x > $this->cursorLeftOffset || $this->cursor->y > 0)) { $this->moveCursor(KeyType::ARROW_LEFT); $this->document->delete($this->cursor); diff --git a/src/FileType.php b/src/FileType.php index 0d6cf50..50897d2 100644 --- a/src/FileType.php +++ b/src/FileType.php @@ -115,7 +115,7 @@ class FileType { 'usize', '&str', 'Copy', 'Drop', 'From', 'Into', 'None', 'Self', 'Send', 'Some', 'Sync', 'bool', 'char', 'i128', 'u128', 'Box', 'Err', 'Ord', 'Vec', 'dyn', 'f32', 'f64', 'i16', 'i32', 'i64', 'str', 'u16', 'u32', 'u64', 'Eq', 'Fn', 'Ok', 'i8', 'u8', - '&mut self', '&mut', '&self', 'self', + '&mut self', '&mut', '&self', 'self', '()', ], [ '...', '=>', '..', '>>=', '<<=', '--', '%=', '>>', ':=', '++', '/=', '<<', '>=', diff --git a/src/Row.php b/src/Row.php index 9a7aa77..1cf5eaa 100644 --- a/src/Row.php +++ b/src/Row.php @@ -263,7 +263,14 @@ class Row { || $this->highlightCommonOperators($i, $syntax) || $this->highlightNumber($i, $syntax) ) { - continue; + if ($i >= $this->rsize) + { + break; + } + else + { + continue; + } } $i++; diff --git a/src/functions.php b/src/functions.php index bb7e437..9042a94 100644 --- a/src/functions.php +++ b/src/functions.php @@ -189,6 +189,12 @@ function tabs_to_spaces(string $str, int $number = KILO_TAB_STOP): string return str_replace(RawKeyCode::TAB, str_repeat(RawKeyCode::SPACE, $number), $str); } +/** + * Get an understandable name for the type of error code + * + * @param int $code + * @return string + */ function error_code_name(int $code): string { return match ($code) { @@ -210,11 +216,28 @@ function error_code_name(int $code): string }; } +/** + * Add two integers, returning the sum, or if the + * sum is greater than $max, returning $max + * + * @param int $a + * @param int $b + * @param int $max + * @return int + */ function saturating_add(int $a, int $b, int $max): int { return ($a + $b > $max) ? $max : $a + $b; } +/** + * Subtract $b from $a, returning the difference + * or 0, whichever is greater + * + * @param int $a + * @param int $b + * @return int + */ function saturating_sub(int $a, int $b): int { if ($b > $a)