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 {
|
namespace cling {
|
||||||
|
class ClingTabCompletion;
|
||||||
class Interpreter;
|
class Interpreter;
|
||||||
class InterpreterCallbacks;
|
class InterpreterCallbacks;
|
||||||
class InterpreterDeserializationListener;
|
class InterpreterDeserializationListener;
|
||||||
@ -45,6 +46,11 @@ namespace cling {
|
|||||||
/// interpreter as it does its thing. Clients can define their hooks here to
|
/// interpreter as it does its thing. Clients can define their hooks here to
|
||||||
/// implement interpreter level tools.
|
/// implement interpreter level tools.
|
||||||
class InterpreterCallbacks {
|
class InterpreterCallbacks {
|
||||||
|
private:
|
||||||
|
///\brief Cling Code Completion object.
|
||||||
|
///
|
||||||
|
ClingTabCompletion* m_Completer;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
///\brief Our interpreter instance.
|
///\brief Our interpreter instance.
|
||||||
@ -165,10 +171,14 @@ namespace cling {
|
|||||||
///\brief Cling creates the code complete consumer for its child interp.
|
///\brief Cling creates the code complete consumer for its child interp.
|
||||||
virtual void CreateCodeCompleteConsumer(Interpreter* child) const;
|
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,
|
virtual void GetCompletionResults(Interpreter* child,
|
||||||
std::vector<std::string>&) const;
|
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
|
///\brief DynamicScopes only! Set to true if it is currently evaluating a
|
||||||
/// dynamic expr.
|
/// dynamic expr.
|
||||||
///
|
///
|
||||||
|
@ -27,6 +27,7 @@ add_cling_library(clingInterpreter
|
|||||||
CIFactory.cpp
|
CIFactory.cpp
|
||||||
ClangInternalState.cpp
|
ClangInternalState.cpp
|
||||||
ClingCodeCompleteConsumer.cpp
|
ClingCodeCompleteConsumer.cpp
|
||||||
|
ClingTabCompletion.cpp
|
||||||
ClingPragmas.cpp
|
ClingPragmas.cpp
|
||||||
DeclCollector.cpp
|
DeclCollector.cpp
|
||||||
DeclExtractor.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/InterpreterCallbacks.h"
|
||||||
|
|
||||||
|
#include "cling/Interpreter/ClingTabCompletion.h"
|
||||||
#include "cling/Interpreter/ClingCodeCompleteConsumer.h"
|
#include "cling/Interpreter/ClingCodeCompleteConsumer.h"
|
||||||
#include "cling/Interpreter/Interpreter.h"
|
#include "cling/Interpreter/Interpreter.h"
|
||||||
|
|
||||||
@ -197,6 +198,7 @@ namespace cling {
|
|||||||
m_PPCallbacks = new InterpreterPPCallbacks(this);
|
m_PPCallbacks = new InterpreterPPCallbacks(this);
|
||||||
PP.addPPCallbacks(std::unique_ptr<InterpreterPPCallbacks>(m_PPCallbacks));
|
PP.addPPCallbacks(std::unique_ptr<InterpreterPPCallbacks>(m_PPCallbacks));
|
||||||
}
|
}
|
||||||
|
m_Completer = new ClingTabCompletion(*m_Interpreter);
|
||||||
}
|
}
|
||||||
|
|
||||||
// pin the vtable here
|
// pin the vtable here
|
||||||
@ -262,6 +264,11 @@ namespace cling {
|
|||||||
consumer->getCompletions(completions);
|
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,
|
void InterpreterCallbacks::UpdateWithNewDecls(const DeclContext *DC,
|
||||||
DeclarationName Name,
|
DeclarationName Name,
|
||||||
llvm::ArrayRef<NamedDecl*> Decls) {
|
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/UserInterface.h"
|
||||||
|
|
||||||
#include "cling/UserInterface/CompilationException.h"
|
#include "cling/UserInterface/CompilationException.h"
|
||||||
|
#include "cling/UserInterface/TabCompletion.h"
|
||||||
#include "cling/Interpreter/Exception.h"
|
#include "cling/Interpreter/Exception.h"
|
||||||
#include "cling/MetaProcessor/MetaProcessor.h"
|
#include "cling/MetaProcessor/MetaProcessor.h"
|
||||||
#include "textinput/TextInput.h"
|
#include "textinput/TextInput.h"
|
||||||
@ -25,8 +26,6 @@
|
|||||||
#include "clang/Basic/LangOptions.h"
|
#include "clang/Basic/LangOptions.h"
|
||||||
#include "clang/Frontend/CompilerInstance.h"
|
#include "clang/Frontend/CompilerInstance.h"
|
||||||
|
|
||||||
#include "ClingTabCompletion.h"
|
|
||||||
|
|
||||||
// Fragment copied from LLVM's raw_ostream.cpp
|
// Fragment copied from LLVM's raw_ostream.cpp
|
||||||
#if defined(HAVE_UNISTD_H)
|
#if defined(HAVE_UNISTD_H)
|
||||||
# include <unistd.h>
|
# include <unistd.h>
|
||||||
@ -121,8 +120,8 @@ namespace cling {
|
|||||||
TextInput TI(*R, *D, histfilePath.empty() ? 0 : histfilePath.c_str());
|
TextInput TI(*R, *D, histfilePath.empty() ? 0 : histfilePath.c_str());
|
||||||
|
|
||||||
// Inform text input about the code complete consumer
|
// Inform text input about the code complete consumer
|
||||||
ClingTabCompletion* CompletionConsumer = new ClingTabCompletion(m_MetaProcessor->getInterpreter());
|
cling::TabCompletion* Completion = new cling::TabCompletion(m_MetaProcessor->getInterpreter());
|
||||||
TI.SetCompletion(CompletionConsumer);
|
TI.SetCompletion(Completion);
|
||||||
|
|
||||||
|
|
||||||
TI.SetPrompt("[cling]$ ");
|
TI.SetPrompt("[cling]$ ");
|
||||||
|
Loading…
Reference in New Issue
Block a user