File indexing completed on 2024-04-28 11:20:35

0001 /*
0002     SPDX-License-Identifier: GPL-2.0-or-later
0003     SPDX-FileCopyrightText: 2018 Nikita Sirgienko <warquark@gmail.com>
0004     SPDX-FileCopyrightText: 2022 Alexander Semke <alexander.semke@web.de>
0005 */
0006 
0007 #include "octavevariablemodel.h"
0008 #include "octavesession.h"
0009 #include "textresult.h"
0010 
0011 #include <QDebug>
0012 
0013 #include "settings.h"
0014 
0015 using namespace Cantor;
0016 
0017 OctaveVariableModel::OctaveVariableModel(OctaveSession* session): DefaultVariableModel(session)
0018 {
0019 }
0020 
0021 void OctaveVariableModel::update()
0022 {
0023     static const QString code = QString::fromLatin1(
0024         "printf('__cantor_delimiter_line__');"
0025         "__cantor_list__ = who();"
0026         "__cantor_split_var__ = split_long_rows(0);"
0027         "__cantor_parse_values__ = %1;"
0028         "for __cantor_index__ = 1:length(__cantor_list__)"
0029         "  __cantor_varname__ = char(__cantor_list__{__cantor_index__});"
0030         "  printf([__cantor_varname__ '\\n']);"
0031         "  if (__cantor_parse_values__)"
0032         "    try"
0033         "      eval(['__cantor_string__ = disp(' __cantor_varname__ ');']);"
0034         "      printf([num2str(eval(['sizeof(' __cantor_varname__ ');'])) '\\n']);"
0035         "      printf([eval(['typeinfo(' __cantor_varname__ ');']) '\\n']);"
0036         "      printf([num2str(eval(['rows(' __cantor_varname__ ');'])) '\\n']);"
0037         "      printf([num2str(eval(['columns(' __cantor_varname__ ');'])) '\\n']);"
0038         "      printf(__cantor_string__);"
0039         "    catch"
0040         "      printf(['<unprintable value>' '\\n']);"
0041         "      printf(['0' '\\n']);"
0042         "    end_try_catch;"
0043         "  else"
0044         "    printf('');"
0045         "  endif;"
0046         "  printf('__cantor_delimiter_line__');"
0047         "endfor;"
0048         "split_long_rows(__cantor_split_var__);"
0049         "clear __cantor_list__;"
0050         "clear __cantor_index__;"
0051         "clear __cantor_varname__;"
0052         "clear __cantor_parse_values__;"
0053         "clear __cantor_string__;"
0054         "clear __cantor_split_var__;"
0055     );
0056 
0057     if (m_expr)
0058         return;
0059 
0060     const QString& cmd = code.arg(OctaveSettings::self()->variableManagement() ? QLatin1String("true") : QLatin1String("false"));
0061     m_expr = session()->evaluateExpression(cmd, Expression::FinishingBehavior::DoNotDelete, true);
0062     connect(m_expr, &Expression::statusChanged, this, &OctaveVariableModel::parseNewVariables);
0063 }
0064 
0065 void OctaveVariableModel::parseNewVariables(Expression::Status status)
0066 {
0067     switch(status)
0068     {
0069         case Expression::Status::Done:
0070         {
0071             static const QLatin1String delimiter("__cantor_delimiter_line__");
0072 
0073             if (m_expr->results().isEmpty())
0074             {
0075                 qWarning() << "Octave code for parsing variables finish with done status, but without results";
0076                 break;
0077             }
0078 
0079             QString text = static_cast<Cantor::TextResult*>(m_expr->result())->plain();
0080             const QStringList& variableData = text.split(delimiter, QString::SkipEmptyParts);
0081             QList<Variable> vars;
0082 
0083             for (const auto& data : variableData)
0084             {
0085                 // every variable data has 4 parts/elements separated by a new line - the name of the variable, its size, type and the actual value
0086                 const auto& elements = data.split(QLatin1String("\n"), QString::SkipEmptyParts);
0087                 int count = elements.count();
0088                 if (count < 6)
0089                     continue;
0090 
0091                 const QString& name = elements.constFirst();
0092 
0093                 // skip the output of results that are not assigned to any varialbe ("ans" used by Octave)
0094                 if (name == QStringLiteral("ans"))
0095                     continue;
0096 
0097                 const QString& size = elements.at(1);
0098                 const QString& type = elements.at(2);
0099                 const QString& rows = elements.at(3);
0100                 const QString& columns = elements.at(4);
0101 
0102                 // the last section(s) contain(s) the value (single-line or multi-line output)
0103                 QString value;
0104                 if (OctaveSettings::self()->variableManagement())
0105                 {
0106                     for (int i = 5; i < count; ++i)
0107                     {
0108                         if (!value.isEmpty())
0109                             value += QStringLiteral("; "); // separate multi-line values like in column vectors or in matrices by a semicolon
0110                         value += elements.at(i).trimmed();
0111                     }
0112                 }
0113 
0114                 value = value.replace(QStringLiteral("   "), QStringLiteral(" ")); // for vectors Octave is separating the values with three blanks, replace with one
0115                 vars << Variable(name, value, size.toULongLong(), type, rows + QStringLiteral("x") + columns);
0116             }
0117 
0118             setVariables(vars);
0119             break;
0120         }
0121         case Expression::Status::Error:
0122             qWarning() << "Octave code for parsing variables finish with error message: " << m_expr->errorMessage();
0123             break;
0124 
0125         default:
0126             return;
0127     }
0128 
0129     m_expr->deleteLater();
0130     m_expr = nullptr;
0131 }