(in-package :sb-thread)

(defun release-foreground% (thread &optional next)
  "Background thread.  If NEXT is supplied, arrange for it to have the foreground next."
  #-sb-thread (declare (ignore next))
  #-sb-thread nil
  #+sb-thread
  (let ((session *session*))
    (with-session-lock (session)
      (symbol-macrolet
          ((interactive-threads (session-interactive-threads session)))
        (setf interactive-threads
              (delete thread interactive-threads))
        (when (and next (thread-alive-p next))
          (setf interactive-threads
                (list* next (delete next interactive-threads))))
        (condition-broadcast (session-interactive-threads-queue session))))))

(defun release-foreground (&optional next)
 (release-foreground% *current-thread* next))


(in-package :cl-user)

  ;; Useful when developing multi-threaded apps in the console (without slime)
  (defun current-thread-to-fg ()
    (sb-thread::release-foreground2
      (sb-thread::main-thread) (bt:current-thread)))

  (defmacro fbreak (&rest args)
    "Foreground Break. Needed because
     (break) bypasses error handling so with-fg-debugger has no effect
     if you need to (break) inside the thread."
    `(progn
       (current-thread-to-fg)
       (break ,@args)))

  (defmacro with-fg-debugger (&body body)
    "Brings the current thread to foreground before invoking the debugger.
     Useful in case errors happen inside body."
    `(handler-case
      (progn ,@body)
      (condition (c)
                 (current-thread-to-fg)
                 (invoke-debugger  c)))))