Skip to content

Commit a0ba5a0

Browse files
committed
Improve formatters
Fix RedisInsight#4278
1 parent 5a6a305 commit a0ba5a0

File tree

5 files changed

+146
-34
lines changed

5 files changed

+146
-34
lines changed

src/modules/value-editor/formattersmanager.cpp

Lines changed: 35 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@
1111

1212
ValueEditor::FormattersManager::FormattersManager() {}
1313

14-
QByteArray ValueEditor::FormattersManager::readStdoutFromExternalProcess(
14+
QPair<QByteArray, QByteArray>
15+
ValueEditor::FormattersManager::readOutputFromExternalProcess(
1516
const QStringList &cmd, const QByteArray &processInput, const QString &wd) {
1617
QProcess formatterProcess;
1718
formatterProcess.setWorkingDirectory(wd);
@@ -27,33 +28,39 @@ QByteArray ValueEditor::FormattersManager::readStdoutFromExternalProcess(
2728
emit error(QString("Cannot start process %1: %2")
2829
.arg(cmd.join(" "))
2930
.arg(formatterProcess.errorString()));
30-
return QByteArray();
31+
return {QByteArray(), QByteArray()};
3132
}
3233

3334
if (!formatterProcess.waitForFinished(3000)) {
3435
formatterProcess.kill();
3536
emit error(QString("Process %1 was killed by timeout: %2")
3637
.arg(cmd.join(" "))
3738
.arg(formatterProcess.errorString()));
38-
return QByteArray();
39+
return {QByteArray(), QByteArray()};
3940
}
4041

41-
return formatterProcess.readAllStandardOutput();
42+
return {formatterProcess.readAllStandardOutput(),
43+
formatterProcess.readAllStandardError()};
4244
}
4345

4446
QJsonObject ValueEditor::FormattersManager::readJsonFromExternalProcess(
4547
const QStringList &cmd, const QByteArray &processInput, const QString &wd) {
4648
qDebug() << cmd;
4749

48-
QByteArray result = readStdoutFromExternalProcess(cmd, processInput, wd);
50+
auto result = readOutputFromExternalProcess(cmd, processInput, wd);
4951

50-
if (result.isEmpty()) return QJsonObject();
52+
if (result.second.size() > 0)
53+
emit error(
54+
QString("%2: %1").arg(QString::fromLocal8Bit(result.second)).arg(wd));
55+
56+
if (result.first.isEmpty()) return QJsonObject();
5157

5258
QJsonParseError err;
53-
QJsonDocument output = QJsonDocument::fromJson(result, &err);
59+
QJsonDocument output = QJsonDocument::fromJson(result.first, &err);
5460

5561
if (err.error != QJsonParseError::NoError || !output.isObject()) {
56-
emit error(QString("Formatter returned invalid json"));
62+
emit error(QString("Formatter returned invalid json: %1")
63+
.arg(QString::fromLocal8Bit(result.first)));
5764
return QJsonObject();
5865
}
5966

@@ -90,21 +97,22 @@ void ValueEditor::FormattersManager::loadFormatters() {
9097

9198
QStringList fullCmd = cmd.toVariant().toStringList();
9299
QStringList versionCmd(fullCmd);
93-
versionCmd.append("--version");
100+
versionCmd.append("info");
94101

95-
QByteArray result = readStdoutFromExternalProcess(
96-
versionCmd, QByteArray(), it.filePath());
102+
QJsonObject outputObj =
103+
readJsonFromExternalProcess(versionCmd, QByteArray(), it.filePath());
97104

98-
if (result.isEmpty()) {
105+
if (outputObj.isEmpty()) {
99106
emit error(
100-
QString("Formatter %1 returned invalid output for version command")
107+
QString("Formatter %1 returned empty output for info command")
101108
.arg(it.filePath()));
102109
continue;
103110
}
104111

105112
QVariantMap data;
106113
data["name"] = it.fileName();
107-
data["version"] = result.simplified();
114+
data["version"] = outputObj["version"].toString();
115+
data["description"] = outputObj["description"].toString();
108116
data["cmd"] = fullCmd.join(" ");
109117
data["cmd_list"] = fullCmd;
110118
data["cwd"] = it.filePath();
@@ -135,6 +143,8 @@ QVariant ValueEditor::FormattersManager::data(const QModelIndex &index,
135143
return data["version"];
136144
} else if (role == cmd) {
137145
return data["cmd"];
146+
} else if (role == description) {
147+
return data["description"];
138148
}
139149

140150
return QVariant();
@@ -144,6 +154,7 @@ QHash<int, QByteArray> ValueEditor::FormattersManager::roleNames() const {
144154
QHash<int, QByteArray> roles;
145155
roles[name] = "name";
146156
roles[version] = "version";
157+
roles[description] = "description";
147158
roles[cmd] = "cmd";
148159
return roles;
149160
}
@@ -202,7 +213,7 @@ void ValueEditor::FormattersManager::isValid(const QString &formatterName,
202213
QVariantMap formatter = m_formattersData[m_mapping[formatterName]];
203214

204215
QStringList cmd = formatter["cmd_list"].toStringList();
205-
cmd.append("is_valid");
216+
cmd.append("validate");
206217

207218
QJsonObject outputObj = readJsonFromExternalProcess(
208219
cmd, data.toBase64(), formatter["cwd"].toString());
@@ -215,8 +226,7 @@ void ValueEditor::FormattersManager::isValid(const QString &formatterName,
215226
}
216227

217228
if (jsCallback.isCallable()) {
218-
jsCallback.call(QJSValueList{outputObj["valid"].toBool(),
219-
outputObj["message"].toString()});
229+
jsCallback.call(QJSValueList{outputObj["valid"].toBool()});
220230
}
221231
}
222232

@@ -235,18 +245,18 @@ void ValueEditor::FormattersManager::encode(const QString &formatterName,
235245
QStringList cmd = formatter["cmd_list"].toStringList();
236246
cmd.append("encode");
237247

238-
QByteArray output = readStdoutFromExternalProcess(
239-
cmd, data.toBase64(), formatter["cwd"].toString());
248+
auto result = readJsonFromExternalProcess(cmd, data.toBase64(),
249+
formatter["cwd"].toString());
240250

241-
if (output.isEmpty()) {
251+
if (result.isEmpty()) {
242252
emit error(QCoreApplication::translate(
243253
"RDM", "Cannot encode value using %1 formatter. ")
244254
.arg(formatterName));
245255
return;
246256
}
247257

248258
if (jsCallback.isCallable()) {
249-
jsCallback.call(QJSValueList{QString::fromUtf8(output)});
259+
jsCallback.call(QJSValueList{result["output"].toString()});
250260
}
251261
}
252262

@@ -263,6 +273,10 @@ QString ValueEditor::FormattersManager::formattersPath() {
263273
}
264274
}
265275

276+
bool ValueEditor::FormattersManager::isInstalled(const QString &name) {
277+
return m_mapping.contains(name);
278+
}
279+
266280
void ValueEditor::FormattersManager::fillMapping() {
267281
int index = 0;
268282

src/modules/value-editor/formattersmanager.h

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ class FormattersManager : public QAbstractListModel {
88
Q_OBJECT
99

1010
public:
11-
enum Roles { name = Qt::UserRole + 1, version, cmd };
11+
enum Roles { name = Qt::UserRole + 1, version, description, cmd };
1212

1313
public:
1414
FormattersManager();
@@ -40,12 +40,14 @@ class FormattersManager : public QAbstractListModel {
4040

4141
Q_INVOKABLE QString formattersPath();
4242

43+
Q_INVOKABLE bool isInstalled(const QString& name);
44+
4345
private:
4446
void fillMapping();
4547

46-
QByteArray readStdoutFromExternalProcess(const QStringList& cmd,
47-
const QByteArray& processInput,
48-
const QString& wd);
48+
QPair<QByteArray, QByteArray> readOutputFromExternalProcess(
49+
const QStringList& cmd, const QByteArray& processInput,
50+
const QString& wd);
4951

5052
QJsonObject readJsonFromExternalProcess(const QStringList& cmd,
5153
const QByteArray& processInput,

src/qml/GlobalSettings.qml

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -140,15 +140,22 @@ Dialog {
140140

141141
TableViewColumn {
142142
role: "name"
143-
title: "Name"
143+
title: qsTranslate("RDM","Name")
144144
}
145145
TableViewColumn {
146146
role: "version"
147-
title: "Version"
147+
width: 75
148+
title: qsTranslate("RDM","Version")
148149
}
149150
TableViewColumn {
150151
role: "cmd"
151-
title: "Command"
152+
title: qsTranslate("RDM","Command")
153+
}
154+
155+
TableViewColumn {
156+
width: 250
157+
role: "description"
158+
title: qsTranslate("RDM","Description")
152159
}
153160

154161
model: formattersManager

src/qml/value-editor/editors/MultilineEditor.qml

Lines changed: 41 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -67,8 +67,11 @@ ColumnLayout
6767
}
6868

6969
function loadFormattedValue(val) {
70+
var guessFormatter = false
71+
7072
if (val) {
7173
root.value = val
74+
guessFormatter = true
7275
}
7376

7477
if (!root.value) {
@@ -87,13 +90,47 @@ ColumnLayout
8790
binaryFlag.visible = isBin
8891

8992
// If current formatter is plain text - try to guess formatter
90-
if (formatterSelector.currentIndex == 0) {
91-
formatterSelector.currentIndex = Formatters.guessFormatter(isBin)
93+
if (guessFormatter && formatterSelector.currentIndex == 0) {
94+
_guessFormatter(isBin, function() {
95+
_loadFormatter(isBin)
96+
})
97+
} else {
98+
_loadFormatter(isBin)
99+
}
100+
}
101+
102+
function _guessFormatter(isBin, callback) {
103+
console.log("Guessing formatter")
104+
105+
var candidates = Formatters.guessFormatter(isBin)
106+
107+
console.log("candidates:", candidates)
108+
109+
if (Array.isArray(candidates)) {
110+
111+
for (var index in candidates) {
112+
var cFormatter = formatterSelector.model[candidates[index]]
113+
114+
cFormatter.instance.isValid(root.value, function (isValid) {
115+
if (isValid && formatterSelector.currentIndex == 0) {
116+
formatterSelector.currentIndex = candidates[index]
117+
callback()
118+
}
119+
})
120+
121+
if (formatterSelector.currentIndex !== 0)
122+
break
123+
}
124+
} else {
125+
formatterSelector.currentIndex = candidates
126+
callback()
92127
}
128+
}
93129

130+
function _loadFormatter(isBin) {
94131
var formatter = formatterSelector.model[formatterSelector.currentIndex]
95132

96-
uiBlocker.visible = true
133+
uiBlocker.visible = true
97134

98135
formatter.instance.getFormatted(root.value, function (error, formatted, isReadOnly, format) {
99136

@@ -113,7 +150,7 @@ ColumnLayout
113150
root.isEdited = false
114151
uiBlocker.visible = false
115152
})
116-
} else {
153+
} else {
117154
textView.model = qmlUtils.wrapLargeText(formatted)
118155
textView.readOnly = isReadOnly
119156
root.isEdited = false

src/qml/value-editor/editors/formatters/formatters.js

Lines changed: 54 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@ var plain = {
1616
return callback("", raw, false, FORMAT_PLAIN_TEXT)
1717
},
1818

19+
isValid: function (raw, callback) {
20+
return callback(true)
21+
},
22+
1923
getRaw: function (formatted, callback) {
2024
return callback("", formatted)
2125
}
@@ -28,6 +32,10 @@ var hex = {
2832
return callback("", qmlUtils.printable(raw), false, FORMAT_PLAIN_TEXT)
2933
},
3034

35+
isValid: function (raw, callback) {
36+
return callback(true)
37+
},
38+
3139
getRaw: function (formatted, callback) {
3240
return callback("", qmlUtils.printableToValue(formatted))
3341
}
@@ -36,6 +44,10 @@ var hex = {
3644
var hexTable = {
3745
title: "HEX TABLE",
3846

47+
isValid: function (raw, callback) {
48+
return callback(true)
49+
},
50+
3951
getFormatted: function (raw, callback) {
4052
return callback("", Hexy.hexy(qmlUtils.valueToBinary(raw), {'html': true}), true, FORMAT_HTML)
4153
},
@@ -53,7 +65,16 @@ var json = {
5365
} catch (e) {
5466
return callback(qsTranslate("RDM", "Invalid JSON: ") + e)
5567
}
56-
},
68+
},
69+
70+
isValid: function (raw, callback) {
71+
try {
72+
JSONFormatter.prettyPrint(String(raw))
73+
return callback(true)
74+
} catch (e) {
75+
return callback(false)
76+
}
77+
},
5778

5879
getRaw: function (formatted, callback) {
5980
try {
@@ -86,6 +107,10 @@ function buildFormattersModel()
86107

87108
getRaw: function (formatted, callback) {
88109
return formattersManager.encode(formatterName, formatted, callback)
110+
},
111+
112+
isValid: function (raw, callback) {
113+
return formattersManager.isValid(formatterName, raw, callback)
89114
}
90115
}
91116
}
@@ -101,7 +126,34 @@ function buildFormattersModel()
101126
return formatters
102127
}
103128

129+
function getFormatterIndex(name) {
130+
var indexInNativeFormatters = -1
131+
132+
if (!formattersManager.isInstalled(name))
133+
return indexInNativeFormatters
134+
135+
var plainList = formattersManager.getPlainList()
136+
137+
for (var index in plainList) {
138+
if (plainList[index] === name) {
139+
indexInNativeFormatters = index
140+
break
141+
}
142+
}
143+
144+
return parseInt(indexInNativeFormatters) + enabledFormatters.length
145+
146+
}
147+
104148
function guessFormatter(isBinary)
105149
{
106-
return isBinary? 2 : 0
150+
if (isBinary) {
151+
if (formattersManager.isInstalled("python-decompresser")) {
152+
return [getFormatterIndex("python-decompresser"), 2]
153+
}
154+
155+
return 2
156+
} else {
157+
return 0
158+
}
107159
}

0 commit comments

Comments
 (0)