Commit b77babcf authored by Christoph Cullmann's avatar Christoph Cullmann

Merge branch 'multi-project-ctags' into 'master'

Multi project ctags

See merge request !43
parents 1fbfc2a3 bd659ff0
......@@ -180,18 +180,25 @@ void KateProjectCompletion::completionInvoked(KTextEditor::View *view, const KTe
void KateProjectCompletion::allMatches(QStandardItemModel &model, KTextEditor::View *view, const KTextEditor::Range &range) const
{
/**
* get project for this document, else fail
* get project scope for this document, else fail
*/
KateProject *project = m_plugin->projectForDocument(view->document());
if (!project) {
return;
QList<KateProject *> projects;
if (m_plugin->multiProjectCompletion()) {
projects = m_plugin->projects();
} else {
auto project = m_plugin->projectForDocument(view->document());
if (project) {
projects.push_back(project);
}
}
/**
* let project index fill the completion for this document
*/
if (project->projectIndex()) {
project->projectIndex()->findMatches(model, view->document()->text(range), KateProjectIndex::CompletionMatches);
for (const auto &project : projects) {
if (project->projectIndex()) {
project->projectIndex()->findMatches(model, view->document()->text(range), KateProjectIndex::CompletionMatches);
}
}
}
......
......@@ -67,6 +67,17 @@ KateProjectConfigPage::KateProjectConfigPage(QWidget *parent, KateProjectPlugin
group->setLayout(vbox);
layout->addWidget(group);
vbox = new QVBoxLayout;
group = new QGroupBox(i18nc("Groupbox title", "Cross-Project Functionality"), this);
group->setWhatsThis(i18n("Project plugin is able to perform some operations across multiple projects"));
m_cbMultiProjectCompletion = new QCheckBox(i18n("Cross-Project Completion"), this);
vbox->addWidget(m_cbMultiProjectCompletion);
m_cbMultiProjectGoto = new QCheckBox(i18n("Cross-Project Goto Symbol"), this);
vbox->addWidget(m_cbMultiProjectGoto);
vbox->addStretch(1);
group->setLayout(vbox);
layout->addWidget(group);
layout->insertStretch(-1, 10);
reset();
......@@ -77,6 +88,8 @@ KateProjectConfigPage::KateProjectConfigPage(QWidget *parent, KateProjectPlugin
connect(m_cbIndexEnabled, &QCheckBox::stateChanged, this, &KateProjectConfigPage::slotMyChanged);
connect(m_indexPath, &KUrlRequester::textChanged, this, &KateProjectConfigPage::slotMyChanged);
connect(m_indexPath, &KUrlRequester::urlSelected, this, &KateProjectConfigPage::slotMyChanged);
connect(m_cbMultiProjectCompletion, &QCheckBox::stateChanged, this, &KateProjectConfigPage::slotMyChanged);
connect(m_cbMultiProjectGoto, &QCheckBox::stateChanged, this, &KateProjectConfigPage::slotMyChanged);
}
QString KateProjectConfigPage::name() const
......@@ -104,6 +117,7 @@ void KateProjectConfigPage::apply()
m_plugin->setAutoRepository(m_cbAutoGit->checkState() == Qt::Checked, m_cbAutoSubversion->checkState() == Qt::Checked, m_cbAutoMercurial->checkState() == Qt::Checked);
m_plugin->setIndex(m_cbIndexEnabled->checkState() == Qt::Checked, m_indexPath->url());
m_plugin->setMultiProject(m_cbMultiProjectCompletion->checkState() == Qt::Checked, m_cbMultiProjectGoto->checkState() == Qt::Checked);
}
void KateProjectConfigPage::reset()
......@@ -113,6 +127,8 @@ void KateProjectConfigPage::reset()
m_cbAutoMercurial->setCheckState(m_plugin->autoMercurial() ? Qt::Checked : Qt::Unchecked);
m_cbIndexEnabled->setCheckState(m_plugin->getIndexEnabled() ? Qt::Checked : Qt::Unchecked);
m_indexPath->setUrl(m_plugin->getIndexDirectory());
m_cbMultiProjectCompletion->setCheckState(m_plugin->multiProjectCompletion() ? Qt::Checked : Qt::Unchecked);
m_cbMultiProjectGoto->setCheckState(m_plugin->multiProjectGoto() ? Qt::Checked : Qt::Unchecked);
m_changed = false;
}
......
......@@ -53,6 +53,8 @@ private:
QCheckBox *m_cbAutoMercurial;
QCheckBox *m_cbIndexEnabled;
KUrlRequester *m_indexPath;
QCheckBox *m_cbMultiProjectCompletion;
QCheckBox *m_cbMultiProjectGoto;
KateProjectPlugin *m_plugin;
bool m_changed = false;
};
......
......@@ -160,7 +160,7 @@ void KateProjectIndex::openCtags()
m_ctagsIndexHandle = tagsOpen(m_ctagsIndexFile->fileName().toLocal8Bit().constData(), &info);
}
void KateProjectIndex::findMatches(QStandardItemModel &model, const QString &searchWord, MatchType type)
void KateProjectIndex::findMatches(QStandardItemModel &model, const QString &searchWord, MatchType type, int options)
{
/**
* abort if no ctags index
......@@ -183,7 +183,10 @@ void KateProjectIndex::findMatches(QStandardItemModel &model, const QString &sea
* fail if none found
*/
tagEntry entry;
if (tagsFind(m_ctagsIndexHandle, &entry, word.constData(), TAG_PARTIALMATCH | TAG_OBSERVECASE) != TagSuccess) {
if (options == -1) {
options = TAG_PARTIALMATCH | TAG_OBSERVECASE;
}
if (tagsFind(m_ctagsIndexHandle, &entry, word.constData(), options) != TagSuccess) {
return;
}
......
......@@ -77,8 +77,9 @@ public:
* @param model model to fill with matches
* @param searchWord word to search for
* @param type type of matches
* @param options ctags find options (use default if -1)
*/
void findMatches(QStandardItemModel &model, const QString &searchWord, MatchType type);
void findMatches(QStandardItemModel &model, const QString &searchWord, MatchType type, int options = -1);
/**
* Check if running ctags was successful. This can be used
......
......@@ -25,8 +25,8 @@
#include <klocalizedstring.h>
#include <kmessagewidget.h>
KateProjectInfoViewIndex::KateProjectInfoViewIndex(KateProjectPluginView *pluginView, KateProject *project)
: QWidget()
KateProjectInfoViewIndex::KateProjectInfoViewIndex(KateProjectPluginView *pluginView, KateProject *project, QWidget *parent)
: QWidget(parent)
, m_pluginView(pluginView)
, m_project(project)
, m_messageWidget(nullptr)
......@@ -68,7 +68,12 @@ KateProjectInfoViewIndex::KateProjectInfoViewIndex(KateProjectPluginView *plugin
connect(m_pluginView, &KateProjectPluginView::projectLookupWord, m_lineEdit, &QLineEdit::setText);
connect(m_lineEdit, &QLineEdit::textChanged, this, &KateProjectInfoViewIndex::slotTextChanged);
connect(m_treeView, &QTreeView::clicked, this, &KateProjectInfoViewIndex::slotClicked);
connect(m_project, &KateProject::indexChanged, this, &KateProjectInfoViewIndex::indexAvailable);
if (m_project) {
connect(m_project, &KateProject::indexChanged, this, &KateProjectInfoViewIndex::indexAvailable);
} else {
connect(m_pluginView, &KateProjectPluginView::gotoSymbol, this, &KateProjectInfoViewIndex::slotGotoSymbol);
enableWidgets(true);
}
/**
* trigger once search with nothing
......@@ -80,6 +85,17 @@ KateProjectInfoViewIndex::~KateProjectInfoViewIndex()
{
}
void KateProjectInfoViewIndex::slotGotoSymbol(const QString &text, int &results)
{
// trigger fill model
m_lineEdit->setText(text);
results = m_model->rowCount();
// immediately goto if only a single option
if (results == 1) {
slotClicked(m_model->index(0, 0));
}
}
void KateProjectInfoViewIndex::slotTextChanged(const QString &text)
{
/**
......@@ -91,8 +107,14 @@ void KateProjectInfoViewIndex::slotTextChanged(const QString &text)
/**
* get results
*/
if (m_project->projectIndex() && !text.isEmpty()) {
if (m_project && m_project->projectIndex() && !text.isEmpty()) {
m_project->projectIndex()->findMatches(*m_model, text, KateProjectIndex::FindMatches);
} else if (!text.isEmpty()) {
for (const auto &project : m_pluginView->plugin()->projects()) {
if (project->projectIndex()) {
project->projectIndex()->findMatches(*m_model, text, KateProjectIndex::FindMatches, TAG_FULLMATCH | TAG_OBSERVECASE);
}
}
}
/**
......@@ -132,11 +154,16 @@ void KateProjectInfoViewIndex::slotClicked(const QModelIndex &index)
}
void KateProjectInfoViewIndex::indexAvailable()
{
const bool valid = m_project->projectIndex() && m_project->projectIndex()->isValid();
enableWidgets(valid);
}
void KateProjectInfoViewIndex::enableWidgets(bool valid)
{
/**
* update enabled state of widgets
*/
const bool valid = m_project->projectIndex() && m_project->projectIndex()->isValid();
m_lineEdit->setEnabled(valid);
m_treeView->setEnabled(valid);
......
......@@ -43,7 +43,7 @@ public:
* @param pluginView our plugin view
* @param project project this view is for
*/
KateProjectInfoViewIndex(KateProjectPluginView *pluginView, KateProject *project);
KateProjectInfoViewIndex(KateProjectPluginView *pluginView, KateProject *project, QWidget *parent = nullptr);
/**
* deconstruct info view
......@@ -78,6 +78,19 @@ private Q_SLOTS:
*/
void indexAvailable();
/**
* called to enable or disable widgets
* @param enable
*/
void enableWidgets(bool enable);
/**
* called if goto symbol is requested
* @param text target symbol
* @param number of results
*/
void slotGotoSymbol(const QString &text, int &results);
private:
/**
* our plugin view
......
......@@ -343,6 +343,23 @@ QUrl KateProjectPlugin::getIndexDirectory() const
return m_indexDirectory;
}
bool KateProjectPlugin::multiProjectCompletion() const
{
return m_multiProjectCompletion;
}
bool KateProjectPlugin::multiProjectGoto() const
{
return m_multiProjectGoto;
}
void KateProjectPlugin::setMultiProject(bool completion, bool gotoSymbol)
{
m_multiProjectCompletion = completion;
m_multiProjectGoto = gotoSymbol;
writeConfig();
}
void KateProjectPlugin::readConfig()
{
KConfigGroup config(KSharedConfig::openConfig(), "project");
......@@ -364,6 +381,11 @@ void KateProjectPlugin::readConfig()
m_indexEnabled = config.readEntry("index", false);
m_indexDirectory = config.readEntry("indexDirectory", QUrl());
m_multiProjectCompletion = config.readEntry("multiProjectCompletion", false);
m_multiProjectGoto = config.readEntry("multiProjectCompletion", false);
emit configUpdated();
}
void KateProjectPlugin::writeConfig()
......@@ -387,6 +409,11 @@ void KateProjectPlugin::writeConfig()
config.writeEntry("index", m_indexEnabled);
config.writeEntry("indexDirectory", m_indexDirectory);
config.writeEntry("multiProjectCompletion", m_multiProjectCompletion);
config.writeEntry("multiProjectGoto", m_multiProjectGoto);
emit configUpdated();
}
#if KTEXTEDITOR_VERSION >= QT_VERSION_CHECK(5, 63, 0)
......
......@@ -115,6 +115,10 @@ public:
bool getIndexEnabled() const;
QUrl getIndexDirectory() const;
void setMultiProject(bool completion, bool gotoSymbol);
bool multiProjectCompletion() const;
bool multiProjectGoto() const;
Q_SIGNALS:
/**
* Signal that a new project got created.
......@@ -122,6 +126,11 @@ Q_SIGNALS:
*/
void projectCreated(KateProject *project);
/**
* Signal that plugin configuration changed
*/
void configUpdated();
public Q_SLOTS:
/**
* New document got created, we need to update our connections
......@@ -184,6 +193,8 @@ private:
bool m_autoSubversion : 1;
bool m_autoMercurial : 1;
bool m_indexEnabled : 1;
bool m_multiProjectCompletion : 1;
bool m_multiProjectGoto : 1;
QUrl m_indexDirectory;
ThreadWeaver::Queue *m_weaver;
......
......@@ -51,7 +51,10 @@ KateProjectPluginView::KateProjectPluginView(KateProjectPlugin *plugin, KTextEdi
, m_mainWindow(mainWin)
, m_toolView(nullptr)
, m_toolInfoView(nullptr)
, m_toolMultiView(nullptr)
, m_lookupAction(nullptr)
, m_gotoSymbolAction(nullptr)
, m_gotoSymbolActionAppMenu(nullptr)
{
KXMLGUIClient::setComponentName(QStringLiteral("kateproject"), i18n("Kate Project Manager"));
setXMLFile(QStringLiteral("ui.rc"));
......@@ -95,6 +98,7 @@ KateProjectPluginView::KateProjectPluginView(KateProjectPlugin *plugin, KTextEdi
* connect to important signals, e.g. for auto project view creation
*/
connect(m_plugin, &KateProjectPlugin::projectCreated, this, &KateProjectPluginView::viewForProject);
connect(m_plugin, &KateProjectPlugin::configUpdated, this, &KateProjectPluginView::slotConfigUpdated);
connect(m_mainWindow, &KTextEditor::MainWindow::viewChanged, this, &KateProjectPluginView::slotViewChanged);
connect(m_mainWindow, &KTextEditor::MainWindow::viewCreated, this, &KateProjectPluginView::slotViewCreated);
......@@ -117,14 +121,17 @@ KateProjectPluginView::KateProjectPluginView(KateProjectPlugin *plugin, KTextEdi
actionCollection()->setDefaultShortcut(a, QKeySequence(Qt::CTRL | Qt::ALT | Qt::Key_Left));
a = actionCollection()->addAction(KStandardAction::Forward, QStringLiteral("projects_next_project"), this, SLOT(slotProjectNext()));
actionCollection()->setDefaultShortcut(a, QKeySequence(Qt::CTRL | Qt::ALT | Qt::Key_Right));
a = actionCollection()->addAction(KStandardAction::Goto, QStringLiteral("projects_goto_index"), this, SLOT(slotProjectIndex()));
a = actionCollection()->addAction(QStringLiteral("projects_goto_index"), this, SLOT(slotProjectIndex()));
a->setText(i18n("Lookup"));
actionCollection()->setDefaultShortcut(a, QKeySequence(Qt::ALT | Qt::Key_1));
m_gotoSymbolActionAppMenu = a = actionCollection()->addAction(KStandardAction::Goto, QStringLiteral("projects_goto_symbol"), this, SLOT(slotGotoSymbol()));
// popup menu
auto popup = new KActionMenu(i18n("Project"), this);
actionCollection()->addAction(QStringLiteral("popup_project"), popup);
m_lookupAction = popup->menu()->addAction(i18n("Lookup: %1", QString()), this, &KateProjectPluginView::slotProjectIndex);
m_gotoSymbolAction = popup->menu()->addAction(i18n("Goto: %1", QString()), this, &KateProjectPluginView::slotGotoSymbol);
connect(popup->menu(), &QMenu::aboutToShow, this, &KateProjectPluginView::slotContextMenuAboutToShow);
......@@ -132,6 +139,11 @@ KateProjectPluginView::KateProjectPluginView(KateProjectPlugin *plugin, KTextEdi
* add us to gui
*/
m_mainWindow->guiFactory()->addClient(this);
/**
* align to current config
*/
slotConfigUpdated();
}
KateProjectPluginView::~KateProjectPluginView()
......@@ -153,6 +165,8 @@ KateProjectPluginView::~KateProjectPluginView()
m_toolView = nullptr;
delete m_toolInfoView;
m_toolInfoView = nullptr;
delete m_toolMultiView;
m_toolMultiView = nullptr;
/**
* cu gui client
......@@ -160,6 +174,22 @@ KateProjectPluginView::~KateProjectPluginView()
m_mainWindow->guiFactory()->removeClient(this);
}
void KateProjectPluginView::slotConfigUpdated()
{
if (!m_plugin->multiProjectGoto()) {
delete m_toolMultiView;
m_toolMultiView = nullptr;
} else if (!m_toolMultiView) {
m_toolMultiView = m_mainWindow->createToolView(m_plugin, QStringLiteral("kateprojectmulti"), KTextEditor::MainWindow::Bottom, QIcon::fromTheme(QStringLiteral("view-choose")), i18n("Projects Index"));
auto gotoindex = new KateProjectInfoViewIndex(this, nullptr, m_toolMultiView);
m_toolMultiView->layout()->addWidget(gotoindex);
}
// update action state
m_gotoSymbolActionAppMenu->setEnabled(m_toolMultiView);
m_gotoSymbolAction->setEnabled(m_toolMultiView);
}
QPair<KateProjectView *, KateProjectInfoView *> KateProjectPluginView::viewForProject(KateProject *project)
{
/**
......@@ -461,6 +491,22 @@ void KateProjectPluginView::slotProjectIndex()
}
}
void KateProjectPluginView::slotGotoSymbol()
{
if (!m_toolMultiView) {
return;
}
const QString word = currentWord();
if (!word.isEmpty()) {
int results = 0;
emit gotoSymbol(word, results);
if (results > 1) {
m_mainWindow->showToolView(m_toolMultiView);
}
}
}
void KateProjectPluginView::slotContextMenuAboutToShow()
{
const QString word = currentWord();
......@@ -470,6 +516,7 @@ void KateProjectPluginView::slotContextMenuAboutToShow()
const QString squeezed = KStringHandler::csqueeze(word, 30);
m_lookupAction->setText(i18n("Lookup: %1", squeezed));
m_gotoSymbolAction->setText(i18n("Goto: %1", squeezed));
}
#include "kateprojectpluginview.moc"
......@@ -102,6 +102,15 @@ public:
return m_mainWindow;
}
/**
* the plugin we belong to
* @return our plugin
*/
KateProjectPlugin *plugin() const
{
return m_plugin;
}
public Q_SLOTS:
/**
* Create views for given project.
......@@ -112,6 +121,11 @@ public Q_SLOTS:
QPair<KateProjectView *, KateProjectInfoView *> viewForProject(KateProject *project);
private Q_SLOTS:
/**
* Plugin config updated
*/
void slotConfigUpdated();
/**
* New view got created, we need to update our connections
* @param view new created view
......@@ -145,6 +159,11 @@ private Q_SLOTS:
*/
void slotProjectIndex();
/**
* Goto current word
*/
void slotGotoSymbol();
Q_SIGNALS:
/**
* Emitted if projectFileName changed.
......@@ -162,6 +181,12 @@ Q_SIGNALS:
*/
void projectLookupWord(const QString &word);
/**
* Emitted when a ctags goto sysmbol is requested
* @param word lookup word
*/
void gotoSymbol(const QString &word, int &results);
private Q_SLOTS:
/**
* This slot is called whenever the active view changes in our main window.
......@@ -211,6 +236,11 @@ private:
*/
QWidget *m_toolInfoView;
/**
* our cross-projects toolview
*/
QWidget *m_toolMultiView;
/**
* combo box with all loaded projects inside
*/
......@@ -251,6 +281,12 @@ private:
* lookup action
*/
QAction *m_lookupAction;
/**
* goto symbol action
*/
QAction *m_gotoSymbolAction;
QAction *m_gotoSymbolActionAppMenu;
};
#endif
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE kpartgui>
<gui name="kateprojectplugin" library="kateprojectplugin" version="8" translationDomain="kateproject">
<gui name="kateprojectplugin" library="kateprojectplugin" version="9" translationDomain="kateproject">
<MenuBar>
<Menu name="projects">
<text>&amp;Projects</text>
<Action name="projects_prev_project"/>
<Action name="projects_next_project"/>
<Action name="projects_goto_index" />
<Action name="projects_goto_symbol" />
</Menu>
</MenuBar>
<Menu name="ktexteditor_popup" noMerge="1">
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment