pythonlanguagesupport.cpp 8.03 KB
Newer Older
Piyush Verma's avatar
Piyush Verma committed
1 2 3
/*****************************************************************************
 * Copyright (c) 2007 Andreas Pakulat <apaku@gmx.de>                         *
 * Copyright (c) 2007 Piyush verma <piyush.verma@gmail.com>                  *
4
 * Copyright (c) 2012-2016 Sven Brauch <svenbrauch@gmail.com>                *
Piyush Verma's avatar
Piyush Verma committed
5
 *                                                                           *
6 7 8 9
 * This program is free software; you can redistribute it and/or             *
 * modify it under the terms of the GNU General Public License as            *
 * published by the Free Software Foundation; either version 2 of            *
 * the License, or (at your option) any later version.                       *
10
 *                                                                           *
11 12 13 14
 * This program is distributed in the hope that it will be useful,           *
 * but WITHOUT ANY WARRANTY; without even the implied warranty of            *
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             *
 * GNU General Public License for more details.                              *
15
 *                                                                           *
16 17 18 19
 * You should have received a copy of the GNU General Public License         *
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.     *
 *****************************************************************************
 */
Piyush Verma's avatar
Piyush Verma committed
20

21 22
#include "pythonlanguagesupport.h"

23
#include <QMutexLocker>
24
#include <QReadWriteLock>
Piyush Verma's avatar
Piyush Verma committed
25

26 27 28
#include <KPluginFactory>
#include <KPluginLoader>

29 30 31 32
#include <interfaces/icore.h>
#include <interfaces/ilanguagecontroller.h>
#include <interfaces/iplugincontroller.h>
#include <interfaces/idocument.h>
33
#include <interfaces/isourceformatter.h>
34
#include <interfaces/idocumentcontroller.h>
35 36
#include <interfaces/context.h>
#include <interfaces/contextmenuextension.h>
37 38
#include <interfaces/iprojectcontroller.h>
#include <interfaces/iproject.h>
39
#include <interfaces/isession.h>
40 41
#include <language/assistant/renameassistant.h>
#include <language/assistant/staticassistantsmanager.h>
42
#include <language/interfaces/editorcontext.h>
43
#include <language/duchain/duchain.h>
44
#include <language/duchain/duchainlock.h>
45 46 47
#include <language/codecompletion/codecompletion.h>
#include <language/codecompletion/codecompletionmodel.h>

Piyush Verma's avatar
Piyush Verma committed
48
#include "pythonparsejob.h"
49
#include "pythonhighlighting.h"
50
#include "duchain/pythoneditorintegrator.h"
51
#include "codecompletion/model.h"
52
#include "codegen/refactoring.h"
53
#include "codegen/correctionfilegenerator.h"
54
#include "kdevpythonversion.h"
55
#include "pep8kcm/kcm_pep8.h"
56
#include "projectconfig/projectconfigpage.h"
57
#include "docfilekcm/kcm_docfiles.h"
58 59
#include "pythonstylechecking.h"
#include "helpers.h"
60

61
#include <QDebug>
62
#include <QProcess>
63
#include "pythondebug.h"
64

Piyush Verma's avatar
Piyush Verma committed
65
using namespace KDevelop;
66

Alex Richardson's avatar
Alex Richardson committed
67
K_PLUGIN_FACTORY_WITH_JSON( KDevPythonSupportFactory, "kdevpythonsupport.json", registerPlugin<Python::LanguageSupport>(); )
68

