Added a way to open the current source file & line in an external editor, and you can turn this on with:

lldb -e

llvm-svn: 112502
This commit is contained in:
Jim Ingham 2010-08-30 19:44:40 +00:00
parent 9026d4b488
commit e40e42181f
12 changed files with 202 additions and 7 deletions

View File

@ -106,6 +106,14 @@ public:
lldb::SBSourceManager &
GetSourceManager ();
// FIXME: Once we get the set show stuff in place, the driver won't need
// an interface to the Set/Get UseExternalEditor.
bool
SetUseExternalEditor (bool input);
bool
UseExternalEditor ();
bool
GetDefaultArchitecture (char *arch_name, size_t arch_name_len);

View File

@ -143,6 +143,20 @@ public:
static lldb::DebuggerSP
FindDebuggerWithID (lldb::user_id_t id);
bool
SetUseExternalEditor (bool value)
{
bool old_value = m_use_external_editor;
m_use_external_editor = value;
return old_value;
}
bool
UseExternalEditor ()
{
return m_use_external_editor;
}
protected:
@ -170,6 +184,7 @@ protected:
std::stack<lldb::InputReaderSP> m_input_readers;
std::string m_input_reader_data;
bool m_use_external_editor; // FIXME: Convert this to a set/show variable on the debugger.
private:

View File

@ -267,6 +267,9 @@ public:
static ArchSpec
GetArchSpecForExistingProcess (const char *process_name);
static bool
OpenFileInExternalEditor (FileSpec &file_spec, uint32_t line_no);
};

View File

@ -356,6 +356,7 @@
4C08CDEC11C81F1E001610A8 /* ThreadSpec.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C08CDEB11C81F1E001610A8 /* ThreadSpec.h */; };
4C5DBBC811E3FEC60035160F /* CommandObjectCommands.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4C5DBBC611E3FEC60035160F /* CommandObjectCommands.cpp */; };
4C5DBBC911E3FEC60035160F /* CommandObjectCommands.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C5DBBC711E3FEC60035160F /* CommandObjectCommands.h */; };
4C74CB6312288704006A8171 /* Carbon.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4C74CB6212288704006A8171 /* Carbon.framework */; };
4CA9637B11B6E99A00780E28 /* CommandObjectApropos.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4CA9637911B6E99A00780E28 /* CommandObjectApropos.cpp */; };
9A19A6AF1163BBB200E0D453 /* SBValue.h in Headers */ = {isa = PBXBuildFile; fileRef = 9A19A6A51163BB7E00E0D453 /* SBValue.h */; settings = {ATTRIBUTES = (Public, ); }; };
9A19A6B01163BBB300E0D453 /* SBValue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9A19A6AD1163BB9800E0D453 /* SBValue.cpp */; };
@ -960,6 +961,7 @@
4C51FF1611A4C486007C962F /* ObjCTrampolineHandler.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ObjCTrampolineHandler.cpp; sourceTree = "<group>"; };
4C5DBBC611E3FEC60035160F /* CommandObjectCommands.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CommandObjectCommands.cpp; path = source/Commands/CommandObjectCommands.cpp; sourceTree = "<group>"; };
4C5DBBC711E3FEC60035160F /* CommandObjectCommands.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CommandObjectCommands.h; path = source/Commands/CommandObjectCommands.h; sourceTree = "<group>"; };
4C74CB6212288704006A8171 /* Carbon.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Carbon.framework; path = /System/Library/Frameworks/Carbon.framework; sourceTree = "<absolute>"; };
4C98D3DA118FB96F00E575D0 /* ClangFunction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ClangFunction.cpp; path = source/Expression/ClangFunction.cpp; sourceTree = "<group>"; };
4C98D3DB118FB96F00E575D0 /* RecordingMemoryManager.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = RecordingMemoryManager.cpp; path = source/Expression/RecordingMemoryManager.cpp; sourceTree = "<group>"; };
4C98D3E0118FB98F00E575D0 /* ClangFunction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ClangFunction.h; path = include/lldb/Expression/ClangFunction.h; sourceTree = "<group>"; };
@ -1075,6 +1077,7 @@
26680231115FD1A0008E1FE4 /* Foundation.framework in Frameworks */,
26680232115FD1A4008E1FE4 /* libpython2.6.dylib in Frameworks */,
26680233115FD1A7008E1FE4 /* libobjc.dylib in Frameworks */,
4C74CB6312288704006A8171 /* Carbon.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -1105,6 +1108,7 @@
08FB7795FE84155DC02AAC07 /* Source */,
26F5C22410F3D950009D5894 /* Tools */,
1AB674ADFE9D54B511CA2CBB /* Products */,
4C74CB6212288704006A8171 /* Carbon.framework */,
);
name = lldb;
sourceTree = "<group>";

