;;; jde-xemacs.el -- xemacs specific code for JDEE. ;; Keywords: java, tools, debugging ;; Copyright (C) 2002, 2003 Andy Piper <andy@xemacs.org> ;; Copyright (C) 2002 Paul Kinnucan <paulk@mathworks.com> ;; ;; This file is part of XEmacs. ;; ;; XEmacs is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 2 of the License, or ;; (at your option) any later version. ;; ;; XEmacs is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with XEmacs; if not, write to the Free Software ;; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ;; Please send bug reports and enhancement suggestions ;; to Andy Piper at <andy@xemacs.org> ;; ;; If you don't use XEmacs, you should! XEmacs kicks some serious ;; butt! ;; XEmacs doesn't have replace-regexp-in-string so define our own ;; version (unless (fboundp 'replace-regexp-in-string) (defun replace-regexp-in-string (regexp rep string &optional fixedcase literal subexp start) "Replace all matches for REGEXP with REP in STRING. Return a new string containing the replacements. Optional arguments FIXEDCASE, LITERAL and SUBEXP are like the arguments with the same names of function `replace-match'. If START is non-nil, start replacements at that index in STRING. REP is either a string used as the NEWTEXT arg of `replace-match' or a function. If it is a function it is applied to each match to generate the replacement passed to `replace-match'; the match-data at this point are such that match 0 is the function's argument. To replace only the first match (if any), make REGEXP match up to \\' and replace a sub-expression, e.g. (replace-regexp-in-string \"\\(foo\\).*\\'\" \"bar\" \" foo foo\" nil nil 1) => \" bar foo\" " ;; To avoid excessive consing from multiple matches in long strings, ;; don't just call `replace-match' continually. Walk down the ;; string looking for matches of REGEXP and building up a (reversed) ;; list MATCHES. This comprises segments of STRING which weren't ;; matched interspersed with replacements for segments that were. ;; [For a `large' number of replacments it's more efficient to ;; operate in a temporary buffer; we can't tell from the function's ;; args whether to choose the buffer-based implementation, though it ;; might be reasonable to do so for long enough STRING.] (let ((l (length string)) (start (or start 0)) matches str mb me) (save-match-data (while (and (< start l) (string-match regexp string start)) (setq mb (match-beginning 0) me (match-end 0)) ;; If we matched the empty string, make sure we advance by one char (when (= me mb) (setq me (min l (1+ mb)))) ;; Generate a replacement for the matched substring. ;; Operate only on the substring to minimize string consing. ;; Set up match data for the substring for replacement; ;; presumably this is likely to be faster than munging the ;; match data directly in Lisp. (string-match regexp (setq str (substring string mb me))) (setq matches (cons (replace-match (if (stringp rep) rep (funcall rep (match-string 0 str))) fixedcase literal str subexp) (cons (substring string start mb) ; unmatched prefix matches))) (setq start me)) ;; Reconstruct a string from the pieces. (setq matches (cons (substring string start l) matches)) ; leftover (apply #'concat (nreverse matches))))) ) (unless (fboundp 'subst-char-in-string) (defun subst-char-in-string (fromchar tochar string &optional inplace) "Replace FROMCHAR with TOCHAR in STRING each time it occurs. Unless optional argument INPLACE is non-nil, return a new string." (let ((i (length string)) (newstr (if inplace string (copy-sequence string)))) (while (> i 0) (setq i (1- i)) (if (eq (aref newstr i) fromchar) (aset newstr i tochar))) newstr))) ;; For non-MULE versions of xemacs (unless (fboundp 'coding-system-list) (defun coding-system-list (&optional base-only) '(raw-text))) (require 'debug-toolbar) (require 'jde-bug) (require 'jde-compile) ;; Install gui options on XEmacs versions that can understand them (when (and (featurep 'widget) (>= emacs-major-version 21) (>= emacs-minor-version 4) (>= emacs-patch-level 10)) (require 'efc-xemacs)) ;; Redefine toolbar-debug and toolbar-compile so that clicking the ;; icons on the toolbar will pop us into jde functions. (defun toolbar-debug () (interactive) (call-interactively 'jde-debug)) (defun toolbar-compile () (interactive) (call-interactively 'jde-compile)) (add-hook 'jde-bug-minor-mode-hook '(lambda (&optional on) (if on (easy-menu-add jde-bug-menu-spec jde-bug-mode-map) (easy-menu-remove jde-bug-menu-spec)))) (defvar jde-xemacs-old-toolbar nil "Saved toolbar for buffer.") (defvar jde-xemacs-old-hooks nil "Saved hooks for buffer.") (defvar jde-xemacs-bug-mode-active nil "Indicates whether jde-xemacs-bug-minor-mode is active.") (defvar jde-xemacs-bug-minor-mode nil "Indicates whether buffer is in jde-xemacs-bug-minor-mode or not") (make-variable-buffer-local 'jde-xemacs-bug-minor-mode) ;; Make sure we only get the toolbar when we start debugging. (add-hook 'jde-dbs-debugger-hook 'jde-xemacs-bug-minor-mode) (defvar jde-xemacs-bug-initial-readonly 'undefined "read-only status of buffer when not in jde-xemacs-bug-minor-mode") (defvar jde-xemacs-bug-minor-mode-map (let ((map (make-sparse-keymap))) (suppress-keymap map) (set-keymap-name map 'jde-xemacs-bug-minor-mode-map) ; (set-keymap-parent map jde-bug-mode-map) (define-key map "\C-x\C-q" 'jde-xemacs-bug-minor-mode) ; toggle read-only (define-key map "c" 'jde-bug-continue) (define-key map "n" 'jde-bug-step-over) (define-key map "i" 'jde-bug-step-into) (define-key map "b" 'jde-bug-toggle-breakpoint) (define-key map "r" 'jde-bug-step-out) (define-key map "g" 'jde-debug) (define-key map "u" 'jde-bug-up-stack) (define-key map "d" 'jde-bug-down-stack) (define-key map "p" 'jde-bug-evaluate-expression) (define-key map "q" 'jde-bug-exit) map) "Minor keymap for buffers in jde-xemacs-bug-minor-mode") ;; Create a new minor mode jde-bug-minor-mode is no good because it is ;; unconditionally on. (semantic-add-minor-mode 'jde-xemacs-bug-minor-mode "[src]" jde-xemacs-bug-minor-mode-map) (defvar jde-xemacs-toolbar '([debug::toolbar-stop-at-icon jde-bug-toggle-breakpoint t "Stop at selected position"] [debug::toolbar-stop-in-icon jde-bug-set-conditional-breakpoint nil "Stop in function whose name is selected"] [debug::toolbar-clear-at-icon jde-bug-toggle-breakpoint t "Clear at selected position"] [debug::toolbar-evaluate-icon jde-bug-evaluate-expression (and (jde-dbs-debugger-running-p) (jde-dbs-get-target-process)) "Evaluate selected expression"] [debug::toolbar-run-icon jde-debug t "Run current program"] [debug::toolbar-cont-icon jde-bug-continue (jde-dbs-target-process-runnable-p) "Continue current program"] [debug::toolbar-step-into-icon jde-bug-step-into (jde-dbs-target-process-steppable-p) "Step into (aka step)"] [debug::toolbar-step-over-icon jde-bug-step-over (jde-dbs-target-process-steppable-p) "Step over (aka next)"] [debug::toolbar-up-icon jde-xemacs-toolbar-up (or (not (jde-dbs-target-process-steppable-p)) (let* ((process (jde-dbs-get-target-process)) (stack-max (if (slot-boundp process 'stack) (1- (length (oref process stack))) 0)) (stack-ptr (oref process stack-ptr))) (< stack-ptr stack-max))) "Go Up (towards \"cooler\" - less recently visited - frames, or superclass)"] [debug::toolbar-down-icon jde-xemacs-toolbar-down (or (not (jde-dbs-target-process-steppable-p)) (let* ((process (jde-dbs-get-target-process)) (stack-ptr (oref process stack-ptr))) (> stack-ptr 0))) "Go Down (towards \"warmer\" - more recently visited - frames, or class at point)"] [debug::toolbar-fix-icon nil nil "Fix (not available with jde-bug)"] [debug::toolbar-build-icon jde-compile t "Compile the current file"] )) (defun jde-xemacs-bug-minor-mode (arg &optional quiet) "Minor mode for interacting with JDEbug from a Java source file. With arg, turn jde-xemacs-bug-minor-mode on iff arg is positive. In jde-xemacs-bug-minor-mode, you may send an associated JDEbug buffer commands from the current buffer containing Java source code." (interactive "P") (setq jde-xemacs-bug-minor-mode (if (null arg) (not jde-xemacs-bug-minor-mode) (> (prefix-numeric-value arg) 0))) (cond (jde-xemacs-bug-minor-mode ;; Turn on jde-xemacs-bug-minor-mode (when (not (local-variable-p 'jde-xemacs-bug-initial-readonly (current-buffer))) (set (make-local-variable 'jde-xemacs-bug-initial-readonly) buffer-read-only)) (jde-xemacs-insert-toolbar nil) (setq buffer-read-only t) ;; Save old hooks and make sure we get turned on for new ;; buffers. (unless jde-xemacs-bug-mode-active (setq jde-xemacs-old-hooks jde-entering-java-buffer-hook) (setq jde-entering-java-buffer-hook '(jde-xemacs-bug-minor-mode-hook)) ;; Make sure turning off jde-bug mode turns us off also. (add-hook 'jde-bug-minor-mode-hook 'jde-xemacs-bug-minor-mode) (setq jde-xemacs-bug-mode-active t)) ;; Killing the buffer kills the mode (make-local-hook 'kill-buffer-hook) (add-hook 'kill-buffer-hook 'jde-xemacs-bug-minor-mode-reset nil t) (or quiet (message "Entering jde-xemacs-bug-minor-mode..."))) (t ;; Turn off jde-xemacs-bug-minor-mode (and (local-variable-p 'jde-xemacs-bug-initial-readonly (current-buffer)) (progn (setq buffer-read-only jde-xemacs-bug-initial-readonly) (kill-local-variable 'jde-xemacs-bug-initial-readonly) )) (jde-xemacs-insert-toolbar t) ;; First time through kill the hooks and reset all other ;; associated buffers. (when jde-xemacs-bug-mode-active (setq jde-entering-java-buffer-hook jde-xemacs-old-hooks) (setq jde-xemacs-old-hooks nil) (setq jde-xemacs-bug-mode-active nil) (remove-hook 'jde-bug-minor-mode-hook 'jde-xemacs-bug-minor-mode) (jde-xemacs-bug-minor-mode-reset)) (or quiet (message "Exiting jde-xemacs-bug-minor-mode...")))) (redraw-modeline t)) (defun jde-xemacs-bug-minor-mode-hook () "Hook function to run when entering a Java buffer while in bug-minor-mode." (jde-xemacs-bug-minor-mode t t)) (defun jde-xemacs-bug-minor-mode-reset () ;; tidy house and turn off jde-xemacs-bug-minor-mode in all buffers (mapcar #'(lambda (buffer) (set-buffer buffer) (cond ((local-variable-p 'jde-xemacs-bug-initial-readonly (current-buffer)) (jde-xemacs-bug-minor-mode -1 t)))) (buffer-list))) ;;;###autoload (defun jde-xemacs-insert-toolbar (&optional remove) "Insert or remove JDE toolbar in the XEmacs toolbar." (interactive "P") (when (featurep 'toolbar) (if remove (progn (if (and jde-xemacs-old-toolbar (not (eq jde-xemacs-old-toolbar 'default))) (set-specifier default-toolbar (cons (current-buffer) jde-xemacs-old-toolbar)) (remove-specifier default-toolbar (current-buffer))) (kill-local-variable 'jde-xemacs-old-toolbar)) (unless jde-xemacs-old-toolbar (set (make-local-variable 'jde-xemacs-old-toolbar) (or (specifier-specs default-toolbar (current-buffer)) 'default))) (set-specifier default-toolbar (cons (current-buffer) jde-xemacs-toolbar))))) (defun jde-xemacs-toolbar-up () (interactive) (if (jde-dbs-target-process-steppable-p) (jde-bug-up-stack) (jde-show-superclass-source))) (defun jde-xemacs-toolbar-down () (interactive) (if (jde-dbs-target-process-steppable-p) (jde-bug-down-stack) (jde-show-class-source))) (provide 'jde-xemacs)