69 70
namespace Python
{
71
LanguageSupport* LanguageSupport::m_self = nullptr;
72

73
ContextMenuExtension LanguageSupport::contextMenuExtension(Context* context, QWidget* parent)
74 75
{
    ContextMenuExtension cm;
76 77
    EditorContext *ec = dynamic_cast<KDevelop::EditorContext *>(context);

78
    if (ec && ICore::self()->languageController()->languagesForUrl(ec->url()).contains(this)) {
79
        // It's a Python file, let's add our context menu.
80
        m_refactoring->fillContextMenu(cm, context, parent);
81
        TypeCorrection::self().doContextMenu(cm, context);
82
    }
83 84 85
    return cm;
}

86
LanguageSupport::LanguageSupport( QObject* parent, const QVariantList& /*args*/ )
Sven Brauch's avatar
Sven Brauch committed
87
    : KDevelop::IPlugin("pythonlanguagesupport", parent )
Kevin Funk's avatar
Kevin Funk committed
88 89 90
    , KDevelop::ILanguageSupport()
    , m_highlighting( new Highlighting( this ) )
    , m_refactoring( new Refactoring( this ) )
91
    , m_styleChecking( new StyleChecking( this ) )
92
{
93
    m_self = this;
94

95 96
    PythonCodeCompletionModel* codeCompletion = new PythonCodeCompletionModel(this);
    new KDevelop::CodeCompletion(this, codeCompletion, "Python");
97

98 99 100
    auto assistantsManager = core()->languageController()->staticAssistantsManager();
    assistantsManager->registerAssistant(StaticAssistant::Ptr(new RenameAssistant(this)));

101 102
    QObject::connect(ICore::self()->documentController(), &IDocumentController::documentOpened,
                     this, &LanguageSupport::documentOpened);
103 104 105 106
}

void LanguageSupport::documentOpened(IDocument* doc)
{
107
    if ( ! ICore::self()->languageController()->languagesForUrl(doc->url()).contains(this) ) {
108 109 110 111
        // not a python file
        return;
    }

112
    DUChainReadLocker lock;
113
    ReferencedTopDUContext top = DUChain::self()->chainForDocument(doc->url());
114
    lock.unlock();
115 116 117 118 119 120
    updateStyleChecking(top);
}

void LanguageSupport::updateStyleChecking(KDevelop::ReferencedTopDUContext top)
{
    m_styleChecking->updateStyleChecking(top);
121
}
Andreas Pakulat's avatar
Andreas Pakulat committed
122

123
LanguageSupport::~LanguageSupport()
124
{
125 126 127 128
    parseLock()->lockForWrite();
    // By locking the parse-mutexes, we make sure that parse jobs get a chance to finish in a good state
    parseLock()->unlock();

129
    delete m_highlighting;
130
    m_highlighting = nullptr;
131 132
}

133
KDevelop::ParseJob *LanguageSupport::createParseJob( const IndexedString& url )
134
{
135
    return new ParseJob(url, this);
136 137
}

138
QString LanguageSupport::name() const
139 140 141 142
{
    return "Python";
}

143 144 145 146 147
LanguageSupport* LanguageSupport::self()
{
    return m_self;
}

Sven Brauch's avatar
Sven Brauch committed
148
SourceFormatterItemList LanguageSupport::sourceFormatterItems() const
149
{
150 151 152
    SourceFormatterStyle autopep8("autopep8");
    autopep8.setCaption("autopep8");
    autopep8.setDescription(i18n("Format source with the autopep8 formatter."));
153 154 155
    autopep8.setOverrideSample("class klass:\n def method(arg1,arg2):\n  a=3+5\n"
                               "def function(arg,*vararg,**kwargs): return arg+kwarg[0]\nfunction(3, 5, 7)");
    using P = SourceFormatterStyle::MimeHighlightPair;
156 157
    autopep8.setMimeTypes(SourceFormatterStyle::MimeList{ P{"text/x-python", "Python"},
                                                          P{"text/x-python3", "Python 3"} });
158 159
    QString autopep8path = QStandardPaths::findExecutable("autopep8");
    if (autopep8path.isEmpty()) {
160
        // TODO: proper error handling/user notification
161
        qCDebug(KDEV_PYTHON) << "Could not find the autopep8 executable";
162
        autopep8path = "/usr/bin/autopep8";
163
    }
164
    autopep8.setContent(autopep8path + " -i $TMPFILE");
165 166 167 168

    return SourceFormatterItemList{SourceFormatterStyleItem{"customscript", autopep8}};
}

169
KDevelop::ICodeHighlighting* LanguageSupport::codeHighlighting() const
170
{
171
    return m_highlighting;
172 173
}

174 175 176 177 178
BasicRefactoring* LanguageSupport::refactoring() const
{
    return m_refactoring;
}

179 180
int LanguageSupport::suggestedReparseDelayForChange(KTextEditor::Document* doc, const KTextEditor::Range& changedRange,
                                                    const QString& changedText, bool /*removal*/) const
Sven Brauch's avatar
Sven Brauch committed
181
{
182 183 184 185 186
    if ( changedRange.start().line() != changedRange.end().line() ) {
        // instant update
        return 0;
    }
    if ( std::all_of(changedText.begin(), changedText.end(), [](const QChar& c) { return c.isSpace(); }) ) {
187
        qCDebug(KDEV_PYTHON) << changedText << changedRange.end().column() << doc->lineLength(changedRange.end().line());
188 189 190 191 192
        if ( changedRange.end().column()-1 == doc->lineLength(changedRange.end().line()) ) {
            return ILanguageSupport::NoUpdateRequired;
        }
    }
    return ILanguageSupport::DefaultDelay;
Sven Brauch's avatar
Sven Brauch committed
193 194
}

195

196 197
QList<ILanguageCheck*> LanguageSupport::providedChecks()
{
198
    return {};
199 200
}

201 202
int LanguageSupport::configPages() const
{
203
    return 2;
204 205 206 207 208 209
}

KDevelop::ConfigPage* LanguageSupport::configPage(int number, QWidget* parent)
{
    if (number == 0) {
        return new PEP8KCModule(this, parent);
210 211
    } else if (number == 1) {
        return new DocfilesKCModule(this, parent);
212 213 214 215
    }
    return nullptr;
}

216 217 218 219 220 221 222 223 224 225 226 227 228
int LanguageSupport::perProjectConfigPages() const
{
    return 1;
}

KDevelop::ConfigPage* LanguageSupport::perProjectConfigPage(int number, const KDevelop::ProjectConfigOptions& options, QWidget* parent)
{
    if ( number == 0 ) {
        return new Python::ProjectConfigPage(this, options, parent);
    }
    return nullptr;
}

229 230
}

231
#include "pythonlanguagesupport.moc"