Initial Commit
[packages] / xemacs-packages / crisp / crisp.el
1 ;; @(#) crisp.el -- CRiSP/Brief Emacs emulator
2
3 ;; Author: Gary D. Foster <Gary.Foster@gmail.com>
4 ;; Created: 01 Mar 1996
5 ;; Version: 1.35
6 ;; Keywords: emulations brief crisp
7 ;; X-Modified-by:
8 ;;      crisp.el,v
9 ;;      Revision 1.34  1998/08/11 21:18:53  gfoster
10 ;;      Rewrote large portions to further abstract the functionality
11 ;;      and enhance the portability.  Significant contributions from
12 ;;      RMS.
13 ;;
14 ;;      No new functionality this time.
15 ;;
16 ;;      Revision 1.33  1998/06/19 00:40:55  gfoster
17 ;;      Abstract the marking and selection interfaces so that we can be
18 ;;      compatible with both GNU Emacs and XEmacs... and try and make the
19 ;;      behavior as close as possible under both environments so that there
20 ;;      are no surprises.
21 ;;
22 ;;      Revision 1.32  1998/04/14 16:53:49  gfoster
23 ;;      change email address _again_
24 ;;
25 ;;      Revision 1.31  1997/12/23 07:38:09  gfoster
26 ;;      More cleanup on the bug report function I robbed from Barry.
27 ;;
28 ;;      Revision 1.30  1997/12/23 07:17:52  gfoster
29 ;;      removed S-right and S-left bindings.  Don't know where my head was on
30 ;;      these.
31 ;;
32 ;;      Revision 1.29  1997/12/03 07:24:53  gfoster
33 ;;      removed cc-vars dependency left over from swiping the bug-report defun
34 ;;
35 ;;      Revision 1.28  1997/11/26 16:18:43  gfoster
36 ;;      Removed reference to CC mode in doc string for
37 ;;      `crisp-submit-bug-report'
38 ;;      no need to save point on crisp-copy-line
39 ;;
40 ;;      Revision 1.27  1997/11/19 07:03:16  gfoster
41 ;;      changed bug email address
42 ;;
43 ;;      Revision 1.26  1997/11/18 05:41:02  gfoster
44 ;;      Added several new keybindings:
45 ;;              C-home  top of window
46 ;;              C-end   bottom of window
47 ;;              M-home  beginning of line
48 ;;              M-end   end-of-line
49 ;;              C-F     format region
50 ;;              M-l     mark line
51 ;;              M-m     set mark
52 ;;      Added crisp-version function
53 ;;
54 ;;      Revision 1.25  1997/11/18 04:19:09  gfoster
55 ;;      Shortened the version numbering, removed the release-version tracking
56 ;;
57 ;;      Revision 1.24  1997/11/18 04:15:54  gfoster
58 ;;      Added `crisp-submit-bug-report' (shamelessly cribbed from Barry's
59 ;;      cc-mode.  Thanks Barry!)
60 ;;
61 ;;      Bound the above to C-c b
62 ;;
63 ;;      Changed the behavior of `crisp-(kill|copy)-line' so (kill|copy)ing
64 ;;      works on the region from point to eol instead of the entire line, when
65 ;;      a region is not highlighted.
66 ;;
67 ;;      Revision 1.23  1997/11/11 19:47:02  gfoster
68 ;;      Merged changes suggested by Hrvoje Niksic
69 ;;         make crisp-mode-map a sparse keymap parented from current-global-map
70 ;;         don't copy the keymap in (crisp-mode-original-keymap)
71 ;;         declare last-last-command to shut up the byte-compiler
72 ;;         make (crisp-mode) honor ARG
73 ;;
74 ;;      Revision 1.22  1997/11/11 19:37:44  gfoster
75 ;;      kp-add/minus now copy/kill the current line if there is no highlighted
76 ;;      region.  These also honor the universal prefix argument conventions.
77 ;;
78 ;;      Revision 1.21  1997/10/16 18:52:54  gfoster
79 ;;      Fixed bogus XEmacs/Lucid string-match checking
80 ;;      made modeline entry mouse2-able
81 ;;
82 ;;      Revision 1.20  1997/08/22 18:49:11  gfoster
83 ;;      Added next-buffer/previous-buffer keybindings (bound to M-n/M-p)
84 ;;      Added crisp-unbury-buffer function
85 ;;      Standardized headers for Steve
86 ;;
87
88 ;; This file is part of XEmacs.
89
90 ;; XEmacs is free software; you can redistribute it and/or modify it
91 ;; under the terms of the GNU General Public License as published by
92 ;; the Free Software Foundation; either version 2, or (at your option)
93 ;; any later version.
94
95 ;; XEmacs is distributed in the hope that it will be useful, but
96 ;; WITHOUT ANY WARRANTY; without even the implied warranty of
97 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
98 ;; General Public License for more details.
99
100 ;; You should have received a copy of the GNU General Public License
101 ;; along with XEmacs; see the file COPYING.  If not, write to the Free
102 ;; Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
103 ;; 02111-1307, USA.
104
105 ;; CRiSP is a registered trademark of Foxtrot Systems Ltd.
106
107 ;;; Commentary:
108
109 ;; Keybindings and minor functions to duplicate the functionality and
110 ;; finger-feel of the CRiSP/Brief editor.  This package is designed to
111 ;; facilitate transitioning from Brief to (XE|E)macs with a minimum
112 ;; amount of hassles.
113
114 ;; Enable this package by putting (require 'crisp) in your .emacs and
115 ;; use M-x crisp-mode to toggle it on or off.
116
117 ;; This package will automatically load the scroll-lock.el package if
118 ;; you put (setq crisp-load-scroll-lock t) in your .emacs before
119 ;; loading this package.  If this feature is enabled, it will bind
120 ;; meta-f1 to the scroll-lock mode toggle.  The scroll-lock package
121 ;; duplicates the scroll-locking feature in CRiSP.
122
123 ;; Also, the default keybindings for brief/CRiSP override the M-x
124 ;; key to exit the editor.  If you don't like this functionality, you
125 ;; can prevent this behavior (or redefine it dynamically) by setting
126 ;; the value of `crisp-override-meta-x' either in your .emacs or
127 ;; interactively.  The default setting is nil, which means that M-x will
128 ;; by default run `execute-extended-command' instead of the command
129 ;; `save-buffers-kill-emacs'.
130
131 ;; Finally, if you want to change the string displayed in the modeline
132 ;; when this mode is in effect, override the definition of
133 ;; `crisp-mode-modeline-string' in your .emacs.  The default value is
134 ;; " *Crisp*" which may be a bit lengthy if you have a lot of things
135 ;; being displayed there.
136
137 ;; All these overrides should go *before* the (require 'crisp) statement.
138
139 ;; Code:
140
141 ;; local variables
142
143 (defgroup crisp nil
144   "Emulator for CRiSP and Brief key bindings."
145   :prefix "crisp-"
146   :group 'emulations)
147
148 (defvar crisp-mode-map (let ((map (make-sparse-keymap)))
149                          (set-keymap-parent map (current-global-map))
150                          map)
151   "Local keymap for CRiSP emulation mode.
152 All the bindings are done here instead of globally to try and be
153 nice to the world.")
154
155 (defcustom crisp-mode-modeline-string " *CRiSP*"
156   "*String to display in the modeline when CRiSP emulation mode is enabled."
157   :type 'string
158   :group 'crisp)
159
160 (defvar crisp-mode-original-keymap (current-global-map)
161   "The original keymap before CRiSP emulation mode remaps anything.
162 This keymap is restored when CRiSP emulation mode is disabled.")
163
164 (defcustom crisp-mode-enabled nil
165   "Track status of CRiSP emulation mode.
166 A value of nil means CRiSP mode is not enabled.  A value of t
167 indicates CRiSP mode is enabled."
168   :type 'boolean
169   :group 'crisp)
170
171 (defcustom crisp-override-meta-x t
172   "*Controls overriding the normal Emacs M-x key binding in the CRiSP emulator.
173 Normally the CRiSP emulator rebinds M-x to `save-buffers-exit-emacs', and
174 provides the usual M-x functionality on the F10 key.  If this variable
175 is non-nil, M-x will exit Emacs."
176   :type 'boolean
177   :group 'crisp)
178
179 (defcustom crisp-load-scroll-lock nil
180   "Controls loading of the Scroll Lock in the CRiSP emulator.
181 Its default behavior is to load and enable the Scroll Lock minor mode
182 package when enabling the CRiSP emulator.
183
184 If this variable is nil when you start the CRiSP emulator, it
185 does not load the scroll-lock package."
186   :type 'boolean
187   :group 'crisp)
188
189 (defcustom crisp-load-hook nil
190   "Hooks to run after loading the CRiSP emulator package."
191   :type 'hook
192   :group 'crisp)
193
194 (defconst crisp-version "1.35"
195   "The version of the CRiSP emulator.")
196
197 (defconst crisp-mode-help-address "Gary.Foster@gmail.com"
198   "The email address of the CRiSP mode author/maintainer.")
199
200 ;; Silence the byte-compiler.
201 (defvar crisp-last-last-command nil
202   "The previous value of `last-command'.")
203
204 ;; The cut and paste routines are different between XEmacs and Emacs
205 ;; so we need to set up aliases for the functions.
206
207 (defalias 'crisp-set-clipboard
208   (if (fboundp 'clipboard-kill-ring-save)
209       'clipboard-kill-ring-save
210     'copy-primary-selection))
211
212 (defalias 'crisp-kill-region
213   (if (fboundp 'clipboard-kill-region)
214       'clipboard-kill-region
215     'kill-primary-selection))
216
217 (defalias 'crisp-yank-clipboard
218   (if (fboundp 'clipboard-yank)
219       'clipboard-yank
220     'yank-clipboard-selection))
221
222 ;; force transient-mark-mode in Emacs, so that the marking routines
223 ;; work as expected.  If the user turns off transient mark mode,
224 ;; most things will still work fine except the crisp-(copy|kill)
225 ;; functions won't work quite as nicely when regions are marked
226 ;; differently and could really confuse people.  Caveat emptor.
227
228 (if (fboundp 'transient-mark-mode)
229     (transient-mark-mode t))
230
231 (defun crisp-region-active ()
232   "Compatibility function to test for an active region."
233   (if (boundp 'zmacs-region-active-p)
234       zmacs-region-active-p
235     mark-active))
236
237 ;; and now the keymap defines
238
239 (define-key crisp-mode-map [(f1)]           'other-window)
240
241 (define-key crisp-mode-map [(f2) (down)]    'enlarge-window)
242 (define-key crisp-mode-map [(f2) (left)]    'shrink-window-horizontally)
243 (define-key crisp-mode-map [(f2) (right)]   'enlarge-window-horizontally)
244 (define-key crisp-mode-map [(f2) (up)]      'shrink-window)
245 (define-key crisp-mode-map [(f3) (down)]    'split-window-vertically)
246 (define-key crisp-mode-map [(f3) (right)]   'split-window-horizontally)
247
248 (define-key crisp-mode-map [(f4)]           'delete-window)
249 (define-key crisp-mode-map [(control f4)]   'delete-other-windows)
250
251 (define-key crisp-mode-map [(f5)]           'search-forward-regexp)
252 (define-key crisp-mode-map [(f19)]          'search-forward-regexp)
253 (define-key crisp-mode-map [(meta f5)]      'search-backward-regexp)
254
255 (define-key crisp-mode-map [(f6)]           'query-replace)
256
257 (define-key crisp-mode-map [(f7)]           'start-kbd-macro)
258 (define-key crisp-mode-map [(meta f7)]      'end-kbd-macro)
259
260 (define-key crisp-mode-map [(f8)]           'call-last-kbd-macro)
261 (define-key crisp-mode-map [(meta f8)]      'save-kbd-macro)
262
263 (define-key crisp-mode-map [(f9)]           'find-file)
264 (define-key crisp-mode-map [(meta f9)]      'load-library)
265
266 (define-key crisp-mode-map [(f10)]          'execute-extended-command)
267 (define-key crisp-mode-map [(meta f10)]     'compile)
268
269 (define-key crisp-mode-map [(SunF37)]       'kill-buffer)
270 (define-key crisp-mode-map [(kp-add)]       'crisp-copy-line)
271 (define-key crisp-mode-map [(kp-subtract)]  'crisp-kill-line)
272 ;; just to cover all the bases (GNU Emacs, for instance)
273 (define-key crisp-mode-map [(f24)]          'crisp-kill-line)
274 (define-key crisp-mode-map [(insert)]       'crisp-yank-clipboard)
275 (define-key crisp-mode-map [(f16)]          'crisp-set-clipboard) ; copy on Sun5 kbd
276 (define-key crisp-mode-map [(f20)]          'crisp-kill-region) ; cut on Sun5 kbd 
277 (define-key crisp-mode-map [(f18)]          'crisp-yank-clipboard) ; paste on Sun5 kbd
278
279 (define-key crisp-mode-map [(control f)]    'fill-paragraph-or-region)
280 (define-key crisp-mode-map [(meta d)]       (lambda ()
281                                               (interactive)
282                                               (beginning-of-line) (kill-line)))
283 (define-key crisp-mode-map [(meta e)]       'find-file)
284 (define-key crisp-mode-map [(meta g)]       'goto-line)
285 (define-key crisp-mode-map [(meta h)]       'help)
286 (define-key crisp-mode-map [(meta i)]       'overwrite-mode)
287 (define-key crisp-mode-map [(meta j)]       'bookmark-jump)
288 (define-key crisp-mode-map [(meta l)]       'crisp-mark-line)
289 (define-key crisp-mode-map [(meta m)]       'set-mark-command)
290 (define-key crisp-mode-map [(meta n)]       'bury-buffer)
291 (define-key crisp-mode-map [(meta p)]       'crisp-unbury-buffer)
292 (define-key crisp-mode-map [(meta u)]       'advertised-undo)
293 (define-key crisp-mode-map [(f14)]          'advertised-undo)
294 (define-key crisp-mode-map [(meta w)]       'save-buffer)
295 (define-key crisp-mode-map [(meta x)]       'crisp-meta-x-wrapper)
296 (define-key crisp-mode-map [(meta ?0)]      (lambda ()
297                                               (interactive)
298                                               (bookmark-set "0")))
299 (define-key crisp-mode-map [(meta ?1)]      (lambda ()
300                                               (interactive)
301                                               (bookmark-set "1")))
302 (define-key crisp-mode-map [(meta ?2)]      (lambda ()
303                                               (interactive)
304                                               (bookmark-set "2")))
305 (define-key crisp-mode-map [(meta ?3)]      (lambda ()
306                                               (interactive)
307                                               (bookmark-set "3")))
308 (define-key crisp-mode-map [(meta ?4)]      (lambda ()
309                                               (interactive)
310                                               (bookmark-set "4")))
311 (define-key crisp-mode-map [(meta ?5)]      (lambda ()
312                                               (interactive)
313                                               (bookmark-set "5")))
314 (define-key crisp-mode-map [(meta ?6)]      (lambda ()
315                                               (interactive)
316                                               (bookmark-set "6")))
317 (define-key crisp-mode-map [(meta ?7)]      (lambda ()
318                                               (interactive)
319                                               (bookmark-set "7")))
320 (define-key crisp-mode-map [(meta ?8)]      (lambda ()
321                                               (interactive)
322                                               (bookmark-set "8")))
323 (define-key crisp-mode-map [(meta ?9)]      (lambda ()
324                                               (interactive)
325                                               (bookmark-set "9")))
326
327 (define-key crisp-mode-map [(shift delete)]    'kill-word)
328 (define-key crisp-mode-map [(shift backspace)] 'backward-kill-word)
329 (define-key crisp-mode-map [(control left)]    'backward-word)
330 (define-key crisp-mode-map [(control right)]   'forward-word)
331
332 (define-key crisp-mode-map [(home)]            'crisp-home)
333 (define-key crisp-mode-map [(control home)]    (lambda ()
334                                                  (interactive)
335                                                  (move-to-window-line 0)))
336 (define-key crisp-mode-map [(meta home)]       'beginning-of-line)
337 (define-key crisp-mode-map [(end)]             'crisp-end)
338 (define-key crisp-mode-map [(control end)]     (lambda ()
339                                                  (interactive)
340                                                  (move-to-window-line -1)))
341 (define-key crisp-mode-map [(meta end)]        'end-of-line)
342
343 (define-key crisp-mode-map [(control c) (b)]   'crisp-submit-bug-report)
344
345 (defun crisp-version (&optional arg)
346   "Version number of the CRiSP emulator package.
347 If ARG, insert results at point."
348   (interactive "P")
349   (let ((foo (concat "CRiSP version " crisp-version)))
350     (if arg
351         (insert (message foo))
352       (message foo))))
353
354 (defun crisp-mark-line (arg)
355   "Set mark at the end of the line.  Arg works as in `end-of-line'."
356   (interactive "p")
357   (let (newmark)
358     (save-excursion
359       (end-of-line arg)
360       (setq newmark (point)))
361     (push-mark newmark nil t)))
362
363 (defun crisp-kill-line (arg)
364   "Mark and kill line(s).
365 Marks from point to end of the current line (honoring prefix arguments),
366 copies the region to the kill ring and clipboard, and then deletes it."
367   (interactive "*p")
368   (if (crisp-region-active)
369       (call-interactively 'crisp-kill-region)
370     (crisp-mark-line arg)
371     (call-interactively 'crisp-kill-region)))
372
373 (defun crisp-copy-line (arg)
374   "Mark and copy line(s).
375 Marks from point to end of the current line (honoring prefix arguments),
376 copies the region to the kill ring and clipboard, and then deactivates
377 the region."
378   (interactive "*p")
379     (if (crisp-region-active)
380         (call-interactively 'crisp-set-clipboard)
381       (crisp-mark-line arg)
382       (call-interactively 'crisp-set-clipboard))
383     ;; clear the region after the operation is complete
384     ;; XEmacs does this automagically, Emacs doesn't.
385     (if (boundp 'mark-active)
386         (setq mark-active nil)))
387
388 (defun crisp-home ()
389   "\"Home\" the point, the way CRiSP would do it.
390 The first use moves point to beginning of the line.  Second
391 consecutive use moves point to beginning of the screen.  Third
392 consecutive use moves point to the beginning of the buffer."
393   (interactive nil)
394   (cond
395     ((and (eq last-command 'crisp-home)
396           (eq crisp-last-last-command 'crisp-home))
397      (goto-char (point-min)))
398     ((eq last-command 'crisp-home)
399      (move-to-window-line 0))
400     (t
401      (beginning-of-line)))
402   (setq crisp-last-last-command last-command))
403
404 (defun crisp-end ()
405   "\"End\" the point, the way CRiSP would do it.
406 The first use moves point to end of the line.  Second
407 consecutive use moves point to the end of the screen.  Third
408 consecutive use moves point to the end of the buffer."
409   (interactive nil)
410   (cond
411     ((and (eq last-command 'crisp-end)
412           (eq crisp-last-last-command 'crisp-end))
413      (goto-char (point-max)))
414     ((eq last-command 'crisp-end)
415      (move-to-window-line -1)
416      (end-of-line))
417     (t
418      (end-of-line)))
419   (setq crisp-last-last-command last-command))
420
421 (defun crisp-unbury-buffer ()
422   "Go back one buffer"
423   (interactive)
424   (switch-to-buffer (car (last (buffer-list)))))
425  
426 (defun crisp-meta-x-wrapper ()
427   "Wrapper function to conditionally override the normal M-x bindings.
428 When `crisp-override-meta-x' is non-nil, M-x will exit Emacs (the
429 normal CRiSP binding) and when it is nil M-x will run
430 `execute-extended-command' (the normal Emacs binding)."
431   (interactive)
432   (if crisp-override-meta-x
433       (save-buffers-kill-emacs)
434     (call-interactively 'execute-extended-command)))
435
436 ;; bug reporter
437
438 (defun crisp-submit-bug-report ()
439   "Submit via mail a bug report on CRiSP Mode."
440   (interactive)
441   ;; load in reporter
442   (let ((reporter-prompt-for-summary-p t)
443         (reporter-dont-compact-list '(c-offsets-alist)))
444     (and
445      (if (y-or-n-p "Do you want to submit a report on CRiSP Mode? ")
446          t (message "") nil)
447      (require 'reporter)
448      (reporter-submit-bug-report
449       crisp-mode-help-address
450       (concat "CRiSP Mode [" crisp-version "]")
451       nil
452       nil
453       nil
454       "Dear Gary,"
455       ))))
456
457 ;; Now enable the mode
458
459 (defun crisp-mode (&optional arg)
460   "Toggle CRiSP emulation minor mode.
461 With ARG, turn CRiSP mode on if ARG is positive, off otherwise."
462   (interactive "P")
463   (setq crisp-mode-enabled (if (null arg)
464                                (not crisp-mode-enabled)
465                              (> (prefix-numeric-value arg) 0)))
466   (cond
467    ((eq crisp-mode-enabled 't)
468     (use-global-map crisp-mode-map)
469     (if crisp-load-scroll-lock
470         (require 'scroll-lock))
471     (if (featurep 'scroll-lock)
472         (define-key crisp-mode-map [(meta f1)] 'scroll-lock-mode))
473     (run-hooks 'crisp-load-hook))
474    ((eq crisp-mode-enabled 'nil)
475     (use-global-map crisp-mode-original-keymap))))
476
477 (if (fboundp 'add-minor-mode)
478     (add-minor-mode 'crisp-mode-enabled 'crisp-mode-modeline-string
479                     nil nil 'crisp-mode)
480   (or (assq 'crisp-mode-enabled minor-mode-alist)
481       (setq minor-mode-alist
482             (cons '(crisp-mode-enabled crisp-mode-modeline-string) minor-mode-alist))))
483
484 (provide 'crisp)
485
486 ;;; crisp.el ends here
487