@@ -298,6 +298,7 @@ def process
298298 process_request ( req )
299299 end
300300 ensure
301+ restore_debuggee_stdio
301302 send_event :terminated unless @sock . closed?
302303 end
303304
@@ -314,6 +315,7 @@ def process_request req
314315 UI_DAP . local_fs_map_set req . dig ( 'arguments' , 'localfs' ) || req . dig ( 'arguments' , 'localfsMap' ) || true
315316 @nonstop = true
316317
318+ capture_debuggee_stdio
317319 load_extensions req
318320
319321 when 'attach'
@@ -326,6 +328,7 @@ def process_request req
326328 @nonstop = false
327329 end
328330
331+ capture_debuggee_stdio
329332 load_extensions req
330333
331334 when 'configurationDone'
@@ -397,6 +400,7 @@ def process_request req
397400 terminate = args . fetch ( "terminateDebuggee" , false )
398401
399402 SESSION . clear_all_breakpoints
403+ restore_debuggee_stdio
400404 send_response req
401405
402406 if SESSION . in_subsession?
@@ -506,6 +510,56 @@ def puts result = ""
506510 send_event 'output' , category : 'console' , output : "#{ result &.chomp } \n "
507511 end
508512
513+ def capture_debuggee_stdio
514+ return if @stdio_captured
515+
516+ @original_stdout = $stdout
517+ @original_stderr = $stderr
518+
519+ @stdout_reader , @stdout_writer = IO . pipe
520+ @stderr_reader , @stderr_writer = IO . pipe
521+
522+ @stdout_writer . sync = true
523+ @stderr_writer . sync = true
524+
525+ $stdout = @stdout_writer
526+ $stderr = @stderr_writer
527+ @stdio_captured = true
528+
529+ @stdout_monitor = start_monitor_thread ( @stdout_reader , 'stdout' )
530+ @stderr_monitor = start_monitor_thread ( @stderr_reader , 'stderr' )
531+ end
532+
533+ def restore_debuggee_stdio
534+ return unless @stdio_captured
535+
536+ $stdout = @original_stdout if @original_stdout
537+ $stderr = @original_stderr if @original_stderr
538+
539+ [ @stdout_writer , @stderr_writer ]
540+ . filter { |writer | !writer &.closed? }
541+ . each ( &:close )
542+
543+ [ @stdout_monitor , @stderr_monitor ] . each { |monitor | monitor &.join }
544+ [ @stdout_reader , @stderr_reader ] . each { |reader | reader &.close unless reader &.closed? }
545+
546+ @stdio_captured = false
547+ end
548+
549+ private
550+
551+ def start_monitor_thread ( reader , category )
552+ Thread . new do
553+ reader . each_line do |line |
554+ send_event 'output' , category : category , output : line
555+ end
556+ rescue IOError , Errno ::EBADF
557+ # Pipe closed, exit gracefully
558+ end
559+ end
560+
561+ public
562+
509563 def ignore_output_on_suspend?
510564 true
511565 end
0 commit comments