1 ;;; jde-xemacs.el -- xemacs specific code for JDEE.
2 ;; Keywords: java, tools, debugging
4 ;; Copyright (C) 2002, 2003, 2004 Andy Piper <andy@xemacs.org>
5 ;; Copyright (C) 2002 Paul Kinnucan <paulk@mathworks.com>
7 ;; This file is part of XEmacs.
9 ;; XEmacs is free software; you can redistribute it and/or modify
10 ;; it under the terms of the GNU General Public License as published by
11 ;; the Free Software Foundation; either version 2 of the License, or
12 ;; (at your option) any later version.
14 ;; XEmacs is distributed in the hope that it will be useful,
15 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
16 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 ;; GNU General Public License for more details.
19 ;; You should have received a copy of the GNU General Public License
20 ;; along with XEmacs; if not, write to the Free Software
21 ;; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 ;; Please send bug reports and enhancement suggestions
24 ;; to Andy Piper at <andy@xemacs.org>
26 ;; If you don't use XEmacs, you should! XEmacs kicks some serious
30 ;; XEmacs doesn't have replace-regexp-in-string so define our own
32 (unless (fboundp 'replace-regexp-in-string)
33 (defun replace-regexp-in-string (regexp rep string &optional
34 fixedcase literal subexp start)
35 "Replace all matches for REGEXP with REP in STRING.
37 Return a new string containing the replacements.
39 Optional arguments FIXEDCASE, LITERAL and SUBEXP are like the
40 arguments with the same names of function `replace-match'. If START
41 is non-nil, start replacements at that index in STRING.
43 REP is either a string used as the NEWTEXT arg of `replace-match' or a
44 function. If it is a function it is applied to each match to generate
45 the replacement passed to `replace-match'; the match-data at this
46 point are such that match 0 is the function's argument.
48 To replace only the first match (if any), make REGEXP match up to \\'
49 and replace a sub-expression, e.g.
50 (replace-regexp-in-string \"\\(foo\\).*\\'\" \"bar\" \" foo foo\" nil nil 1)
54 ;; To avoid excessive consing from multiple matches in long strings,
55 ;; don't just call `replace-match' continually. Walk down the
56 ;; string looking for matches of REGEXP and building up a (reversed)
57 ;; list MATCHES. This comprises segments of STRING which weren't
58 ;; matched interspersed with replacements for segments that were.
59 ;; [For a `large' number of replacments it's more efficient to
60 ;; operate in a temporary buffer; we can't tell from the function's
61 ;; args whether to choose the buffer-based implementation, though it
62 ;; might be reasonable to do so for long enough STRING.]
63 (let ((l (length string))
67 (while (and (< start l) (string-match regexp string start))
68 (setq mb (match-beginning 0)
70 ;; If we matched the empty string, make sure we advance by one char
71 (when (= me mb) (setq me (min l (1+ mb))))
72 ;; Generate a replacement for the matched substring.
73 ;; Operate only on the substring to minimize string consing.
74 ;; Set up match data for the substring for replacement;
75 ;; presumably this is likely to be faster than munging the
76 ;; match data directly in Lisp.
77 (string-match regexp (setq str (substring string mb me)))
79 (cons (replace-match (if (stringp rep)
81 (funcall rep (match-string 0 str)))
82 fixedcase literal str subexp)
83 (cons (substring string start mb) ; unmatched prefix
86 ;; Reconstruct a string from the pieces.
87 (setq matches (cons (substring string start l) matches)) ; leftover
88 (apply #'concat (nreverse matches)))))
91 (unless (fboundp 'subst-char-in-string)
92 (defun subst-char-in-string (fromchar tochar string &optional inplace)
93 "Replace FROMCHAR with TOCHAR in STRING each time it occurs.
94 Unless optional argument INPLACE is non-nil, return a new string."
95 (let ((i (length string))
96 (newstr (if inplace string (copy-sequence string))))
99 (if (eq (aref newstr i) fromchar)
100 (aset newstr i tochar)))
103 ;; For non-MULE versions of xemacs
104 (unless (fboundp 'coding-system-list)
105 (defun coding-system-list (&optional base-only)
108 ;; XEmacs is missing `match-string-no-properties'.
109 (unless (fboundp 'match-string-no-properties)
110 (defun match-string-no-properties (num &optional string)
111 "Return string of text matched by last search, without text properties.
112 NUM specifies which parenthesized expression in the last regexp.
113 Value is nil if NUMth pair didn't match, or there were less than NUM pairs.
114 Zero means the entire text matched by the whole regexp or whole string.
115 STRING should be given if the last search was by `string-match' on STRING."
116 (let ((match (match-string num string)))
117 (and match (set-text-properties 0 (length match) nil match))
120 (unless (fboundp 'line-beginning-position)
121 (defun line-beginning-position (&optional n)
122 "Return the character position of the first character on the
123 current line. With argument N not nil or 1, move forward N - 1 lines first.
124 If scan reaches end of buffer, return that position."
125 (save-excursion (beginning-of-line n) (point))))
127 (unless (fboundp 'line-end-position)
128 (defun line-end-position (&optional n)
129 "Return the character position of the last character on the
130 current line. With argument N not nil or 1, move forward N - 1 lines first.
131 If scan reaches end of buffer, return that position."
132 (save-excursion (end-of-line n) (point))))
134 ;; XEmacs does not define run-with-timer and run-with-idle-timer
136 (unless (fboundp 'run-with-timer)
137 (defun run-with-timer (secs repeat function &rest args)
138 (start-itimer "timer" function secs repeat
139 nil (if args t nil) args))
140 (defun run-with-idle-timer (secs repeat function &rest args)
141 (start-itimer "idle timer"
142 function secs (if repeat secs nil)
143 t (if args t nil) args)))
145 (when (featurep 'toolbar)
146 (require 'debug-toolbar))
149 (require 'jde-compile)
151 ;; Install gui options on XEmacs versions that can understand them
152 (when (and (featurep 'widget)
153 (>= emacs-major-version 21)
154 (>= emacs-minor-version 4)
155 (>= emacs-patch-level 10))
156 (require 'efc-xemacs))
158 ;; Redefine toolbar-debug and toolbar-compile so that clicking the
159 ;; icons on the toolbar will pop us into jde functions.
160 (defun toolbar-debug ()
162 (call-interactively 'jde-debug))
164 (defun toolbar-compile ()
166 (call-interactively 'jde-compile))
168 (add-hook 'jde-bug-minor-mode-hook
169 '(lambda (&optional on)
171 (easy-menu-add jde-bug-menu-spec jde-bug-mode-map)
172 (easy-menu-remove jde-bug-menu-spec))))
174 (defvar jde-xemacs-old-toolbar nil
175 "Saved toolbar for buffer.")
177 (defvar jde-xemacs-old-hooks nil
178 "Saved hooks for buffer.")
180 (defvar jde-xemacs-bug-mode-active nil
181 "Indicates whether jde-xemacs-bug-minor-mode is active.")
183 (defvar jde-xemacs-bug-minor-mode nil
184 "Indicates whether buffer is in jde-xemacs-bug-minor-mode or not")
185 (make-variable-buffer-local 'jde-xemacs-bug-minor-mode)
187 ;; Make sure we only get the toolbar when we start debugging.
188 (add-hook 'jde-dbs-debugger-hook 'jde-xemacs-bug-minor-mode)
190 (defvar jde-xemacs-bug-initial-readonly 'undefined
191 "read-only status of buffer when not in jde-xemacs-bug-minor-mode")
193 (defvar jde-xemacs-bug-minor-mode-map
194 (let ((map (make-sparse-keymap)))
195 (suppress-keymap map)
196 (set-keymap-name map 'jde-xemacs-bug-minor-mode-map)
197 ; (set-keymap-parent map jde-bug-mode-map)
198 (define-key map "\C-x\C-q" 'jde-xemacs-bug-minor-mode) ; toggle read-only
199 (define-key map "c" 'jde-bug-continue)
200 (define-key map "n" 'jde-bug-step-over)
201 (define-key map "i" 'jde-bug-step-into)
202 (define-key map "b" 'jde-bug-toggle-breakpoint)
203 (define-key map "r" 'jde-bug-step-out)
204 (define-key map "g" 'jde-debug)
205 (define-key map "u" 'jde-bug-up-stack)
206 (define-key map "d" 'jde-bug-down-stack)
207 (define-key map "p" 'jde-bug-evaluate-expression)
208 (define-key map "q" 'jde-bug-exit)
210 "Minor keymap for buffers in jde-xemacs-bug-minor-mode")
212 ;; Create a new minor mode jde-bug-minor-mode is no good because it is
213 ;; unconditionally on.
214 (semantic-add-minor-mode 'jde-xemacs-bug-minor-mode "[src]" jde-xemacs-bug-minor-mode-map)
216 (defvar jde-xemacs-toolbar
217 '([debug::toolbar-stop-at-icon
218 jde-bug-toggle-breakpoint
220 "Stop at selected position"]
221 [debug::toolbar-stop-in-icon
222 jde-bug-set-conditional-breakpoint
224 "Stop in function whose name is selected"]
225 [debug::toolbar-clear-at-icon
226 jde-bug-toggle-breakpoint
228 "Clear at selected position"]
229 [debug::toolbar-evaluate-icon
230 jde-bug-evaluate-expression
232 (jde-dbs-debugger-running-p)
233 (jde-dbs-get-target-process))
234 "Evaluate selected expression"]
235 [debug::toolbar-run-icon
238 "Run current program"]
239 [debug::toolbar-cont-icon
241 (jde-dbs-target-process-runnable-p)
242 "Continue current program"]
243 [debug::toolbar-step-into-icon
245 (jde-dbs-target-process-steppable-p)
246 "Step into (aka step)"]
247 [debug::toolbar-step-over-icon
249 (jde-dbs-target-process-steppable-p)
250 "Step over (aka next)"]
251 [debug::toolbar-up-icon
252 jde-xemacs-toolbar-up
254 (not (jde-dbs-target-process-steppable-p))
255 (let* ((process (jde-dbs-get-target-process))
257 (if (slot-boundp process 'stack)
258 (1- (length (oref process stack)))
260 (stack-ptr (oref process stack-ptr)))
261 (< stack-ptr stack-max)))
262 "Go Up (towards \"cooler\" - less recently visited - frames, or superclass)"]
263 [debug::toolbar-down-icon
264 jde-xemacs-toolbar-down
266 (not (jde-dbs-target-process-steppable-p))
267 (let* ((process (jde-dbs-get-target-process))
268 (stack-ptr (oref process stack-ptr)))
270 "Go Down (towards \"warmer\" - more recently visited - frames, or class at point)"]
271 [debug::toolbar-fix-icon
274 "Fix (not available with jde-bug)"]
275 [debug::toolbar-build-icon
278 "Compile the current file"]
281 (defun jde-xemacs-bug-minor-mode (arg &optional quiet)
282 "Minor mode for interacting with JDEbug from a Java source file.
283 With arg, turn jde-xemacs-bug-minor-mode on iff arg is positive. In
284 jde-xemacs-bug-minor-mode, you may send an associated JDEbug buffer commands
285 from the current buffer containing Java source code."
287 (setq jde-xemacs-bug-minor-mode
289 (not jde-xemacs-bug-minor-mode)
290 (> (prefix-numeric-value arg) 0)))
292 (cond (jde-xemacs-bug-minor-mode
293 ;; Turn on jde-xemacs-bug-minor-mode
294 (when (not (local-variable-p 'jde-xemacs-bug-initial-readonly (current-buffer)))
295 (set (make-local-variable 'jde-xemacs-bug-initial-readonly)
297 (jde-xemacs-insert-toolbar nil)
298 (setq buffer-read-only t)
299 ;; Save old hooks and make sure we get turned on for new
301 (unless jde-xemacs-bug-mode-active
302 (setq jde-xemacs-old-hooks jde-entering-java-buffer-hook)
303 (setq jde-entering-java-buffer-hook '(jde-xemacs-bug-minor-mode-hook))
304 ;; Make sure turning off jde-bug mode turns us off also.
305 (add-hook 'jde-bug-minor-mode-hook 'jde-xemacs-bug-minor-mode)
306 (setq jde-xemacs-bug-mode-active t))
307 ;; Killing the buffer kills the mode
308 (make-local-hook 'kill-buffer-hook)
309 (add-hook 'kill-buffer-hook 'jde-xemacs-bug-minor-mode-reset nil t)
310 (or quiet (message "Entering jde-xemacs-bug-minor-mode...")))
312 ;; Turn off jde-xemacs-bug-minor-mode
313 (and (local-variable-p 'jde-xemacs-bug-initial-readonly (current-buffer))
315 (setq buffer-read-only jde-xemacs-bug-initial-readonly)
316 (kill-local-variable 'jde-xemacs-bug-initial-readonly)
318 (jde-xemacs-insert-toolbar t)
319 ;; First time through kill the hooks and reset all other
320 ;; associated buffers.
321 (when jde-xemacs-bug-mode-active
322 (setq jde-entering-java-buffer-hook jde-xemacs-old-hooks)
323 (setq jde-xemacs-old-hooks nil)
324 (setq jde-xemacs-bug-mode-active nil)
325 (remove-hook 'jde-bug-minor-mode-hook 'jde-xemacs-bug-minor-mode)
326 (jde-xemacs-bug-minor-mode-reset))
327 (or quiet (message "Exiting jde-xemacs-bug-minor-mode..."))))
330 (defun jde-xemacs-bug-minor-mode-hook ()
331 "Hook function to run when entering a Java buffer while in bug-minor-mode."
332 (jde-xemacs-bug-minor-mode t t))
334 (defun jde-xemacs-bug-minor-mode-reset ()
335 ;; tidy house and turn off jde-xemacs-bug-minor-mode in all buffers
336 (mapcar #'(lambda (buffer)
338 (cond ((local-variable-p 'jde-xemacs-bug-initial-readonly (current-buffer))
339 (jde-xemacs-bug-minor-mode -1 t))))
343 (defun jde-xemacs-insert-toolbar (&optional remove)
344 "Insert or remove JDE toolbar in the XEmacs toolbar."
346 (when (featurep 'toolbar)
349 (if (and jde-xemacs-old-toolbar (not (eq jde-xemacs-old-toolbar 'default)))
350 (set-specifier default-toolbar
351 (cons (current-buffer)
352 jde-xemacs-old-toolbar))
353 (remove-specifier default-toolbar (current-buffer)))
354 (kill-local-variable 'jde-xemacs-old-toolbar))
355 (unless jde-xemacs-old-toolbar
356 (set (make-local-variable 'jde-xemacs-old-toolbar)
357 (or (specifier-specs default-toolbar (current-buffer)) 'default)))
358 (set-specifier default-toolbar (cons (current-buffer)
359 jde-xemacs-toolbar)))))
361 (defun jde-xemacs-toolbar-up ()
363 (if (jde-dbs-target-process-steppable-p)
365 (jde-show-superclass-source)))
367 (defun jde-xemacs-toolbar-down ()
369 (if (jde-dbs-target-process-steppable-p)
371 (jde-show-class-source)))
373 (provide 'jde-xemacs)