@@ -78,8 +78,9 @@ def remove_breakpoint(self, filename, linenumber):
7878 del self ._location_to_id [location ]
7979 return breakpoint_id
8080
81- def __init__ (self , executable ):
81+ def __init__ (self , executable , stacktrace_to_clipboard = False ):
8282 self ._executable = executable
83+ self ._stacktrace_to_clipboard = stacktrace_to_clipboard
8384 self ._debugger = lldb .SBDebugger .Create ()
8485 self ._debugger .SetAsync (False )
8586 self ._command_interpreter = self ._debugger .GetCommandInterpreter ()
@@ -143,6 +144,26 @@ def clear(arguments):
143144 arguments = parts [1 :]
144145 locals ()[command ](arguments )
145146
147+ def _copy_stacktrace_to_clipboard (self , stacktrace ):
148+ stacktrace_text = '\n ' .join ('File "{}", line {:d},' .format (file , line ) for file , line in reversed (stacktrace ))
149+ platform_system = platform .system ()
150+ process = None
151+ if platform_system == 'Darwin' :
152+ process = subprocess .Popen ('pbcopy' , env = {'LANG' : 'en_US.UTF-8' }, stdin = subprocess .PIPE )
153+ else :
154+ # assume we are running on Linux
155+ for cmd in (['xclip' , '-selection' , 'clipboard' ], ['xsel' , '--clipboard' ]):
156+ try :
157+ process = subprocess .Popen (cmd , stdin = subprocess .PIPE )
158+ break
159+ except OSError :
160+ pass
161+ else :
162+ print (prefix_output ('Stacktrace cannot be copied to clipboard! Either install xclip or xsel.' ,
163+ 'warning: ' ))
164+ if process is not None :
165+ process .communicate (stacktrace_text .encode ('utf-8' ))
166+
146167 @property
147168 def debugger_output (self ):
148169 if self ._last_debugger_return_obj is not None :
@@ -154,7 +175,7 @@ def debugger_output(self):
154175
155176 @property
156177 def where (self ):
157- def extract_where (backtrace ):
178+ def extract_where (backtrace , collect_complete_stacktrace = False ):
158179 where = None
159180 pattern = re .compile ('at:([^:]+):(\d+)' )
160181 backtrace_lines = backtrace .split ('\n ' )
@@ -164,16 +185,25 @@ def extract_where(backtrace):
164185 filepath = match_obj .group (1 )
165186 linenumber = int (match_obj .group (2 ))
166187 if os .access (filepath , os .R_OK ):
167- where = FilePosition (filepath , linenumber )
168- break
188+ if collect_complete_stacktrace :
189+ if where is None :
190+ where = []
191+ where .append (FilePosition (filepath , linenumber ))
192+ else :
193+ where = FilePosition (filepath , linenumber )
194+ break
169195 return where
170196
171197 where = None
172198 self .run_command ('bt' )
173199 debugger_output = self .debugger_output
174200 if debugger_output is not None :
175- where = extract_where (debugger_output )
176- return where
201+ where = extract_where (debugger_output , self ._stacktrace_to_clipboard )
202+ if self ._stacktrace_to_clipboard and where is not None :
203+ self ._copy_stacktrace_to_clipboard (where )
204+ return where [0 ]
205+ else :
206+ return where
177207
178208 @property
179209 def program_stdout (self ):
@@ -223,9 +253,9 @@ def main():
223253 if len (sys .argv ) < 2 :
224254 sys .stderr .write ('An executable is needed as an argument.\n ' )
225255 sys .exit (1 )
226-
227256 executable = sys .argv [1 ]
228- debugger = Debugger (executable )
257+ stacktrace_to_clipboard = (len (sys .argv ) > 2 and sys .argv [2 ] == '--stacktrace_to_clipboard' )
258+ debugger = Debugger (executable , stacktrace_to_clipboard )
229259
230260 try :
231261 while True :
0 commit comments