osdir.com
mailing list archive
Mozy Online Backup: 2GB Free. Automatic. Secure.

Subject: Keyboard shortcuts for the debugger (patch) - msg#00011

List: lisp.mcclim.devel

Date: Prev Next Index Thread: Prev Next Index
I have added SLIME-style keyboard shortcuts to the McCLIM debugger
(Apps/Debugger/clim-debugger.lisp), as well as a pointer-documentation
pane. These changes may be generally useful, so a patch is attached
to this post.

--
\ Troels "Athas" Henriksen
/\ sigkill.dk/blog (Danish)
Index: Apps/Debugger/clim-debugger.lisp
===================================================================
RCS file: /project/mcclim/cvsroot/mcclim/Apps/Debugger/clim-debugger.lisp,v
retrieving revision 1.1
diff -u -r1.1 clim-debugger.lisp
--- Apps/Debugger/clim-debugger.lisp 26 Apr 2005 03:19:34 -0000 1.1
+++ Apps/Debugger/clim-debugger.lisp 19 Jan 2006 22:01:28 -0000
@@ -151,7 +151,12 @@
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(defclass debugger-pane (application-pane)
- ((condition-info :reader condition-info :initarg :condition-info)))
+ ((condition-info :reader condition-info :initarg :condition-info)
+ (selected-stackframe
+ :accessor selected-stackframe
+ :initarg :selected-strackframe
+ :type 'integer
+ :initform 0)))

;; FIXME - These two variables should be removed!
;; Used to return the chosen reatart in the debugger.
@@ -173,9 +178,12 @@
(define-application-frame clim-debugger ()
()
(:panes
- (debugger-pane (make-debugger-pane)))
+ (debugger-pane (make-debugger-pane))
+ (pointer-doc :pointer-documentation))
(:layouts
- (default (vertically () (scrolling () debugger-pane))))
+ (default (vertically ()
+ (scrolling () debugger-pane)
+ pointer-doc)))
(:geometry :height 600 :width 800))

(defun run-debugger-frame ()
@@ -225,7 +233,133 @@
(setf (view stack-frame) +minimized-stack-frame-view+))
(change-space-requirements (frame-panes *application-frame*))))

+;;; We want to be able to invoke restarts with the 1-9 letters on the
+;;; keyboard.

