Skip to content

Commit

Permalink
module and symbol locator; refactoring, singleton TclEngine
Browse files Browse the repository at this point in the history
  • Loading branch information
Rochus Keller committed Jan 30, 2019
1 parent 4fda001 commit 97500f3
Show file tree
Hide file tree
Showing 18 changed files with 441 additions and 62 deletions.
14 changes: 6 additions & 8 deletions README.md
Expand Up @@ -12,21 +12,21 @@ The plugin is still work in progress, but it already has enough functionality to

### Implemented Features

- Syntax highlighting (including ifdefed out blocks)
- Syntax highlighting (including ifdefed out blocks and markers)
- Inline code warnings and errors
- Parentheses and begin/end block matching/navigation
- Hover tooltips
- Follow symbol under cursor, follow includes (multi-file support)
- Drop-down menu to jump to modules, module instances, functions and tasks in current file
- Show where a symbol is used
- Code folding and some other features supported by QtCreator, see http://doc.qt.io/qtcreator/
- Drop-down menu to jump to modules, module instances, functions and tasks in current file
- Outline view; see [screenshot](http://software.rochus-keller.info/vlcreator_outline_screenshot.png)
- Module locator (global) and symbol locator (current document); see [screenshot 1](http://software.rochus-keller.info/vlcreator_module_locator_screenshot.png) and [screenshot 2](http://software.rochus-keller.info/vlcreator_symbol_locator_screenshot.png)
- Syntax based code folding and some other features supported by QtCreator, see http://doc.qt.io/qtcreator/
- Marker based code folding (MBCF); use section markers like //{ and //}, or //> and //<; see [screenshot 1](http://software.rochus-keller.info/vlcreator_mbcf_screenshot1.png) and [screenshot 2](http://software.rochus-keller.info/vlcreator_mbcf_screenshot2.png)
- Project file to configure source files, include dirs, defines and libraries
- Icarus Verilog build and run configuration; directly run compiler and simulator from within QtCreator
- Verilator and Yosys build configurations; generate command files, optional arguments
- Build configuration based on custom Tcl scripts which can access project configuration (e.g. to run Vivado commands)
- Marker based code folding (MBCF); use section markers like //{ and //}, or //> and //<; see [screenshot 1](http://software.rochus-keller.info/vlcreator_mbcf_screenshot1.png) and [screenshot 2](http://software.rochus-keller.info/vlcreator_mbcf_screenshot2.png)
- Outline view; see [screenshot 1](http://software.rochus-keller.info/vlcreator_outline_screenshot.png)


### Project file format

Expand Down Expand Up @@ -120,8 +120,6 @@ Since I currently consider the effort to reverse engineer each QtCreator version
- Documentation
- Semantic indenter (the current one simply adjusts to the previous line)
- Parse output of Icarus/Verilator/Yosys and post it to the Issues pane
- Implement locator popup
- Implement outline and include panes
- Implement wizzard to add or import files, generate stub modules and automatically update the vlpro file
- Improve hover text
- Implement options dialog (format settings, paths, etc.)
Expand Down
4 changes: 2 additions & 2 deletions VerilogCreator.json.in
@@ -1,7 +1,7 @@
{
\"Name\" : \"VerilogCreator\",
\"Version\" : \"0.6.1\",
\"CompatVersion\" : \"0.6.1\",
\"Version\" : \"0.6.2\",
\"CompatVersion\" : \"0.6.2\",
\"Vendor\" : \"Rochus Keller\",
\"Copyright\" : \"(C) 2019 Rochus Keller\",
\"License\" : \"GPL\",
Expand Down
8 changes: 6 additions & 2 deletions VerilogCreator.pro
Expand Up @@ -100,7 +100,9 @@ SOURCES += \
VlTclEngine.cpp \
VlAutoCompleter.cpp \
VlCompletionAssistProvider.cpp \
VlOutlineWidget.cpp
VlOutlineWidget.cpp \
VlModuleLocator.cpp \
VlSymbolLocator.cpp

HEADERS += \
verilogcreator_global.h \
Expand All @@ -126,7 +128,9 @@ HEADERS += \
VlTclEngine.h \
VlAutoCompleter.h \
VlCompletionAssistProvider.h \
VlOutlineWidget.h
VlOutlineWidget.h \
VlModuleLocator.h \
VlSymbolLocator.h

include (../Verilog/Verilog.pri )

Expand Down
106 changes: 92 additions & 14 deletions VlCompletionAssistProvider.cpp
Expand Up @@ -18,34 +18,92 @@
*/

#include "VlCompletionAssistProvider.h"
#include "VlConstants.h"
#include <texteditor/codeassist/iassistproposal.h>
#include <texteditor/codeassist/assistinterface.h>
#include <texteditor/codeassist/iassistprocessor.h>
#include <texteditor/codeassist/assistproposalitem.h>
#include <texteditor/codeassist/genericproposalmodel.h>
#include <texteditor/codeassist/genericproposal.h>
#include <coreplugin/id.h>
#include <QTextBlock>
#include <QTextDocument>
#include <QtDebug>

namespace Vl
{
// borrowed from RubyCreator
static const QString &nameFor(const QString &s)
{
return s;
}
template<typename T>
static void addProposalFromSet(QList<TextEditor::AssistProposalItem*> &proposals,
const T &container, const QString &myTyping,
const QIcon &icon, int order = 0)
{
foreach (const typename T::value_type &item, container)
{
const QString &name = nameFor(item);
if (myTyping == name)
continue;

auto proposal = new TextEditor::AssistProposalItem();

int indexOfParenthesis = name.indexOf(QLatin1Char('('));
if (indexOfParenthesis != -1) {
proposal->setText(name.mid(0, indexOfParenthesis));
proposal->setDetail(name);
} else {
proposal->setText(name);
}

proposal->setIcon(icon);
proposal->setOrder(order);
proposals << proposal;
}
}

class CompletionAssistProcessor : public TextEditor::IAssistProcessor
{
public:
CompletionAssistProcessor() {}
~CompletionAssistProcessor()
{
qDebug() << "CompletionAssistProcessor deleted";
//qDebug() << "CompletionAssistProcessor deleted";
}

TextEditor::IAssistProposal* perform(const TextEditor::AssistInterface *interface)
TextEditor::IAssistProposal* perform(const TextEditor::AssistInterface *ai)
{
m_interface.reset(interface);
m_interface.reset(ai);

qDebug() << "CompletionAssistProcessor::perform";
return 0;
}
TextEditor::IAssistProposal *immediateProposal(const TextEditor::AssistInterface *)
{
qDebug() << "CompletionAssistProcessor::immediateProposal";
return 0;
if (ai->reason() == TextEditor::IdleEditor)
return 0;

const int startPosition = ai->position();

const QTextBlock block = ai->textDocument()->findBlock(startPosition);
const int linePosition = startPosition - block.position();
const QString line = ai->textDocument()->findBlock(startPosition).text();


const QString myTyping = ai->textAt(startPosition, ai->position() - startPosition);
const QString fileName = ai->fileName();

qDebug() << "perform" << line << myTyping;

QList<TextEditor::AssistProposalItem *> proposals;

QStringList tmp;
tmp << "alpha" << "beta" << "gamma";
addProposalFromSet(proposals, tmp, myTyping, QIcon(), 1);

if( proposals.isEmpty() )
return 0;

TextEditor::GenericProposalModel *model = new TextEditor::GenericProposalModel();
model->loadContent(proposals);
TextEditor::IAssistProposal *proposal = new TextEditor::GenericProposal(startPosition, model);
return proposal;
}
private:
QScopedPointer<const TextEditor::AssistInterface> m_interface;
Expand All @@ -61,12 +119,32 @@ TextEditor::IAssistProvider::RunType CompletionAssistProvider::runType() const

bool CompletionAssistProvider::supportsEditor(Core::Id editorId) const
{
qDebug() << "CompletionAssistProvider::supportsEditor" << editorId;
return false;
return editorId == Constants::EditorId1;
}

TextEditor::IAssistProcessor*CompletionAssistProvider::createProcessor() const
{
qDebug() << "CompletionAssistProvider::createProcessor";
return new CompletionAssistProcessor();
}

bool CompletionAssistProvider::isActivationCharSequence(const QString& sequence) const
{
if( sequence.size() < SeqLen )
return false;
const QChar cur = sequence[SeqLen-1];
const QChar before1 = sequence[SeqLen-2];
const QChar before2 = sequence[SeqLen-3];
//qDebug() << "isActivationCharSequence" << before2 << before1 << ch;
if( cur == '.' || cur == '(' || cur == '`' )
return true;
if( false ) // cur.isLetter() || cur == '$' || cur == '_' || cur == '`' )
return true;
else
return false;
}

bool CompletionAssistProvider::isContinuationChar(const QChar& c) const
{
//qDebug() << "isContinuationChar" << c;
return c.isLetterOrNumber() || c == '_' || c == '$';
}
4 changes: 4 additions & 0 deletions VlCompletionAssistProvider.h
Expand Up @@ -29,11 +29,15 @@ namespace Vl
{
Q_OBJECT
public:
enum { SeqLen = 3 };

// overrides
RunType runType() const;
bool supportsEditor(Core::Id editorId) const;
TextEditor::IAssistProcessor* createProcessor() const;
int activationCharSequenceLength() const { return SeqLen; }
bool isActivationCharSequence(const QString &sequence) const;
bool isContinuationChar(const QChar &c) const;
};
}

Expand Down
6 changes: 6 additions & 0 deletions VlModelManager.cpp
Expand Up @@ -53,6 +53,7 @@ CrossRefModel*ModelManager::getModelForFile(const QString& fileName)
{
m = new CrossRefModel(this,d_fcache);
connect( m, SIGNAL(sigModelUpdated()), this, SLOT(onModelUpdated()) );
d_paths[m] = fileName;
}
d_lastUsed = m;
return m;
Expand Down Expand Up @@ -95,6 +96,11 @@ CrossRefModel*ModelManager::getModelForCurrentProjectOrDirPath(const QString& di
return mdl;
}

QString ModelManager::getPathOf(CrossRefModel* m) const
{
return d_paths.value(m);
}

ModelManager*ModelManager::instance()
{
if( d_inst )
Expand Down
2 changes: 2 additions & 0 deletions VlModelManager.h
Expand Up @@ -39,6 +39,7 @@ namespace Vl
CrossRefModel* getModelForCurrentProject();
CrossRefModel* getModelForCurrentProjectOrDirPath(const QString& dirPath , bool initIfEmpty = false);
CrossRefModel* getLastUsed() const { return d_lastUsed; }
QString getPathOf(CrossRefModel*) const;

FileCache* getFileCache() const { return d_fcache; }

Expand All @@ -50,6 +51,7 @@ namespace Vl
private:
static ModelManager* d_inst;
QHash<QString,CrossRefModel*> d_models; // Project File -> Code Model
QHash<CrossRefModel*,QString> d_paths;
CrossRefModel* d_lastUsed;
FileCache* d_fcache;
};
Expand Down
75 changes: 75 additions & 0 deletions VlModuleLocator.cpp
@@ -0,0 +1,75 @@
/*
* Copyright 2019 Rochus Keller <mailto:me@rochus-keller.ch>
*
* This file is part of the VerilogCreator plugin.
*
* The following is the license that applies to this copy of the
* plugin. For a license to use the plugin under conditions
* other than those described here, please email to me@rochus-keller.ch.
*
* GNU General Public License Usage
* This file may be used under the terms of the GNU General Public
* License (GPL) versions 2.0 or 3.0 as published by the Free Software
* Foundation and appearing in the file LICENSE.GPL included in
* the packaging of this file. Please review the following information
* to ensure GNU General Public Licensing requirements will be met:
* http://www.fsf.org/licensing/licenses/info/GPLv2.html and
* http://www.gnu.org/copyleft/gpl.html.
*/

#include "VlModuleLocator.h"
#include "VlModelManager.h"
#include <coreplugin/editormanager/editormanager.h>
#include <QDir>
using namespace Vl;

ModuleLocator::ModuleLocator()
{
setId("Modules");
setDisplayName(tr("Verilog modules and UDPs in global namespace"));
setShortcutString(QString(QLatin1Char('m')));
setIncludedByDefault(false);
}

QList<Core::LocatorFilterEntry> ModuleLocator::matchesFor(QFutureInterface<Core::LocatorFilterEntry>& future,
const QString& entry)
{
Q_UNUSED(future);

QList<Core::LocatorFilterEntry> res;

CrossRefModel* mdl = ModelManager::instance()->getModelForCurrentProject();
if( mdl == 0 )
return res;

QDir path( ModelManager::instance()->getPathOf(mdl) );

CrossRefModel::IdentDeclRefList l = mdl->getGlobalNames();

QStringMatcher matcher(entry, Qt::CaseInsensitive); // ByteArrayMatcher is case sensitive instead

QPixmap icon(":/verilogcreator/images/block.png");
foreach(const CrossRefModel::IdentDeclRef& id, l )
{
const QString name = QString::fromLatin1(id->tok().d_val);
if( matcher.indexIn( name ) != -1 )
{
res << Core::LocatorFilterEntry( this, name, QVariant::fromValue(CrossRefModel::SymRef(id)),icon);
res.last().extraInfo = path.relativeFilePath( id->tok().d_sourcePath );
}
}
return res;
}

void ModuleLocator::accept(Core::LocatorFilterEntry selection) const
{
CrossRefModel::SymRef sym = selection.internalData.value<CrossRefModel::SymRef>();
Core::EditorManager::openEditorAt( sym->tok().d_sourcePath,
sym->tok().d_lineNr - 1, sym->tok().d_colNr + 0 );
}

void ModuleLocator::refresh(QFutureInterface<void>& future)
{
Q_UNUSED(future);
}

42 changes: 42 additions & 0 deletions VlModuleLocator.h
@@ -0,0 +1,42 @@
#ifndef VLMODULELOCATOR_H
#define VLMODULELOCATOR_H

/*
* Copyright 2019 Rochus Keller <mailto:me@rochus-keller.ch>
*
* This file is part of the VerilogCreator plugin.
*
* The following is the license that applies to this copy of the
* plugin. For a license to use the plugin under conditions
* other than those described here, please email to me@rochus-keller.ch.
*
* GNU General Public License Usage
* This file may be used under the terms of the GNU General Public
* License (GPL) versions 2.0 or 3.0 as published by the Free Software
* Foundation and appearing in the file LICENSE.GPL included in
* the packaging of this file. Please review the following information
* to ensure GNU General Public Licensing requirements will be met:
* http://www.fsf.org/licensing/licenses/info/GPLv2.html and
* http://www.gnu.org/copyleft/gpl.html.
*/

#include <coreplugin/locator/ilocatorfilter.h>

namespace Vl
{
class ModuleLocator : public Core::ILocatorFilter
{
Q_OBJECT
public:
explicit ModuleLocator();

// overrides
QList<Core::LocatorFilterEntry> matchesFor(QFutureInterface<Core::LocatorFilterEntry> &future,
const QString &entry);
void accept(Core::LocatorFilterEntry selection) const;
void refresh(QFutureInterface<void> &future);

};
}

#endif // VLMODULELOCATOR_H

0 comments on commit 97500f3

Please sign in to comment.