Add save to json/yaml (ctrl-w)

This commit is contained in:
Chris 2024-10-01 21:40:13 +02:00
parent 9bc83ccd56
commit 3caca13e5c
10 changed files with 101 additions and 8 deletions

1
.gitignore vendored
View File

@ -1 +1,2 @@
/vendor/ /vendor/
/*.phar

View File

@ -1,6 +1,6 @@
{ {
"name": "noccylabs/jedit", "name": "noccylabs/jedit",
"description": "JSON/YAML editor for the terminal", "description": "JSON/YAML editor for terminal junkies",
"type": "application", "type": "application",
"license": "GPL-3.0-or-later", "license": "GPL-3.0-or-later",
"autoload": { "autoload": {
@ -20,4 +20,4 @@
"bin": [ "bin": [
"bin/jedit" "bin/jedit"
] ]
} }

View File

@ -204,15 +204,78 @@ class Editor
break; break;
case 'Q': case 'Q':
case "\x03": case "\x03": // ctrl-w
$this->running = false; $this->running = false;
break; break;
case "\x12": // ctrl-r
$readFrom = $this->ask("\e[33mRead from:\e[0m ", "");
$this->term->setCursor(1, $h);
if (!file_exists($readFrom)) {
echo "\e[97;41mFile does not exist\e[K\e[0m";
break;
}
if (!is_readable($readFrom)) {
echo "\e[97;41mFile not readable\e[K\e[0m";
break;
}
$ext = strtolower(pathinfo($readFrom, PATHINFO_EXTENSION));
switch ($ext) {
case 'json':
$doc = json_decode(file_get_contents($readFrom));
break;
case 'yml':
case 'yaml':
$doc = Yaml::parseFile($readFrom);
break;
default:
echo "\e[97;41mUnable to read format: {$ext}\e[K\e[0m";
break(2);
}
$this->filename = $readFrom;
$this->shortfilename = basename($readFrom);
$this->document->load($doc);
$this->currentRow = 0;
$this->list->parseTree();
$this->redrawEditor();
$this->term->setCursor(1, $h);
echo "\e[97;42mLoaded {$readFrom}\e[K\e[0m";
break;
case "\x17": // ctrl-w
$saveTo = $this->ask("\e[33mWrite to:\e[0m ", $this->filename);
$doc = $this->document->save();
$this->term->setCursor(1, $h);
$ext = strtolower(pathinfo($saveTo, PATHINFO_EXTENSION));
switch ($ext) {
case 'json':
file_put_contents($saveTo, json_encode($doc, JSON_PRETTY_PRINT|JSON_UNESCAPED_SLASHES)."\n");
break;
case 'yml':
case 'yaml':
$doc = json_decode(json_encode($doc), true);
file_put_contents($saveTo, Yaml::dump($doc));
break;
default:
echo "\e[97;41mUnable to write format: {$ext}\e[K\e[0m";
}
echo "\e[97;42mWrote to {$saveTo}\e[K\e[0m";
break;
case null: case null:
break; break;
default: default:
$this->term->setCursor(1, $h, true); $this->term->setCursor(1, $h, true);
echo $read; echo sprintf("%s %02x %03d", ctype_print($read)?$read:'.', ord($read), ord($read));
sleep(1); sleep(1);
} }
} }
@ -248,10 +311,11 @@ class Editor
return $value; return $value;
} }
if (ord($ch) == 3) { if (ord($ch) == 3) {
// ctrl-c
$this->term->setCursor(1, $h); $this->term->setCursor(1, $h);
echo "\e[0m\e[K"; echo "\e[0m\e[K";
return null; return null;
} }
} elseif (ord($ch) == 127) { } elseif (ord($ch) == 127) {
if ($cursorPos > 0) { if ($cursorPos > 0) {
$value = substr($value, 0, $cursorPos - 1) . substr($value, $cursorPos); $value = substr($value, 0, $cursorPos - 1) . substr($value, $cursorPos);

View File

@ -154,7 +154,7 @@ class TreeList implements Countable
if (!is_null($entry->key)) { if (!is_null($entry->key)) {
echo (is_int($entry->key) echo (is_int($entry->key)
?"\e[36;2m\u{e0b6}\e[7m#{$entry->key}\e[27m\u{e0b4}\e[22m " ?"\e[36;2m\u{e0b6}\e[7m#{$entry->key}\e[27m\u{e0b4}\e[22m "
:"\e[36m\"{$entry->key}\":\e[37m "); :"\e[36m{$entry->key}:\e[37m ");
} }
if ($entry->node instanceof ArrayNode) { if ($entry->node instanceof ArrayNode) {
echo "["; echo "[";

View File

@ -2,7 +2,6 @@
namespace NoccyLabs\JEdit\Terminal; namespace NoccyLabs\JEdit\Terminal;
class Terminal class Terminal
{ {
private static int $init = 0; private static int $init = 0;

View File

@ -27,5 +27,10 @@ class ArrayNode extends Node implements CollapsibleNode
return new ArrayNode($items); return new ArrayNode($items);
} }
public function jsonSerialize(): mixed
{
return array_values($this->items);
}
} }

View File

@ -2,7 +2,9 @@
namespace NoccyLabs\JEdit\Tree; namespace NoccyLabs\JEdit\Tree;
abstract class Node use JsonSerializable;
abstract class Node implements JsonSerializable
{ {
} }

View File

@ -29,5 +29,10 @@ class ObjectNode extends Node implements CollapsibleNode
return new ObjectNode($properties); return new ObjectNode($properties);
} }
public function jsonSerialize(): mixed
{
return $this->properties;
}
} }

View File

@ -13,6 +13,18 @@ class Tree
return $this; return $this;
} }
public function save(): mixed
{
if (!$this->root)
return null;
return json_decode(
json_encode(
$this->root
)
);
}
private function parseNode(mixed $node): Node private function parseNode(mixed $node): Node
{ {
if (is_array($node) && array_is_list($node)) { if (is_array($node) && array_is_list($node)) {

View File

@ -7,5 +7,10 @@ class ValueNode extends Node
public function __construct(public mixed $value) public function __construct(public mixed $value)
{ {
} }
public function jsonSerialize(): mixed
{
return $this->value;
}
} }