cling/lib/UserInterface/UserInterface.cpp

172 lines
5.5 KiB
C++
Raw Normal View History

//------------------------------------------------------------------------------
// CLING - the C++ LLVM-based InterpreterG :)
// author: Axel Naumann <axel@cern.ch>
2014-01-07 14:08:37 +04:00
//
// This file is dual-licensed: you can choose to license it under the University
// of Illinois Open Source License or the GNU Lesser General Public License. See
// LICENSE.TXT for details.
//------------------------------------------------------------------------------
#include "cling/UserInterface/UserInterface.h"
#include "cling/Interpreter/Exception.h"
#include "cling/MetaProcessor/MetaProcessor.h"
2016-07-19 12:46:57 +03:00
#include "textinput/Callbacks.h"
#include "textinput/TextInput.h"
#include "textinput/StreamReader.h"
#include "textinput/TerminalDisplay.h"
2013-09-19 20:10:25 +04:00
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/ErrorHandling.h"
2013-09-19 18:54:21 +04:00
#include "llvm/Support/Path.h"
#include "llvm/Config/config.h"
#include "clang/Basic/LangOptions.h"
#include "clang/Frontend/CompilerInstance.h"
// Fragment copied from LLVM's raw_ostream.cpp
#if defined(HAVE_UNISTD_H)
# include <unistd.h>
#endif
#if defined(_MSC_VER)
#ifndef STDIN_FILENO
# define STDIN_FILENO 0
#endif
#ifndef STDOUT_FILENO
# define STDOUT_FILENO 1
#endif
#ifndef STDERR_FILENO
# define STDERR_FILENO 2
#endif
#endif
2014-08-01 16:02:15 +04:00
#include <memory>
namespace {
///\brief Class that specialises the textinput TabCompletion to allow Cling
/// to code complete through its own textinput mechanism which is part of the
/// UserInterface.
///
2016-07-19 12:46:57 +03:00
class UITabCompletion : public textinput::TabCompletion {
const cling::Interpreter& m_ParentInterpreter;
public:
2016-07-19 12:46:57 +03:00
UITabCompletion(const cling::Interpreter& Parent) :
m_ParentInterpreter(Parent) {}
~UITabCompletion() {}
bool Complete(textinput::Text& Line /*in+out*/,
2016-07-19 12:46:57 +03:00
size_t& Cursor /*in+out*/,
textinput::EditorRange& R /*out*/,
std::vector<std::string>& Completions /*out*/) override {
m_ParentInterpreter.codeComplete(Line.GetText(), Cursor, Completions);
return true;
}
};
}
namespace cling {
UserInterface::UserInterface(Interpreter& interp) {
// We need stream that doesn't close its file descriptor, thus we are not
// using llvm::outs. Keeping file descriptor open we will be able to use
// the results in pipes (Savannah #99234).
static llvm::raw_fd_ostream m_MPOuts (STDOUT_FILENO, /*ShouldClose*/false);
m_MetaProcessor.reset(new MetaProcessor(interp, m_MPOuts));
llvm::install_fatal_error_handler(&CompilationException::throwingHandler);
}
UserInterface::~UserInterface() {}
void UserInterface::runInteractively(bool nologo /* = false */) {
if (!nologo) {
PrintLogo();
}
2013-09-19 20:10:25 +04:00
llvm::SmallString<512> histfilePath;
if (!getenv("CLING_NOHISTORY")) {
// History file is $HOME/.cling_history
if (llvm::sys::path::home_directory(histfilePath))
llvm::sys::path::append(histfilePath, ".cling_history");
}
using namespace textinput;
2014-08-01 16:02:15 +04:00
std::unique_ptr<StreamReader> R(StreamReader::Create());
std::unique_ptr<TerminalDisplay> D(TerminalDisplay::Create());
TextInput TI(*R, *D, histfilePath.empty() ? 0 : histfilePath.c_str());
2016-06-23 19:09:06 +03:00
// Inform text input about the code complete consumer
// TextInput owns the TabCompletion.
2016-07-19 12:46:57 +03:00
UITabCompletion* Completion =
new UITabCompletion(m_MetaProcessor->getInterpreter());
2016-06-28 20:10:37 +03:00
TI.SetCompletion(Completion);
2016-06-23 19:09:06 +03:00
2016-08-31 06:09:14 +03:00
std::string Line;
std::string Prompt("[cling]$ ");
while (true) {
try {
2016-08-31 06:09:14 +03:00
TI.SetPrompt(Prompt.c_str());
m_MetaProcessor->getOuts().flush();
TextInput::EReadResult RR = TI.ReadInput();
2016-08-31 06:09:14 +03:00
TI.TakeInput(Line);
if (RR == TextInput::kRREOF) {
break;
}
cling::Interpreter::CompilationResult compRes;
2014-01-13 11:57:12 +04:00
MetaProcessor::MaybeRedirectOutputRAII RAII(m_MetaProcessor.get());
2016-08-31 06:09:14 +03:00
const int indent = m_MetaProcessor->process(Line.c_str(), compRes);
// Quit requested?
if (indent < 0)
break;
2016-08-31 06:09:14 +03:00
Prompt.replace(7, std::string::npos,
m_MetaProcessor->getInterpreter().isRawInputEnabled() ? "! " : "$ ");
2016-08-31 06:09:14 +03:00
// Continuation requested?
if (indent > 0) {
Prompt.append(1, '?');
Prompt.append(indent * 3, ' ');
}
}
catch(InvalidDerefException& e) {
2013-09-07 12:44:01 +04:00
e.diagnose();
}
catch(InterpreterException& e) {
2013-09-11 11:36:37 +04:00
llvm::errs() << ">>> Caught an interpreter exception!\n"
<< ">>> " << e.what() << '\n';
}
catch(std::exception& e) {
llvm::errs() << ">>> Caught a std::exception!\n"
<< ">>> " << e.what() << '\n';
}
catch(...) {
llvm::errs() << "Exception occurred. Recovering...\n";
}
}
}
void UserInterface::PrintLogo() {
llvm::raw_ostream& outs = m_MetaProcessor->getOuts();
const clang::LangOptions& LangOpts
= m_MetaProcessor->getInterpreter().getCI()->getLangOpts();
if (LangOpts.CPlusPlus) {
outs << "\n"
"****************** CLING ******************\n"
"* Type C++ code and press enter to run it *\n"
"* Type .q to exit *\n"
"*******************************************\n";
} else {
outs << "\n"
"***************** CLING *****************\n"
"* Type C code and press enter to run it *\n"
"* Type .q to exit *\n"
"*****************************************\n";
}
}
} // end namespace cling