int ListSymbolsJob::execute() { Set<String> out; std::shared_ptr<Project> proj = project(); if (proj) { if (queryFlags() & QueryMessage::WildcardSymbolNames && (string.contains('*') || string.contains('?')) && !string.endsWith('*')) { string += '*'; } List<QueryMessage::PathFilter> filters = pathFilters(); List<Path> paths; for (const auto &filter : filters) { if (filter.mode == QueryMessage::PathFilter::Self) { paths.append(filter.pattern); if (!paths.last().isFile()) { paths.clear(); break; } } else { paths.clear(); break; } } if (!paths.isEmpty()) { out = listSymbolsWithPathFilter(proj, paths); } else { out = listSymbols(proj); } } if (queryFlags() & QueryMessage::Elisp) { write("(list", IgnoreMax | DontQuote); for (Set<String>::const_iterator it = out.begin(); it != out.end(); ++it) { write(*it); } write(")", IgnoreMax | DontQuote); } else { List<String> sorted = out.toList(); if (queryFlags() & QueryMessage::ReverseSort) { std::sort(sorted.begin(), sorted.end(), std::greater<String>()); } else { std::sort(sorted.begin(), sorted.end()); } const int count = sorted.size(); for (int i = 0; i < count; ++i) { write(sorted.at(i)); } } return out.isEmpty() ? 1 : 0; }
Set<String> ListSymbolsJob::imenu(const std::shared_ptr<Project> &project) { Set<String> out; const List<String> paths = pathFilters(); if (paths.isEmpty()) { error() << "--imenu must take path filters"; return out; } for (int i=0; i<paths.size(); ++i) { const Path file = paths.at(i); if (!file.isFile()) { error() << "Invalid path filter for --imenu" << file; continue; } const uint32_t fileId = Location::fileId(file); if (!fileId) continue; auto symbols = project->openSymbols(fileId); if (!symbols) continue; const int count = symbols->count(); for (int j=0; j<count; ++j) { const Symbol &symbol = symbols->valueAt(j); if (RTags::isReference(symbol.kind)) continue; switch (symbol.kind) { case CXCursor_VarDecl: case CXCursor_ParmDecl: case CXCursor_InclusionDirective: case CXCursor_EnumConstantDecl: break; case CXCursor_ClassDecl: case CXCursor_StructDecl: case CXCursor_ClassTemplate: if (!symbol.isDefinition()) break; // fall through default: { const String &symbolName = symbol.symbolName; if (!string.isEmpty() && !symbolName.contains(string)) continue; out.insert(symbolName); break; } } } } return out; }
Set<String> ListSymbolsJob::imenu(const shared_ptr<Project> &project) { Set<String> out; Scope<const SymbolMap&> symbols = project->lockSymbolsForRead(); const SymbolMap &map = symbols.data(); const List<String> paths = pathFilters(); if (paths.isEmpty()) { error() << "--imenu must take path filters"; return out; } for (int i=0; i<paths.size(); ++i) { const Path file = paths.at(i); if (!file.isFile()) { error() << "Invalid path filter for --imenu" << file; continue; } const uint32_t fileId = Location::fileId(file); if (!fileId) continue; for (SymbolMap::const_iterator it = map.lower_bound(Location(fileId, 0)); it != map.end() && it->first.fileId() == fileId; ++it) { const CursorInfo &cursorInfo = it->second; if (RTags::isReference(cursorInfo.kind)) continue; switch (cursorInfo.kind) { case CXCursor_VarDecl: case CXCursor_ParmDecl: case CXCursor_InclusionDirective: case CXCursor_EnumConstantDecl: break; case CXCursor_ClassDecl: case CXCursor_StructDecl: case CXCursor_ClassTemplate: if (!cursorInfo.isDefinition()) break; // fall through default: { const String &symbolName = it->second.symbolName; if (!string.isEmpty() && !symbolName.contains(string)) continue; out.insert(symbolName); break; } } } } return out; }