+(define-clim-debugger-command
+ (com-invoke-restart-by-number
+ :name "Invoke numbered restart")
+ ((number 'integer))
+ ;; `number' is the number of the restart to invoke. This
+ ;; is simply used as an index into a list.
+ (let* ((debugger-pane
+ (get-frame-pane *application-frame* 'debugger-pane))
+ (restarts
+ (restarts
+ (condition-info debugger-pane)))
+ (selected-restart (nth number restarts)))
+ ;; If the restart is not valid, we just ignore the command.
+ (when selected-restart
+ (setf *returned-restart* selected-restart)
+ (frame-exit *application-frame*))))
+
+;;; We associate keystrokes in the interval 0-9 to calls to
+;;; `clim-invoke-restart' with the keystroke as argument. Is this a
+;;; kludge? I couln't find a better way to do it.
+
+;; Define a macro for convenience.
+
+(defmacro keybind-restart-commands (n)
+ "Associate the numeric keys in the interval 0-N with a call to
+`clim-invoke-restart' with the relevant number as argument."
+ `(progn
+ ,@(loop for r from 0 upto n
+ collecting
+ `(add-command-to-command-table
+ '(com-invoke-restart-by-number ,r)
+ 'clim-debugger
+ :keystroke '(,(code-char (+ (char-code #\0) r)))))))
+
+(keybind-restart-commands 9)
+
+;; We also define an abort-command to permit quick exit.
+
+(define-clim-debugger-command
+ (com-invoke-abort-restart
+ :name "Invoke abort restart"
+ :keystroke (#\q))
+ ()
+ (setf *returned-restart* nil)
+ (frame-exit *application-frame*))
+
+;; We want to be able to navigate the list of stack frames
+;; with the keyboard.
+
+(define-clim-debugger-command
+ (com-next-stackframe
+ :name "Next stackframe"
+ :keystroke (#\n :control))
+ ()
+ (let ((debugger-pane (get-frame-pane *application-frame* 'debugger-pane)))
+ (when (< (selected-stackframe debugger-pane)
+ (1- (length (backtrace (condition-info debugger-pane)))))
+ (incf (selected-stackframe debugger-pane)))))
+
+(add-command-to-command-table
+ 'com-next-stackframe
+ 'clim-debugger
+ :errorp nil
+ :keystroke '(#\n))
+
+(define-clim-debugger-command
+ (com-prev-stackframe
+ :name "Previous stackframe"
+ :keystroke (#\p :control))
+ ()
+ (let ((debugger-pane (get-frame-pane *application-frame* 'debugger-pane)))
+ (when (> (selected-stackframe debugger-pane) 0)
+ (decf (selected-stackframe debugger-pane)))))
+
+(add-command-to-command-table
+ 'com-prev-stackframe
+ 'clim-debugger
+ :errorp nil
+ :keystroke '(#\p))
+
+(define-clim-debugger-command
+ (com-toggle-selected-stackframe-view
+ :name "Toggle view of selected stackframe"
+ :keystroke (#\e))
+ ()
+ (let* ((debugger-pane (get-frame-pane *application-frame* 'debugger-pane))
+ (stackframe (nth (selected-stackframe debugger-pane)
+ (backtrace (condition-info debugger-pane)))))
+ (execute-frame-command *application-frame*
+ `(com-toggle-stack-frame-view ,stackframe))))
+
+(define-clim-debugger-command
+ (com-browse-next-stackframe
+ :name "Browse next stackframe"
+ :keystroke (#\N))
+ ()
+ ;; Minize current stackframe, select and expand next stackframe.
+ (let* ((debugger-pane (get-frame-pane *application-frame* 'debugger-pane))
+ (current-stackframe (nth (selected-stackframe debugger-pane)
+ (backtrace (condition-info debugger-pane)))))
+ (setf (view current-stackframe) +minimized-stack-frame-view+)
+ (com-next-stackframe)
+ ;; We have a new current stackframe (this shadowing may be a bit
+ ;; ugly)..
+ (let ((current-stackframe (nth (selected-stackframe debugger-pane)
+ (backtrace (condition-info debugger-pane)))))
+ (setf (view current-stackframe) +maximized-stack-frame-view+))))
+
+(define-clim-debugger-command
+ (com-browse-prev-stackframe
+ :name "Browse previous stackframe"
+ :keystroke (#\P))
+ ()
+ ;; Minize current stackframe, select and expand previous stackframe.
+ (let* ((debugger-pane (get-frame-pane *application-frame* 'debugger-pane))
+ (current-stackframe (nth (selected-stackframe debugger-pane)
+ (backtrace (condition-info debugger-pane)))))
+ (setf (view current-stackframe) +minimized-stack-frame-view+)
+ (com-prev-stackframe)
+ ;; We have a new current stackframe.
+ (let ((current-stackframe (nth (selected-stackframe debugger-pane)
+ (backtrace (condition-info debugger-pane)))))
+ (setf (view current-stackframe) +maximized-stack-frame-view+))))
+
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; Command translators ;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@@ -287,9 +421,12 @@
(formatting-table
(pane)
(loop for r in (restarts (condition-info pane))
+ for rcount from 0
do (formatting-row (pane)
(with-output-as-presentation (pane r 'restart)
(formatting-cell (pane)
+ (format pane "~A." rcount))
+ (formatting-cell (pane)
(format pane "~A" (restart-name r)))

(formatting-cell (pane)
@@ -314,6 +451,9 @@
for i from 0
do (formatting-row (pane)
(with-output-as-presentation (pane stack-frame 'stack-frame)
+ (formatting-cell (pane) (format t "~A" (if (=
(selected-stackframe pane) i)
+ ">"
+ "")))
(bold (pane) (formatting-cell (pane) (format t "~A: " i)))
(formatting-cell (pane)
(present stack-frame 'stack-frame


Was this page helpful?
Yes No
Thread at a glance:

Previous Message by Date: click to view message preview

Re: spec-compliant CLIM impossible on single-threaded systems?

Isn't the lesson here to not read from streams inside event handlers? I don't understand why one would do this.

Next Message by Date: click to view message preview

Re: spec-compliant CLIM impossible on single-threaded systems?

Andy Hefner <ahefner@xxxxxxxxx> wrote: > Isn't the lesson here to not read from streams inside event handlers? In a single-thread system, it does make any difference if it's an event handler or command or something else. And if you think stream-read are too low level anyway, simply think of two accepting-values forms. The second will instantly cause trouble for the first.

Previous Message by Thread: click to view message preview

spec-compliant CLIM impossible on single-threaded systems?

Assume you have two stream panes in a single-thread CLIM implementation (that is *multiprocessing-p* -> nil). By some means you trigger stream-read-char on the first pane. As there is no character available stream-read-char will block and start a subsequent event processing loop, checking if there is a character arriving on its pane. But there won't come any character. In the meanwhile the event processing loop running inside of stream-read-char causes via some other handle-event that a second stream-read-char is started. Again causing an event loop. Problem #1: The event loop of the second stream-read-char does not know anything about the loop condition of the first event loop. Problem #2: Problem #1 can be curred by making some "global" state of event conditions. However, It can't do anything about even if it would know when the first stream-read is supposed to terminate. Because to return to the first event loop, it would have to stop blocking, but it's not allowed to do that. There is no way stream 1 can process its character before stream 2 got its (and further assuming that the code calling stream-read-char exits). Conclusion: CLIM can not be implemented on a single-thread system as it is specified. Continuations a solution? Rather not. event-read would to be specified as a macro that takes a body argument used in a closure. For instance, (event-read (event sheet) (process-event event)) But there is nothing like that in the CLIM spec. So we either support stream reading cleanly or we forbid synchronous event processing at all. We can't have both. Not with this CLIM spec. (Remark: UCW got it right. A former version of UCW uses continuations to fix the problem of "proper problem encoding". Our brain does not think in terms of events. We don't envision problem solutions in terms of state machines. We envison solutions as linear flow. See: http://common-lisp.net/project/ucw/docs/html/rest/rest.html - An interesting thing about UCW is also that it doesn't require deep nesting of sexps as it uses (actually has used) a code walker to transform code into CPS. It can be found here http://common-lisp.net/project/bese/docs/arnesi/html/Automatically_Converting_a_Subset_of_Common_Lisp_to_CPS.html ) I actually wanted to write about the fact that McCLIM does not have per-pane event queues. But before I can have a look at this topic, I rather discuss how CLIM events should be handled at all. If we are actually going to change something in this area, I would also like to define: Who is allowed to read an event and when? What are the priorities if there are more than one event consumers? How is event consumption of event-read related to handle-event; Is handle-event the default event-processing mechanism by the default event-reader, so that handle-event is a fallback if there are no other event-readers (than the default)? See stream-read-char, stream-read-char-no-hang, handle-non-stream-event in stream-input.lisp, standalone-event-loop in panes.lisp, simple-event-loop in frames.lisp for more. -- Fruhwirth Clemens - http://clemens.endorphin.org for robots: sp4mtrap@xxxxxxxxxxxxx

Next Message by Thread: click to view message preview

clisp build issues

Starting with CVS mcclim: clisp -K full -x "(asdf:operate 'asdf:load-source-op :mcclim)" .....[snip]..... *** - MAKE-PATHNAME: illegal :NAME argument "Experimental/menu-choose" This seems to be related to ASDF. If I modify mcclim.asd by removing the slash in the filenames: - (:file "Experimental/menu-choose" ..... + (:file "Experimental.menu-choose" ....... - (:file "Goatee/presentation-history" ...... + (:file "Goatee.presentation-history" ...... - (:file "Looks/pixie" ...... + (:file "Looks.pixie" ...... I have no idea what the kosher way to fix this is. Any ideas? I can get all the way to: *** - READ from #<INPUT BUFFERED FILE-STREAM CHARACTER #P"/home/scottw/.asdf/site/mcclim/Backends/CLX/port.lisp" @1048>: there is no package with name "EXTERNAL-FORMAT" where mcclim wants external-format::ascii-code-to-font-index which is defined medium.lisp. However, mcclim.asd says medium.lisp depends on port.lisp. I'm not quite sure what the right way to resolve this is? In the mean time, in the debugger, I can create the package and the function: Break 1 CLIM-CLX[8]> (make-package "EXTERNAL-FORMAT") Break 1 CLIM-CLX[8]> (defun ascii-code-to-font-index (code) (values code (<= #x00 code #x7f))) Break 1 CLIM-CLX[8]> (export 'ascii-code-to-font-index 'external-format) and redoing the read operation with the redo restart. This allows the loading to continue to *** - READ from #<INPUT BUFFERED FILE-STREAM CHARACTER #P"/home/scottw/.asdf/site/mcclim/Backends/CLX/port.lisp" @1394>: #<PACKAGE XLIB> has no external symbol with name "SET-SELECTION-OWNER" which is a clisp packaging error i fixed by exporting (export 'xlib::set-selection-owner 'xlib) and redoing the read (I'll pass this on to the clisp maintainers). Then the loading of mcclim is complete! Moving on to the examples. (asdf:operate 'asdf:load-source-op :clim-examples) completes successfully. But the first example: [4]> (clim-demo::calculator) *** - XLIB:DRAW-GLYPHS: NIL is not of type XLIB:FONT The following restarts are available: ABORT :R1 ABORT Break 1 [5]> :w EVAL frame for form (XLIB:DRAW-GLYPHS CLIM-CLX::MIRROR CLIM-CLX::GC CLIM-CLX::X CLIM-CLX::Y STRING :START CLIM-CLX::START :END CLIM-CLX::END :SIZE 16 :TRANSLATE #'CLIM-CLX::TRANSLATE) The stack trace is long, but the last recognizable function I can see is (CLIM:MEDIUM-DRAW-TEXT* CLIM:MEDIUM STRING CLIM:POINT-X CLIM:POINT-Y CLIM-INTERNALS::START CLIM-INTERNALS::END CLIM-INTERNALS::ALIGN-X CLIM-INTERNALS::ALIGN-Y CLIM-INTERNALS::TOWARD-X CLIM-INTERNALS::TOWARD-Y CLIM-INTERNALS::TRANSFORM-GLYPHS) Ok, this is where I'm stuck. I don't know much about mcclim, where should I start hunting down this "nil" being passed to xlib:draw-glyphs? I'd be happy to provide more detail where needed. -- Scott
Sign up for updates to this mailing list. email:
Loading Comments...
Home | News | Patents | Sitemap | FAQ | advertise

Advertising by