diff options
author | initial.commit <initial.commit@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-07-26 23:55:29 +0000 |
---|---|---|
committer | initial.commit <initial.commit@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-07-26 23:55:29 +0000 |
commit | 09911bf300f1a419907a9412154760efd0b7abc3 (patch) | |
tree | f131325fb4e2ad12c6d3504ab75b16dd92facfed /chrome/browser/debugger/debugger_shell.cc | |
parent | 586acc5fe142f498261f52c66862fa417c3d52d2 (diff) | |
download | chromium_src-09911bf300f1a419907a9412154760efd0b7abc3.zip chromium_src-09911bf300f1a419907a9412154760efd0b7abc3.tar.gz chromium_src-09911bf300f1a419907a9412154760efd0b7abc3.tar.bz2 |
Add chrome to the repository.
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@15 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/debugger/debugger_shell.cc')
-rw-r--r-- | chrome/browser/debugger/debugger_shell.cc | 419 |
1 files changed, 419 insertions, 0 deletions
diff --git a/chrome/browser/debugger/debugger_shell.cc b/chrome/browser/debugger/debugger_shell.cc new file mode 100644 index 0000000..0679292 --- /dev/null +++ b/chrome/browser/debugger/debugger_shell.cc @@ -0,0 +1,419 @@ +// Copyright 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "chrome/browser/debugger/debugger_shell.h" + +#include "base/file_util.h" +#include "base/path_service.h" +#include "base/string_util.h" +#include "base/thread.h" +#include "chrome/browser/browser.h" +#include "chrome/browser/browser_list.h" +#include "chrome/browser/browser_process.h" +#include "chrome/browser/browser_resources.h" +#include "chrome/browser/render_process_host.h" +#include "chrome/browser/tab_contents.h" +#include "chrome/browser/debugger/debugger_io.h" +#include "chrome/browser/debugger/debugger_node.h" +#include "chrome/common/chrome_paths.h" +#include "chrome/common/resource_bundle.h" +#include "v8/public/v8.h" + +DebuggerShell::DebuggerShell(DebuggerInputOutput* io) : io_(io), + debugger_ready_(true) { +} + +DebuggerShell::~DebuggerShell() { + io_->Stop(); + io_ = NULL; + + v8::HandleScope scope; + SubshellFunction("exit", 0, NULL); + v8::V8::RemoveMessageListeners(&DelegateMessageListener); + v8_this_.Dispose(); + v8_context_.Dispose(); + shell_.Dispose(); +} + +void DebuggerShell::Start() { + io_->Start(this); + + v8::HandleScope scope; + + v8_this_ = v8::Persistent<v8::External>::New(v8::External::New(this)); + + v8::V8::AddMessageListener(&DelegateMessageListener, v8_this_); + + v8::Local<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New(); + + // shell function + v8::Local<v8::FunctionTemplate> shell_template = + v8::FunctionTemplate::New(&DelegateSubshell, v8_this_); + global_template->Set(v8::String::New("shell"), shell_template); + + // print function + v8::Local<v8::FunctionTemplate> print_template = + v8::FunctionTemplate::New(&DelegatePrint, v8_this_); + global_template->Set(v8::String::New("print"), print_template); + + // source function + v8::Local<v8::FunctionTemplate> source_template = + v8::FunctionTemplate::New(&DelegateSource, v8_this_); + global_template->Set(v8::String::New("source"), source_template); + + v8_context_ = v8::Context::New(NULL, global_template); + v8::Context::Scope ctx(v8_context_); + + // This doesn't really leak. It's wrapped by the NewInstance() return value. + ChromeNode* chrome = new ChromeNode(this); + v8_context_->Global()->Set(v8::String::New("chrome"), + chrome->NewInstance()); + + ResourceBundle& rb = ResourceBundle::GetSharedInstance(); + const std::string& debugger_shell_js = + rb.GetDataResource(IDR_DEBUGGER_SHELL_JS); + CompileAndRun(debugger_shell_js, "chrome.dll/debugger_shell.js"); +} + +void DebuggerShell::HandleWeakReference(v8::Persistent<v8::Object> obj, void* data) { + DebuggerNodeWrapper* node = static_cast<DebuggerNodeWrapper*>(data); + node->Release(); +} + +v8::Handle<v8::Value> DebuggerShell::SetDebuggerReady(const v8::Arguments& args, + DebuggerShell* debugger) { + if (args[0]->IsBoolean()) { + bool flag = args[0]->BooleanValue(); + debugger->debugger_ready_ = flag; + debugger->GetIo()->SetDebuggerReady(flag); + } + return v8::Undefined(); +} + +v8::Handle<v8::Value> DebuggerShell::SetDebuggerBreak(const v8::Arguments& args, + DebuggerShell* debugger) { + if (args[0]->IsBoolean()) { + bool flag = args[0]->BooleanValue(); + debugger->GetIo()->SetDebuggerBreak(flag); + } + return v8::Undefined(); +} + +DebuggerInputOutput* DebuggerShell::GetIo() { + return io_.get(); +} + +v8::Handle<v8::Value> DebuggerShell::DelegateSubshell(const v8::Arguments& args) { + DebuggerShell* debugger = + static_cast<DebuggerShell*>(v8::External::Cast(*args.Data())->Value()); + return debugger->Subshell(args); +} + +v8::Handle<v8::Value> DebuggerShell::Subshell(const v8::Arguments& args) { + if (args.Length() != 1) { + return v8::Undefined(); + } + if (!shell_.IsEmpty()) { + shell_.Dispose(); + shell_.Clear(); + v8_context_->Global()->Delete(v8::String::New("shell_")); + } + if (args[0]->IsFunction()) { + v8::Handle<v8::Function> func = v8::Handle<v8::Function>::Cast(args[0]); + v8::Local<v8::Object> obj = func->NewInstance(); + if (!obj->IsUndefined()) { + shell_= v8::Persistent<v8::Object>::New(obj); + v8_context_->Global()->Set(v8::String::New("shell_"), shell_); + } + } else if (args[0]->IsObject()) { + shell_= v8::Persistent<v8::Object>::New(v8::Local<v8::Object>::Cast(args[0])); + v8_context_->Global()->Set(v8::String::New("shell_"), shell_); + } + return v8::Undefined(); +} + +v8::Handle<v8::Value> DebuggerShell::SubshellFunction(const char* func, + int argc, + v8::Handle<v8::Value>* argv) { + if (!shell_.IsEmpty()) { + v8::Context::Scope scope(v8_context_); + v8::Local<v8::Value> function = shell_->Get(v8::String::New(func)); + if (function->IsFunction()) { + v8::Local<v8::Value> ret = + v8::Function::Cast(*function)->Call(shell_, argc, argv); + return ret; + } + } + return v8::Undefined(); +} + +v8::Handle<v8::Value> DebuggerShell::DelegatePrint(const v8::Arguments& args) { + DebuggerShell* debugger = + static_cast<DebuggerShell*>(v8::External::Cast(*args.Data())->Value()); + return debugger->Print(args); +} + +v8::Handle<v8::Value> DebuggerShell::Print(const v8::Arguments& args) { + int len = args.Length(); + for (int i = 0; i < len; i++) { + PrintObject(args[i]); + } + return v8::Undefined(); +} + +v8::Handle<v8::Value> DebuggerShell::DelegateSource(const v8::Arguments& args) { + DebuggerShell* debugger = + static_cast<DebuggerShell*>(v8::External::Cast(*args.Data())->Value()); + std::wstring path; + if (args.Length() == 0) { + debugger->LoadUserConfig(); + } else { + ObjectToString(args[0], &path); + bool ret = debugger->LoadFile(path); + if (!ret) { + return v8::String::New("failed to load"); + } + } + return v8::Undefined(); +} + +void DebuggerShell::DelegateMessageListener(v8::Handle<v8::Message> message, + v8::Handle<v8::Value> data) { + DCHECK(!data.IsEmpty()); + DebuggerShell* debugger = + static_cast<DebuggerShell*>(v8::External::Cast(*data)->Value()); + debugger->MessageListener(message); +} + +void DebuggerShell::MessageListener(v8::Handle<v8::Message> message) { + v8::HandleScope scope; + v8::Local<v8::String> msg_str = message->Get(); + PrintObject(msg_str); + + v8::Handle<v8::Value> data = message->GetScriptResourceName(); + if (!data.IsEmpty() && !data->IsUndefined()) { + std::wstring out; + ObjectToString(data, &out); + int line_number = message->GetLineNumber(); + if (line_number >= 0) + out += StringPrintf(L":%d", line_number); + PrintLine(out); + data = message->GetSourceLine(); + if (!data->IsUndefined()) { + ObjectToString(data, &out); + PrintLine(out); + } + } +} + +void DebuggerShell::Debug(TabContents* tab) { + v8::HandleScope outer; + v8::Context::Scope scope(v8_context_); + + v8::Local<v8::Object> global = v8_context_->Global(); + v8::Local<v8::Value> function = global->Get(v8::String::New("debug")); + if (function->IsFunction()) { + TabNode* node = new TabNode(tab); + v8::Handle<v8::Value> argv[] = {node->NewInstance()}; + PrintObject(v8::Function::Cast(*function)->Call(global, 1, argv)); + } +} + +void DebuggerShell::DebugMessage(const std::wstring& msg) { + v8::HandleScope scope; + + if (msg.length()) { + if ((msg[0] == L'{' || msg[0] == L'[' || msg[0] == L'(') && (!shell_.IsEmpty())) { + // v8's wide String constructor requires uint16 rather than wchar + const uint16* data = reinterpret_cast<const uint16* >(msg.c_str()); + v8::Handle<v8::Value> argv[] = {v8::String::New(data)}; + PrintObject(SubshellFunction("response", 1, argv)); + PrintPrompt(); + } else { + if (msg[msg.length() - 1] == L'\n') + PrintString(msg); + else + PrintLine(msg); + } + } +} + +void DebuggerShell::OnDebugDisconnect() { + v8::HandleScope scope; + SubshellFunction("on_disconnect", 0, NULL); +} + +void DebuggerShell::ObjectToString(v8::Handle<v8::Value> result, std::wstring* str) { + v8::HandleScope scope; + if (!result.IsEmpty() && !result->IsUndefined()) { + v8::Local<v8::String> str_obj = result->ToString(); + if (!str_obj.IsEmpty()) { + int length = str_obj->Length(); + wchar_t* buf = new wchar_t[length + 1]; + int size = str_obj->Write(reinterpret_cast<uint16_t*>(buf)); + str->clear(); + str->append(buf, size); + delete[] buf; + } + } +} + +void DebuggerShell::ObjectToString(v8::Handle<v8::Value> result, std::string* str) { + v8::HandleScope scope; + if (!result.IsEmpty() && !result->IsUndefined()) { + v8::Local<v8::String> str_obj = result->ToString(); + if (!str_obj.IsEmpty()) { + int length = str_obj->Length(); + char* buf = new char[length + 1]; + str_obj->WriteAscii(buf); + str->clear(); + str->append(buf); + delete[] buf; + } + } +} + +void DebuggerShell::PrintObject(v8::Handle<v8::Value> result, bool crlf) { + if (!result.IsEmpty() && !result->IsUndefined()) { + std::wstring out; + ObjectToString(result, &out); + if (crlf) { + PrintLine(out); + } else if (out.length()) { + PrintString(out); + } + } +} + +void DebuggerShell::PrintString(const std::wstring& out) { + if (io_) + io_->Output(out); +} + +void DebuggerShell::PrintLine(const std::wstring& out) { + if (io_) + io_->OutputLine(out); +} + +void DebuggerShell::PrintString(const std::string& out) { + if (io_) + io_->Output(out); +} + +void DebuggerShell::PrintLine(const std::string& out) { + if (io_) + io_->OutputLine(out); +} + +void DebuggerShell::PrintPrompt() { + std::wstring out = L"Chrome> "; + if (!shell_.IsEmpty()) { + if (!debugger_ready_) + return; + v8::HandleScope outer; + v8::Handle<v8::Value> result = CompileAndRun("shell_.prompt()"); + if (!result.IsEmpty() && !result->IsUndefined()) { + ObjectToString(result, &out); + } + } + if (io_) + io_->OutputPrompt(out); +} + +void DebuggerShell::ProcessCommand(const std::string& data) { + v8::HandleScope outer; + v8::Context::Scope scope(v8_context_); + if (!shell_.IsEmpty() && data.substr(0, 7) != "source(") { + if (data == "exit") { + PrintObject(SubshellFunction("exit", 0, NULL)); + v8_context_->Global()->Delete(v8::String::New("shell_")); + shell_.Dispose(); + shell_.Clear(); + } else { + v8::Handle<v8::Value> argv[] = {v8::String::New(data.c_str())}; + PrintObject(SubshellFunction("command", 1, argv)); + } + } else if (data.length()) { + v8::Handle<v8::Value> result = CompileAndRun(data); + PrintObject(result); + } + PrintPrompt(); +} + +bool DebuggerShell::LoadFile(const std::wstring& file) { + if (file_util::PathExists(file)) { + std::string contents; + if (file_util::ReadFileToString(file, &contents)) { + std::string afile = WideToUTF8(file); + CompileAndRun(contents, afile); + return true; + } + } + return false; +} + +void DebuggerShell::LoadUserConfig() { + std::wstring path; + PathService::Get(chrome::DIR_USER_DATA, &path); + file_util::AppendToPath(&path, L"debugger_custom.js"); + LoadFile(path); +} + +void DebuggerShell::DidConnect() { + v8::HandleScope outer; + v8::Context::Scope scope(v8_context_); + + LoadUserConfig(); + + PrintPrompt(); +} + +v8::Handle<v8::Value> DebuggerShell::CompileAndRun(const std::string& str, + const std::string& filename) { + v8::Context::Scope scope(v8_context_); + v8::Handle<v8::String> scriptname; + if (filename.length() > 0) { + scriptname = v8::String::New(filename.c_str()); + } else { + scriptname = v8::String::New(""); + } + v8::ScriptOrigin origin = + v8::ScriptOrigin(scriptname); + v8::Local<v8::Script> code = + v8::Script::Compile(v8::String::New(str.c_str()), &origin); + if (!code.IsEmpty()) { + v8::Local<v8::Value> result = code->Run(); + if (!result.IsEmpty()) { + return result; + } + } + return v8::Undefined(); +} + + |