Editor fixes, code cleanup, bool colors, open dialog
This commit is contained in:
parent
9819b22019
commit
62c78fa14c
@ -2,6 +2,11 @@
|
||||
|
||||
This is an editor for JSON files, that also supports YAML.
|
||||
|
||||
> [!WARNING]
|
||||
> This software is still very much beta. That means there will be bugs. Please
|
||||
> report them, and don't go doing stupid stuff like editing your live configuration
|
||||
> files in place.
|
||||
|
||||
## Features
|
||||
|
||||
- Interactive terminal TUI application
|
||||
@ -35,7 +40,8 @@ $ mv bin/jsonedit.phar ~/bin/jsonedit
|
||||
## Using
|
||||
|
||||
JSONEdit is controlled using hotkeys. The essential keys are always displayed
|
||||
at the bottom of the screen.
|
||||
at the bottom of the screen. Press **h** for the help, which lists all available
|
||||
keys.
|
||||
|
||||
### Creating a document from scratch
|
||||
|
||||
|
@ -10,11 +10,14 @@ use NoccyLabs\JsonEdit\Tree\CollapsibleNode;
|
||||
use NoccyLabs\JsonEdit\Tree\ObjectNode;
|
||||
use NoccyLabs\JsonEdit\Tree\Tree;
|
||||
use NoccyLabs\JsonEdit\Tree\ValueNode;
|
||||
use Symfony\Component\Yaml\Exception\ParseException;
|
||||
use Symfony\Component\Yaml\Yaml;
|
||||
|
||||
class Editor
|
||||
{
|
||||
|
||||
public static string $helpText;
|
||||
|
||||
private Tree $document;
|
||||
|
||||
private TreeList $list;
|
||||
@ -201,7 +204,6 @@ class Editor
|
||||
break;
|
||||
|
||||
case "\x18": // ctrl-x
|
||||
|
||||
if ($this->modified) {
|
||||
$menu = new Menu($this->term, [
|
||||
'cancel' => "Return to editor",
|
||||
@ -321,12 +323,28 @@ class Editor
|
||||
$this->showMessage("Toggle compact groups (c)");
|
||||
break;
|
||||
|
||||
case "\x0d": // enter
|
||||
$node = $this->list->getNodeForIndex($this->currentRow);
|
||||
if ($node instanceof ValueNode) {
|
||||
if ($node->value === true) {
|
||||
$node->value = false;
|
||||
$this->modified = true;
|
||||
$this->redrawEditor();
|
||||
} elseif ($node->value === false) {
|
||||
$node->value = true;
|
||||
$this->modified = true;
|
||||
$this->redrawEditor();
|
||||
} else {
|
||||
$this->doEditValue();
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case "\x03": // ctrl-c
|
||||
$this->showMessage("\e[30;43mPress Ctrl-X to exit.");
|
||||
break;
|
||||
|
||||
case "\x0e": // ctrl-n
|
||||
|
||||
if ($this->modified) {
|
||||
$menu = new Menu($this->term, [
|
||||
'cancel' => "Return to editor",
|
||||
@ -349,6 +367,8 @@ class Editor
|
||||
case 'discard':
|
||||
break;
|
||||
}
|
||||
$this->modified = false;
|
||||
|
||||
}
|
||||
|
||||
$this->document->load((object)[]);
|
||||
@ -359,6 +379,10 @@ class Editor
|
||||
$this->redrawEditor();
|
||||
break;
|
||||
|
||||
case "\x0F": // ctrl-o
|
||||
$this->doOpenFile();
|
||||
break;
|
||||
|
||||
case "\x12": // ctrl-r
|
||||
$this->doReadFile();
|
||||
break;
|
||||
@ -369,6 +393,7 @@ class Editor
|
||||
|
||||
case null:
|
||||
break;
|
||||
|
||||
default:
|
||||
$this->term->setCursor(1, $h, true);
|
||||
echo sprintf("%s %02x %03d", ctype_print($read)?$read:'.', ord($read), ord($read));
|
||||
@ -476,75 +501,68 @@ class Editor
|
||||
|
||||
}
|
||||
|
||||
private function doOpenFile()
|
||||
{
|
||||
$wd = getcwd();
|
||||
while (true) {
|
||||
$items = [
|
||||
dirname($wd) => sprintf(
|
||||
"%-30s %10s %20s",
|
||||
"Parent Directory",
|
||||
"<DIR>",
|
||||
"-"
|
||||
)
|
||||
];
|
||||
$files = glob($wd."/*");
|
||||
foreach ($files as $file) {
|
||||
$items[$file] = sprintf(
|
||||
"%-30s %10s %20s",
|
||||
is_dir($file) ? ("<".basename($file).">") : (basename($file)),
|
||||
is_dir($file) ? "<DIR>" : filesize($file),
|
||||
date("Y-m-d H:i:s", filemtime($file))
|
||||
);
|
||||
}
|
||||
$menu = new Menu($this->term, $items, $wd);
|
||||
$sel = $menu->display(0, 0, 70, 20, null);
|
||||
if ($sel === null) {
|
||||
$this->redrawEditor();
|
||||
return;
|
||||
}
|
||||
if (is_dir($sel)) {
|
||||
$wd = $sel;
|
||||
}
|
||||
if (is_file($sel)) {
|
||||
$body = file_get_contents($sel);
|
||||
$json = json_decode($body);
|
||||
if ($json !== null) {
|
||||
$this->loadDocument($json);
|
||||
break;
|
||||
}
|
||||
try {
|
||||
$yaml = Yaml::parse($body);
|
||||
$this->loadDocument($yaml);
|
||||
break;
|
||||
} catch (ParseException $e) {
|
||||
$this->showMessage("\e[41;93mUnsupported file format");
|
||||
}
|
||||
}
|
||||
}
|
||||
$this->filename = $sel;
|
||||
$this->shortfilename = basename($sel);
|
||||
$this->redrawEditor();
|
||||
$this->showMessage("\e[42;97mOpened {$this->shortfilename}");
|
||||
}
|
||||
|
||||
private function doShowHelp(): void
|
||||
{
|
||||
[$w,$h] = $this->term->getSize();
|
||||
|
||||
$text = <<<EOT
|
||||
Welcome to JSONEdit! The editor you have missed all this time without even knowing it!
|
||||
|
||||
# QuickStart
|
||||
|
||||
To get started, press I (shift-i) and add something to the document. Use the arrow keys to get around. To cancel a prompt, close a menu or close a dialog, press ctrl-C. When you are happy with your work, press ctrl-W and enter a filename to write. You can also press ctrl-R and read in a new file, overwriting your masterpiece.
|
||||
|
||||
## Useful keys
|
||||
|
||||
↑↓ Navigate values in document
|
||||
h Show this help
|
||||
H Show information about the app and license
|
||||
i Insert a new value
|
||||
I Insert value, array or object
|
||||
e Edit selected value
|
||||
E Edit selected key
|
||||
D Delete selected key
|
||||
c Toggle compact list view
|
||||
q Toggle quoted keys in list view
|
||||
^W Write to file
|
||||
^R Read from file
|
||||
^N New document with empty object
|
||||
^C Cancel/Exit
|
||||
|
||||
## Doing stuff
|
||||
|
||||
### Adding keys or values
|
||||
To add a key or a value, navigate to a value in an array or object, or to a specific array or object, and press "i". You will be prompted for the value, and for objects the key.
|
||||
You can also press "I" to add arrays and objects. Just select what you want to add in the menu and press enter.
|
||||
|
||||
### Editing keys
|
||||
You can edit keys on objects. For this, press "E".
|
||||
|
||||
### Editing values
|
||||
To edit a value, press "e". The value is verbatim JSON, so strings should be quoted and all that. Anything that is unparsable JSON will be used as is, resulting in a string.
|
||||
|
||||
### Loading and Saving files
|
||||
To load a file, press ^R and enter the filename to read. To write to a file, press ^W and enter the filename to write to.
|
||||
|
||||
### YAML or JSON?
|
||||
There is no need to select YAML or JSON mode. All operations work the same, and the format is determined on load or save.
|
||||
|
||||
# Disclaimer
|
||||
|
||||
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:
|
||||
|
||||
* 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.
|
||||
* There are crashes, and lock-ups. Data corruption is a possibility.
|
||||
|
||||
# Support
|
||||
|
||||
Go to https://dev.noccylabs.info/noccy/jsonedit to find the source code, issue tracker, and learn more about the project!
|
||||
EOT;
|
||||
|
||||
$width = min(90, $w - 10);
|
||||
$height = min(40, $h - 6);
|
||||
$left = round(($w / 2) - ($width / 2));
|
||||
$top = round(($h / 2) - ($height / 2));
|
||||
|
||||
$msg = new MessageBox($this->term, $text, "Help");
|
||||
$msg = new MessageBox($this->term, self::$helpText, "Help");
|
||||
$this->redrawInfoBar([ '↑/↓' => 'Scroll', '^C' => 'Close' ]);
|
||||
$msg->display($left, $top, $width, $height);
|
||||
$this->redrawEditor();
|
||||
@ -622,7 +640,14 @@ class Editor
|
||||
if ($node instanceof ValueNode) {
|
||||
$val = json_encode($node->value, JSON_UNESCAPED_SLASHES);
|
||||
$newVal = $this->ask("\e[33;1mnew value:\e[0m ", $val);
|
||||
// We get null on ctrl-C, so non-null is input
|
||||
if ($newVal !== null) {
|
||||
// Break out if the value has not changed
|
||||
if ($newVal === $val) {
|
||||
$this->redrawInfoBar();
|
||||
return;
|
||||
}
|
||||
// Attempt to decode the value
|
||||
$val = json_decode($newVal);
|
||||
// If the string decodes to null, but isn't 'null', treat it as a string
|
||||
if ($val === null && $newVal !== 'null') {
|
||||
@ -816,6 +841,8 @@ class Editor
|
||||
$path = $this->list->getPathForIndex($this->currentRow);
|
||||
$node = $this->list->getNodeForIndex($this->currentRow);
|
||||
|
||||
ob_start();
|
||||
|
||||
$modified = $this->modified ? "\e[31m*\e[37m" : "";
|
||||
$this->term->setCursor(1, $h-1);
|
||||
echo "\e[40;37m\e[K{$modified}\e[1m{$this->shortfilename}\e[22m#\e[3m{$path}\e[37;23m";
|
||||
@ -841,6 +868,8 @@ class Editor
|
||||
}
|
||||
// $this->term->setCursor(1, 1);
|
||||
// echo "\e[90;3m«Empty»\e[0m";
|
||||
|
||||
ob_end_flush();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -902,3 +931,63 @@ class Editor
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Editor::$helpText = <<<EOT
|
||||
Welcome to JSONEdit! The editor you never knew you were missing!
|
||||
|
||||
# QuickStart
|
||||
|
||||
To get started, press I (shift-i) and add something to the document. Use the arrow keys to get around. To cancel a prompt, close a menu or close a dialog, press ctrl-C. When you are happy with your work, press ctrl-W and enter a filename to write. You can also press ctrl-R and read in a new file, overwriting your masterpiece.
|
||||
|
||||
# Useful keys
|
||||
|
||||
### Main Window
|
||||
|
||||
↑↓ Navigate values in document
|
||||
h Show this help
|
||||
H Show information about the app and license
|
||||
i Insert a new value
|
||||
I Insert value, array or object
|
||||
e Edit selected value
|
||||
E Edit selected key
|
||||
Enter Edit string/number, toggle booleans
|
||||
D Delete selected key
|
||||
c Toggle compact list view
|
||||
q Toggle quoted keys in list view
|
||||
^W Write to file
|
||||
^R Read from file
|
||||
^O Open file browser
|
||||
^N New document with empty object
|
||||
^X Exit
|
||||
|
||||
### Dialogs/Menus
|
||||
|
||||
↑↓ Select/Scroll
|
||||
Enter Select value
|
||||
^C Cancel
|
||||
|
||||
# Doing stuff
|
||||
|
||||
### Adding keys or values
|
||||
To add a key or a value, navigate to a value in an array or object, or to a specific array or object, and press "i". You will be prompted for the value, and for objects the key.
|
||||
You can also press "I" to add arrays and objects. Just select what you want to add in the menu and press enter.
|
||||
|
||||
### Editing keys
|
||||
You can edit keys on objects. For this, press "E".
|
||||
|
||||
### Editing values
|
||||
To edit a value, press "e". The value is verbatim JSON, so strings should be quoted and all that. Anything that is unparsable JSON will be used as is, resulting in a string.
|
||||
|
||||
### Loading and Saving files
|
||||
To load a file, press ^R and enter the filename to read. To write to a file, press ^W and enter the filename to write to.
|
||||
|
||||
### YAML or JSON?
|
||||
There is no need to select YAML or JSON mode. All operations work the same, and the format is determined on load or save.
|
||||
|
||||
# Disclaimer
|
||||
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:
|
||||
|
||||
# Support
|
||||
Go to https://dev.noccylabs.info/noccy/jsonedit to find the source code, issue tracker, and learn more about the project!
|
||||
EOT;
|
||||
|
@ -241,7 +241,7 @@ class TreeList implements Countable, IteratorAggregate
|
||||
'string' => "\e[33m",
|
||||
'integer' => "\e[94m",
|
||||
'double' => "\e[96m",
|
||||
'boolean' => "\e[35m",
|
||||
'boolean' => ($value?"\e[92m":"\e[32m"),
|
||||
'NULL' => "\e[31m",
|
||||
default => "",
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user