Improve CLI
This commit is contained in:
parent
593e72f121
commit
2dfe0ac902
185
cli/cli.cpp
185
cli/cli.cpp
|
@ -31,7 +31,7 @@ InputMuter::InputMuter()
|
|||
#if defined(PLATFORM_UNIX)
|
||||
tcgetattr(STDIN_FILENO, &m_attr);
|
||||
termios newAttr = m_attr;
|
||||
newAttr.c_lflag &= ~ECHO;
|
||||
newAttr.c_lflag &= ~static_cast<unsigned int>(ECHO);
|
||||
tcsetattr(STDIN_FILENO, TCSANOW, &newAttr);
|
||||
#elif defined(PLATFORM_WINDOWS)
|
||||
m_cinHandle = GetStdHandle(STD_INPUT_HANDLE);
|
||||
|
@ -143,7 +143,7 @@ void InteractiveCli::processCommand(const string &cmd)
|
|||
pwd();
|
||||
} else if (CMD_P("cd")) {
|
||||
cd(param);
|
||||
} else if (CMD("ls")) {
|
||||
} else if (CMD2("ls", "l")) {
|
||||
ls();
|
||||
} else if (CMD2("tree", "t")) {
|
||||
tree();
|
||||
|
@ -239,7 +239,8 @@ void InteractiveCli::openFile(const string &file, bool readOnly)
|
|||
{
|
||||
if (m_file.isOpen()) {
|
||||
m_o << "file \"" << m_file.path() << "\" currently open; close first" << endl;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
m_file.setPath(file);
|
||||
try {
|
||||
try {
|
||||
|
@ -269,23 +270,25 @@ void InteractiveCli::openFile(const string &file, bool readOnly)
|
|||
m_currentEntry = nullptr;
|
||||
}
|
||||
m_modified = false;
|
||||
}
|
||||
}
|
||||
|
||||
void InteractiveCli::closeFile()
|
||||
{
|
||||
if (m_file.isOpen()) {
|
||||
if (!m_file.isOpen()) {
|
||||
m_o << "no file was opened" << endl;
|
||||
return;
|
||||
}
|
||||
m_file.clear();
|
||||
m_currentEntry = nullptr;
|
||||
m_o << "file closed" << endl;
|
||||
} else {
|
||||
m_o << "no file was opened" << endl;
|
||||
}
|
||||
}
|
||||
|
||||
void InteractiveCli::saveFile()
|
||||
{
|
||||
if (m_file.isOpen()) {
|
||||
if (!m_file.isOpen()) {
|
||||
m_o << "nothing to save; no file opened or created" << endl;
|
||||
return;
|
||||
}
|
||||
try {
|
||||
try {
|
||||
m_file.save(*m_file.password());
|
||||
|
@ -309,16 +312,15 @@ void InteractiveCli::saveFile()
|
|||
m_file.clear();
|
||||
}
|
||||
m_modified = false;
|
||||
} else {
|
||||
m_o << "nothing to save; no file opened or created" << endl;
|
||||
}
|
||||
}
|
||||
|
||||
void InteractiveCli::createFile(const string &file)
|
||||
{
|
||||
if (m_file.isOpen()) {
|
||||
m_o << "file \"" << m_file.path() << "\" currently open; close first" << endl;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
m_file.setPath(file);
|
||||
try {
|
||||
try {
|
||||
|
@ -331,7 +333,7 @@ void InteractiveCli::createFile(const string &file)
|
|||
m_o << "IO error occured when creating file \"" << file << "\"" << endl;
|
||||
throw ios_base::failure(what);
|
||||
}
|
||||
} catch (exception &e) {
|
||||
} catch (const exception &e) {
|
||||
if (*e.what() != 0) {
|
||||
m_o << e.what() << endl;
|
||||
}
|
||||
|
@ -339,27 +341,29 @@ void InteractiveCli::createFile(const string &file)
|
|||
m_currentEntry = nullptr;
|
||||
}
|
||||
m_modified = false;
|
||||
}
|
||||
}
|
||||
|
||||
void InteractiveCli::changePassphrase()
|
||||
{
|
||||
if (m_file.isOpen()) {
|
||||
m_o << "can not set passphrase; no file opened or created" << endl;
|
||||
return;
|
||||
}
|
||||
try {
|
||||
m_file.setPassword(askForPassphrase(true));
|
||||
m_modified = true;
|
||||
m_o << "passphrase changed; use save to apply" << endl;
|
||||
} catch (runtime_error &) {
|
||||
} catch (const runtime_error &) {
|
||||
m_o << "passphrase has not changed" << endl;
|
||||
}
|
||||
} else {
|
||||
m_o << "can not set passphrase; no file opened or created" << endl;
|
||||
}
|
||||
}
|
||||
|
||||
void InteractiveCli::removePassphrase()
|
||||
{
|
||||
if (m_file.isOpen()) {
|
||||
if (!m_file.isOpen()) {
|
||||
m_o << "nothing to remove; no file opened or created" << endl;
|
||||
return;
|
||||
}
|
||||
if (*m_file.password()) {
|
||||
m_file.clearPassword();
|
||||
m_o << "passphrase removed; use save to apply" << endl;
|
||||
|
@ -367,63 +371,63 @@ void InteractiveCli::removePassphrase()
|
|||
} else {
|
||||
m_o << "nothing to remove; no passphrase present on current file" << endl;
|
||||
}
|
||||
} else {
|
||||
m_o << "nothing to remove; no file opened or created" << endl;
|
||||
}
|
||||
}
|
||||
|
||||
void InteractiveCli::pwd()
|
||||
{
|
||||
if (m_file.isOpen()) {
|
||||
if (!m_file.isOpen()) {
|
||||
m_o << "no file open" << endl;
|
||||
return;
|
||||
}
|
||||
auto path = m_currentEntry->path();
|
||||
m_o << path.front() << ": /";
|
||||
path.pop_front();
|
||||
m_o << joinStrings(path, "/") << endl;
|
||||
} else {
|
||||
m_o << "no file open" << endl;
|
||||
}
|
||||
}
|
||||
|
||||
void InteractiveCli::cd(const string &path)
|
||||
{
|
||||
if (m_file.isOpen()) {
|
||||
if (!m_file.isOpen()) {
|
||||
m_o << "can not change directory; no file open" << endl;
|
||||
return;
|
||||
}
|
||||
if (Entry *entry = resolvePath(path)) {
|
||||
m_currentEntry = entry;
|
||||
m_o << "changed to \"" << entry->label() << "\"" << endl;
|
||||
}
|
||||
} else {
|
||||
m_o << "can not change directory; no file open" << endl;
|
||||
}
|
||||
}
|
||||
|
||||
void InteractiveCli::ls()
|
||||
{
|
||||
if (m_file.isOpen()) {
|
||||
if (!m_file.isOpen()) {
|
||||
m_o << "can not list any entires; no file open" << endl;
|
||||
return;
|
||||
}
|
||||
switch (m_currentEntry->type()) {
|
||||
case EntryType::Account: {
|
||||
m_o << "fields:";
|
||||
for (const Field &field : static_cast<AccountEntry *>(m_currentEntry)->fields()) {
|
||||
m_o << " " << field.name();
|
||||
m_o << "\n" << field.name();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case EntryType::Node: {
|
||||
m_o << "entries:";
|
||||
for (const Entry *entry : static_cast<NodeEntry *>(m_currentEntry)->children()) {
|
||||
m_o << " " << entry->label();
|
||||
m_o << "\n" << entry->label();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
m_o << endl;
|
||||
} else {
|
||||
m_o << "can not list any entires; no file open" << endl;
|
||||
}
|
||||
}
|
||||
|
||||
void InteractiveCli::tree()
|
||||
{
|
||||
if (m_file.isOpen()) {
|
||||
if (!m_file.isOpen()) {
|
||||
m_o << "can not print tree; no file open" << endl;
|
||||
return;
|
||||
}
|
||||
function<void(const Entry *entry, unsigned char level)> printEntries;
|
||||
printEntries = [&printEntries, this](const Entry *entry, unsigned char level) {
|
||||
for (unsigned char i = 0; i < level; ++i) {
|
||||
|
@ -437,14 +441,14 @@ void InteractiveCli::tree()
|
|||
}
|
||||
};
|
||||
printEntries(m_currentEntry, 0);
|
||||
} else {
|
||||
m_o << "can not print tree; no file open" << endl;
|
||||
}
|
||||
}
|
||||
|
||||
void InteractiveCli::makeEntry(EntryType entryType, const string &label)
|
||||
{
|
||||
if (m_file.isOpen()) {
|
||||
if (!m_file.isOpen()) {
|
||||
m_o << "can not make entry; no file open" << endl;
|
||||
return;
|
||||
}
|
||||
switch (m_currentEntry->type()) {
|
||||
case EntryType::Node:
|
||||
switch (entryType) {
|
||||
|
@ -460,14 +464,14 @@ void InteractiveCli::makeEntry(EntryType entryType, const string &label)
|
|||
case EntryType::Account:
|
||||
m_o << "can not make entry; current entry is no node entry" << endl;
|
||||
}
|
||||
} else {
|
||||
m_o << "can not make entry; no file open" << endl;
|
||||
}
|
||||
}
|
||||
|
||||
void InteractiveCli::removeEntry(const string &path)
|
||||
{
|
||||
if (m_file.isOpen()) {
|
||||
if (!m_file.isOpen()) {
|
||||
m_o << "can not remove entry; no file open" << endl;
|
||||
return;
|
||||
}
|
||||
if (Entry *entry = resolvePath(path)) {
|
||||
if (entry == m_file.rootEntry()) {
|
||||
m_o << "can not remove root entry" << endl;
|
||||
|
@ -480,14 +484,14 @@ void InteractiveCli::removeEntry(const string &path)
|
|||
m_modified = true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
m_o << "can not remove entry; no file open" << endl;
|
||||
}
|
||||
}
|
||||
|
||||
void InteractiveCli::renameEntry(const string &path)
|
||||
{
|
||||
if (m_file.isOpen()) {
|
||||
if (!m_file.isOpen()) {
|
||||
m_o << "can not rename entry; no file open" << endl;
|
||||
return;
|
||||
}
|
||||
if (Entry *entry = resolvePath(path)) {
|
||||
string label;
|
||||
m_o << "enter new name: " << endl;
|
||||
|
@ -500,14 +504,14 @@ void InteractiveCli::renameEntry(const string &path)
|
|||
m_modified = true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
m_o << "can not rename entry; no file open" << endl;
|
||||
}
|
||||
}
|
||||
|
||||
void InteractiveCli::moveEntry(const string &path)
|
||||
{
|
||||
if (m_file.isOpen()) {
|
||||
if (!m_file.isOpen()) {
|
||||
m_o << "can not rename entry; no file open" << endl;
|
||||
return;
|
||||
}
|
||||
if (Entry *entry = resolvePath(path)) {
|
||||
string newParentPath;
|
||||
m_o << "enter path of new parent: " << endl;
|
||||
|
@ -534,15 +538,19 @@ void InteractiveCli::moveEntry(const string &path)
|
|||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
m_o << "can not rename entry; no file open" << endl;
|
||||
}
|
||||
}
|
||||
|
||||
void InteractiveCli::readField(const string &fieldName)
|
||||
{
|
||||
if (m_file.isOpen()) {
|
||||
if (m_currentEntry->type() == EntryType::Account) {
|
||||
if (!m_file.isOpen()) {
|
||||
m_o << "can not read field; no file open" << endl;
|
||||
return;
|
||||
}
|
||||
if (m_currentEntry->type() != EntryType::Account) {
|
||||
m_o << "can not read field; current entry is no account entry" << endl;
|
||||
return;
|
||||
}
|
||||
|
||||
const vector<Field> &fields = static_cast<AccountEntry *>(m_currentEntry)->fields();
|
||||
bool valuesFound = false;
|
||||
for (const Field &field : fields) {
|
||||
|
@ -554,18 +562,18 @@ void InteractiveCli::readField(const string &fieldName)
|
|||
if (!valuesFound) {
|
||||
m_o << "field \"" << fieldName << "\" does not exist" << endl;
|
||||
}
|
||||
} else {
|
||||
m_o << "can not read field; current entry is no account entry" << endl;
|
||||
}
|
||||
} else {
|
||||
m_o << "can not read field; no file open" << endl;
|
||||
}
|
||||
}
|
||||
|
||||
void InteractiveCli::setField(bool useMuter, const string &fieldName)
|
||||
{
|
||||
if (m_file.isOpen()) {
|
||||
if (m_currentEntry->type() == EntryType::Account) {
|
||||
if (!m_file.isOpen()) {
|
||||
m_o << "can not set field; no file open" << endl;
|
||||
return;
|
||||
}
|
||||
if (m_currentEntry->type() != EntryType::Account) {
|
||||
m_o << "can not set field; current entry is no account entry" << endl;
|
||||
return;
|
||||
}
|
||||
vector<Field> &fields = static_cast<AccountEntry *>(m_currentEntry)->fields();
|
||||
unsigned int valuesFound = 0;
|
||||
string value;
|
||||
|
@ -626,33 +634,36 @@ void InteractiveCli::setField(bool useMuter, const string &fieldName)
|
|||
m_o << valuesFound << " values updated" << endl;
|
||||
m_modified = true;
|
||||
}
|
||||
} else {
|
||||
m_o << "can not set field; current entry is no account entry" << endl;
|
||||
}
|
||||
} else {
|
||||
m_o << "can not set field; no file open" << endl;
|
||||
}
|
||||
}
|
||||
|
||||
void InteractiveCli::removeField(const string &fieldName)
|
||||
{
|
||||
if (m_file.isOpen()) {
|
||||
if (m_currentEntry->type() == EntryType::Account) {
|
||||
if (!m_file.isOpen()) {
|
||||
m_o << "can not remove field; no file open" << endl;
|
||||
return;
|
||||
}
|
||||
if (m_currentEntry->type() != EntryType::Account) {
|
||||
m_o << "can not remove field; current entry is no account entry" << endl;
|
||||
return;
|
||||
}
|
||||
vector<Field> &fields = static_cast<AccountEntry *>(m_currentEntry)->fields();
|
||||
unsigned int valuesFound = 0;
|
||||
for (Field &field : fields) {
|
||||
for (const Field &field : fields) {
|
||||
if (field.name() == fieldName) {
|
||||
++valuesFound;
|
||||
}
|
||||
}
|
||||
switch (valuesFound) {
|
||||
valuesFound = 0;
|
||||
case 0:
|
||||
m_o << "can not remove field; specified field \"" << fieldName << "\" not found" << endl;
|
||||
break;
|
||||
case 1:
|
||||
fields.erase(remove_if(fields.begin(), fields.end(), [&fieldName](Field &field) { return field.name() == fieldName; }));
|
||||
m_o << "field removed" << endl;
|
||||
m_modified = true;
|
||||
break;
|
||||
default:
|
||||
valuesFound = 0;
|
||||
fields.erase(remove_if(fields.begin(), fields.end(), [this, &fieldName, &valuesFound](Field &field) {
|
||||
if (field.name() == fieldName) {
|
||||
m_o << "remove " << ++valuesFound << ". occurrence? [y]=yes, different key=no " << endl;
|
||||
|
@ -663,25 +674,9 @@ void InteractiveCli::removeField(const string &fieldName)
|
|||
return false;
|
||||
}
|
||||
}));
|
||||
}
|
||||
switch (valuesFound) {
|
||||
case 0:
|
||||
m_o << "can not remove field; specified field \"" << fieldName << "\" not found" << endl;
|
||||
break;
|
||||
case 1:
|
||||
m_o << "field removed" << endl;
|
||||
m_modified = true;
|
||||
break;
|
||||
default:
|
||||
m_o << valuesFound << " fields removed" << endl;
|
||||
m_modified = true;
|
||||
}
|
||||
} else {
|
||||
m_o << "can not remove field; current entry is no account entry" << endl;
|
||||
}
|
||||
} else {
|
||||
m_o << "can not remove field; no file open" << endl;
|
||||
}
|
||||
}
|
||||
|
||||
void InteractiveCli::printHelp()
|
||||
|
@ -742,7 +737,8 @@ string InteractiveCli::askForPassphrase(bool confirm)
|
|||
m_o << endl;
|
||||
if (input1.empty()) {
|
||||
m_o << "you did not enter a passphrase" << endl;
|
||||
} else {
|
||||
return input1;
|
||||
}
|
||||
if (confirm) {
|
||||
m_o << "confirm new passphrase: ";
|
||||
m_o.flush();
|
||||
|
@ -757,7 +753,6 @@ string InteractiveCli::askForPassphrase(bool confirm)
|
|||
throw runtime_error("confirmation failed");
|
||||
}
|
||||
}
|
||||
}
|
||||
return input1;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -39,8 +39,8 @@
|
|||
#include <QUndoView>
|
||||
|
||||
#include <cassert>
|
||||
#include <stdexcept>
|
||||
#include <functional>
|
||||
#include <stdexcept>
|
||||
|
||||
using namespace std;
|
||||
using namespace IoUtilities;
|
||||
|
|
1
main.cpp
1
main.cpp
|
@ -47,6 +47,7 @@ int main(int argc, char *argv[])
|
|||
qtConfigArgs.qtWidgetsGuiArg().addSubArgument(&fileArg);
|
||||
// cli argument
|
||||
Argument cliArg("interactive-cli", 'i', "starts the interactive command line interface");
|
||||
cliArg.setDenotesOperation(true);
|
||||
cliArg.setSubArguments({ &fileArg });
|
||||
// help argument
|
||||
HelpArgument helpArg(parser);
|
||||
|
|
Loading…
Reference in New Issue