root/trunk/lisp/emulation/edt.el

Revision 4220, 91.7 kB (checked in by miyoshi, 9 months ago)

Sync up with Emacs22.2.

  • Property svn:eol-style set to LF
Line 
1 ;;; edt.el --- enhanced EDT keypad mode emulation for GNU Emacs 19
2
3 ;; Copyright (C) 1986, 1992, 1993, 1994, 1995, 2000, 2001, 2002, 2003,
4 ;;   2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
5
6 ;; Author: Kevin Gallagher <Kevin.Gallagher@boeing.com>
7 ;; Maintainer: Kevin Gallagher <Kevin.Gallagher@boeing.com>
8 ;; Keywords: emulations
9
10 ;; This file is part of GNU Emacs.
11
12 ;; GNU Emacs is free software; you can redistribute it and/or modify
13 ;; it under the terms of the GNU General Public License as published
14 ;; by the Free Software Foundation; either version 3, or (at your
15 ;; option) any later version.
16
17 ;; GNU Emacs is distributed in the hope that it will be useful, but
18 ;; WITHOUT ANY WARRANTY; without even the implied warranty of
19 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
20 ;; General Public License for more details.
21
22 ;; You should have received a copy of the GNU General Public License
23 ;; along with GNU Emacs; see the file COPYING.  If not, write to the
24 ;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
25 ;; Boston, MA 02110-1301, USA.
26
27
28
29 ;;; Commentary:
30 ;;
31
32 ;; This is Version 4.0 of the EDT Emulation for Emacs 19 and above.
33 ;; It comes with special functions which replicate nearly all of EDT's
34 ;; keypad mode behavior.  It sets up default keypad and function key
35 ;; bindings which closely match those found in EDT.  Support is
36 ;; provided so that users may reconfigure most keypad and function key
37 ;; bindings to their own liking.
38
39 ;; NOTE: Version 4.0 contains several enhancements.  See the
40 ;; Enhancement section below for the details.
41
42 ;; Getting Started:
43
44 ;; To start the EDT Emulation, first start Emacs and then enter
45 ;;
46 ;;    M-x edt-emulation-on
47 ;;
48 ;; to begin the emulation.  After initialization is complete, the
49 ;; following message will appear below the status line informing you
50 ;; that the emulation has been enabled: "Default EDT keymap active".
51
52 ;; You can have the EDT Emulation start up automatically, each time
53 ;; you initiate a GNU Emacs session, by adding the following line to
54 ;; your .emacs file:
55 ;;
56 ;;    (add-hook term-setup-hook 'edt-emulation-on)
57
58 ;; IMPORTANT: Be sure to read the file, edt-user.doc, located in the
59 ;; Emacs "etc" directory.  It contains very helpful user information.
60
61 ;; The EDT emulation consists of the following files:
62 ;;
63 ;; edt-user.doc     - User Instructions and Sample Customization File
64 ;; edt.el           - EDT Emulation Functions and Default Configuration
65 ;; edt-lk201.el     - Built-in support for DEC LK-201 Keyboards
66 ;; edt-vt100.el     - Built-in support for DEC VT-100 (and above) terminals
67 ;; edt-pc.el        - Built-in support for PC 101 Keyboards under MS-DOS
68 ;; edt-mapper.el    - Create an EDT LK-201 Map File for Keyboards Without
69 ;;                      Built-in Support
70
71 ;; Enhancements:
72
73 ;; Version 4.0 contains the following enhancements:
74
75 ;;  1.  Scroll margins at the top and bottom of the window are now
76 ;;      supported.  (The design was copied from tpu-extras.el.)  By
77 ;;      default, this feature is enabled, with the top margin set to
78 ;;      10% of the window and the bottom margin set to 15% of the
79 ;;      window.  To change these settings, you can invoke the function
80 ;;      edt-set-scroll-margins in your .emacs file.  For example, the
81 ;;      following line
82 ;;
83 ;;           (edt-set-scroll-margins "20%" "25%")
84 ;;
85 ;;      sets the top margin to 20% of the window and the bottom margin
86 ;;      to 25% of the window.  To disable this feature, set each
87 ;;      margin to 0%.  You can also invoke edt-set-scroll-margins
88 ;;      interactively while EDT Emulation is active to change the
89 ;;      settings for that session.
90 ;;
91 ;;      NOTE: Another way to set the scroll margins is to use the
92 ;;      Emacs customization feature (not available in Emacs 19) to set
93 ;;      the following two variables directly:
94 ;;
95 ;;           edt-top-scroll-margin and edt-bottom-scroll-margin
96 ;;
97 ;;      Enter the Emacs `customize' command.  First select the Editing
98 ;;      group and then select the Emulations group.  Finally, select
99 ;;      the Edt group and follow the directions.
100 ;;
101 ;;  2.  The SUBS command is now supported and bound to GOLD-Enter by
102 ;;      default.  (This design was copied from tpu-edt.el.)  Note, in
103 ;;      earlier versions of EDT Emulation, GOLD-Enter was assigned to
104 ;;      the Emacs function `query-replace'.  The binding of
105 ;;      `query-replace' has been moved to GOLD-/.  If you prefer to
106 ;;      restore `query-replace' to GOLD-Enter, then use an EDT user
107 ;;      customization file, edt-user.el, to do this.  See edt-user.doc
108 ;;      for details.
109
110 ;;  3.  EDT Emulation now also works in XEmacs, including the
111 ;;      highlighting of selected text.
112
113 ;;  4.  If you access a workstation using an X Server, observe that
114 ;;      the initialization file generated by edt-mapper.el will now
115 ;;      contain the name of the X Server vendor.  This is a
116 ;;      convenience for those who have access to their Unix account
117 ;;      from more than one type of X Server.  Since different X
118 ;;      Servers typically require different EDT emulation
119 ;;      initialization files, edt-mapper.el will now generate these
120 ;;      different initialization files and save them with different
121 ;;      names.  Then, the correct initialization file for the
122 ;;      particular X server in use is loaded correctly automatically.
123
124 ;;  5.  Also, edt-mapper.el is now capable of binding an ASCII key
125 ;;      sequence, providing the ASCII key sequence prefix is already
126 ;;      known by Emacs to be a prefix.  As a result of providing this
127 ;;      support, some terminal/keyboard/window system configurations,
128 ;;      which don't have a complete set of sensible function key
129 ;;      bindings built into Emacs in `function-key-map', can still be
130 ;;      configured for use with EDT Emulation.  (Note: In a few rare
131 ;;      circumstances this does not work properly.  In particular, it
132 ;;      does not work if a subset of the leading ASCII characters in a
133 ;;      key sequence are recognized by Emacs as having an existing
134 ;;      binding.  For example, if the keypad 7 (KP-7) key generates
135 ;;      the sequence \"<ESC>Ow\" and \"<ESC>O\" is already bound to a
136 ;;      function, pressing KP-7 when told to do so by edt-mapper.el
137 ;;      will result in edt-mapper.el incorrectly mapping \"<ESC>O\" to
138 ;;      KP-7 and \"w\" to KP-8.  If something like this happens to
139 ;;      you, it is probably a bug in the support for your keyboard
140 ;;      within Emacs OR a bug in the Unix termcap/terminfo support for
141 ;;      your terminal OR a bug in the terminal emulation software you
142 ;;      are using.)
143
144 ;;  6.  The edt-quit function (bound to GOLD-q by default) has been
145 ;;      modified to warn the user when file-related buffer
146 ;;      modifications exist.  It now cautions the user that those
147 ;;      modifications will be lost if the user quits without saving
148 ;;      those buffers.
149
150
151 ;;; History:
152 ;;
153 ;;  Version 4.0    2000    Added New Features and Fixed a Few Bugs
154 ;;
155
156
157 ;;; Code:
158
159 ;;;  Electric Help functions are used for keypad help displays.  A few
160 ;;;  picture functions are used in rectangular cut and paste commands.
161
162 (require 'ehelp)
163 (require 'picture)
164
165 ;;;;
166 ;;;; VARIABLES and CONSTANTS
167 ;;;;
168
169 ;; For backward compatibility to Emacs 19.
170 (or (fboundp 'defgroup)
171     (defmacro defgroup (&rest rest)))
172
173 (defgroup edt nil
174   "Emacs emulating EDT."
175   :prefix "edt-"
176   :group 'emulations)
177
178 ;; To silence the byte-compiler
179 (eval-when-compile
180   (defvar *EDT-keys*)
181   (defvar edt-default-global-map)
182   (defvar edt-last-copied-word)
183   (defvar edt-learn-macro-count)
184   (defvar edt-orig-page-delimiter)
185   (defvar edt-orig-transient-mark-mode)
186   (defvar edt-rect-start-point)
187   (defvar edt-user-global-map)
188   (defvar rect-start-point)
189   (defvar time-string)
190   (defvar zmacs-region-stays))
191
192 ;;;
193 ;;;  Version Information
194 ;;;
195 (defconst edt-version "4.0" "EDT Emulation version number.")
196
197 ;;;
198 ;;;  User Configurable Variables
199 ;;;
200
201 ;; For backward compatibility to Emacs 19.
202 (or (fboundp 'defcustom)
203     (defmacro defcustom (var value doc &rest ignore)
204       `(defvar ,var ,value ,doc)))
205
206 (defcustom edt-keep-current-page-delimiter nil
207   "*Emacs MUST be restarted for a change in value to take effect!
208 Non-nil leaves Emacs value of `page-delimiter' unchanged within EDT
209 Emulation.  If set to nil (the default), the `page-delimiter' variable
210 is set to \"\\f\" when edt-emulation-on is first invoked.  This
211 setting replicates EDT's page delimiter behavior.  The original value
212 is restored when edt-emulation-off is called."
213   :type 'boolean
214   :group 'edt)
215
216 (defcustom edt-use-EDT-control-key-bindings nil
217   "*Emacs MUST be restarted for a change in value to take effect!
218 Non-nil causes the control key bindings to be replaced with EDT
219 bindings.  If set to nil (the default), EDT control key bindings are
220 not used and the current Emacs control key bindings are retained for
221 use within the EDT emulation."
222   :type 'boolean
223   :group 'edt)
224
225 (defcustom edt-word-entities '(?\t)
226   "*Specifies the list of EDT word entity characters.
227 The default list, (\?\\t), contains just the TAB character, which
228 emulates EDT.  Characters are specified in the list using their
229 decimal ASCII values.  A question mark, followed by the actual
230 character, can be used to indicate the numerical value of the
231 character, instead of the actual decimal value.  So, ?A means the
232 numerical value for the letter A, \?/ means the numerical value for /,
233 etc.  Several unprintable and special characters have special
234 representations, which you can also use:
235
236             \?\\b  specifies  BS, C-h
237             \?\\t  specifies  TAB, C-i
238             \?\\n  specifies  LFD, C-j
239             \?\\v  specifies  VTAB, C-k
240             \?\\f  specifies  FF, C-l
241             \?\\r  specifies  CR, C-m
242             \?\\e  specifies  ESC, C-[
243             \?\\\\  specifies  \\
244
245 In EDT Emulation movement-by-word commands, each character in the list
246 will be treated as if it were a separate word."
247   :type '(repeat integer)
248   :group 'edt)
249
250 (defcustom edt-top-scroll-margin 10
251   "*Scroll margin at the top of the screen.
252 Interpreted as a percent of the current window size with a default
253 setting of 10%.  If set to 0, top scroll margin is disabled."
254   :type 'integer
255   :group 'edt)
256
257 (defcustom edt-bottom-scroll-margin 15
258   "*Scroll margin at the bottom of the screen.
259 Interpreted as a percent of the current window size with a default
260 setting of 15%.  If set to 0, bottom scroll margin is disabled."
261   :type 'integer
262   :group 'edt)
263
264 ;;;
265 ;;; Internal Variables
266 ;;;
267
268 (defvar edt-last-deleted-lines ""
269   "Last text deleted by the EDT emulation DEL L command.")
270
271 (defvar edt-last-deleted-words ""
272   "Last text deleted by the EDT emulation DEL W command.")
273
274 (defvar edt-last-deleted-chars ""
275   "Last text deleted by the EDT emulation DEL C command.")
276
277 (defvar edt-find-last-text ""
278   "Last text found by the EDT emulation FIND command.")
279
280 (defvar edt-match-beginning-mark (make-marker)
281   "Used internally by the EDT emulation SUBS command.")
282
283 (defvar edt-match-end-mark (make-marker)
284   "Used internally by the EDT emulation SUBS command.")
285
286 (defvar edt-last-replaced-key-definition nil
287   "Key definition replaced with `edt-define-key' or `edt-learn' command.")
288
289 (defvar edt-direction-string ""
290   "String indicating current direction of movement.")
291
292 (defvar edt-select-mode nil
293   "Non-nil means select mode is active.")
294
295 (defvar edt-select-mode-current ""
296   "Text displayed in mode line to indicate the state of EDT select mode.
297 When select mode is inactive, it is set to an empty string.")
298
299 (defconst edt-select-mode-string " Select"
300   "Used in mode line to indicate select mode is active.")
301
302 (defconst edt-forward-string " ADVANCE"
303   "Direction string in mode line to indicate forward movement.")
304
305 (defconst edt-backward-string "  BACKUP"
306   "Direction string in mode line to indicate backward movement.")
307
308 (defvar edt-default-map-active nil
309   "Non-nil indicates that default EDT emulation key bindings are active.
310 nil means user-defined custom bindings are active.")
311
312 (defvar edt-user-map-configured nil
313   "Non-nil indicates that user custom EDT key bindings are configured.
314 This means that an edt-user.el file was found in the user's `load-path'.")
315
316 (defvar edt-term nil
317   "Specifies the terminal type, if applicable.")
318
319 ;;;
320 ;;;  Emacs version identifiers - currently referenced by
321 ;;;
322 ;;;     o edt-emulation-on      o edt-load-keys
323 ;;;
324 (defconst edt-emacs19-p (not (string-lessp emacs-version "19"))
325   "Non-nil if we are running GNU Emacs or XEmacs version 19, or higher.")
326
327 (defconst edt-x-emacs19-p
328   (and edt-emacs19-p (string-match "XEmacs" emacs-version))
329   "Non-nil if we are running XEmacs version 19, or higher.")
330
331 (defconst edt-gnu-emacs19-p (and edt-emacs19-p (not edt-x-emacs19-p))
332   "Non-nil if we are running GNU Emacs version 19, or higher.")
333
334 (defconst edt-emacs-variant (if edt-gnu-emacs19-p "gnu" "xemacs")
335   "Indicates Emacs variant:  GNU Emacs or XEmacs \(aka Lucid Emacs\).")
336
337 (defconst edt-window-system (if edt-gnu-emacs19-p window-system (console-type))
338   "Indicates window system \(in GNU Emacs\) or console type \(in XEmacs\).")
339
340 (defconst edt-xserver (if (eq edt-window-system 'x)
341                           (if edt-x-emacs19-p
342                               ;; The Cygwin window manager has a `/' in its
343                               ;; name, which breaks the generated file name of
344                               ;; the custom key map file.  Replace `/' with a
345                               ;; `-' to work around that.
346                               (replace-in-string (x-server-vendor) "[ /]" "-")
347                             (subst-char-in-string ?/ ?- (subst-char-in-string ?  ?- (x-server-vendor))))
348                         nil)
349   "Indicates X server vendor name, if applicable.")
350
351 (defvar edt-keys-file nil
352   "User's custom keypad and function keys mappings to emulate LK-201 keyboard.")
353
354 (defvar edt-last-copied-word nil
355   "Last word that the user copied.")
356
357 (defvar zmacs-region-stays)
358
359 ;;;;
360 ;;;; EDT Emulation Commands
361 ;;;;
362
363 ;;; Almost all of EDT's keypad mode commands have equivalent Emacs
364 ;;; function counterparts.  But many of these counterparts behave
365 ;;; somewhat differently in Emacs.
366 ;;;
367 ;;; So, the following Emacs functions emulate, where practical, the
368 ;;; exact behavior of the corresponding EDT keypad mode commands.  In
369 ;;; a few cases, the emulation is not exact, but it should be close
370 ;;; enough for most EDT die-hards.
371 ;;;
372
373 ;;;
374 ;;; PAGE
375 ;;;
376 ;;; Emacs uses the regexp assigned to page-delimiter to determine what
377 ;;; marks a page break.  This is normally "^\f", which causes the
378 ;;; edt-page command to ignore form feeds not located at the beginning
379 ;;; of a line.  To emulate the EDT PAGE command exactly,
380 ;;; page-delimiter is set to "\f" when EDT emulation is turned on, and
381 ;;; restored to its original value when EDT emulation is turned off.
382 ;;; But this can be overridden if the EDT definition is not desired by
383 ;;; placing
384 ;;;
385 ;;;         (setq edt-keep-current-page-delimiter t)
386 ;;;
387 ;;; in your .emacs file.
388
389 (defun edt-page-forward (num)
390   "Move forward to just after next page delimiter.
391 Argument NUM is the number of page delimiters to move."
392   (interactive "p")
393   (edt-check-prefix num)
394   (if (eobp)
395       (error "End of buffer")
396         (progn
397           (forward-page num)
398           (if (eobp)
399                   (edt-line-to-bottom-of-window)
400                 (edt-line-to-top-of-window)))))
401
402 (defun edt-page-backward (num)
403   "Move backward to just after previous page delimiter.
404 Argument NUM is the number of page delimiters to move."
405   (interactive "p")
406   (edt-check-prefix num)
407   (if (bobp)
408       (error "Beginning of buffer")
409         (progn
410           (backward-page num)
411       (edt-line-to-top-of-window)
412           (if edt-x-emacs19-p (setq zmacs-region-stays t)))))
413
414 (defun edt-page (num)
415   "Move in current direction to next page delimiter.
416 Argument NUM is the number of page delimiters to move."
417   (interactive "p")
418   (if (equal edt-direction-string edt-forward-string)
419       (edt-page-forward num)
420     (edt-page-backward num)))
421
422 ;;;
423 ;;; SECT
424 ;;;
425 ;;; EDT defaults a section size to be 16 lines of its one and only
426 ;;; 24-line window.  That's two-thirds of the window at a time.  The
427 ;;; EDT SECT commands moves the cursor, not the window.
428 ;;;
429 ;;; This emulation of EDT's SECT moves the cursor approximately
430 ;;; two-thirds of the current window at a time.
431
432 (defun edt-sect-forward (num)
433   "Move cursor forward two-thirds of a window's number of lines.
434 Argument NUM is the number of sections to move."
435   (interactive "p")
436   (edt-check-prefix num)
437   (edt-line-forward (* (* (/ (- (window-height) 1) 3) 2) num)))
438
439
440 (defun edt-sect-backward (num)
441   "Move cursor backward two-thirds of a window.
442 Argument NUM is the number of sections to move."
443   (interactive "p")
444   (edt-check-prefix num)
445   (edt-line-backward (* (* (/ (- (window-height) 1) 3) 2) num)))
446
447 (defun edt-sect (num)
448   "Move in current direction a full window.
449 Argument NUM is the number of sections to move."
450   (interactive "p")
451   (if (equal edt-direction-string edt-forward-string)
452       (edt-sect-forward num)
453     (edt-sect-backward num)))
454
455 ;;;
456 ;;; BEGINNING OF LINE
457 ;;;
458 ;;; EDT's beginning-of-line command is not affected by current
459 ;;; direction, for some unknown reason.
460
461 (defun edt-beginning-of-line (num)
462   "Move backward to next beginning of line mark.
463 Argument NUM is the number of BOL marks to move."
464   (interactive "p")
465   (edt-check-prefix num)
466   (let ((beg (edt-current-line)))
467     (if (bolp)
468         (forward-line (* -1 num))
469       (progn
470         (setq num (1- num))
471         (forward-line (* -1 num))))
472     (edt-top-check beg num))
473   (if edt-x-emacs19-p (setq zmacs-region-stays t)))
474
475
476 ;;;
477 ;;; EOL (End of Line)
478 ;;;
479
480 (defun edt-end-of-line-forward (num)
481   "Move forward to next end of line mark.
482 Argument NUM is the number of EOL marks to move."
483   (interactive "p")
484   (edt-check-prefix num)
485   (let ((beg (edt-current-line)))
486     (forward-char)
487     (end-of-line num)
488     (edt-bottom-check beg num))
489   (if edt-x-emacs19-p (setq zmacs-region-stays t)))
490
491
492 (defun edt-end-of-line-backward (num)
493   "Move backward to next end of line mark.
494 Argument NUM is the number of EOL marks to move."
495   (interactive "p")
496   (edt-check-prefix num)
497   (let ((beg (edt-current-line)))
498     (end-of-line (1- num))
499     (edt-top-check beg num))
500   (if edt-x-emacs19-p (setq zmacs-region-stays t)))
501
502
503 (defun edt-end-of-line (num)
504   "Move in current direction to next end of line mark.
505 Argument NUM is the number of EOL marks to move."
506   (interactive "p")
507   (if (equal edt-direction-string edt-forward-string)
508       (edt-end-of-line-forward num)
509     (edt-end-of-line-backward num)))
510
511 ;;;
512 ;;; WORD
513 ;;;
514 ;;; This one is a tad messy.  To emulate EDT's behavior everywhere in
515 ;;; the file (beginning of file, end of file, beginning of line, end
516 ;;; of line, etc.) it takes a bit of special handling.
517 ;;;
518 ;;; The variable edt-word-entities contains a list of characters which
519 ;;; are to be viewed as distinct words where ever they appear in the
520 ;;; buffer.  This emulates the EDT line mode command SET ENTITY WORD.
521
522
523 (defun edt-one-word-forward ()
524   "Move forward to first character of next word."
525   (interactive)
526   (if (eobp)
527       (error "End of buffer"))
528   (if (eolp)
529       (forward-char)
530     (progn
531       (if (memq (following-char) edt-word-entities)
532           (forward-char)
533         (while (and
534                 (not (eolp))
535                 (not (eobp))
536                 (not (eq ?\  (char-syntax (following-char))))
537                 (not (memq (following-char) edt-word-entities)))
538           (forward-char)))
539       (while (and
540               (not (eolp))
541               (not (eobp))
542               (eq ?\  (char-syntax (following-char)))
543               (not (memq (following-char) edt-word-entities)))
544         (forward-char))))
545   (if edt-x-emacs19-p (setq zmacs-region-stays t)))
546
547 (defun edt-one-word-backward ()
548   "Move backward to first character of previous word."
549   (interactive)
550   (if (bobp)
551       (error "Beginning of buffer"))
552   (if (bolp)
553       (backward-char)
554     (progn
555       (backward-char)
556       (while (and
557               (not (bolp))
558               (not (bobp))
559               (eq ?\  (char-syntax (following-char)))
560               (not (memq (following-char) edt-word-entities)))
561         (backward-char))
562       (if (not (memq (following-char) edt-word-entities))
563           (while (and
564                   (not (bolp))
565                   (not (bobp))
566                   (not (eq ?\  (char-syntax (preceding-char))))
567                   (not (memq (preceding-char) edt-word-entities)))
568             (backward-char)))))
569   (if edt-x-emacs19-p (setq zmacs-region-stays t)))
570
571 (defun edt-word-forward (num)
572   "Move forward to first character of next word.
573 Argument NUM is the number of words to move."
574   (interactive "p")
575   (edt-check-prefix num)
576   (while (> num 0)
577     (edt-one-word-forward)
578     (setq num (1- num))))
579
580 (defun edt-word-backward (num)
581   "Move backward to first character of previous word.
582 Argument NUM is the number of words to move."
583   (interactive "p")
584   (edt-check-prefix num)
585   (while (> num 0)
586     (edt-one-word-backward)
587     (setq num (1- num))))
588
589 (defun edt-word (num)
590   "Move in current direction to first character of next word.
591 Argument NUM is the number of words to move."
592   (interactive "p")
593   (if (equal edt-direction-string edt-forward-string)
594       (edt-word-forward num)
595     (edt-word-backward num)))
596
597 ;;;
598 ;;; CHAR
599 ;;;
600
601 (defun edt-character (num)
602   "Move in current direction to next character.
603 Argument NUM is the number of characters to move."
604   (interactive "p")
605   (edt-check-prefix num)
606   (if (equal edt-direction-string edt-forward-string)
607       (forward-char num)
608     (backward-char num))
609   (if edt-x-emacs19-p (setq zmacs-region-stays t)))
610
611 ;;;
612 ;;; LINE
613 ;;;
614 ;;; When direction is set to BACKUP, LINE behaves just like BEGINNING
615 ;;; OF LINE in EDT.  So edt-line-backward is not really needed as a
616 ;;; separate function.
617
618 (defun edt-line-backward (num)
619   "Move backward to next beginning of line mark.
620 Argument NUM is the number of BOL marks to move."
621   (interactive "p")
622   (edt-beginning-of-line num))
623
624 (defun edt-line-forward (num)
625   "Move forward to next beginning of line mark.
626 Argument NUM is the number of BOL marks to move."
627   (interactive "p")
628   (edt-check-prefix num)
629   (let ((beg (edt-current-line)))
630     (forward-line num)
631     (edt-bottom-check beg num))
632   (if edt-x-emacs19-p (setq zmacs-region-stays t)))
633
634 (defun edt-line (num)
635   "Move in current direction to next beginning of line mark.
636 Argument NUM is the number of BOL marks to move."
637   (interactive "p")
638   (if (equal edt-direction-string edt-forward-string)
639       (edt-line-forward num)
640     (edt-line-backward num)))
641
642 ;;;
643 ;;; UP and DOWN Arrows
644 ;;;
645
646 (defun edt-next-line (num)
647   "Move cursor down one line.
648 Argument NUM is the number of lines to move."
649   (interactive "p")
650   (edt-check-prefix num)
651   (let ((beg (edt-current-line)))
652     (next-line num)
653     (edt-bottom-check beg num))
654   (if edt-x-emacs19-p (setq zmacs-region-stays t)))
655
656 (defun edt-previous-line (num)
657   "Move cursor up one line.
658 Argument NUM is the number of lines to move."
659   (interactive "p")
660   (edt-check-prefix num)
661   (let ((beg (edt-current-line)))
662     (previous-line num)
663     (edt-top-check beg num))
664   (if edt-x-emacs19-p (setq zmacs-region-stays t)))
665
666
667 ;;;
668 ;;; TOP
669 ;;;
670
671 (defun edt-top ()
672   "Move cursor to the beginning of buffer."
673   (interactive)
674   (goto-char (point-min))
675   (if edt-x-emacs19-p (setq zmacs-region-stays t)))
676
677 ;;;
678 ;;; BOTTOM
679 ;;;
680
681 (defun edt-bottom ()
682   "Move cursor to the end of buffer."
683   (interactive)
684   (goto-char (point-max))
685   (edt-line-to-bottom-of-window))
686
687 ;;;
688 ;;; FIND
689 ;;;
690
691 (defun edt-find-forward (&optional find)
692   "Find first occurrence of a string in forward direction and save it.
693 Optional argument FIND is t is this function is called from `edt-find'."
694   (interactive)
695   (if (not find)
696       (set 'edt-find-last-text (read-string "Search forward: ")))
697   (let* ((left nil)
698          (beg (edt-current-line))
699          (height (window-height))
700          (top-percent
701           (if (= 0 edt-top-scroll-margin) 10 edt-top-scroll-margin))
702          (bottom-percent
703           (if (= 0 edt-bottom-scroll-margin) 15 edt-bottom-scroll-margin))
704          (top-margin (/ (* height top-percent) 100))
705          (bottom-up-margin (+ 1 (/ (* height bottom-percent) 100)))
706          (bottom-margin (max beg (- height bottom-up-margin 1)))
707          (top (save-excursion (move-to-window-line top-margin) (point)))
708          (bottom (save-excursion (move-to-window-line bottom-margin) (point)))
709          (far (save-excursion
710                 (goto-char bottom) (forward-line (- height 2)) (point))))
711     (if (search-forward edt-find-last-text)
712         (progn
713           (search-backward edt-find-last-text)
714           (edt-set-match)
715           (cond((> (point) far)
716                 (setq left (save-excursion (forward-line height)))
717                 (if (= 0 left) (recenter top-margin)
718                   (recenter (- left bottom-up-margin))))
719                (t
720                 (and (> (point) bottom) (recenter bottom-margin)))))))
721   (if edt-x-emacs19-p (setq zmacs-region-stays t)))
722
723 (defun edt-find-backward (&optional find)
724   "Find first occurrence of a string in the backward direction and save it.
725 Optional argument FIND is t if this function is called from `edt-find'."
726   (interactive)
727   (if (not find)
728       (set 'edt-find-last-text (read-string "Search backward: ")))
729   (let* ((left nil)
730          (beg (edt-current-line))
731          (height (window-height))
732          (top-percent
733           (if (= 0 edt-top-scroll-margin) 10 edt-top-scroll-margin))
734          (bottom-percent
735           (if (= 0 edt-bottom-scroll-margin) 15 edt-bottom-scroll-margin))
736          (top-margin (/ (* height top-percent) 100))
737          (bottom-up-margin (+ 1 (/ (* height bottom-percent) 100)))
738          (bottom-margin (max beg (- height bottom-up-margin 1)))
739          (top (save-excursion (move-to-window-line top-margin) (point)))
740          (bottom (save-excursion (move-to-window-line bottom-margin) (point)))
741          (far (save-excursion
742                 (goto-char bottom) (forward-line (- height 2)) (point))))
743     (if (search-backward edt-find-last-text)
744         (edt-set-match))
745     (and (< (point) top) (recenter (min beg top-margin))))
746   (if edt-x-emacs19-p (setq zmacs-region-stays t)))
747
748 (defun edt-find ()
749   "Find first occurrence of string in current direction and save it."
750   (interactive)
751   (set 'edt-find-last-text (read-string "Search: "))
752   (if (equal edt-direction-string edt-forward-string)
753       (edt-find-forward t)
754       (edt-find-backward t)))
755
756
757 ;;;
758 ;;; FNDNXT
759 ;;;
760
761 (defun edt-find-next-forward ()
762   "Find next occurrence of a string in forward direction."
763   (interactive)
764   (let* ((left nil)
765          (beg (edt-current-line))
766          (height (window-height))
767          (top-percent
768           (if (= 0 edt-top-scroll-margin) 10 edt-top-scroll-margin))
769          (bottom-percent
770           (if (= 0 edt-bottom-scroll-margin) 15 edt-bottom-scroll-margin))
771          (top-margin (/ (* height top-percent) 100))
772          (bottom-up-margin (+ 1 (/ (* height bottom-percent) 100)))
773          (bottom-margin (max beg (- height bottom-up-margin 1)))
774          (top (save-excursion (move-to-window-line top-margin) (point)))
775          (bottom (save-excursion (move-to-window-line bottom-margin) (point)))
776          (far (save-excursion
777                 (goto-char bottom) (forward-line (- height 2)) (point))))
778     (forward-char 1)
779     (if (search-forward edt-find-last-text nil t)
780         (progn
781           (search-backward edt-find-last-text)
782           (edt-set-match)
783           (cond((> (point) far)
784                 (setq left (save-excursion (forward-line height)))
785                 (if (= 0 left) (recenter top-margin)
786                   (recenter (- left bottom-up-margin))))
787                (t
788                 (and (> (point) bottom) (recenter bottom-margin)))))
789       (progn
790         (backward-char 1)
791         (error "Search failed: \"%s\"" edt-find-last-text))))
792   (if edt-x-emacs19-p (setq zmacs-region-stays t)))
793
794 (defun edt-find-next-backward ()
795   "Find next occurrence of a string in backward direction."
796   (interactive)
797   (let* ((left nil)
798          (beg (edt-current-line))
799          (height (window-height))
800          (top-percent
801           (if (= 0 edt-top-scroll-margin) 10 edt-top-scroll-margin))
802          (bottom-percent
803           (if (= 0 edt-bottom-scroll-margin) 15 edt-bottom-scroll-margin))
804          (top-margin (/ (* height top-percent) 100))
805          (bottom-up-margin (+ 1 (/ (* height bottom-percent) 100)))
806          (bottom-margin (max beg (- height bottom-up-margin 1)))
807          (top (save-excursion (move-to-window-line top-margin) (point)))
808          (bottom (save-excursion (move-to-window-line bottom-margin) (point)))
809          (far (save-excursion
810                 (goto-char bottom) (forward-line (- height 2)) (point))))
811     (if (not (search-backward edt-find-last-text nil t))
812         (error "Search failed: \"%s\"" edt-find-last-text)
813       (progn
814         (edt-set-match)
815         (and (< (point) top) (recenter (min beg top-margin))))))
816   (if edt-x-emacs19-p (setq zmacs-region-stays t)))
817
818 (defun edt-find-next ()
819   "Find next occurrence of a string in current direction."
820   (interactive)
821   (if (equal edt-direction-string edt-forward-string)
822       (edt-find-next-forward)
823     (edt-find-next-backward)))
824
825 ;;;
826 ;;; APPEND
827 ;;;
828
829 (defun edt-append ()
830   "Append this kill region to last killed region."
831   (interactive "*")
832   (edt-check-selection)
833   (append-next-kill)
834   (kill-region (mark) (point))
835   (message "Selected text APPENDED to kill ring"))
836
837 ;;;
838 ;;; DEL L
839 ;;;
840
841 (defun edt-delete-line (num)
842   "Delete from cursor up to and including the end of line mark.
843 Argument NUM is the number of lines to delete."
844   (interactive "*p")
845   (edt-check-prefix num)
846   (let ((beg (point)))
847     (forward-line num)
848     (if (not (eq (preceding-char) ?\n))
849         (insert "\n"))
850     (setq edt-last-deleted-lines
851           (buffer-substring beg (point)))
852     (delete-region beg (point))))
853
854 ;;;
855 ;;; DEL EOL
856