From ca613746546fd4ba9176fbca93b998da3dc8425e Mon Sep 17 00:00:00 2001 From: Christopher Vagnetoft Date: Tue, 8 Oct 2024 11:04:26 +0200 Subject: [PATCH] Add duplicate (^D), basic search, bugfixes * Use ^D to duplicate array items * Use / to search, matching keys will be highlighted * Don't attempt to load non-existing files when passed on command line --- src/Editor/Editor.php | 58 ++++++++++++++++++++++++++++--------------- src/List/TreeList.php | 16 ++++++++---- src/Tree/Tree.php | 37 +++++++++++++++++++++++++++ src/entry.php | 2 +- 4 files changed, 87 insertions(+), 26 deletions(-) diff --git a/src/Editor/Editor.php b/src/Editor/Editor.php index e73a147..ba351b4 100644 --- a/src/Editor/Editor.php +++ b/src/Editor/Editor.php @@ -146,21 +146,21 @@ class Editor break; // FIXME make sure this clones; editing a clone updates original as well - // case 'd': - // $node = $this->list->getNodeForIndex($this->currentRow); - // $coll = $this->list->findNearestCollection($this->currentRow, true); - // if (!$coll) - // break; - // $collNode = $this->list->getNodeForIndex($coll); - // if ($collNode instanceof ArrayNode) { - // $collNode->append(clone $node); - // $this->list->parseTree(); - // $this->redrawEditor(); - // } else { - // $this->term->setCursor(1, $h); - // echo "\e[97;41mCan only duplicate in arrays, node={$this->currentRow}, coll={$coll}\e[K\e[0m"; - // } - // break; + case "\x04": // ctrl-d + $node = $this->list->getNodeForIndex($this->currentRow); + $coll = $this->list->findNearestCollection($this->currentRow, true); + if (!$coll) + break; + $collNode = $this->list->getNodeForIndex($coll); + if ($collNode instanceof ArrayNode) { + $collNode->append(clone $node); + $this->modified = true; + $this->list->parseTree(); + $this->redrawEditor(); + } else { + $this->showMessage("\e[97;41mCan only duplicate in arrays"); + } + break; case 'I': $this->doInsertMenu(); @@ -259,6 +259,10 @@ class Editor $this->showMessage("Toggle compact groups (c)"); break; + case "/": + $this->doSearch(); + break; + case "\x0d": // enter $node = $this->list->getNodeForIndex($this->currentRow); if ($node instanceof ValueNode) { @@ -343,12 +347,25 @@ class Editor Settings::save(SETTINGS_FILE); - // for ($n = 0; $n < 20; $n++) { - // $this->currentRow = $n; - // $this->redrawEditor(); - // sleep(1); - // } + } + public function doSearch(): void + { + + $search = $this->ask("\e[36mSearch: "); + + if ($search === null) { + $this->redrawEditor(); + return; + } + + if ($search === '') { + $this->list->searchResults = []; + } else { + $this->list->searchResults = $this->document->search($search); + } + + $this->redrawEditor(); } /** @@ -1063,6 +1080,7 @@ To get started, press I (shift-i) and add something to the document. Use the arr E Edit selected key Enter Edit string/number, toggle booleans D Delete selected key + ^D Duplicate array item c Toggle compact list view q Toggle quoted keys in list view g Toggle indentation guide lines visibility diff --git a/src/List/TreeList.php b/src/List/TreeList.php index 33a7d09..e5b63c7 100644 --- a/src/List/TreeList.php +++ b/src/List/TreeList.php @@ -36,6 +36,8 @@ class TreeList implements Countable, IteratorAggregate private const ICON_BOOL_FALSE = "\u{f630}"; private const ICON_NULL = "\u{f141}"; + public array $searchResults = []; + public function __construct(private Tree $tree) { } @@ -219,16 +221,20 @@ class TreeList implements Countable, IteratorAggregate default => self::ICON_STRING, }." "; } + $keyStyle = "36"; + if (in_array($entry->node, $this->searchResults)) { + $keyStyle = "1;97"; + } echo (is_int($entry->key) - ?(Settings::$highlightIndices - ?"\e[36;2m\u{e0b6}\e[7m#{$entry->key}\e[27m\u{e0b4}\e[22;37m " - :"\e[36;2m#{$entry->key}\e[22;37m " + ?"\e[{$keyStyle};2m\u{e0b6}\e[7m#{$entry->key}\e[27m\u{e0b4}\e[22;37m " + :"\e[{$keyStyle};2m#{$entry->key}\e[22;37m " ) :(Settings::$editorQuotedKeys - ? "\e[36m\"{$entry->key}\":\e[37m " - : "\e[36m{$entry->key}:\e[37m " + ? "\e[{$keyStyle}m\"{$entry->key}\"" + : "\e[{$keyStyle}m{$entry->key}" )); + echo ($selected?"\e[22;44;97m":"\e[0;37m").": "; } $node = $entry->node; if ($node instanceof ArrayNode) { diff --git a/src/Tree/Tree.php b/src/Tree/Tree.php index 775158f..232fcc9 100644 --- a/src/Tree/Tree.php +++ b/src/Tree/Tree.php @@ -43,5 +43,42 @@ class Tree } } + public function search(string $search): array + { + return $this->searchNode(null, $this->root, $search); + } + + /** + * + * + * @return array + */ + private function searchNode(?string $key, Node $node, string $search): array + { + $results = []; + + if ($node instanceof ArrayNode) { + if ($key && str_contains($key, $search)) { + $results[] = $node; + } + foreach ($node->items as $index=>$item) { + $results = [ ...$results, ...$this->searchNode($index, $item, $search) ]; + } + } elseif ($node instanceof ObjectNode) { + if ($key && str_contains($key, $search)) { + $results[] = $node; + } + foreach ($node->properties as $key=>$item) { + $results = [ ...$results, ...$this->searchNode($key, $item, $search) ]; + } + } elseif ($node instanceof ValueNode) { + if (str_contains($node->value, $search) || ($key && str_contains($key, $search))) { + $results[] = $node; + } + } + + return $results; + } + } diff --git a/src/entry.php b/src/entry.php index 4958fd0..c77eee7 100644 --- a/src/entry.php +++ b/src/entry.php @@ -58,7 +58,7 @@ $terminal = new NoccyLabs\JsonEdit\Terminal\Terminal(); Settings::load(SETTINGS_FILE); $editor = new NoccyLabs\JsonEdit\Editor\Editor($terminal); -if ($filename) { +if ($filename && file_exists($filename)) { $editor->loadFile($filename); } else { $editor->loadDocument((object)[]);