Glue the cling tab completion to ROOT.

This commit is contained in:
CristinaCristescu 2016-06-28 19:10:37 +02:00 committed by sftnight
parent cc5da51f21
commit 0381b517c1
9 changed files with 246 additions and 5 deletions

View File

@ -0,0 +1,48 @@
#ifndef CLINGCODECOMPLETECONSUMER_H
#define CLINGCODECOMPLETECONSUMER_H
#include "clang/Sema/CodeCompleteConsumer.h"
using namespace clang;
class ClingCodeCompleteConsumer : public CodeCompleteConsumer {
/// \brief The raw output stream.
raw_ostream &OS;
CodeCompletionTUInfo CCTUInfo;
/// \ brief Results of the completer to be printed by the text interface.
std::vector<std::string> m_completions;
public:
/// \brief Create a new printing code-completion consumer that prints its
/// results to the given raw output stream.
ClingCodeCompleteConsumer(const CodeCompleteOptions &CodeCompleteOpts,
raw_ostream &OS)
: CodeCompleteConsumer(CodeCompleteOpts, false), OS(OS),
CCTUInfo(new GlobalCodeCompletionAllocator) {}
~ClingCodeCompleteConsumer() {}
/// \brief Prints the finalized code-completion results.
void ProcessCodeCompleteResults(Sema &S, CodeCompletionContext Context,
CodeCompletionResult *Results,
unsigned NumResults) override;
void ProcessOverloadCandidates(Sema &S, unsigned CurrentArg,
OverloadCandidate *Candidates,
unsigned NumCandidates) override {}
bool isResultFilteredOut(StringRef Filter, CodeCompletionResult Results) override;
CodeCompletionAllocator &getAllocator() override {
return CCTUInfo.getAllocator();
}
CodeCompletionTUInfo &getCodeCompletionTUInfo() override { return CCTUInfo; }
void getCompletions(std::vector<std::string>& completions) {
completions = m_completions;
}
};
#endif

View File

@ -0,0 +1,23 @@
#ifndef CLINGTABCOMPLETION_H
#define CLINGTABCOMPLETION_H
#include <string>
#include <vector>
namespace cling {
class Interpreter;
class ClingTabCompletion {
const cling::Interpreter& ParentInterp;
public:
ClingTabCompletion(cling::Interpreter& Parent) : ParentInterp(Parent) {}
~ClingTabCompletion() {}
bool Complete(const std::string& Line /*in+out*/,
size_t& Cursor /*in+out*/,
std::vector<std::string>& DisplayCompletions /*out*/);
};
}
#endif

View File

