File indexing completed on 2024-04-28 05:49:17

0001 /***************************************************************************
0002                            python_parser.cpp  -  description
0003                              -------------------
0004     begin                : Apr 2 2003
0005     author               : 2003 Massimo Callegari
0006     email                : massimocallegari@yahoo.it
0007 
0008     modified             : 2023-05-20 16:25:28
0009     author               : 2023 Cezar M. Tigaret
0010     email                : cezar.tigaret@gmail.com
0011  ***************************************************************************/
0012 /***************************************************************************
0013  *                                                                         *
0014  *   SPDX-License-Identifier: GPL-2.0-or-later
0015  *                                                                         *
0016  ***************************************************************************/
0017 #include "plugin_katesymbolviewer.h"
0018 
0019 void KatePluginSymbolViewerView::parsePythonSymbols(void)
0020 {
0021     if (!m_mainWindow->activeView()) {
0022         return;
0023     }
0024 
0025     m_macro->setText(i18n("Show Functions"));
0026     m_struct->setText(i18n("Show Methods"));
0027     m_func->setText(i18n("Show Classes"));
0028 
0029     bool commentLine = false;
0030 
0031     QString name;
0032     QString params;
0033     QString returnAnnot;
0034     QString endcolon;
0035     QString current_class_name;
0036 
0037     QTreeWidgetItem *node = nullptr;
0038     QTreeWidgetItem *functionNode = nullptr, *mtdNode = nullptr, *clsNode = nullptr;
0039     QTreeWidgetItem *lastMcrNode = nullptr, *lastMtdNode = nullptr, *lastClsNode = nullptr;
0040 
0041     KTextEditor::Document *kv = m_mainWindow->activeView()->document();
0042 
0043     if (m_treeOn->isChecked()) {
0044         clsNode = new QTreeWidgetItem(m_symbols, QStringList(i18n("Classes")));
0045         functionNode = new QTreeWidgetItem(m_symbols, QStringList(i18n("Functions")));
0046         functionNode->setIcon(0, m_icon_function);
0047         clsNode->setIcon(0, m_icon_class);
0048 
0049         if (m_expandOn->isChecked()) {
0050             m_symbols->expandItem(functionNode);
0051             m_symbols->expandItem(clsNode);
0052         }
0053         lastClsNode = clsNode;
0054         lastMcrNode = functionNode;
0055         mtdNode = clsNode;
0056         lastMtdNode = clsNode;
0057         m_symbols->setRootIsDecorated(1);
0058     } else {
0059         m_symbols->setRootIsDecorated(0);
0060     }
0061 
0062     // static const QString contStr(0x21b5);
0063     static const QString contStr(QChar(0x21b5));
0064 
0065     static const QRegularExpression comment_regexp(QLatin1String("^[#]"), QRegularExpression::UseUnicodePropertiesOption);
0066     static const QRegularExpression ml_docsctring_regexp(QLatin1String("\"\"\""), QRegularExpression::UseUnicodePropertiesOption);
0067     static const QRegularExpression sl_docstring_regexp(QLatin1String("\"\"\"(.*)?\"\"\""), QRegularExpression::UseUnicodePropertiesOption);
0068 
0069     static const QRegularExpression class_regexp(QLatin1String("^class ([\\w]+)\\s*(\\([\\w.,\\s]*\\)?)?\\s*(:$)?"),
0070                                                  QRegularExpression::UseUnicodePropertiesOption);
0071 
0072     static const QRegularExpression function_regexp(
0073         QLatin1String("^( *)def\\s+([\\w]+)\\s*(\\([\\w,;.:*=\\/\\[\\]\\s\"\']*\\)?)?\\s*(-> [\\w.,\\s\\[\\]]+)?\\s*(:$)?"),
0074         QRegularExpression::UseUnicodePropertiesOption);
0075 
0076     QRegularExpressionMatch match;
0077 
0078     for (int i = 0; i < kv->lines(); i++) {
0079         int line = i;
0080         QString cl = kv->line(i);
0081         if (cl.isEmpty()) {
0082             continue;
0083         }
0084         // concatenate continued lines and remove continuation marker
0085         while (cl[cl.length() - 1] == QLatin1Char('\\')) {
0086             cl = cl.left(cl.length() - 1);
0087             i++;
0088             if (i < kv->lines()) {
0089                 cl += kv->line(i);
0090             } else {
0091                 break;
0092             }
0093             if (cl.isEmpty()) {
0094                 break;
0095             }
0096         }
0097 
0098         match = ml_docsctring_regexp.match(cl);
0099 
0100         if (match.hasMatch()) {
0101             match = sl_docstring_regexp.match(cl);
0102             if (match.hasMatch()) {
0103                 commentLine = false;
0104                 continue;
0105 
0106             } else {
0107                 commentLine = !commentLine;
0108                 continue;
0109             }
0110         } else {
0111             match = sl_docstring_regexp.match(cl);
0112             if (match.hasMatch()) {
0113                 commentLine = false;
0114                 continue;
0115             }
0116         }
0117 
0118         if (commentLine) {
0119             continue;
0120         }
0121 
0122         Symbol type;
0123         match = class_regexp.match(cl);
0124         if (match.hasMatch()) {
0125             type = Symbol::Class;
0126         } else {
0127             match = function_regexp.match(cl);
0128             if (match.hasMatch()) {
0129                 if (match.captured(1).isEmpty() || current_class_name.isEmpty()) // case where function is declared inside a block
0130                 {
0131                     type = Symbol::Function;
0132                     current_class_name.clear();
0133                 } else {
0134                     type = Symbol::Method;
0135                 }
0136             } else {
0137                 // nothing to do in this iteration
0138                 continue;
0139             }
0140         }
0141 
0142         // if either class or function definition found
0143         if (type == Symbol::Class) {
0144             name = match.captured(1);
0145             params = match.captured(2);
0146             endcolon = match.captured(3);
0147             current_class_name = name;
0148 
0149             if (endcolon.isEmpty()) {
0150                 params += QLatin1Char(' ');
0151                 params += contStr;
0152             }
0153 
0154         } else {
0155             name = match.captured(2);
0156             params = match.captured(3);
0157             returnAnnot = match.captured(4);
0158             endcolon = match.captured(5);
0159 
0160             if (!returnAnnot.isEmpty()) {
0161                 params += QLatin1Char(' ');
0162                 params += returnAnnot;
0163             }
0164 
0165             if (endcolon.isEmpty()) {
0166                 params += QLatin1Char(' ');
0167                 params += contStr;
0168             }
0169         }
0170         if (m_typesOn->isChecked()) {
0171             name += params;
0172         }
0173 
0174         if (m_func->isChecked() && type == Symbol::Class) {
0175             if (m_treeOn->isChecked()) {
0176                 node = new QTreeWidgetItem(clsNode, lastClsNode);
0177                 if (m_expandOn->isChecked()) {
0178                     m_symbols->expandItem(node);
0179                 }
0180                 lastClsNode = node;
0181                 mtdNode = lastClsNode;
0182                 lastMtdNode = lastClsNode;
0183             } else {
0184                 node = new QTreeWidgetItem(m_symbols);
0185             }
0186 
0187             node->setText(0, name);
0188             node->setIcon(0, m_icon_class);
0189             node->setText(1, QString::number(line, 10));
0190         }
0191 
0192         if (m_struct->isChecked() && type == Symbol::Method) {
0193             if (m_treeOn->isChecked()) {
0194                 node = new QTreeWidgetItem(mtdNode, lastMtdNode);
0195                 lastMtdNode = node;
0196             } else {
0197                 node = new QTreeWidgetItem(m_symbols);
0198             }
0199 
0200             node->setText(0, name);
0201             node->setIcon(0, m_icon_function);
0202             node->setText(1, QString::number(line, 10));
0203         }
0204 
0205         if (m_macro->isChecked() && type == Symbol::Function) {
0206             if (m_treeOn->isChecked()) {
0207                 node = new QTreeWidgetItem(functionNode, lastMcrNode);
0208                 lastMcrNode = node;
0209             } else {
0210                 node = new QTreeWidgetItem(m_symbols);
0211             }
0212 
0213             node->setText(0, name);
0214             node->setIcon(0, m_icon_function);
0215             node->setText(1, QString::number(line, 10));
0216         }
0217 
0218         name.clear();
0219         params.clear();
0220     }
0221 }