Glue the cling tab completion to ROOT.
This commit is contained in:
parent
cc5da51f21
commit
0381b517c1
48
include/cling/Interpreter/ClingCodeCompleteConsumer.h
Normal file
48
include/cling/Interpreter/ClingCodeCompleteConsumer.h
Normal 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
|
23
include/cling/Interpreter/ClingTabCompletion.h
Normal file
23
include/cling/Interpreter/ClingTabCompletion.h
Normal 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
|
@ -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.
|
||||
///
|
||||
|
@ -27,6 +27,7 @@ add_cling_library(clingInterpreter
|
||||
CIFactory.cpp
|
||||
ClangInternalState.cpp
|
||||
ClingCodeCompleteConsumer.cpp
|
||||
ClingTabCompletion.cpp
|
||||
ClingPragmas.cpp
|
||||
DeclCollector.cpp
|
||||
DeclExtractor.cpp
|
||||
|
74
lib/Interpreter/ClingCodeCompleteConsumer.cpp
Normal file
74
lib/Interpreter/ClingCodeCompleteConsumer.cpp
Normal 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.");
|
||||
}
|
||||
}
|
49
lib/Interpreter/ClingTabCompletion.cpp
Normal file
49
lib/Interpreter/ClingTabCompletion.cpp
Normal 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;
|
||||
}
|
||||
}
|
||||
|
@ -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) {
|
||||
|
30
lib/Interpreter/TabCompletion.h
Normal file
30
lib/Interpreter/TabCompletion.h
Normal 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
|
@ -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]$ ");
|
||||
|
Loading…
Reference in New Issue
Block a user