View File

@ -563,3 +563,23 @@ SBDebugger::FindDebuggerWithID (int id)
sb_debugger.reset (debugger_sp);
return sb_debugger;
}
bool
SBDebugger::SetUseExternalEditor (bool value)
{
if (m_opaque_sp)
return m_opaque_sp->SetUseExternalEditor (value);
else
return false;
}
bool
SBDebugger::UseExternalEditor ()
{
if (m_opaque_sp)
return m_opaque_sp->UseExternalEditor ();
else
return false;
}

View File

@ -114,12 +114,19 @@ public:
if (exe_ctx.frame)
{
bool already_shown = false;
SymbolContext frame_sc(exe_ctx.frame->GetSymbolContext(eSymbolContextLineEntry));
if (interpreter.GetDebugger().UseExternalEditor() && frame_sc.line_entry.file && frame_sc.line_entry.line != 0)
{
already_shown = Host::OpenFileInExternalEditor (frame_sc.line_entry.file, frame_sc.line_entry.line);
}
if (DisplayFrameForExecutionContext (exe_ctx.thread,
exe_ctx.frame,
interpreter,
result.GetOutputStream(),
true,
true,
!already_shown,
3,
3))
{

View File

@ -60,13 +60,21 @@ lldb_private::DisplayThreadInfo
// Show one frame with only the first showing source
if (show_source)
{
bool already_shown = false;
StackFrameSP frame_sp = thread->GetStackFrameAtIndex(0);
SymbolContext frame_sc(frame_sp->GetSymbolContext (eSymbolContextLineEntry));
if (interpreter.GetDebugger().UseExternalEditor() && frame_sc.line_entry.file && frame_sc.line_entry.line != 0)
{
already_shown = Host::OpenFileInExternalEditor (frame_sc.line_entry.file, frame_sc.line_entry.line);
}
DisplayFramesForExecutionContext (thread,
interpreter,
strm,
0, // Start at first frame
1, // Number of frames to show
false,// Don't show the frame info since we already displayed most of it above...
1, // Show source for the first frame
!already_shown, // Show source for the first frame
3, // lines of source context before
3); // lines of source context after
}

View File

@ -128,7 +128,8 @@ Debugger::Debugger () :
m_command_interpreter_ap (new CommandInterpreter (*this, eScriptLanguageDefault, false)),
m_exe_ctx (),
m_input_readers (),
m_input_reader_data ()
m_input_reader_data (),
m_use_external_editor(false)
{
m_command_interpreter_ap->Initialize ();
}

View File

@ -24,6 +24,8 @@
#include <objc/objc-auto.h>
#include <Foundation/Foundation.h>
#include <CoreServices/CoreServices.h>
#include <Carbon/Carbon.h>
#include "cfcpp/CFCBundle.h"
#include "cfcpp/CFCReleaser.h"
@ -779,3 +781,116 @@ Host::GetArchSpecForExistingProcess (const char *process_name)
}
return returnSpec;
}
bool
Host::OpenFileInExternalEditor (FileSpec &file_spec, uint32_t line_no)
{
// We attach this to an 'odoc' event to specify a particular selection
typedef struct {
int16_t reserved0; // must be zero
int16_t fLineNumber;
int32_t fSelStart;
int32_t fSelEnd;
uint32_t reserved1; // must be zero
uint32_t reserved2; // must be zero
} BabelAESelInfo;
char file_path[PATH_MAX];
file_spec.GetPath(file_path, PATH_MAX);
CFCString file_cfstr (file_path, kCFStringEncodingUTF8);
CFCReleaser<CFURLRef> file_URL(::CFURLCreateWithFileSystemPath(NULL, file_cfstr.get(), kCFURLPOSIXPathStyle, false));
OSStatus error;
BabelAESelInfo file_and_line_info;
AEKeyDesc file_and_line_desc;
bzero(&file_and_line_info, sizeof (file_and_line_info));
file_and_line_info.fSelStart = 1;
file_and_line_info.fSelEnd = 1;
file_and_line_info.fLineNumber = line_no - 1;
error = AECreateDesc(typeChar, &file_and_line_info, sizeof (file_and_line_info), &(file_and_line_desc.descContent));
if (error != noErr)
{
return false;
}
file_and_line_desc.descKey = keyAEPosition;
LSApplicationParameters app_params;
bzero (&app_params, sizeof (app_params));
app_params.flags = kLSLaunchDefaults | kLSLaunchDontSwitch;
ProcessSerialNumber psn;
CFCReleaser<CFArrayRef> file_array(CFArrayCreate (NULL, (const void **) file_URL.ptr_address(false), 1, NULL));
error = LSOpenURLsWithRole(file_array.get(), kLSRolesAll, &file_and_line_desc, &app_params, &psn, 1);
AEDisposeDesc (&(file_and_line_desc.descContent));
if (error != noErr)
{
return false;
}
ProcessInfoRec which_process;
bzero(&which_process, sizeof(which_process));
unsigned char ap_name[PATH_MAX];
which_process.processName = ap_name;
error = GetProcessInformation (&psn, &which_process);
bool using_xcode = strncmp((char *) ap_name+1, "Xcode", 5) == 0;
// Xcode doesn't obey the line number in the Open Apple Event. So I have to send
// it an AppleScript to focus on the right line.
if (using_xcode)
{
static ComponentInstance osa_component = NULL;
static const char *as_template = "tell application \"Xcode\"\n"
"set doc to the first document whose path is \"%s\"\n"
"set the selection to paragraph %d of doc\n"
"--- set the selected paragraph range to {%d, %d} of doc\n"
"end tell\n";
const int chars_for_int = 32;
static int as_template_len = strlen (as_template);
char *as_str;
AEDesc as_desc;
if (osa_component == NULL)
{
osa_component = OpenDefaultComponent (kOSAComponentType,
kAppleScriptSubtype);
}
if (osa_component == NULL)
{
return false;
}
uint32_t as_str_size = as_template_len + strlen (file_path) + 3 * chars_for_int + 1;
as_str = (char *) malloc (as_str_size);
snprintf (as_str, as_str_size - 1, as_template, file_path, line_no, line_no, line_no);
error = AECreateDesc (typeChar, as_str, strlen (as_str), &as_desc);
free (as_str);
if (error != noErr)
return false;
OSAID ret_OSAID;
error = OSACompileExecute (osa_component, &as_desc, kOSANullScript,
kOSAModeNeverInteract, &ret_OSAID);
OSADispose (osa_component, ret_OSAID);
AEDisposeDesc (&as_desc);
if (error != noErr)
return false;
}
return true;
}