@ -34,6 +34,7 @@ namespace clang {
}
namespace cling {
class ClingTabCompletion;
class Interpreter;
class InterpreterCallbacks;
class InterpreterDeserializationListener;
@ -45,6 +46,11 @@ namespace cling {
/// interpreter as it does its thing. Clients can define their hooks here to
/// implement interpreter level tools.
class InterpreterCallbacks {
private:
///\brief Cling Code Completion object.
///
ClingTabCompletion* m_Completer;
protected:
///\brief Our interpreter instance.
@ -165,10 +171,14 @@ namespace cling {
///\brief Cling creates the code complete consumer for its child interp.
virtual void CreateCodeCompleteConsumer(Interpreter* child) const;
///\brief Get the resukts of the code completion.
///\brief Get the results of the code completion.
virtual void GetCompletionResults(Interpreter* child,
std::vector<std::string>&) const;
///\brief Get the results of the code completion.
virtual void CodeComplete(const std::string&, size_t&,
std::vector<std::string>&) const;
///\brief DynamicScopes only! Set to true if it is currently evaluating a
/// dynamic expr.
///

View File

@ -27,6 +27,7 @@ add_cling_library(clingInterpreter
CIFactory.cpp
ClangInternalState.cpp
ClingCodeCompleteConsumer.cpp
ClingTabCompletion.cpp
ClingPragmas.cpp
DeclCollector.cpp
DeclExtractor.cpp

View File

@ -0,0 +1,74 @@
#include "cling/Interpreter/ClingCodeCompleteConsumer.h"
#include "clang/Sema/Sema.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Lex/Preprocessor.h"
void
ClingCodeCompleteConsumer::ProcessCodeCompleteResults(Sema &SemaRef,
CodeCompletionContext Context,
CodeCompletionResult *Results,
unsigned NumResults) {
std::stable_sort(Results, Results + NumResults);
StringRef Filter = SemaRef.getPreprocessor().getCodeCompletionFilter();
// Print the results.
for (unsigned I = 0; I != NumResults; ++I) {
if(!Filter.empty() && isResultFilteredOut(Filter, Results[I]))
continue;
switch (Results[I].Kind) {
case CodeCompletionResult::RK_Declaration:
if (CodeCompletionString *CCS
= Results[I].CreateCodeCompletionString(SemaRef, Context,
getAllocator(),
CCTUInfo,
includeBriefComments())) {
m_completions.push_back(CCS->getAsString());
}
break;
case CodeCompletionResult::RK_Keyword:
m_completions.push_back(Results[I].Keyword);
break;
case CodeCompletionResult::RK_Macro: {
if (CodeCompletionString *CCS
= Results[I].CreateCodeCompletionString(SemaRef, Context,
getAllocator(),
CCTUInfo,
includeBriefComments())) {
m_completions.push_back(CCS->getAsString());
}
break;
}
case CodeCompletionResult::RK_Pattern: {
m_completions.push_back(Results[I].Pattern->getAsString());
break;
}
}
}
}
bool ClingCodeCompleteConsumer::isResultFilteredOut(StringRef Filter,
CodeCompletionResult Result) {
switch (Result.Kind) {
case CodeCompletionResult::RK_Declaration: {
return !(Result.Declaration->getIdentifier() &&
(*Result.Declaration).getIdentifier()->getName().startswith(Filter));
}
case CodeCompletionResult::RK_Keyword: {
return !((StringRef(Result.Keyword)).startswith(Filter));
}
case CodeCompletionResult::RK_Macro: {
return !(Result.Macro->getName().startswith(Filter));
}
case CodeCompletionResult::RK_Pattern: {
return !(StringRef((Result.Pattern->getAsString())).startswith(Filter));
}
default: llvm_unreachable("Unknown code completion result Kind.");
}
}

View File

@ -0,0 +1,49 @@
#include "cling/Interpreter/ClingTabCompletion.h"
#include "cling/Interpreter/Interpreter.h"
#include "clang/Sema/Sema.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Frontend/CompilerInstance.h"
#include "cling/Interpreter/InterpreterCallbacks.h"
namespace cling {
bool ClingTabCompletion::Complete(const std::string& Line /*in+out*/,
size_t& Cursor /*in+out*/,
std::vector<std::string>& DisplayCompletions /*out*/) {
//Get the results
const char * const argV = "cling";
cling::Interpreter CodeCompletionInterp(ParentInterp, 1, &argV);
// Create the CodeCompleteConsumer with InterpreterCallbacks
// from the parent interpreter and set the consumer for the child
// interpreter
// Yuck! But I need the const/non-const to be fixed somehow.
const InterpreterCallbacks* callbacks = ParentInterp.getCallbacks();
callbacks->CreateCodeCompleteConsumer(&CodeCompletionInterp);
clang::CompilerInstance* codeCompletionCI = CodeCompletionInterp.getCI();
clang::Sema& codeCompletionSemaRef = codeCompletionCI->getSema();
// Ignore diagnostics when we tab complete
clang::IgnoringDiagConsumer* ignoringDiagConsumer = new clang::IgnoringDiagConsumer();
codeCompletionSemaRef.getDiagnostics().setClient(ignoringDiagConsumer, true);
auto Owner = ParentInterp.getCI()->getSema().getDiagnostics().takeClient();
auto Client = ParentInterp.getCI()->getSema().getDiagnostics().getClient();
ParentInterp.getCI()->getSema().getDiagnostics().setClient(ignoringDiagConsumer, false);
CodeCompletionInterp.codeComplete(Line, Cursor);
callbacks->GetCompletionResults(&CodeCompletionInterp, DisplayCompletions);
// Restore the original diag client for parent interpreter
ParentInterp.getCI()->getSema().getDiagnostics().setClient(Client, Owner.release() != nullptr);
// FIX-ME : Change it in the Incremental Parser
// It does not work even if I call unload in IncrementalParser, I think
// it would be to early.
CodeCompletionInterp.unload(1);
return true;
}
}

View File

@ -9,6 +9,7 @@
#include "cling/Interpreter/InterpreterCallbacks.h"
#include "cling/Interpreter/ClingTabCompletion.h"
#include "cling/Interpreter/ClingCodeCompleteConsumer.h"
#include "cling/Interpreter/Interpreter.h"
@ -197,6 +198,7 @@ namespace cling {
m_PPCallbacks = new InterpreterPPCallbacks(this);
PP.addPPCallbacks(std::unique_ptr<InterpreterPPCallbacks>(m_PPCallbacks));
}
m_Completer = new ClingTabCompletion(*m_Interpreter);
}
// pin the vtable here
@ -262,6 +264,11 @@ namespace cling {
consumer->getCompletions(completions);
}
void InterpreterCallbacks::CodeComplete(const std::string& line, size_t& cursor,
std::vector<std::string>& displayCompletions) const {
m_Completer->Complete(line, cursor, displayCompletions);
}
void InterpreterCallbacks::UpdateWithNewDecls(const DeclContext *DC,
DeclarationName Name,
llvm::ArrayRef<NamedDecl*> Decls) {

View File

@ -0,0 +1,30 @@
#ifndef TABCOMPLETION_H
#define TABCOMPLETION_H
#include "textinput/Callbacks.h"
namespace textinput {
class TabCompletion;
class Text;
class EditorRange;
}
namespace cling {
class TabCompletion : public textinput::TabCompletion {
const cling::Interpreter& ParentInterp;
public:
TabCompletion(cling::Interpreter& Parent) : ParentInterp(Parent) {}
~TabCompletion() {}
bool Complete(textinput::Text& Line /*in+out*/,
size_t& Cursor /*in+out*/,
textinput::EditorRange& R /*out*/,
std::vector<std::string>& DisplayCompletions /*out*/) override {
const InterpreterCallbacks* callbacks = ParentInterp.getCallbacks();
callbacks->Complete(Line.GetText(), Cursor, DisplayCompletions);
}
};
}
#endif

View File

@ -10,6 +10,7 @@
#include "cling/UserInterface/UserInterface.h"
#include "cling/UserInterface/CompilationException.h"
#include "cling/UserInterface/TabCompletion.h"
#include "cling/Interpreter/Exception.h"
#include "cling/MetaProcessor/MetaProcessor.h"
#include "textinput/TextInput.h"
@ -25,8 +26,6 @@
#include "clang/Basic/LangOptions.h"
#include "clang/Frontend/CompilerInstance.h"
#include "ClingTabCompletion.h"
// Fragment copied from LLVM's raw_ostream.cpp
#if defined(HAVE_UNISTD_H)
# include <unistd.h>
@ -121,8 +120,8 @@ namespace cling {
TextInput TI(*R, *D, histfilePath.empty() ? 0 : histfilePath.c_str());
// Inform text input about the code complete consumer
ClingTabCompletion* CompletionConsumer = new ClingTabCompletion(m_MetaProcessor->getInterpreter());
TI.SetCompletion(CompletionConsumer);
cling::TabCompletion* Completion = new cling::TabCompletion(m_MetaProcessor->getInterpreter());
TI.SetCompletion(Completion);
TI.SetPrompt("[cling]$ ");