File indexing completed on 2024-05-05 05:51:37
0001 /* 0002 SPDX-FileCopyrightText: 2020 Waqar Ahmed <waqar.17a@gmail.com> 0003 0004 SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 #include "gotosymbolmodel.h" 0007 0008 #include "hostprocess.h" 0009 0010 #include <KLocalizedString> 0011 #include <QProcess> 0012 #include <QStandardPaths> 0013 0014 GotoSymbolModel::GotoSymbolModel(QObject *parent) 0015 : QAbstractTableModel(parent) 0016 { 0017 } 0018 0019 int GotoSymbolModel::columnCount(const QModelIndex &) const 0020 { 0021 return 1; 0022 } 0023 0024 int GotoSymbolModel::rowCount(const QModelIndex &) const 0025 { 0026 return m_rows.count(); 0027 } 0028 0029 QVariant GotoSymbolModel::data(const QModelIndex &index, int role) const 0030 { 0031 if (!index.isValid()) { 0032 return {}; 0033 } 0034 0035 const auto &row = m_rows.at(index.row()); 0036 if (role == Qt::DisplayRole) { 0037 if (index.column() == 0) { 0038 return row.name; 0039 } 0040 } else if (role == Qt::DecorationRole) { 0041 if (index.column() == 0) { 0042 return row.icon; 0043 } 0044 } else if (role == Qt::UserRole) { 0045 return row.line; 0046 } 0047 0048 return QVariant(); 0049 } 0050 0051 void GotoSymbolModel::refresh(const QString &filePath) 0052 { 0053 static const QIcon nsIcon = QIcon::fromTheme(QStringLiteral("code-block")); 0054 static const QIcon classIcon = QIcon::fromTheme(QStringLiteral("code-class")); 0055 static const QIcon funcIcon = QIcon::fromTheme(QStringLiteral("code-function")); 0056 static const QIcon varIcon = QIcon::fromTheme(QStringLiteral("code-variable")); 0057 static const QIcon defIcon = nsIcon; 0058 0059 beginResetModel(); 0060 m_rows.clear(); 0061 endResetModel(); 0062 0063 // only use ctags from PATH 0064 static const auto fullExecutablePath = safeExecutableName(QStringLiteral("ctags")); 0065 if (fullExecutablePath.isEmpty()) { 0066 beginResetModel(); 0067 m_rows.append(SymbolItem{i18n("CTags executable not found."), -1, QIcon()}); 0068 endResetModel(); 0069 return; 0070 } 0071 0072 QProcess p; 0073 startHostProcess(p, fullExecutablePath, {QStringLiteral("-x"), QStringLiteral("--_xformat=%{name}%{signature}\t%{kind}\t%{line}"), filePath}); 0074 0075 QByteArray out; 0076 if (p.waitForFinished()) { 0077 out = p.readAllStandardOutput(); 0078 } else { 0079 beginResetModel(); 0080 m_rows.append(SymbolItem{i18n("CTags executable failed to execute."), -1, QIcon()}); 0081 endResetModel(); 0082 return; 0083 } 0084 0085 QList<SymbolItem> symItems; 0086 const auto tags = out.split('\n'); 0087 symItems.reserve(tags.size()); 0088 for (const auto &tag : tags) { 0089 const auto items = tag.split('\t'); 0090 if (items.isEmpty() || items.count() < 3) { 0091 continue; 0092 } 0093 0094 SymbolItem item; 0095 item.name = QLatin1String(items.at(0)); 0096 // this happens in markdown names for some reason 0097 if (item.name.endsWith(QLatin1Char('-'))) { 0098 item.name.chop(1); 0099 } 0100 0101 switch (items.at(1).at(0)) { 0102 case 'f': 0103 item.icon = funcIcon; 0104 break; 0105 case 'm': 0106 if (items.at(1) == "method") { 0107 item.icon = funcIcon; 0108 } else { 0109 item.icon = defIcon; 0110 } 0111 break; 0112 case 'g': 0113 if (items.at(1) == "getter") { 0114 item.icon = funcIcon; 0115 } else { 0116 item.icon = defIcon; 0117 } 0118 break; 0119 case 'c': 0120 case 's': 0121 if (items.at(1) == "class" || items.at(1) == "struct") { 0122 item.icon = classIcon; 0123 } else { 0124 item.icon = defIcon; 0125 } 0126 break; 0127 case 'n': 0128 if (items.at(1) == "namespace") { 0129 item.icon = nsIcon; 0130 } 0131 break; 0132 case 'v': 0133 item.icon = varIcon; 0134 break; 0135 default: 0136 item.icon = defIcon; 0137 break; 0138 } 0139 0140 item.line = items.at(2).toInt(); 0141 symItems.append(item); 0142 } 0143 0144 beginResetModel(); 0145 if (!symItems.isEmpty()) { 0146 m_rows = std::move(symItems); 0147 } else { 0148 m_rows.append(SymbolItem{i18n("CTags was unable to parse this file."), -1, QIcon()}); 0149 } 0150 endResetModel(); 0151 } 0152 0153 #include "moc_gotosymbolmodel.cpp"