Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
better PHP code completion
Test Plan:
manual testing with commands taking PHP code

DiffCamp Revision: 148762
Reviewed By: mwilliams
CC: mwilliams, hphp-diffs@lists
Revert Plan:
OK
  • Loading branch information
haiping authored and macvicar committed Aug 22, 2010
1 parent 87dfb06 commit 5c02d02
Show file tree
Hide file tree
Showing 8 changed files with 100 additions and 82 deletions.
24 changes: 11 additions & 13 deletions src/runtime/eval/debugger/cmd/cmd_info.cpp
Expand Up @@ -168,7 +168,7 @@ String CmdInfo::GetProtoType(DebuggerClient *client, const std::string &cls,
info = info[0];
if (info.exists("params")) {
StringBuffer sb;
sb.printf("<?php function %s%s(%s);\n",
sb.printf("function %s%s(%s);\n",
info["ref"].toBoolean() ? "&" : "",
info["name"].toString().data(),
GetParams(info["params"], info["varg"]).data());
Expand All @@ -190,18 +190,16 @@ bool CmdInfo::onServer(DebuggerProxy *proxy) {
&(*m_acLiveLists)[DebuggerClient::AutoCompleteClassConstants]);

FrameInjection *frame = ThreadInfo::s_threadInfo->m_top;
if (frame) {
bool global;
Array variables = CmdVariable::GetLocalVariables(frame, global);
if (!global) {
variables += CmdVariable::GetGlobalVariables();
}
vector<String> &vars =
(*m_acLiveLists)[DebuggerClient::AutoCompleteVariables];
vars.reserve(variables.size());
for (ArrayIter iter(variables); iter; ++iter) {
vars.push_back(String("$") + iter.second().toString());
}
bool global;
Array variables = CmdVariable::GetLocalVariables(frame, global);
if (!global) {
variables += CmdVariable::GetGlobalVariables();
}
vector<String> &vars =
(*m_acLiveLists)[DebuggerClient::AutoCompleteVariables];
vars.reserve(variables.size());
for (ArrayIter iter(variables); iter; ++iter) {
vars.push_back(String("$") + iter.first().toString());
}

return proxy->send(this);
Expand Down
7 changes: 6 additions & 1 deletion src/runtime/eval/debugger/cmd/cmd_list.cpp
Expand Up @@ -155,7 +155,12 @@ bool CmdList::onClient(DebuggerClient *client) {
m_line2 = m_line1 + DebuggerClient::CodeBlockSize;
}
if (m_file.empty()) {
client->error("There is no current source file.");
string code = client->getCode();
if (code.empty()) {
client->error("There is no current source file.");
return true;
}
client->print(highlight_php(code));
return true;
}
}
Expand Down
16 changes: 8 additions & 8 deletions src/runtime/eval/debugger/cmd/cmd_print.cpp
Expand Up @@ -130,19 +130,19 @@ void CmdPrint::recvImpl(DebuggerThriftBuffer &thrift) {
}

void CmdPrint::list(DebuggerClient *client) {
if (client->arg(1, "clear")) {
client->addCompletion("all");
return;
}
client->addCompletion(DebuggerClient::AutoCompleteCode);

if (client->argCount() == 0) {
client->addCompletion(Formats);
client->addCompletion("always");
client->addCompletion("list");
client->addCompletion("clear");
client->addCompletion(DebuggerClient::AutoCompleteCode);
} else if (client->argCount() == 1) {
if (client->arg(1, "always")) {
client->addCompletion(Formats);
client->addCompletion(DebuggerClient::AutoCompleteCode);
} else if (client->arg(1, "clear")) {
client->addCompletion("all");
}
} else if (client->argCount() == 1 && client->arg(1, "always")) {
client->addCompletion(Formats);
}
}

Expand Down
4 changes: 3 additions & 1 deletion src/runtime/eval/debugger/cmd/cmd_variable.cpp
Expand Up @@ -127,9 +127,11 @@ Array CmdVariable::GetGlobalVariables() {

Array CmdVariable::GetLocalVariables(FrameInjection* frame, bool &global) {
Array ret;
if (!frame || (global = FrameInjection::IsGlobalScope(frame))) {
if (!frame || FrameInjection::IsGlobalScope(frame)) {
global = true;
ret = GetGlobalVariables();
} else {
global = false;
EvalFrameInjection *eframe = dynamic_cast<EvalFrameInjection*>(frame);
if (eframe) {
ret = eframe->getEnv().getDefinedVariables();
Expand Down
9 changes: 9 additions & 0 deletions src/runtime/eval/debugger/debugger_base.cpp
Expand Up @@ -464,6 +464,15 @@ static void append_line_no(StringBuffer &sb, const char *text,
if (end) sb.append(end);
}

String highlight_code(CStrRef source, int line /* = 0 */,
int lineFocus /* = 0 */) {
String prepended = "<?php\n";
prepended += source;
String highlighted = highlight_php(prepended, line, lineFocus);
int pos = highlighted.find("\n");
return highlighted.substr(pos + 1);
}

String highlight_php(CStrRef source, int line /* = 0 */,
int lineFocus /* = 0 */) {
Lock lock(Eval::Parser::s_lock);
Expand Down
2 changes: 2 additions & 0 deletions src/runtime/eval/debugger/debugger_base.h
Expand Up @@ -56,8 +56,10 @@ enum CodeColor {
/**
* "line", starting line number, or 0 for no line number display.
* "lineFocus", the line to highlight, with gray background.
* highlight_code() doesn't need <?php and will treat source entirely PHP.
*/
String highlight_php(CStrRef source, int line = 0, int lineFocus = 0);
String highlight_code(CStrRef source, int line = 0, int lineFocus = 0);

extern const char *PHP_KEYWORDS[];

Expand Down
117 changes: 59 additions & 58 deletions src/runtime/eval/debugger/debugger_client.cpp
Expand Up @@ -36,7 +36,7 @@
using namespace std;
using namespace HPHP::Util::TextArt;

#define PHP_WORD_BREAK_CHARACTERS " \t\n\"\\'`@>=:;,.|{[()]}+-*/%^!~&"
#define PHP_WORD_BREAK_CHARACTERS " \t\n\"\\'`@>=:;,|{[()]}+*%^!~&"

namespace HPHP { namespace Eval {
///////////////////////////////////////////////////////////////////////////////
Expand Down Expand Up @@ -64,6 +64,9 @@ void DebuggerClient::onSignal(int sig) {
if (m_inputState == TakingInterrupt) {
info("Pausing program execution, please wait...");
m_signum = CmdSignal::SignalBreak;
} else {
rl_replace_line("", 0);
rl_redisplay();
}
}

Expand Down Expand Up @@ -510,37 +513,36 @@ void DebuggerClient::updateLiveLists() {
m_acLiveListsDirty = false;
}

void DebuggerClient::phpCompletion(const char *text) {
void DebuggerClient::promptFunctionPrototype() {
if (m_acProtoTypePrompted) return;
m_acProtoTypePrompted = true;

const char *p0 = rl_line_buffer;
int len = strlen(p0);
if (len) {
const char *pLast = p0 + len - 1;
while (isspace(*pLast)) --pLast;
if (*pLast-- == '(') {
while (isspace(*pLast)) --pLast;
const char *p = pLast;
while (p >= p0 && (isalnum(*p) || *p == '_')) --p;
if (pLast > p) {
string cls;
string func(p + 1, pLast - p);
if (p > text && *p-- == ':' && *p-- == ':') {
pLast = p;
while (p >= text && (isalnum(*p) || *p == '_')) --p;
if (pLast > p) {
cls = string(p + 1, pLast - p);
}
}

rl_save_prompt();
String output = CmdInfo::GetProtoType(this, cls, func);
rl_message("\n%s\n", output.data());
rl_restore_prompt();
}
if (len < 2) return;

const char *pLast = p0 + len - 1;
while (pLast > p0 && isspace(*pLast)) --pLast;
if (pLast == p0 || *pLast-- != '(') return;
while (pLast > p0 && isspace(*pLast)) --pLast;

const char *p = pLast;
while (p >= p0 && (isalnum(*p) || *p == '_')) --p;
if (p == pLast) return;

string cls;
string func(p + 1, pLast - p);
if (p > p0 && *p-- == ':' && *p-- == ':') {
pLast = p;
while (p >= p0 && (isalnum(*p) || *p == '_')) --p;
if (pLast > p) {
cls = string(p + 1, pLast - p);
}
}

// generic bare word that can be any of these
addCompletion(AutoCompleteCode);
String output = highlight_code(CmdInfo::GetProtoType(this, cls, func));
print("\n%s", output.data());
rl_forced_update_display();
}

bool DebuggerClient::setCompletion(const char *text, int start, int end) {
Expand Down Expand Up @@ -578,9 +580,9 @@ void DebuggerClient::addCompletion(AutoComplete type) {
m_acLists.push_back((const char **)type);
}

if (type == AutoCompleteVariables) {
addCompletion("$this");
addCompletion("$this->");
if (type == AutoCompleteFunctions || type == AutoCompleteClassMethods) {
rl_completion_suppress_append = 1;
promptFunctionPrototype();
}
}

Expand Down Expand Up @@ -621,7 +623,7 @@ char *DebuggerClient::getCompletion(const std::vector<const char *> &items,
}

static char first_non_whitespace(const char *s) {
while (isspace(*s)) s++;
while (*s && isspace(*s)) s++;
return *s;
}

Expand All @@ -633,38 +635,41 @@ char *DebuggerClient::getCompletion(const char *text, int state) {
m_acLists.clear();
m_acStrings.clear();
m_acItems.clear();
m_acProtoTypePrompted = false;
if (m_inputState == TakingCommand) {
if (m_command.empty()) {
addCompletion(GetCommands());
addCompletion("=");
addCompletion("$");
addCompletion("<?php");
addCompletion("?>");
} else {
DebuggerCommand *cmd = createCommand();
if (cmd) {
DebuggerCommandPtr deleter(cmd);
cmd->list(this);
} else {
switch (first_non_whitespace(rl_line_buffer)) {
case '<':
if (strncasecmp(m_command.substr(0, 5).c_str(), "<?php", 5)) {
break;
}
case '=':
case '$': {
phpCompletion(text);
break;
switch (first_non_whitespace(rl_line_buffer)) {
case '<':
if (strncasecmp(m_command.substr(0, 5).c_str(), "<?php", 5)) {
addCompletion("<?php");
break;
}
case '=':
case '$': {
addCompletion(AutoCompleteCode);
break;
}
default: {
if (m_command.empty()) {
addCompletion(GetCommands());
addCompletion("=");
addCompletion("<?php");
addCompletion("?>");
} else {
DebuggerCommand *cmd = createCommand();
if (cmd) {
DebuggerCommandPtr deleter(cmd);
cmd->list(this);
}
}
break;
}
}
} else {
ASSERT(m_inputState == TakingCode);
if (!*rl_line_buffer) {
addCompletion("?>"); // so we tab, we're done
} else {
phpCompletion(text); // context-sensitive help with PHP
addCompletion(AutoCompleteCode);
}
}
}
Expand Down Expand Up @@ -860,11 +865,7 @@ bool DebuggerClient::console() {
void DebuggerClient::code(CStrRef source, int lineFocus, int line1 /* = 0 */,
int line2 /* = 0 */) {
if (line1 == 0 && line2 == 0) {
String prepended = "<?php\n";
prepended += source;
String highlighted = highlight_php(prepended, 0, lineFocus);
int pos = highlighted.find("\n");
print("%s", highlighted.data() + pos + 1);
print(highlight_code(source, 0, lineFocus));
return;
}

Expand Down
3 changes: 2 additions & 1 deletion src/runtime/eval/debugger/debugger_client.h
Expand Up @@ -243,7 +243,6 @@ class DebuggerClient {
void addCompletion(const char **list);
void addCompletion(const char *name);
void addCompletion(const std::vector<String> &items);
void phpCompletion(const char *text);
void setLiveLists(LiveListsPtr liveLists) { m_acLiveLists = liveLists;}

/**
Expand Down Expand Up @@ -290,6 +289,7 @@ class DebuggerClient {
std::vector<String> m_acItems;
bool m_acLiveListsDirty;
LiveListsPtr m_acLiveLists;
bool m_acProtoTypePrompted;

std::string m_line;
std::string m_command;
Expand Down Expand Up @@ -337,6 +337,7 @@ class DebuggerClient {
DebuggerCommand *createCommand();

void updateLiveLists();
void promptFunctionPrototype();
char *getCompletion(const std::vector<String> &items,
const char *text);
char *getCompletion(const std::vector<const char *> &items,
Expand Down

0 comments on commit 5c02d02

Please sign in to comment.