Fix arrow key movement and use Position class for cursor and offset
This commit is contained in:
parent
e4ffe8eb98
commit
fdd90e289e
242
src/Editor.php
242
src/Editor.php
@ -12,14 +12,34 @@ use Aviat\Kilo\Tokens\PHP8;
|
|||||||
class Editor {
|
class Editor {
|
||||||
use Traits\MagicProperties;
|
use Traits\MagicProperties;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string The screen buffer
|
||||||
|
*/
|
||||||
private string $outputBuffer = '';
|
private string $outputBuffer = '';
|
||||||
|
|
||||||
protected int $cursorX = 0;
|
/**
|
||||||
protected int $cursorY = 0;
|
* @var Position The 0-based location of the cursor in the current viewport
|
||||||
|
*/
|
||||||
|
protected Position $cursor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var Position The scroll offset of the file in the current viewport
|
||||||
|
*/
|
||||||
|
protected Position $offset;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var int The rendered cursor position
|
||||||
|
*/
|
||||||
protected int $renderX = 0;
|
protected int $renderX = 0;
|
||||||
protected int $rowOffset = 0;
|
|
||||||
protected int $colOffset = 0;
|
/**
|
||||||
|
* @var int The size of the current terminal in rows
|
||||||
|
*/
|
||||||
protected int $screenRows = 0;
|
protected int $screenRows = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var int The size of the current terminal in columns
|
||||||
|
*/
|
||||||
protected int $screenCols = 0;
|
protected int $screenCols = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -45,6 +65,8 @@ class Editor {
|
|||||||
private function __construct()
|
private function __construct()
|
||||||
{
|
{
|
||||||
$this->statusMsgTime = time();
|
$this->statusMsgTime = time();
|
||||||
|
$this->cursor = Position::default();
|
||||||
|
$this->offset = Position::default();
|
||||||
|
|
||||||
[$this->screenRows, $this->screenCols] = Terminal::getWindowSize();
|
[$this->screenRows, $this->screenCols] = Terminal::getWindowSize();
|
||||||
|
|
||||||
@ -65,13 +87,11 @@ class Editor {
|
|||||||
public function __debugInfo(): array
|
public function __debugInfo(): array
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
'colOffset' => $this->colOffset,
|
'cursor' => $this->cursor,
|
||||||
'cursorX' => $this->cursorX,
|
'offset' => $this->offset,
|
||||||
'cursorY' => $this->cursorY,
|
|
||||||
'dirty' => $this->dirty,
|
'dirty' => $this->dirty,
|
||||||
'filename' => $this->filename,
|
'filename' => $this->filename,
|
||||||
'renderX' => $this->renderX,
|
'renderX' => $this->renderX,
|
||||||
'rowOffset' => $this->rowOffset,
|
|
||||||
'rows' => $this->rows,
|
'rows' => $this->rows,
|
||||||
'screenCols' => $this->screenCols,
|
'screenCols' => $this->screenCols,
|
||||||
'screenRows' => $this->screenRows,
|
'screenRows' => $this->screenRows,
|
||||||
@ -257,41 +277,41 @@ class Editor {
|
|||||||
|
|
||||||
protected function insertChar(string $c): void
|
protected function insertChar(string $c): void
|
||||||
{
|
{
|
||||||
if ($this->cursorY === $this->numRows)
|
if ($this->cursor->y === $this->numRows)
|
||||||
{
|
{
|
||||||
$this->insertRow($this->numRows, '');
|
$this->insertRow($this->numRows, '');
|
||||||
}
|
}
|
||||||
$this->rows[$this->cursorY]->insertChar($this->cursorX, $c);
|
$this->rows[$this->cursor->y]->insertChar($this->cursor->x, $c);
|
||||||
|
|
||||||
// Re-tokenize the file
|
// Re-tokenize the file
|
||||||
$this->refreshPHPSyntax();
|
$this->refreshPHPSyntax();
|
||||||
|
|
||||||
$this->cursorX++;
|
$this->cursor->x++;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function insertNewline(): void
|
protected function insertNewline(): void
|
||||||
{
|
{
|
||||||
// @TODO attempt smart indentation on newline?
|
// @TODO attempt smart indentation on newline?
|
||||||
|
|
||||||
if ($this->cursorX === 0)
|
if ($this->cursor->x === 0)
|
||||||
{
|
{
|
||||||
$this->insertRow($this->cursorY, '');
|
$this->insertRow($this->cursor->y, '');
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
$row = $this->rows[$this->cursorY];
|
$row = $this->rows[$this->cursor->y];
|
||||||
$chars = $row->chars;
|
$chars = $row->chars;
|
||||||
$newChars = substr($chars, 0, $this->cursorX);
|
$newChars = substr($chars, 0, $this->cursor->x);
|
||||||
|
|
||||||
// Truncate the previous row
|
// Truncate the previous row
|
||||||
$row->chars = $newChars;
|
$row->chars = $newChars;
|
||||||
|
|
||||||
// Add a new row, with the contents from the cursor to the end of the line
|
// Add a new row, with the contents from the cursor to the end of the line
|
||||||
$this->insertRow($this->cursorY + 1, substr($chars, $this->cursorX));
|
$this->insertRow($this->cursor->y + 1, substr($chars, $this->cursor->x));
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->cursorY++;
|
$this->cursor->y++;
|
||||||
$this->cursorX = 0;
|
$this->cursor->x = 0;
|
||||||
|
|
||||||
// Re-tokenize the file
|
// Re-tokenize the file
|
||||||
$this->refreshPHPSyntax();
|
$this->refreshPHPSyntax();
|
||||||
@ -299,23 +319,23 @@ class Editor {
|
|||||||
|
|
||||||
protected function deleteChar(): void
|
protected function deleteChar(): void
|
||||||
{
|
{
|
||||||
if ($this->cursorY === $this->numRows || ($this->cursorX === 0 && $this->cursorY === 0))
|
if ($this->cursor->y === $this->numRows || ($this->cursor->x === 0 && $this->cursor->y === 0))
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$row = $this->rows[$this->cursorY];
|
$row = $this->rows[$this->cursor->y];
|
||||||
if ($this->cursorX > 0)
|
if ($this->cursor->x > 0)
|
||||||
{
|
{
|
||||||
$row->deleteChar($this->cursorX - 1);
|
$row->deleteChar($this->cursor->x - 1);
|
||||||
$this->cursorX--;
|
$this->cursor->x--;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
$this->cursorX = $this->rows[$this->cursorY - 1]->size;
|
$this->cursor->x = $this->rows[$this->cursor->y - 1]->size;
|
||||||
$this->rows[$this->cursorY -1]->appendString($row->chars);
|
$this->rows[$this->cursor->y -1]->appendString($row->chars);
|
||||||
$this->deleteRow($this->cursorY);
|
$this->deleteRow($this->cursor->y);
|
||||||
$this->cursorY--;
|
$this->cursor->y--;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Re-tokenize the file
|
// Re-tokenize the file
|
||||||
@ -457,9 +477,9 @@ class Editor {
|
|||||||
if ($match !== FALSE)
|
if ($match !== FALSE)
|
||||||
{
|
{
|
||||||
$lastMatch = $current;
|
$lastMatch = $current;
|
||||||
$this->cursorY = (int)$current;
|
$this->cursor->y = (int)$current;
|
||||||
$this->cursorX = $this->rowRxToCx($row, $match);
|
$this->cursor->x = $this->rowRxToCx($row, $match);
|
||||||
$this->rowOffset = $this->numRows;
|
$this->offset->y = $this->numRows;
|
||||||
|
|
||||||
$savedHlLine = $current;
|
$savedHlLine = $current;
|
||||||
$savedHl = $row->hl;
|
$savedHl = $row->hl;
|
||||||
@ -473,10 +493,10 @@ class Editor {
|
|||||||
|
|
||||||
protected function find(): void
|
protected function find(): void
|
||||||
{
|
{
|
||||||
$savedCx = $this->cursorX;
|
$savedCx = $this->cursor->x;
|
||||||
$savedCy = $this->cursorY;
|
$savedCy = $this->cursor->y;
|
||||||
$savedColOff = $this->colOffset;
|
$savedColOff = $this->offset->x;
|
||||||
$savedRowOff = $this->rowOffset;
|
$savedRowOff = $this->offset->y;
|
||||||
|
|
||||||
$query = $this->prompt('Search: %s (Use ESC/Arrows/Enter)', [$this, 'findCallback']);
|
$query = $this->prompt('Search: %s (Use ESC/Arrows/Enter)', [$this, 'findCallback']);
|
||||||
|
|
||||||
@ -484,10 +504,10 @@ class Editor {
|
|||||||
// restore original cursor and scroll locations
|
// restore original cursor and scroll locations
|
||||||
if ($query === '')
|
if ($query === '')
|
||||||
{
|
{
|
||||||
$this->cursorX = $savedCx;
|
$this->cursor->x = $savedCx;
|
||||||
$this->cursorY = $savedCy;
|
$this->cursor->y = $savedCy;
|
||||||
$this->colOffset = $savedColOff;
|
$this->offset->x = $savedColOff;
|
||||||
$this->rowOffset = $savedRowOff;
|
$this->offset->y = $savedRowOff;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -498,29 +518,29 @@ class Editor {
|
|||||||
protected function scroll(): void
|
protected function scroll(): void
|
||||||
{
|
{
|
||||||
$this->renderX = 0;
|
$this->renderX = 0;
|
||||||
if ($this->cursorY < $this->numRows)
|
if ($this->cursor->y < $this->numRows)
|
||||||
{
|
{
|
||||||
$this->renderX = $this->rowCxToRx($this->rows[$this->cursorY], $this->cursorX);
|
$this->renderX = $this->rowCxToRx($this->rows[$this->cursor->y], $this->cursor->x);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Vertical Scrolling
|
// Vertical Scrolling
|
||||||
if ($this->cursorY < $this->rowOffset)
|
if ($this->cursor->y < $this->offset->y)
|
||||||
{
|
{
|
||||||
$this->rowOffset = $this->cursorY;
|
$this->offset->y = $this->cursor->y;
|
||||||
}
|
}
|
||||||
if ($this->cursorY >= ($this->rowOffset + $this->screenRows))
|
else if ($this->cursor->y >= ($this->offset->y + $this->screenRows))
|
||||||
{
|
{
|
||||||
$this->rowOffset = $this->cursorY - $this->screenRows + 1;
|
$this->offset->y = $this->cursor->y - $this->screenRows + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Horizontal Scrolling
|
// Horizontal Scrolling
|
||||||
if ($this->renderX < $this->colOffset)
|
if ($this->renderX < $this->offset->x)
|
||||||
{
|
{
|
||||||
$this->colOffset = $this->renderX;
|
$this->offset->x = $this->renderX;
|
||||||
}
|
}
|
||||||
if ($this->renderX >= ($this->colOffset + $this->screenCols))
|
else if ($this->renderX >= ($this->offset->x + $this->screenCols))
|
||||||
{
|
{
|
||||||
$this->colOffset = $this->renderX - $this->screenCols + 1;
|
$this->offset->x = $this->renderX - $this->screenCols + 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -528,7 +548,7 @@ class Editor {
|
|||||||
{
|
{
|
||||||
for ($y = 0; $y < $this->screenRows; $y++)
|
for ($y = 0; $y < $this->screenRows; $y++)
|
||||||
{
|
{
|
||||||
$filerow = $y + $this->rowOffset;
|
$filerow = $y + $this->offset->y;
|
||||||
|
|
||||||
($filerow >= $this->numRows)
|
($filerow >= $this->numRows)
|
||||||
? $this->drawPlaceholderRow($y)
|
? $this->drawPlaceholderRow($y)
|
||||||
@ -541,7 +561,7 @@ class Editor {
|
|||||||
|
|
||||||
protected function drawRow(int $rowIdx): void
|
protected function drawRow(int $rowIdx): void
|
||||||
{
|
{
|
||||||
$len = $this->rows[$rowIdx]->rsize - $this->colOffset;
|
$len = $this->rows[$rowIdx]->rsize - $this->offset->x;
|
||||||
if ($len < 0)
|
if ($len < 0)
|
||||||
{
|
{
|
||||||
$len = 0;
|
$len = 0;
|
||||||
@ -551,8 +571,8 @@ class Editor {
|
|||||||
$len = $this->screenCols;
|
$len = $this->screenCols;
|
||||||
}
|
}
|
||||||
|
|
||||||
$chars = substr($this->rows[$rowIdx]->render, $this->colOffset, (int)$len);
|
$chars = substr($this->rows[$rowIdx]->render, $this->offset->x, (int)$len);
|
||||||
$hl = array_slice($this->rows[$rowIdx]->hl, $this->colOffset, (int)$len);
|
$hl = array_slice($this->rows[$rowIdx]->hl, $this->offset->x, (int)$len);
|
||||||
|
|
||||||
$currentColor = -1;
|
$currentColor = -1;
|
||||||
|
|
||||||
@ -639,7 +659,7 @@ class Editor {
|
|||||||
$syntaxType = ($this->syntax !== NULL) ? $this->syntax->filetype : 'no ft';
|
$syntaxType = ($this->syntax !== NULL) ? $this->syntax->filetype : 'no ft';
|
||||||
$isDirty = ($this->dirty > 0) ? '(modified)' : '';
|
$isDirty = ($this->dirty > 0) ? '(modified)' : '';
|
||||||
$status = sprintf('%.20s - %d lines %s', $statusFilename, $this->numRows, $isDirty);
|
$status = sprintf('%.20s - %d lines %s', $statusFilename, $this->numRows, $isDirty);
|
||||||
$rstatus = sprintf('%s | %d/%d', $syntaxType, $this->cursorY + 1, $this->numRows);
|
$rstatus = sprintf('%s | %d/%d', $syntaxType, $this->cursor->y + 1, $this->numRows);
|
||||||
$len = strlen($status);
|
$len = strlen($status);
|
||||||
$rlen = strlen($rstatus);
|
$rlen = strlen($rstatus);
|
||||||
if ($len > $this->screenCols)
|
if ($len > $this->screenCols)
|
||||||
@ -692,8 +712,8 @@ class Editor {
|
|||||||
|
|
||||||
// Specify the current cursor position
|
// Specify the current cursor position
|
||||||
$this->outputBuffer .= ANSI::moveCursor(
|
$this->outputBuffer .= ANSI::moveCursor(
|
||||||
$this->cursorY - $this->rowOffset,
|
$this->cursor->y - $this->offset->y,
|
||||||
$this->renderX - $this->colOffset
|
$this->renderX - $this->offset->x
|
||||||
);
|
);
|
||||||
|
|
||||||
$this->outputBuffer .= ANSI::SHOW_CURSOR;
|
$this->outputBuffer .= ANSI::SHOW_CURSOR;
|
||||||
@ -753,58 +773,78 @@ class Editor {
|
|||||||
|
|
||||||
protected function moveCursor(string $key): void
|
protected function moveCursor(string $key): void
|
||||||
{
|
{
|
||||||
$row = ($this->cursorY >= $this->numRows)
|
$row = $this->rows[$this->cursor->y];
|
||||||
? NULL
|
|
||||||
: $this->rows[$this->cursorY];
|
|
||||||
|
|
||||||
switch ($key)
|
switch ($key)
|
||||||
{
|
{
|
||||||
case KeyType::ARROW_LEFT:
|
case KeyType::ARROW_LEFT:
|
||||||
if ($this->cursorX !== 0)
|
if ($this->cursor->x !== 0)
|
||||||
{
|
{
|
||||||
$this->cursorX--;
|
$this->cursor->x--;
|
||||||
}
|
}
|
||||||
else if ($this->cursorY > 0)
|
else if ($this->cursor->y > 0)
|
||||||
{
|
{
|
||||||
$this->cursorY--;
|
$this->cursor->y--;
|
||||||
$this->cursorX = $this->rows[$this->cursorY]->size;
|
$this->cursor->x = $this->rows[$this->cursor->y]->size;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case KeyType::ARROW_RIGHT:
|
case KeyType::ARROW_RIGHT:
|
||||||
if ($row && $this->cursorX < $row->size)
|
if ($row && $this->cursor->x < $row->size)
|
||||||
{
|
{
|
||||||
$this->cursorX++;
|
$this->cursor->x++;
|
||||||
}
|
}
|
||||||
else if ($row && $this->cursorX === $row->size)
|
else if ($row && $this->cursor->x === $row->size)
|
||||||
{
|
{
|
||||||
$this->cursorY++;
|
$this->cursor->y++;
|
||||||
$this->cursorX = 0;
|
$this->cursor->x = 0;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case KeyType::ARROW_UP:
|
case KeyType::ARROW_UP:
|
||||||
if ($this->cursorY !== 0)
|
if ($this->cursor->y !== 0)
|
||||||
{
|
{
|
||||||
$this->cursorY--;
|
$this->cursor->y--;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case KeyType::ARROW_DOWN:
|
case KeyType::ARROW_DOWN:
|
||||||
if ($this->cursorY < $this->numRows)
|
if ($this->cursor->y < $this->numRows)
|
||||||
{
|
{
|
||||||
$this->cursorY++;
|
$this->cursor->y++;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case KeyType::PAGE_UP:
|
||||||
|
$this->cursor->y = ($this->cursor->y > $this->screenRows)
|
||||||
|
? $this->cursor->y - $this->screenRows
|
||||||
|
: 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case KeyType::PAGE_DOWN:
|
||||||
|
$this->cursor->y = ($this->cursor->y + $this->screenRows < $this->numRows)
|
||||||
|
? $this->cursor->y + $this->screenRows
|
||||||
|
: $this->numRows;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case KeyType::HOME_KEY:
|
||||||
|
$this->cursor->x = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case KeyType::END_KEY:
|
||||||
|
if ($this->cursor->y < $this->numRows)
|
||||||
|
{
|
||||||
|
$this->cursor->x = $this->rows[$this->cursor->y]->size - 1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
// Do nothing
|
||||||
}
|
}
|
||||||
|
|
||||||
$row = ($this->cursorY >= $this->numRows)
|
if ($this->cursor->x > $row->size)
|
||||||
? NULL
|
|
||||||
: $this->rows[$this->cursorY];
|
|
||||||
$rowlen = $row->size ?? 0;
|
|
||||||
if ($this->cursorX > $rowlen)
|
|
||||||
{
|
{
|
||||||
$this->cursorX = $rowlen;
|
$this->cursor->x = $row->size;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -834,25 +874,12 @@ class Editor {
|
|||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
Terminal::clear();
|
Terminal::clear();
|
||||||
|
return NULL;
|
||||||
return NULL;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case KeyCode::CTRL('s'):
|
case KeyCode::CTRL('s'):
|
||||||
$this->save();
|
$this->save();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case KeyType::HOME_KEY:
|
|
||||||
$this->cursorX = 0;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case KeyType::END_KEY:
|
|
||||||
if ($this->cursorY < $this->numRows)
|
|
||||||
{
|
|
||||||
$this->cursorX = $this->rows[$this->cursorY]->size - 1;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case KeyCode::CTRL('f'):
|
case KeyCode::CTRL('f'):
|
||||||
$this->find();
|
$this->find();
|
||||||
break;
|
break;
|
||||||
@ -866,15 +893,14 @@ class Editor {
|
|||||||
$this->deleteChar();
|
$this->deleteChar();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case KeyType::PAGE_UP:
|
|
||||||
case KeyType::PAGE_DOWN:
|
|
||||||
$this->pageUpOrDown($c);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case KeyType::ARROW_UP:
|
case KeyType::ARROW_UP:
|
||||||
case KeyType::ARROW_DOWN:
|
case KeyType::ARROW_DOWN:
|
||||||
case KeyType::ARROW_LEFT:
|
case KeyType::ARROW_LEFT:
|
||||||
case KeyType::ARROW_RIGHT:
|
case KeyType::ARROW_RIGHT:
|
||||||
|
case KeyType::PAGE_UP:
|
||||||
|
case KeyType::PAGE_DOWN:
|
||||||
|
case KeyType::HOME_KEY:
|
||||||
|
case KeyType::END_KEY:
|
||||||
$this->moveCursor($c);
|
$this->moveCursor($c);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -893,28 +919,6 @@ class Editor {
|
|||||||
return $c;
|
return $c;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function pageUpOrDown(string $c): void
|
|
||||||
{
|
|
||||||
if ($c === KeyType::PAGE_UP)
|
|
||||||
{
|
|
||||||
$this->cursorY = $this->rowOffset;
|
|
||||||
}
|
|
||||||
else if ($c === KeyType::PAGE_DOWN)
|
|
||||||
{
|
|
||||||
$this->cursorY = $this->rowOffset + $this->screenRows - 1;
|
|
||||||
if ($this->cursorY > $this->numRows)
|
|
||||||
{
|
|
||||||
$this->cursorY = $this->numRows;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$times = $this->screenRows;
|
|
||||||
for (; $times > 0; $times--)
|
|
||||||
{
|
|
||||||
$this->moveCursor($c === KeyType::PAGE_UP ? KeyType::ARROW_UP : KeyType::ARROW_DOWN);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function refreshSyntax(): void
|
protected function refreshSyntax(): void
|
||||||
{
|
{
|
||||||
// Update the syntax highlighting for all the rows of the file
|
// Update the syntax highlighting for all the rows of the file
|
||||||
|
17
src/Position.php
Normal file
17
src/Position.php
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
<?php declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Aviat\Kilo;
|
||||||
|
|
||||||
|
class Position {
|
||||||
|
private function __construct(public int $x, public int $y) {}
|
||||||
|
|
||||||
|
public static function new(int $x, int $y): self
|
||||||
|
{
|
||||||
|
return new Position($x, $y);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function default(): self
|
||||||
|
{
|
||||||
|
return new Position(0, 0);
|
||||||
|
}
|
||||||
|
}
|
@ -118,7 +118,7 @@ function is_separator(string $char): bool
|
|||||||
* @param int $length The number of indices to update
|
* @param int $length The number of indices to update
|
||||||
* @param mixed $value The value to replace in the range
|
* @param mixed $value The value to replace in the range
|
||||||
*/
|
*/
|
||||||
function array_replace_range(array &$array, int $offset, int $length, $value):void
|
function array_replace_range(array &$array, int $offset, int $length, mixed $value):void
|
||||||
{
|
{
|
||||||
if ($length === 1)
|
if ($length === 1)
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user