View File

@ -96,11 +96,14 @@ public:
// assertion fires, check the offending code, or call
// reset() prior to using the "ptr_address()" member to make
// sure any owned objects has CFRelease called on it.
// I had to add the "enforce_null" bool here because some
// API's require the pointer address even though they don't change it.
//----------------------------------------------------------
T*
ptr_address()
ptr_address(bool enforce_null = true)
{
assert (_ptr == NULL);
if (enforce_null)
assert (_ptr == NULL);
return &_ptr;
}

View File

@ -70,6 +70,9 @@ static lldb::OptionDefinition g_options[] =
{ LLDB_OPT_SET_3, true, "file", 'f', required_argument, NULL, NULL, "<filename>",
"Tells the debugger to use the file <filename> as the program to be debugged." },
{ LLDB_OPT_SET_ALL, false, "editor", 'e', no_argument, NULL, NULL, "<external-editor>",
"Tells the debugger to open source files using the host's \"external editor\" mechanism." },
// { LLDB_OPT_SET_4, true, "crash-log", 'c', required_argument, NULL, NULL, "<file>",
// "Load executable images from a crash log for symbolication." },
@ -324,7 +327,8 @@ Driver::OptionData::OptionData () :
m_debug_mode (false),
m_print_version (false),
m_print_help (false),
m_seen_options()
m_seen_options(),
m_use_external_editor(false)
{
}
@ -341,6 +345,7 @@ Driver::OptionData::Clear ()
m_debug_mode = false;
m_print_help = false;
m_print_version = false;
m_use_external_editor = false;
}
void
@ -508,7 +513,10 @@ Driver::ParseArgs (int argc, const char *argv[], FILE *out_fh, bool &exit)
case 'c':
m_option_data.m_crash_log = optarg;
break;
case 'e':
m_option_data.m_use_external_editor = true;
break;
case 'f':
{
SBFileSpec file(optarg);
@ -1042,6 +1050,8 @@ Driver::MainLoop ()
m_debugger.SetErrorFileHandle (stderr, false);
m_debugger.SetOutputFileHandle (stdout, false);
m_debugger.SetInputFileHandle (stdin, true);
m_debugger.SetUseExternalEditor(m_option_data.m_use_external_editor);
// You have to drain anything that comes to the master side of the PTY. master_out_comm is
// for that purpose. The reason you need to do this is a curious reason... editline will echo

View File

@ -103,6 +103,7 @@ public:
bool m_debug_mode;
bool m_print_version;
bool m_print_help;
bool m_use_external_editor; // FIXME: When we have set/show variables we can remove this from here.
typedef std::set<char> OptionSet;
OptionSet m_seen_options;
};