Navigation Menu

Skip to content

Commit

Permalink
Scripting|libappfw: Improvements for the Doomsday Script REPL widget
Browse files Browse the repository at this point in the history
The language keywords and built-in identifiers are used for
autocompletion. All native modules are automatically imported to
the interactive script process (App, Config, etc.). Results of
entered scripts are automatically printed (no need for "print").
  • Loading branch information
skyjake committed Jun 8, 2014
1 parent eb0f94c commit 793ea65
Show file tree
Hide file tree
Showing 2 changed files with 94 additions and 7 deletions.
1 change: 1 addition & 0 deletions doomsday/libappfw/include/de/widgets/scriptcommandwidget.h
Expand Up @@ -48,6 +48,7 @@ class LIBAPPFW_PUBLIC ScriptCommandWidget : public CommandWidget
protected:
bool isAcceptedAsCommand(String const &text);
void executeCommand(String const &text);
void autoCompletionBegan(String const &prefix);

private:
DENG2_PRIVATE(d)
Expand Down
100 changes: 93 additions & 7 deletions doomsday/libappfw/src/widgets/scriptcommandwidget.cpp
Expand Up @@ -19,18 +19,88 @@
#include "de/ScriptCommandWidget"
#include "de/PopupWidget"

#include <de/charsymbols.h>
#include <de/game/Game>
#include <de/shell/Lexicon>
#include <de/App>
#include <de/Script>
#include <de/ScriptLex>
#include <de/ScriptSystem>
#include <de/BuiltInExpression>
#include <de/Process>
#include <de/RecordValue>
#include <de/RefValue>

namespace de {

DENG2_PIMPL(ScriptCommandWidget)
, DENG2_OBSERVES(App, StartupComplete)
, DENG2_OBSERVES(App, GameChange)
{
Script script;
Process process;

Instance(Public *i) : Base(i)
{}
{
App::app().audienceForStartupComplete() += this;
App::app().audienceForGameChange() += this;
}

~Instance()
{
App::app().audienceForStartupComplete() -= this;
App::app().audienceForGameChange() -= this;
}

void appStartupCompleted()
{
importNativeModules();
updateLexicon();
}

void currentGameChanged(game::Game const &)
{
importNativeModules();
updateLexicon();
}

void importNativeModules()
{
// Automatically import all native modules into the interactive process.
foreach(String const &name, App::scriptSystem().nativeModules())
{
process.globals().add(new Variable(name,
new RecordValue(App::scriptSystem().nativeModule(name))));
}
}

void updateLexicon()
{
shell::Lexicon lexi;
lexi.setCaseSensitive(true);
lexi.setAdditionalWordChars("_");

// Add the variables in the global scope.
/// @todo Should be determined dynamically based on the scope at the cursor position.
DENG2_FOR_EACH_CONST(Record::Members, i, process.globals().members())
{
lexi.addTerm(i.key());
}

// Add all built-in Doomsday Script functions.
foreach(String name, BuiltInExpression::identifiers())
{
lexi.addTerm(name);
}

// Add all Doomsday Script keywords.
foreach(String keyword, ScriptLex::keywords())
{
lexi.addTerm(keyword);
}

self.setLexicon(lexi);
}

bool shouldShowAsPopup(Error const &)
{
Expand Down Expand Up @@ -92,14 +162,30 @@ void ScriptCommandWidget::executeCommand(String const &text)
LOG_SCR_WARNING("Error in script:\n") << er.asText();
}

/*
// Print the result.
Value const &result = d->process.context().evaluator().result();
if(!result.is<NoneValue>())
// Print the result (if possible).
try
{
Value const &result = d->process.context().evaluator().result();
if(!result.is<NoneValue>())
{
String msg = DENG2_CHAR_RIGHT_DOUBLEARROW " " _E(>)_E(m) + result.asText();
LOG_SCR_MSG(msg);
}
}
catch(Error const &)
{}
}

void ScriptCommandWidget::autoCompletionBegan(String const &prefix)
{
// Prepare a list of annotated completions to show in the popup.
QStringList const compls = suggestedCompletions();
if(compls.size() > 1)
{
LOG_INFO("%s") << result.asText();
showAutocompletionPopup(tr("Completions for %1:\n")
.arg(_E(b) + prefix + _E(.)) +
_E(m) + compls.join("\n"));
}
*/
}

} // namespace de

0 comments on commit 793ea65

Please sign in to comment.