Improve tail line, fix edit box
* Edit box now supports the usual keys; left/right plus home/end, and does the appropriate scrolling. * Tail line is now a top bar. * Added option to toggle tail bar, but not bound to any key.
This commit is contained in:
parent
466406733d
commit
19ba6a9bee
@ -49,6 +49,8 @@ class Editor
|
||||
// ]);
|
||||
|
||||
$this->list = new TreeList($this->document);
|
||||
|
||||
$this->setWindowTitle($this->shortfilename." - JSONEdit");
|
||||
}
|
||||
|
||||
/**
|
||||
@ -73,6 +75,7 @@ class Editor
|
||||
default:
|
||||
throw new \RuntimeException("Unable to read file of type {$ext}");
|
||||
}
|
||||
$this->setWindowTitle($this->shortfilename." - JSONEdit");
|
||||
$this->document->load($doc);
|
||||
$this->list->parseTree();
|
||||
}
|
||||
@ -108,7 +111,7 @@ class Editor
|
||||
$this->redrawEditor();
|
||||
break;
|
||||
case 'k{DOWN}':
|
||||
$this->currentRow = min(count($this->list) - 1, $this->currentRow + 1);
|
||||
$this->currentRow = min(count($this->list), $this->currentRow + 1);
|
||||
$this->redrawEditor();
|
||||
break;
|
||||
case 'k{PGUP}':
|
||||
@ -260,13 +263,45 @@ class Editor
|
||||
$this->redrawEditor();
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case "-":
|
||||
foreach ($this->list as $path => $entry) {
|
||||
$node = $entry->node;
|
||||
if ($path == "/") {
|
||||
if ($node instanceof CollapsibleNode) {
|
||||
$node->collapse(false);
|
||||
}
|
||||
} else {
|
||||
if ($node instanceof CollapsibleNode) {
|
||||
$node->collapse(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
$this->currentRow = 0;
|
||||
$this->list->parseTree();
|
||||
$this->redrawEditor();
|
||||
break;
|
||||
|
||||
case "k{LEFT}":
|
||||
$node = $this->list->getNodeForIndex($this->currentRow);
|
||||
if ($node instanceof CollapsibleNode) {
|
||||
if ($node->isCollapsed()) {
|
||||
$path = $this->list->getPathForIndex($this->currentRow);
|
||||
$parent = $this->list->getIndexForPath(dirname($path));
|
||||
if ($parent) {
|
||||
$this->currentRow = $parent;
|
||||
}
|
||||
}
|
||||
$node->collapse(true);
|
||||
$this->list->parseTree();
|
||||
$this->redrawEditor();
|
||||
} else {
|
||||
$path = $this->list->getPathForIndex($this->currentRow);
|
||||
$parent = $this->list->getIndexForPath(dirname($path));
|
||||
if ($parent) {
|
||||
$this->currentRow = $parent;
|
||||
}
|
||||
$this->redrawEditor();
|
||||
}
|
||||
break;
|
||||
|
||||
@ -373,6 +408,8 @@ class Editor
|
||||
$this->list->parseTree();
|
||||
$this->redrawEditor();
|
||||
|
||||
$this->setWindowTitle($this->shortfilename." - JSONEdit");
|
||||
|
||||
$this->showMessage("\e[97;42mLoaded {$readFrom}");
|
||||
}
|
||||
|
||||
@ -413,6 +450,8 @@ class Editor
|
||||
$this->modified = false;
|
||||
$this->redrawEditor();
|
||||
|
||||
$this->setWindowTitle($this->shortfilename." - JSONEdit");
|
||||
|
||||
$this->showMessage("\e[97;42mWrote to {$saveTo}");
|
||||
return true;
|
||||
|
||||
@ -469,14 +508,11 @@ class Editor
|
||||
This is beta software, if not alpha. It kinda works, but there will be issues. Feel free to help out with a patch, or by filing bug reports.
|
||||
Known issues include:
|
||||
|
||||
* Editing long lines will blow up. Don't try to edit anything longer than the terminal is wide.
|
||||
* There is no fullscreen editing, so verbatim blocks in twig will probably not work well either.
|
||||
* Comments are not preserved.
|
||||
* Files are overwritten without confirmation.
|
||||
* There is no command mode, no search.
|
||||
* Some things just don't work yet.
|
||||
* Unhandled keys will appear in the bottom left of the screen with a delay.
|
||||
* Folding is not yet implemented.
|
||||
* There are crashes, and lock-ups. Data corruption is a possibility.
|
||||
|
||||
# Support
|
||||
@ -643,12 +679,22 @@ class Editor
|
||||
$promptLen = mb_strlen($plainPrompt);
|
||||
[$w,$h] = $this->term->getSize();
|
||||
|
||||
$available = $w - $promptLen - 1;
|
||||
|
||||
$prompting = true;
|
||||
$cursorPos = mb_strlen($value);
|
||||
$scrollPos = max(0, $cursorPos - $available);
|
||||
while ($prompting) {
|
||||
while (($cursorPos - $scrollPos) > $available) {
|
||||
$scrollPos++;
|
||||
}
|
||||
while (($cursorPos - $scrollPos) < 0) {
|
||||
$scrollPos--;
|
||||
}
|
||||
$cursorOffs = $cursorPos - $scrollPos;
|
||||
$this->term->setCursor(1, $h);
|
||||
echo $prompt."\e[0m\e[K".$value;
|
||||
$this->term->setCursor($promptLen+$cursorPos+1, $h, true);
|
||||
echo $prompt."\e[0m\e[K".mb_substr($value, $scrollPos, $available);
|
||||
$this->term->setCursor($promptLen+$cursorOffs+1, $h, true);
|
||||
while (null === ($ch = $this->term->readKey())) {
|
||||
usleep(10000);
|
||||
}
|
||||
@ -684,6 +730,12 @@ class Editor
|
||||
if ($cursorPos < mb_strlen($value))
|
||||
$cursorPos++;
|
||||
break;
|
||||
case "k{HOME}":
|
||||
$cursorPos = 0;
|
||||
break;
|
||||
case "k{END}":
|
||||
$cursorPos = mb_strlen($value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -699,9 +751,16 @@ class Editor
|
||||
{
|
||||
[$w,$h] = $this->term->getSize();
|
||||
|
||||
// Jump to the tail line if the cursor is past the end of the entry list
|
||||
if ($this->currentRow > count($this->list)) $this->currentRow = count($this->list);
|
||||
|
||||
// Make sure the selection is in view
|
||||
while ($this->currentRow < $this->scrollOffset) $this->scrollOffset--;
|
||||
while ($this->currentRow > $h + $this->scrollOffset - 3) $this->scrollOffset++;
|
||||
|
||||
// Nudge back so the tail line is visible but not selected
|
||||
if ($this->currentRow == count($this->list)) $this->currentRow--;
|
||||
|
||||
$path = $this->list->getPathForIndex($this->currentRow);
|
||||
$node = $this->list->getNodeForIndex($this->currentRow);
|
||||
|
||||
@ -770,9 +829,10 @@ class Editor
|
||||
}
|
||||
|
||||
$this->term->setCursor(1, $h);
|
||||
echo "\e[0;40m\e[K";
|
||||
echo "\e[37;40m\e[K";
|
||||
foreach ($keys as $key=>$info)
|
||||
echo "\e[37;40;2m\u{e0b6}\e[7;37m{$key} \e[22m {$info} \e[27m\u{e0b4}\e[0m";
|
||||
echo "\e[2m\u{f104}\e[22;97;1m{$key}\e[22;37;2m\u{f105} \e[22;36m{$info}\e[37m ";
|
||||
//echo "\e[37;40;2m\u{e0b6}\e[7;37m{$key} \e[22m {$info} \e[27m\u{e0b4}\e[0m";
|
||||
//echo " \e[1m{$key}\e[2m \e[3m{$info}\e[0m \e[90m\u{2502}\e[0m";
|
||||
}
|
||||
|
||||
@ -784,4 +844,9 @@ class Editor
|
||||
|
||||
}
|
||||
|
||||
private function setWindowTitle(string $title): void
|
||||
{
|
||||
echo "\e]2;{$title}\x07";
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -2,7 +2,9 @@
|
||||
|
||||
namespace NoccyLabs\JsonEdit\List;
|
||||
|
||||
use ArrayIterator;
|
||||
use Countable;
|
||||
use IteratorAggregate;
|
||||
use NoccyLabs\JsonEdit\Settings;
|
||||
use NoccyLabs\JsonEdit\Tree\ArrayNode;
|
||||
use NoccyLabs\JsonEdit\Tree\CollapsibleNode;
|
||||
@ -10,8 +12,9 @@ use NoccyLabs\JsonEdit\Tree\Tree;
|
||||
use NoccyLabs\JsonEdit\Tree\Node;
|
||||
use NoccyLabs\JsonEdit\Tree\ObjectNode;
|
||||
use NoccyLabs\JsonEdit\Tree\ValueNode;
|
||||
use Traversable;
|
||||
|
||||
class TreeList implements Countable
|
||||
class TreeList implements Countable, IteratorAggregate
|
||||
{
|
||||
/** @var array<string,Entry> */
|
||||
public array $list = [];
|
||||
@ -31,6 +34,11 @@ class TreeList implements Countable
|
||||
{
|
||||
}
|
||||
|
||||
public function getIterator(): Traversable
|
||||
{
|
||||
return new ArrayIterator($this->list);
|
||||
}
|
||||
|
||||
public function count(): int
|
||||
{
|
||||
return count($this->list);
|
||||
@ -146,7 +154,7 @@ class TreeList implements Countable
|
||||
echo "\e[{$screenRow};1H";
|
||||
if ($entryRow >= count($keys)) {
|
||||
echo ($selected?"\e[44;97m":"\e[0;90m")."\e[K";
|
||||
if ($entryRow == count($keys)) echo str_repeat("\u{2574}",$columns);
|
||||
if ($entryRow == count($keys) && Settings::$tailLine) echo str_repeat("\u{2594}",$columns);
|
||||
echo "\e[0m";
|
||||
//else echo "\e[90m\u{2805}\e[0m";
|
||||
return;
|
||||
@ -183,10 +191,10 @@ class TreeList implements Countable
|
||||
if ($entry->node instanceof CollapsibleNode) {
|
||||
if ($entry->node->isCollapsed()) {
|
||||
//echo "\e[90m\u{25ba} \e[37m";
|
||||
echo "\e[90m".self::TREE_FOLD_OPEN." \e[37m";
|
||||
echo "\e[37m".self::TREE_FOLD_OPEN." \e[37m";
|
||||
} else {
|
||||
//echo "\e[90m\u{25bc} \e[37m";
|
||||
echo "\e[90m".self::TREE_FOLD_CLOSE." \e[37m";
|
||||
echo "\e[37m".self::TREE_FOLD_CLOSE." \e[37m";
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -231,8 +239,8 @@ class TreeList implements Countable
|
||||
$value = $entry->node->value;
|
||||
echo match (gettype($value)) {
|
||||
'string' => "\e[33m",
|
||||
'integer' => "\e[34m",
|
||||
'double' => "\e[32m",
|
||||
'integer' => "\e[94m",
|
||||
'double' => "\e[96m",
|
||||
'boolean' => "\e[35m",
|
||||
'NULL' => "\e[31m",
|
||||
default => "",
|
||||
|
@ -14,6 +14,8 @@ class Settings
|
||||
|
||||
public static bool $highlightRow = true;
|
||||
|
||||
public static bool $tailLine = true;
|
||||
|
||||
public static function load(string $filename): void
|
||||
{
|
||||
if (file_exists($filename) && is_readable($filename)) {
|
||||
|
@ -115,6 +115,12 @@ class Terminal
|
||||
} elseif (strncmp($this->inputBuffer, "\e[D", 3) === 0) {
|
||||
$this->inputBuffer = mb_substr($this->inputBuffer, 3);
|
||||
return "k{LEFT}";
|
||||
} elseif (strncmp($this->inputBuffer, "\e[H", 3) === 0) {
|
||||
$this->inputBuffer = mb_substr($this->inputBuffer, 3);
|
||||
return "k{HOME}";
|
||||
} elseif (strncmp($this->inputBuffer, "\e[F", 3) === 0) {
|
||||
$this->inputBuffer = mb_substr($this->inputBuffer, 3);
|
||||
return "k{END}";
|
||||
} elseif (strncmp($this->inputBuffer, "\e[5~", 4) === 0) {
|
||||
$this->inputBuffer = mb_substr($this->inputBuffer, 4);
|
||||
return "k{PGUP}";
|
||||
|
Loading…
Reference in New Issue
Block a user