feat: async calculator
This commit is contained in:
parent
3c819cac1b
commit
9d36f5c314
3 changed files with 132 additions and 2 deletions
|
|
@ -12,8 +12,13 @@ Item {
|
||||||
required property var list
|
required property var list
|
||||||
readonly property string math: list.search.text.slice(`${Config.launcher.actionPrefix}calc `.length)
|
readonly property string math: list.search.text.slice(`${Config.launcher.actionPrefix}calc `.length)
|
||||||
|
|
||||||
|
onMathChanged: {
|
||||||
|
if (math.length > 0)
|
||||||
|
Qalculator.evalAsync(math);
|
||||||
|
}
|
||||||
|
|
||||||
function onClicked(): void {
|
function onClicked(): void {
|
||||||
Quickshell.execDetached(["wl-copy", Qalculator.eval(math, false)]);
|
Quickshell.execDetached(["wl-copy", Qalculator.rawResult]);
|
||||||
root.list.visibilities.launcher = false;
|
root.list.visibilities.launcher = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -55,7 +60,7 @@ Item {
|
||||||
return Colours.palette.m3onSurface;
|
return Colours.palette.m3onSurface;
|
||||||
}
|
}
|
||||||
|
|
||||||
text: root.math.length > 0 ? Qalculator.eval(root.math) : qsTr("Type an expression to calculate")
|
text: root.math.length > 0 ? (Qalculator.result || qsTr("Calculating...")) : qsTr("Type an expression to calculate")
|
||||||
elide: Text.ElideLeft
|
elide: Text.ElideLeft
|
||||||
|
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,13 @@
|
||||||
#include "qalculator.hpp"
|
#include "qalculator.hpp"
|
||||||
|
|
||||||
#include <libqalculate/qalculate.h>
|
#include <libqalculate/qalculate.h>
|
||||||
|
#include <qfuturewatcher.h>
|
||||||
|
#include <qtconcurrentrun.h>
|
||||||
|
|
||||||
namespace caelestia {
|
namespace caelestia {
|
||||||
|
|
||||||
|
QMutex Qalculator::s_calculatorMutex;
|
||||||
|
|
||||||
Qalculator::Qalculator(QObject* parent)
|
Qalculator::Qalculator(QObject* parent)
|
||||||
: QObject(parent) {
|
: QObject(parent) {
|
||||||
if (!CALCULATOR) {
|
if (!CALCULATOR) {
|
||||||
|
|
@ -19,6 +23,8 @@ QString Qalculator::eval(const QString& expr, bool printExpr) const {
|
||||||
return QString();
|
return QString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QMutexLocker locker(&s_calculatorMutex);
|
||||||
|
|
||||||
EvaluationOptions eo;
|
EvaluationOptions eo;
|
||||||
PrintOptions po;
|
PrintOptions po;
|
||||||
|
|
||||||
|
|
@ -49,4 +55,100 @@ QString Qalculator::eval(const QString& expr, bool printExpr) const {
|
||||||
return QString::fromStdString(result);
|
return QString::fromStdString(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Qalculator::evalAsync(const QString& expr) {
|
||||||
|
const quint64 gen = ++m_generation;
|
||||||
|
|
||||||
|
if (expr.isEmpty()) {
|
||||||
|
if (!m_result.isEmpty()) {
|
||||||
|
m_result.clear();
|
||||||
|
emit resultChanged();
|
||||||
|
}
|
||||||
|
if (!m_rawResult.isEmpty()) {
|
||||||
|
m_rawResult.clear();
|
||||||
|
emit rawResultChanged();
|
||||||
|
}
|
||||||
|
if (m_busy) {
|
||||||
|
m_busy = false;
|
||||||
|
emit busyChanged();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!m_busy) {
|
||||||
|
m_busy = true;
|
||||||
|
emit busyChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto future = QtConcurrent::run([expr]() -> QPair<QString, QString> {
|
||||||
|
QMutexLocker locker(&s_calculatorMutex);
|
||||||
|
|
||||||
|
EvaluationOptions eo;
|
||||||
|
PrintOptions po;
|
||||||
|
|
||||||
|
std::string parsed;
|
||||||
|
std::string result = CALCULATOR->calculateAndPrint(
|
||||||
|
CALCULATOR->unlocalizeExpression(expr.toStdString(), eo.parse_options), 100, eo, po, &parsed);
|
||||||
|
|
||||||
|
std::string error;
|
||||||
|
while (CALCULATOR->message()) {
|
||||||
|
if (!CALCULATOR->message()->message().empty()) {
|
||||||
|
if (CALCULATOR->message()->type() == MESSAGE_ERROR) {
|
||||||
|
error += "error: ";
|
||||||
|
} else if (CALCULATOR->message()->type() == MESSAGE_WARNING) {
|
||||||
|
error += "warning: ";
|
||||||
|
}
|
||||||
|
error += CALCULATOR->message()->message();
|
||||||
|
}
|
||||||
|
CALCULATOR->nextMessage();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!error.empty()) {
|
||||||
|
const QString errorStr = QString::fromStdString(error);
|
||||||
|
return { errorStr, errorStr };
|
||||||
|
}
|
||||||
|
|
||||||
|
const QString rawStr = QString::fromStdString(result);
|
||||||
|
return { QString("%1 = %2").arg(parsed).arg(result), rawStr };
|
||||||
|
});
|
||||||
|
|
||||||
|
auto* watcher = new QFutureWatcher<QPair<QString, QString>>(this);
|
||||||
|
|
||||||
|
connect(watcher, &QFutureWatcher<QPair<QString, QString>>::finished, this, [this, watcher, gen]() {
|
||||||
|
watcher->deleteLater();
|
||||||
|
|
||||||
|
if (gen != m_generation) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto [formatted, raw] = watcher->result();
|
||||||
|
|
||||||
|
if (m_result != formatted) {
|
||||||
|
m_result = formatted;
|
||||||
|
emit resultChanged();
|
||||||
|
}
|
||||||
|
if (m_rawResult != raw) {
|
||||||
|
m_rawResult = raw;
|
||||||
|
emit rawResultChanged();
|
||||||
|
}
|
||||||
|
if (m_busy) {
|
||||||
|
m_busy = false;
|
||||||
|
emit busyChanged();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
watcher->setFuture(future);
|
||||||
|
}
|
||||||
|
|
||||||
|
QString Qalculator::result() const {
|
||||||
|
return m_result;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString Qalculator::rawResult() const {
|
||||||
|
return m_rawResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Qalculator::busy() const {
|
||||||
|
return m_busy;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace caelestia
|
} // namespace caelestia
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <qmutex.h>
|
||||||
#include <qobject.h>
|
#include <qobject.h>
|
||||||
#include <qqmlintegration.h>
|
#include <qqmlintegration.h>
|
||||||
|
|
||||||
|
|
@ -10,10 +11,32 @@ class Qalculator : public QObject {
|
||||||
QML_ELEMENT
|
QML_ELEMENT
|
||||||
QML_SINGLETON
|
QML_SINGLETON
|
||||||
|
|
||||||
|
Q_PROPERTY(QString result READ result NOTIFY resultChanged)
|
||||||
|
Q_PROPERTY(QString rawResult READ rawResult NOTIFY rawResultChanged)
|
||||||
|
Q_PROPERTY(bool busy READ busy NOTIFY busyChanged)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit Qalculator(QObject* parent = nullptr);
|
explicit Qalculator(QObject* parent = nullptr);
|
||||||
|
|
||||||
Q_INVOKABLE QString eval(const QString& expr, bool printExpr = true) const;
|
Q_INVOKABLE QString eval(const QString& expr, bool printExpr = true) const;
|
||||||
|
Q_INVOKABLE void evalAsync(const QString& expr);
|
||||||
|
|
||||||
|
[[nodiscard]] QString result() const;
|
||||||
|
[[nodiscard]] QString rawResult() const;
|
||||||
|
[[nodiscard]] bool busy() const;
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void resultChanged();
|
||||||
|
void rawResultChanged();
|
||||||
|
void busyChanged();
|
||||||
|
|
||||||
|
private:
|
||||||
|
static QMutex s_calculatorMutex;
|
||||||
|
|
||||||
|
QString m_result;
|
||||||
|
QString m_rawResult;
|
||||||
|
bool m_busy = false;
|
||||||
|
quint64 m_generation = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace caelestia
|
} // namespace caelestia
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue