mirror of
git://git.sv.gnu.org/emacs.git
synced 2026-01-30 12:21:25 -08:00
Initial revision
This commit is contained in:
parent
1a44ec7ad7
commit
bf078b466b
2 changed files with 1123 additions and 0 deletions
300
lisp/mail/uce.el
Normal file
300
lisp/mail/uce.el
Normal file
|
|
@ -0,0 +1,300 @@
|
|||
;;; uce.el --- facilitate reply to unsolicited commercial email
|
||||
|
||||
;; Copyright (C) 1996 Free Software Foundation, Inc.
|
||||
|
||||
;; Author: stanislav shalunov <shalunov@math.wisc.edu>
|
||||
;; Created: 10 Dec 1996
|
||||
;; Version: 1.0
|
||||
;; Keywords: uce, unsolicited commercial email
|
||||
|
||||
;; This file is part of GNU Emacs.
|
||||
|
||||
;; This program 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, or (at
|
||||
;; your option) any later version.
|
||||
|
||||
;; This program 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 GNU Emacs; see the file COPYING. If not, write to the
|
||||
;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
;; Boston, MA 02111-1307, USA.
|
||||
|
||||
;;; Commentary:
|
||||
|
||||
;; Code in this file provides semi-automatic means of replying to
|
||||
;; UCE's you might get. It works currently only with Rmail. If you
|
||||
;; would like to make it work with other mail readers, Rmail-specific
|
||||
;; section is marked below. If you want to play with code, would you
|
||||
;; please grab the newest version from
|
||||
;; http://math.wisc.edu/~shalunov/uce.el and let me know, if you would
|
||||
;; like, about your changes so I can incorporate them. I'd appreciate
|
||||
;; it.
|
||||
|
||||
;; Function uce-reply-to-uce, if called when current message in RMAIL
|
||||
;; buffer is a UCE, will setup *mail* buffer in the following way: it
|
||||
;; scans full headers of message for 1) normal return address of
|
||||
;; sender (From, Reply-To lines); and puts these addresses into To:
|
||||
;; header, it also puts abuse@offenders.host address there 2) mailhub
|
||||
;; that first saw this message; and puts address of its postmaster
|
||||
;; into To: header 3) finally, it looks at Message-Id and adds
|
||||
;; posmaster of that host to the list of addresses.
|
||||
|
||||
;; Then, we add "Errors-To: nobody@localhost" header, so that if some
|
||||
;; of these addresses are not actually correct, we will never see
|
||||
;; bounced mail. Also, mail-self-blind and mail-archive-file-name
|
||||
;; take no effect: the ideology is that we don't want to save junk or
|
||||
;; replies to junk.
|
||||
|
||||
;; Then we put template into buffer (customizable message that
|
||||
;; explains what has happened), customizable signature, and the
|
||||
;; original message with full headers and envelope for postmasters.
|
||||
;; Then buffer is left for editing.
|
||||
|
||||
;; The reason that function uce-reply-to-uce is Rmail dependant is
|
||||
;; that we want full headers of the original message, nothing
|
||||
;; stripped. If we use normal means of inserting of the original
|
||||
;; message into *mail* buffer headers like Received: (not really
|
||||
;; headers, but envelope lines) will be stripped while they bear
|
||||
;; valuable for us and postmasters information. I do wish that there
|
||||
;; would be some way to write this function in some portable way, but
|
||||
;; I am not aware of any.
|
||||
|
||||
;;; Change log:
|
||||
|
||||
;; Dec 10, 1996 -- posted draft version to gnu.sources.emacs
|
||||
|
||||
;; Dec 11, 1996 -- fixed some typos, and Francesco Potorti`
|
||||
;; <F.Potorti@cnuce.cnr.it> pointed out that my use of defvar was
|
||||
;; weird, suggested fix, and added let form.
|
||||
|
||||
;; Dec 17, 1996 -- made scanning for host names little bit more clever
|
||||
;; (obviously bogus stuff like localhost is now ignored).
|
||||
|
||||
;;; Setup:
|
||||
|
||||
;; put in your ~./emacs the following line:
|
||||
|
||||
;; (autoload 'uce-reply-to-uce "uce" "Reply to UCEs" t nil)
|
||||
|
||||
;; store this file (uce.el) somewhere in load-path and byte-compile it.
|
||||
|
||||
;;; Variables:
|
||||
|
||||
;; uce-message-text is template that will be inserted into buffer. It
|
||||
;; has reasonable default. If you want to write some scarier one,
|
||||
;; please do so and send it to me. Please keep it polite.
|
||||
|
||||
;; uce-signature behaves just like mail-signature. If nil, nothing is
|
||||
;; inserted, if t, file ~/.signature is used, if a string, its
|
||||
;; contents are inserted into buffer.
|
||||
|
||||
;; uce-uce-separator is line that separates your message from the UCE
|
||||
;; that you enclose.
|
||||
|
||||
;; uce-subject-line will be used as subject of outgoing message. If
|
||||
;; nil, left blank.
|
||||
|
||||
;;; Code:
|
||||
|
||||
(require 'sendmail)
|
||||
(require 'rmail)
|
||||
|
||||
(defvar uce-setup-hook nil
|
||||
"Hook to run after UCE rant message is composed.
|
||||
This hook is run after mail-setup-hook, which is run as well.")
|
||||
|
||||
(defvar uce-message-text
|
||||
"Recently, I have received an Unsolicited Commercial E-mail from you.
|
||||
I do not like UCE's and I would like to inform you that sending
|
||||
unsolicited messages to someone while he or she may have to pay for
|
||||
reading your message may be illegal. Anyway, it is highly annoying
|
||||
and not welcome by anyone. It is rude, after all.
|
||||
|
||||
If you think that this is a good way to advertise your products or
|
||||
services you are mistaken. Spamming will only make people hate you, not
|
||||
buy from you.
|
||||
|
||||
If you have any list of people you send unsolicited commercial emails to,
|
||||
REMOVE me from such list immediately. I suggest that you make this list
|
||||
just empty.
|
||||
|
||||
Note to the postmaster(s): I append the text of UCE in question to
|
||||
this message, I would like to hear from you about action(s) taken.
|
||||
This message has been sent to postmasters at the host that is
|
||||
mentioned as original sender's host and to the postmaster whose host
|
||||
was used as mail relay for this message. If message was sent not by
|
||||
your user, could you please compare time when this message was sent
|
||||
(use time in Received: field of the envelope rather than Date: field)
|
||||
with your sendmail logs and see what host was using your sendmail at
|
||||
this moment of time.
|
||||
|
||||
Thank you."
|
||||
|
||||
"This is the text that uce-reply-to-uce command will put in reply buffer.
|
||||
Some of spamming programs in use will be set up to read all incoming
|
||||
to spam address email, and will remove people who put the word `remove'
|
||||
on beginning of some line from the spamming list. So, when you set it
|
||||
up, it might be a good idea to actually use this feature.
|
||||
|
||||
Value nil means insert no text by default, lets you type it in.")
|
||||
|
||||
(defvar uce-uce-separator
|
||||
"----- original unsolicited commercial email follows -----"
|
||||
"Line that will begin quoting of the UCE.
|
||||
Value nil means use no separator.")
|
||||
|
||||
(defvar uce-signature mail-signature
|
||||
"Text to put as your signature after the note to UCE sender.
|
||||
Value nil means none, t means insert ~/.signature file (if it happens
|
||||
to exist), if this variable is a string this string will be inserted
|
||||
as your signature.")
|
||||
|
||||
(defvar uce-default-headers
|
||||
"Errors-To: nobody@localhost\nPrecedence: bulk\n"
|
||||
"Additional headers to use when responding to a UCE with \\[uce-reply-to-uce].
|
||||
These are mostly meant for headers that prevent delivery errors reporting.")
|
||||
|
||||
(defvar uce-subject-line
|
||||
"Spam alert: unsolicited commercial e-mail"
|
||||
"Subject of the message that will be sent in response to a UCE.")
|
||||
|
||||
(defun uce-reply-to-uce (&optional ignored)
|
||||
"Send reply to UCE in Rmail.
|
||||
UCE stands for unsolicited commercial email. Function will set up reply
|
||||
buffer with default To: to the sender, his postmaster, his abuse@
|
||||
address, and postmaster of the mail relay used."
|
||||
(interactive "P")
|
||||
(let ((to (mail-strip-quoted-names (mail-fetch-field "from" t)))
|
||||
(reply-to (mail-fetch-field "reply-to"))
|
||||
temp)
|
||||
;; Initial setting of the list of recipients of our message; that's
|
||||
;; what they are pretending to be (and in many cases, really are).
|
||||
(if to
|
||||
(setq to (format "%s" (mail-strip-quoted-names to)))
|
||||
(setq to ""))
|
||||
(if reply-to
|
||||
(setq to (format "%s, %s" to (mail-strip-quoted-names reply-to))))
|
||||
(let (first-at-sign end-of-hostname sender-host)
|
||||
(setq first-at-sign (string-match "@" to)
|
||||
end-of-hostname (string-match "[ ,>]" to first-at-sign)
|
||||
sender-host (substring to first-at-sign end-of-hostname))
|
||||
(if (string-match "\\." sender-host)
|
||||
(setq to (format "%s, postmaster%s, abuse%s"
|
||||
to sender-host sender-host))))
|
||||
(setq mail-send-actions nil)
|
||||
(setq mail-reply-buffer nil)
|
||||
;; Begin of Rmail dependant section.
|
||||
(or (get-buffer "RMAIL")
|
||||
(error "No buffer RMAIL, cannot find UCE"))
|
||||
(switch-to-buffer "RMAIL")
|
||||
(save-excursion
|
||||
(save-restriction
|
||||
(widen)
|
||||
(rmail-maybe-set-message-counters)
|
||||
(copy-region-as-kill (rmail-msgbeg rmail-current-message)
|
||||
(rmail-msgend rmail-current-message))))
|
||||
(switch-to-buffer "*mail*")
|
||||
(erase-buffer)
|
||||
(setq temp (point))
|
||||
(yank)
|
||||
(goto-char temp)
|
||||
(forward-line 2)
|
||||
(while (looking-at "Summary-Line:\\|Mail-From:")
|
||||
(forward-line 1))
|
||||
(delete-region temp (point))
|
||||
;; Now find the mail hub that first accepted this message.
|
||||
(while (or (looking-at "Received:")
|
||||
(looking-at " ")
|
||||
(looking-at "\t"))
|
||||
(forward-line 1))
|
||||
(while (or (looking-at " ")
|
||||
(looking-at "\t"))
|
||||
(forward-line -1))
|
||||
;; Is this always good? It's the only thing I saw when I checked
|
||||
;; a few messages.
|
||||
(search-forward ": from ")
|
||||
(setq temp (point))
|
||||
(search-forward " ")
|
||||
(forward-char -1)
|
||||
;; And add its postmaster to the list of addresses.
|
||||
(if (string-match "\\." (buffer-substring temp (point)))
|
||||
(setq to (format "%s, postmaster@%s"
|
||||
to (buffer-substring temp (point)))))
|
||||
;; Also look at the message-id, it helps *very* often.
|
||||
(search-forward "\nMessage-Id: ")
|
||||
(search-forward "@")
|
||||
(setq temp (point))
|
||||
(search-forward ">")
|
||||
(forward-char -1)
|
||||
(if (string-match "\\." (buffer-substring temp (point)))
|
||||
(setq to (format "%s, postmaster@%s"
|
||||
to (buffer-substring temp (point)))))
|
||||
(search-forward "\n*** EOOH ***\n")
|
||||
(forward-line -1)
|
||||
(setq temp (point))
|
||||
(search-forward "\n\n" nil t)
|
||||
(delete-region temp (point))
|
||||
;; End of Rmail dependent section.
|
||||
(auto-save-mode auto-save-default)
|
||||
(mail-mode)
|
||||
(goto-char (point-min))
|
||||
(insert "To: ")
|
||||
(save-excursion
|
||||
(if to
|
||||
(let ((fill-prefix "\t")
|
||||
(address-start (point)))
|
||||
(insert to "\n")
|
||||
(fill-region-as-paragraph address-start (point)))
|
||||
(newline))
|
||||
(insert "Subject: " uce-subject-line "\n")
|
||||
(if uce-default-headers
|
||||
(insert uce-default-headers))
|
||||
(if mail-default-headers
|
||||
(insert mail-default-headers))
|
||||
(if mail-default-reply-to
|
||||
(insert "Reply-to: " mail-default-reply-to "\n"))
|
||||
(insert mail-header-separator "\n")
|
||||
;; Insert all our text. Then go back to the place where we started.
|
||||
(if to (setq to (point)))
|
||||
;; Text of ranting.
|
||||
(if uce-message-text
|
||||
(insert uce-message-text))
|
||||
;; Signature.
|
||||
(cond ((eq uce-signature t)
|
||||
(if (file-exists-p "~/.signature")
|
||||
(progn
|
||||
(insert "\n\n-- \n")
|
||||
(insert-file "~/.signature")
|
||||
;; Function insert-file leaves point where it was,
|
||||
;; while we want to place signature in the ``middle''
|
||||
;; of the message.
|
||||
(exchange-point-and-mark))))
|
||||
(uce-signature
|
||||
(insert "\n\n-- \n" uce-signature)))
|
||||
;; And text of the original message.
|
||||
(if uce-uce-separator
|
||||
(insert "\n\n" uce-uce-separator "\n"))
|
||||
;; If message doesn't end with a newline, insert it.
|
||||
(goto-char (point-max))
|
||||
(or (bolp) (newline)))
|
||||
;; And go back to the beginning of text.
|
||||
(if to (goto-char to))
|
||||
(or to (set-buffer-modified-p nil))
|
||||
;; Run hooks before we leave buffer for editing. Reasonable usage
|
||||
;; might be to set up special key bindings, replace standart
|
||||
;; functions in mail-mode, etc.
|
||||
(run-hooks 'mail-setup-hook 'uce-setup-hook)))
|
||||
|
||||
(defun uce-insert-ranting (&optional ignored)
|
||||
"Insert text of the usual reply to UCE into current buffer."
|
||||
(interactive "P")
|
||||
(insert uce-message-text))
|
||||
|
||||
(provide 'uce)
|
||||
|
||||
;;; uce.el ends here
|
||||
823
lisp/vcursor.el
Normal file
823
lisp/vcursor.el
Normal file
|
|
@ -0,0 +1,823 @@
|
|||
;;; vcursor.el --- manipulate an alternative ("virtual") cursor.
|
||||
|
||||
;; Copyright (C) 1994, 1996 Peter Stephenson <pws@ifh.de>
|
||||
|
||||
;; Author: Peter Stephenson <pws@ifh.de>
|
||||
;; Keywords: virtual cursor, display, copying
|
||||
|
||||
;; This program 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.
|
||||
|
||||
;; This program 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 GNU Emacs; see the file COPYING. If not, write to the
|
||||
;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
;; Boston, MA 02111-1307, USA.
|
||||
|
||||
;;; Commentary:
|
||||
|
||||
;; Virtual cursor commands. I got this idea from the old BBC micro.
|
||||
;; You need Emacs 19 (I have not tried XEmacs) and a windowing
|
||||
;; system: I have tried X Windows and Oemacs but any system which
|
||||
;; supports multiple windows should have the ability to run vcursor.
|
||||
;; In fact, only overlays are required to work, though some of the
|
||||
;; key-bindings may need changing.
|
||||
;;
|
||||
;; This is much easier to use than the instructions are to read.
|
||||
;; I suggest you simply load it and play around with holding down Ctrl
|
||||
;; and Shift and pressing up, down, left, right, tab, return, and see
|
||||
;; what happens. (Find a scratch buffer before using C-S-tab: that
|
||||
;; toggles copying.)
|
||||
;;
|
||||
;; Most of the functions described in this documentation are in
|
||||
;; parentheses so that if you have the package loaded you can type C-h
|
||||
;; f on top of them for help.
|
||||
;;
|
||||
;; Using the cursor keys with both control and shift held down moves
|
||||
;; around a virtual cursor, which is initially at point. When active,
|
||||
;; it appears with an underline through it to distinguish it from the
|
||||
;; normal cursor. You can then use one of the other commands to copy
|
||||
;; characters from the location of the virtual cursor to point. This
|
||||
;; is very useful, for example, when copying some previous text while
|
||||
;; making changes to it at the same time, since you never have to move
|
||||
;; the "real" cursor away from where you are inserting.
|
||||
;;
|
||||
;; The remaining default key bindings are based around the PC-type
|
||||
;; cluster found above the cursor keys on a lot of keyboards, the
|
||||
;; function keys which my limited knowledge of X terminals expects to
|
||||
;; find at the top. Some functions are duplicated in more obvious
|
||||
;; places for the X version.
|
||||
;;
|
||||
;; All the keybindings require you to hold down control and shift at
|
||||
;; once. I assumed this combination wouldn't be heavily bound by most
|
||||
;; people and that it would be easy to type with the left hand.
|
||||
;; Inevitably it will clash with some other packages, but I can't help
|
||||
;; that: an intuitive binding is a prerequisite here. See below for
|
||||
;; other alternatives (search for "Oemacs").
|
||||
;;
|
||||
;; Holding down control and shift and pressing insert (vcursor-copy)
|
||||
;; copies one character from wherever the virtual cursor is to point;
|
||||
;; point and the virtual cursor advance in the separate and equal
|
||||
;; station to which... (etc.). M-C-S-return (vcursor-copy-line)
|
||||
;; copies to the end of the line instead of just one character,
|
||||
;; C-S-delete or C-S-remove (vcursor-copy-word) copies a word.
|
||||
;;
|
||||
;; A more general way of copying is to use C-S-tab, which is a toggle.
|
||||
;; In the "on" state, moving the virtual cursor will copy the
|
||||
;; moved-over text to the normal cursor position (including when going
|
||||
;; backwards, though each piece of text moved over is copied forwards:
|
||||
;; compare the behaviour of C-S-up and C-S-left).
|
||||
;;
|
||||
;; However, that's just a small part of the magic. If the virtual
|
||||
;; cursor goes off the display, it will be redisplayed in some other
|
||||
;; window. (See the function (vcursor-find-window) for details of how
|
||||
;; this window is chosen.) This gives you fingertip control over two
|
||||
;; windows at once.
|
||||
;;
|
||||
;; C-S-return (vcursor-disable) disables the virtual cursor, removing
|
||||
;; it so that it starts from point whenever you move it again --- note
|
||||
;; that simply moving the cursor and virtual cursor on top of one
|
||||
;; another does not have this effect.
|
||||
;;
|
||||
;; If you gave C-S-return a positive prefix arg, it will also delete the
|
||||
;; window (unless it's the current one). Whenever the virtual cursor
|
||||
;; goes off-screen in its own window, point in that window is moved as
|
||||
;; well to restore it to view. (It's easier that way, that's why.
|
||||
;; However, point doesn't move unless the view in the window does, so
|
||||
;; it's not tied to the virtual cursor location.)
|
||||
;;
|
||||
;; You can also use C-S-return with a negative prefix argument which
|
||||
;; forces the vcursor to appear at point. This is particularly useful if
|
||||
;; you actually want to edit in another window but would like to
|
||||
;; remember the current cursor location for examining or copying from
|
||||
;; that buffer. (I just hit C-S-right C-S-left, but I'm a hopeless
|
||||
;; lowbrow.)
|
||||
;;
|
||||
;; There is also C-S-f6 (vcursor-other-window) which behaves like
|
||||
;; C-x o on the virtual rather than the real cursor, except that it
|
||||
;; will create another window if necessary.
|
||||
;;
|
||||
;; The keys C-S-prior (vcursor-scroll-down) and C-S-next
|
||||
;; (vcursor-scroll-up) (i.e., PageUp and PageDown) will scroll the
|
||||
;; virtual cursor window, appropriately chosen. They will always
|
||||
;; create a new window or take over an old one if necessary.
|
||||
;; Likewise, M-C-S-left and M-C-S-right move you to the
|
||||
;; beginning or end of a line, C-S-home and C-S-end the
|
||||
;; beginning or end of a buffer (these are also on M-C-S-up and
|
||||
;; M-C-S-down for those of us stuck with DEC keyboards).
|
||||
;;
|
||||
;; C-S-f7 (vcursor-goto) will take you to the vcursor position
|
||||
;; (swapping windows if it seems sensible) and (unless you give it a
|
||||
;; prefix argument) delete the virtual cursor, so this is useful for
|
||||
;; you to take over editing at the virtual cursor position. It is not
|
||||
;; an error if the virtual cursor is not active; it simply leaves you
|
||||
;; at point, because that is where the virtual cursor would start
|
||||
;; from.
|
||||
;;
|
||||
;; In a similar vein, M-C-S-tab (hope your left hand's flexible;
|
||||
;; C-S-select on DEC keyboards) (vcursor-swap-point) will take you to
|
||||
;; the virtual cursor position but simultaneously put the virtual
|
||||
;; cursor at the old cursor position. It is also supposed to ensure
|
||||
;; that both are visible.
|
||||
;;
|
||||
;; C-S-f8 (C-S-find on DEC keyboards) (vcursor-isearch-forward)
|
||||
;; allows you to do an isearch in another window. It works a bit like
|
||||
;; vcursor-scroll-*; it moves into another window, calls isearch
|
||||
;; there, and sets the virtual cursor position to the point found. In
|
||||
;; other words, it works just like isearch but with the virtual cursor
|
||||
;; instead of the real one (that's why it's called a "virtual
|
||||
;; cursor"). While you are isearching, you are editing in the virtual
|
||||
;; cursor window, but when you have finished you return to where you
|
||||
;; started. Note that once you are in isearch all the keys are normal
|
||||
;; --- use C-s, not C-S-f8, to search for the next occurrence.
|
||||
;;
|
||||
;; If you set the variable vcursor-auto-disable, then any command
|
||||
;; which does not involve moving or copying from the virtual cursor
|
||||
;; causes the virtual cursor to be disabled. If you don't intend to
|
||||
;; use this, you can comment out the `add-hook' line at the bottom of
|
||||
;; this file. (This feature partially emulates the way the "copy" key
|
||||
;; on the BBC micro worked; actually, the copy cursor was homed when
|
||||
;; you hit return. This was in keeping with the line-by-line way of
|
||||
;; entering BASIC, but is less appropriate here.)
|
||||
;;
|
||||
;; There is a way of moving the virtual cursor using ordinary
|
||||
;; commands: C-S-f9 (vcursor-execute-key) reads a key string,
|
||||
;; moves to the virtual cursor position, executes the command bound to
|
||||
;; the string, then returns to the original point. Thus C-S-f9 M-m
|
||||
;; moves the virtual cursor back to the first non-whitespace character
|
||||
;; on its line. As the command is called interactively all the usual
|
||||
;; ways of passing information to the command called, such as by a
|
||||
;; prefix argument, are available. C-S-f10 (C-S-x)
|
||||
;; (vcursor-execute-command) behaves the same way but you enter the
|
||||
;; name of the command. Of course, only some commands are useful
|
||||
;; here, mainly simple movement commands. Killing at the virtual
|
||||
;; cursor position in this way works as well; you can even save
|
||||
;; another buffer with C-S-f9 C-x C-s. To do anything more
|
||||
;; complicated, you are better off using M-C-S-tab
|
||||
;; (vcursor-swap-point), doing whatever it is, then calling M-C-S-tab
|
||||
;; again.
|
||||
;;
|
||||
;; If you want to add your own moving or copying functions you should
|
||||
;; be able to do this fairly easily with (vcursor-relative-move) and
|
||||
;; (vcursor-copy) together with (vcursor-get-char-count). If you want to
|
||||
;; do something in a different window, use (vcursor-window-funcall).
|
||||
;;
|
||||
;; There is an alternative set of key bindings which will be used
|
||||
;; automatically for a PC if Oemacs is detected. This set uses separate
|
||||
;; control, shift and meta keys with function keys 1 to 10. In
|
||||
;; particular, movement keys are concentrated on f5 to f8 with (in
|
||||
;; increasing order of distance travelled) C-, M- and S- as prefixes.
|
||||
;; See the actual bindings below (search for C-f1). This is because the
|
||||
;; C-S- prefix is represented by weird key sequences and the set is
|
||||
;; incomplete; if you don't mind that, some hints are given in comments
|
||||
;; below.
|
||||
;;
|
||||
;; You can specify the usual or the Oemacs bindings by setting the
|
||||
;; variable vcursor-key-bindings to `xterm' or `oemacs'. You can also set
|
||||
;; it to nil, in which case vcursor will not make any key bindings
|
||||
;; and you can define your own. The default is t, which makes vcursor
|
||||
;; guess (it will use xterm unless it thinks Oemacs is running). The
|
||||
;; oemacs set will work on an X terminal with function keys, but the
|
||||
;; xterm set will not work under Oemacs.
|
||||
;;
|
||||
;; Un-features:
|
||||
;; - The vcursor will not move to point-max, since otherwise it would
|
||||
;; disappear. However, no error is flagged as point-max is a valid
|
||||
;; point in the buffer. Thus cursor right or down at the second
|
||||
;; last point in the file does not flag an error, which is inconsistent,
|
||||
;; and if copying is on the last character (typically newline) will
|
||||
;; be repeatedly copied. (I've tried making it flag an error
|
||||
;; instead and that's worse since often the vcursor is sent to
|
||||
;; point in some other window, which may be point-max.)
|
||||
;; - The vcursor widens when over a tab character or right at the
|
||||
;; end of the line. You're welcome to consider this a feature;
|
||||
;; it's just a part of how overlays work.
|
||||
;; - The vcursor obscures the real cursor. Creative use of overlays
|
||||
;; could cure this.
|
||||
;; - The vcursor does not remember its own previous positions. If
|
||||
;; you cycle it back into a window it was in before, it will be at
|
||||
;; point in that window. Often, that is where a previous recenter
|
||||
;; left point, not where the vcursor was before.
|
||||
;; (Note, however, that the vcursor does remember where it *is*,
|
||||
;; even if it's off-screen. This can also lead to surprises, but I
|
||||
;; don't think it's a bug.)
|
||||
;; - vcursor-window-funcall could perhaps be smarter about restoring
|
||||
;; the previous window state on failure.
|
||||
;; - The logic in vcursor-find-window is rather complicated and
|
||||
;; therefore bug-prone, though in practice it seems to work OK.
|
||||
;;
|
||||
;; Possible enhnacements:
|
||||
;; It would be easy to implement vcursor-push (save vcursor position
|
||||
;; as mark and deactivate) and vcursor-pop (deactivate vcursor and
|
||||
;; move to last pushed position) functions.
|
||||
|
||||
;;; Code:
|
||||
|
||||
(or (memq 'vcursor (face-list))
|
||||
(progn
|
||||
(copy-face 'modeline 'vcursor)
|
||||
(if (or (fboundp 'oemacs-version) (x-display-color-p))
|
||||
(progn
|
||||
(set-face-foreground 'vcursor "blue")
|
||||
(set-face-background 'vcursor "cyan")))
|
||||
(set-face-underline-p 'vcursor t)))
|
||||
|
||||
(defvar vcursor-auto-disable nil
|
||||
"*If non-nil, disable the virtual cursor after use.
|
||||
Any non-vcursor command will force `vcursor-disable' to be called.")
|
||||
|
||||
(defvar vcursor-key-bindings t
|
||||
"*How to bind keys when vcursor is loaded.
|
||||
If t (the default), guess; if xterm, use bindings suitable for an
|
||||
X terminal; if oemacs, use bindings which work on a PC with Oemacs.
|
||||
If nil, don't define any key bindings.")
|
||||
|
||||
(defvar vcursor-overlay nil
|
||||
"Overlay for the virtual cursor.
|
||||
It is nil if that is not enabled.")
|
||||
|
||||
(defvar vcursor-window nil
|
||||
"Last window to have displayed the virtual cursor.
|
||||
See the function `vcursor-find-window' for how this is used.")
|
||||
|
||||
(defvar vcursor-last-command nil
|
||||
"Non-nil if last command was a vcursor command.
|
||||
The commands `vcursor-copy', `vcursor-relative-move' and the ones for
|
||||
scrolling set this. It is used by the `vcursor-auto-disable' code.")
|
||||
;; could do some memq-ing with last-command instead, but this will
|
||||
;; automatically handle any new commands using the primitives.
|
||||
|
||||
(defvar vcursor-copy-flag nil
|
||||
"*Non-nil means moving vcursor should copy characters moved over to point.")
|
||||
|
||||
(defvar vcursor-temp-goal-column nil
|
||||
"Keeps track of temporary goal columns for the virtual cursor.")
|
||||
|
||||
(cond
|
||||
((not vcursor-key-bindings)) ;; don't set any key bindings
|
||||
((or (eq vcursor-key-bindings 'oemacs)
|
||||
(and (eq vcursor-key-bindings t) (fboundp 'oemacs-version)))
|
||||
(global-set-key [C-f1] 'vcursor-toggle-copy)
|
||||
(global-set-key [C-f2] 'vcursor-copy)
|
||||
(global-set-key [C-f3] 'vcursor-copy-word)
|
||||
(global-set-key [C-f4] 'vcursor-copy-line)
|
||||
|
||||
(global-set-key [S-f1] 'vcursor-disable)
|
||||
(global-set-key [S-f2] 'vcursor-other-window)
|
||||
(global-set-key [S-f3] 'vcursor-goto)
|
||||
(global-set-key [S-f4] 'vcursor-swap-point)
|
||||
|
||||
(global-set-key [C-f5] 'vcursor-backward-char)
|
||||
(global-set-key [C-f6] 'vcursor-previous-line)
|
||||
(global-set-key [C-f7] 'vcursor-next-line)
|
||||
(global-set-key [C-f8] 'vcursor-forward-char)
|
||||
|
||||
(global-set-key [M-f5] 'vcursor-beginning-of-line)
|
||||
(global-set-key [M-f6] 'vcursor-backward-word)
|
||||
(global-set-key [M-f6] 'vcursor-forward-word)
|
||||
(global-set-key [M-f8] 'vcursor-end-of-line)
|
||||
|
||||
(global-set-key [S-f5] 'vcursor-beginning-of-buffer)
|
||||
(global-set-key [S-f6] 'vcursor-scroll-down)
|
||||
(global-set-key [S-f7] 'vcursor-scroll-up)
|
||||
(global-set-key [S-f8] 'vcursor-end-of-buffer)
|
||||
|
||||
(global-set-key [C-f9] 'vcursor-isearch-forward)
|
||||
|
||||
(global-set-key [S-f9] 'vcursor-execute-key)
|
||||
(global-set-key [S-f10] 'vcursor-execute-command)
|
||||
|
||||
;;; Partial dictionary of Oemacs key sequences for you to roll your own,
|
||||
;;; e.g C-S-up: (global-set-key "\M-[\C-f\M-\C-m" 'vcursor-previous-line)
|
||||
;;; Sequence: Sends:
|
||||
;;; "\M-[\C-f\M-\C-m" C-S-up
|
||||
;;; "\M-[\C-f\M-\C-q" C-S-down
|
||||
;;; "\M-[\C-fs" C-S-left
|
||||
;;; "\M-[\C-ft" C-S-right
|
||||
;;;
|
||||
;;; "\M-[\C-fw" C-S-home
|
||||
;;; "\M-[\C-b\C-o" S-tab
|
||||
;;; "\M-[\C-f\M-\C-r" C-S-insert
|
||||
;;; "\M-[\C-fu" C-S-end
|
||||
;;; "\M-[\C-f\M-\C-s" C-S-delete
|
||||
;;; "\M-[\C-f\M-\C-d" C-S-prior
|
||||
;;; "\M-[\C-fv" C-S-next
|
||||
;;;
|
||||
;;; "\M-[\C-f^" C-S-f1
|
||||
;;; "\M-[\C-f_" C-S-f2
|
||||
;;; "\M-[\C-f`" C-S-f3
|
||||
;;; "\M-[\C-fa" C-S-f4
|
||||
;;; "\M-[\C-fb" C-S-f5
|
||||
;;; "\M-[\C-fc" C-S-f6
|
||||
;;; "\M-[\C-fd" C-S-f7
|
||||
;;; "\M-[\C-fe" C-S-f8
|
||||
;;; "\M-[\C-ff" C-S-f9
|
||||
;;; "\M-[\C-fg" C-S-f10
|
||||
)
|
||||
(t
|
||||
(global-set-key [C-S-up] 'vcursor-previous-line)
|
||||
(global-set-key [C-S-down] 'vcursor-next-line)
|
||||
(global-set-key [C-S-left] 'vcursor-backward-char)
|
||||
(global-set-key [C-S-right] 'vcursor-forward-char)
|
||||
|
||||
(global-set-key [C-S-return] 'vcursor-disable)
|
||||
(global-set-key [C-S-insert] 'vcursor-copy)
|
||||
(global-set-key [C-S-delete] 'vcursor-copy-word)
|
||||
(global-set-key [C-S-remove] 'vcursor-copy-word)
|
||||
(global-set-key [C-S-tab] 'vcursor-toggle-copy)
|
||||
(global-set-key [C-S-home] 'vcursor-beginning-of-buffer)
|
||||
(global-set-key [M-C-S-up] 'vcursor-beginning-of-buffer)
|
||||
(global-set-key [C-S-end] 'vcursor-end-of-buffer)
|
||||
(global-set-key [M-C-S-down] 'vcursor-end-of-buffer)
|
||||
(global-set-key [C-S-prior] 'vcursor-scroll-down)
|
||||
(global-set-key [C-S-next] 'vcursor-scroll-up)
|
||||
|
||||
(global-set-key [C-S-f6] 'vcursor-other-window)
|
||||
(global-set-key [C-S-f7] 'vcursor-goto)
|
||||
|
||||
(global-set-key [C-S-select] 'vcursor-swap-point) ; DEC keyboards
|
||||
(global-set-key [M-C-S-tab] 'vcursor-swap-point)
|
||||
|
||||
(global-set-key [C-S-find] 'vcursor-isearch-forward) ; DEC keyboards
|
||||
(global-set-key [C-S-f8] 'vcursor-isearch-forward)
|
||||
|
||||
(global-set-key [M-C-S-left] 'vcursor-beginning-of-line)
|
||||
(global-set-key [M-C-S-right] 'vcursor-end-of-line)
|
||||
|
||||
(global-set-key [M-C-S-prior] 'vcursor-backward-word)
|
||||
(global-set-key [M-C-S-next] 'vcursor-forward-word)
|
||||
|
||||
(global-set-key [M-C-S-return] 'vcursor-copy-line)
|
||||
|
||||
(global-set-key [C-S-f9] 'vcursor-execute-key)
|
||||
(global-set-key [C-S-f10] 'vcursor-execute-command)
|
||||
))
|
||||
|
||||
(defun vcursor-locate ()
|
||||
"Go to the starting point of the virtual cursor.
|
||||
If that's disabled, don't go anywhere but don't complain."
|
||||
;; This is where we go off-mass-shell. Assume there is a
|
||||
;; save-excursion to get us back to the pole, er, point.
|
||||
|
||||
(and (overlayp vcursor-overlay)
|
||||
(overlay-buffer vcursor-overlay)
|
||||
(set-buffer (overlay-buffer vcursor-overlay))
|
||||
(goto-char (overlay-start vcursor-overlay)))
|
||||
)
|
||||
|
||||
(defun vcursor-find-window (&optional not-this new-win this-frame)
|
||||
"Return a suitable window for displaying the virtual cursor.
|
||||
This is the first window in cyclic order where the vcursor is visible.
|
||||
|
||||
With optional NOT-THIS non-nil never return the current window.
|
||||
|
||||
With NEW-WIN non-nil, display the virtual cursor buffer in another
|
||||
window if the virtual cursor is not currently visible \(note, however,
|
||||
that this function never changes window-point\).
|
||||
|
||||
With THIS-FRAME non-nil, don't search other frames for a new window
|
||||
\(though if the vcursor is already off-frame then its current window is
|
||||
always considered, and the value of `pop-up-frames' is always respected\).
|
||||
|
||||
Returns nil if the virtual cursor is not visible anywhere suitable.
|
||||
Set `vcursor-window' to the returned value as a side effect."
|
||||
|
||||
;; The order of priorities (respecting NOT-THIS) is (1)
|
||||
;; vcursor-window if the virtual cursor is visible there (2) any
|
||||
;; window displaying the virtual cursor (3) vcursor-window provided
|
||||
;; it is still displaying the buffer containing the virtual cursor and
|
||||
;; is not selected (4) any unselected window displaying the vcursor
|
||||
;; buffer (5) with NEW-WIN, a window selected by display-buffer (so
|
||||
;; the variables pop-up-windows and pop-up-frames are significant)
|
||||
;; (6) nil.
|
||||
|
||||
(let ((thiswin (selected-window)) winok winbuf)
|
||||
(save-excursion
|
||||
(vcursor-locate)
|
||||
(or (and (window-live-p vcursor-window)
|
||||
(eq (current-buffer) (window-buffer vcursor-window))
|
||||
(not (and not-this (eq thiswin vcursor-window))))
|
||||
(setq vcursor-window nil))
|
||||
(or (and vcursor-window ; choice 1
|
||||
(pos-visible-in-window-p (point) vcursor-window))
|
||||
(progn
|
||||
(walk-windows
|
||||
(function
|
||||
(lambda (win)
|
||||
(and (not winok)
|
||||
(eq (current-buffer) (window-buffer win))
|
||||
(not (and not-this (eq thiswin win)))
|
||||
(cond
|
||||
((pos-visible-in-window-p (point) win) (setq winok win))
|
||||
((eq thiswin win))
|
||||
((not winbuf) (setq winbuf win))))))
|
||||
nil (not this-frame))
|
||||
(setq vcursor-window
|
||||
(cond
|
||||
(winok) ; choice 2
|
||||
((and vcursor-window ; choice 3
|
||||
(not (eq thiswin vcursor-window))) vcursor-window)
|
||||
(winbuf) ; choice 4
|
||||
(new-win (display-buffer (current-buffer) t)) ; choice 5
|
||||
(t nil))))))) ; default (choice 6)
|
||||
vcursor-window
|
||||
)
|
||||
|
||||
(defun vcursor-toggle-copy (&optional arg nomsg)
|
||||
"Toggle copying to point when the vcursor is moved.
|
||||
With a prefix ARG, turn on if non-negative, off if negative.
|
||||
Display a message unless optional NOMSG is non-nil."
|
||||
(interactive "P")
|
||||
(setq vcursor-copy-flag
|
||||
(cond ((not arg) (not vcursor-copy-flag))
|
||||
((< (prefix-numeric-value arg) 0) nil)
|
||||
(t))
|
||||
vcursor-last-command t)
|
||||
(or nomsg (message "Copying from the vcursor is now %s."
|
||||
(if vcursor-copy-flag "on" "off")))
|
||||
)
|
||||
|
||||
(defun vcursor-move (pt)
|
||||
"Move the virtual cursor to the character to the right of PT.
|
||||
PT is an absolute location in the current buffer.
|
||||
|
||||
If the new virtual cursor location would not be visible, display it in
|
||||
another window."
|
||||
;; this works even if we're on-mass-shell, but usually we won't be.
|
||||
|
||||
(if (eq pt (point-max)) (setq pt (1- pt)))
|
||||
(if (vcursor-check t)
|
||||
(move-overlay vcursor-overlay pt (+ pt 1) (current-buffer))
|
||||
(setq vcursor-overlay (make-overlay pt (+ pt 1)))
|
||||
(overlay-put vcursor-overlay 'face 'vcursor))
|
||||
(vcursor-find-window nil t)
|
||||
;; vcursor-window now contains the right buffer
|
||||
(or (pos-visible-in-window-p pt vcursor-window)
|
||||
(set-window-point vcursor-window pt))
|
||||
)
|
||||
|
||||
(defun vcursor-relative-move (fn &rest args)
|
||||
"Use FUNCTION with arbitrary ARG1 ... to move the virtual cursor.
|
||||
|
||||
This is called by most of the virtual-cursor motion commands."
|
||||
(let (text opoint)
|
||||
(save-excursion
|
||||
(vcursor-locate)
|
||||
(setq opoint (point))
|
||||
(apply fn args)
|
||||
(and (eq opoint (point-max)) (eq opoint (point))
|
||||
(signal 'end-of-buffer nil))
|
||||
(vcursor-move (point))
|
||||
(if vcursor-copy-flag (setq text (buffer-substring opoint (point)))))
|
||||
(if text (insert text)))
|
||||
(setq vcursor-last-command t)
|
||||
)
|
||||
|
||||
(defun vcursor-goto (&optional arg)
|
||||
"Move the real cursor to the virtual cursor position.
|
||||
If the virtual cursor is (or was recently) visible in another window,
|
||||
switch to that first. Without a prefix ARG, disable the virtual
|
||||
cursor as well."
|
||||
|
||||
(interactive "P")
|
||||
(and (vcursor-find-window) (select-window vcursor-window))
|
||||
(let ((buf (and vcursor-overlay (overlay-buffer vcursor-overlay))))
|
||||
(and buf (not (eq (current-buffer) buf)) (switch-to-buffer buf)))
|
||||
(vcursor-locate)
|
||||
(or arg (vcursor-disable))
|
||||
)
|
||||
|
||||
(defun vcursor-swap-point ()
|
||||
"Swap the location of point and that of the virtual cursor.
|
||||
|
||||
The virtual cursor window becomes the selected window and the old
|
||||
window becomes the virtual cursor window. If the virtual cursor would
|
||||
not be visible otherwise, display it in another window."
|
||||
|
||||
(interactive)
|
||||
(let ((buf (current-buffer)) (here (point)) (win (selected-window)))
|
||||
(vcursor-goto) ; will disable the vcursor
|
||||
(save-excursion
|
||||
(set-buffer buf)
|
||||
(setq vcursor-window win)
|
||||
(vcursor-move here)))
|
||||
)
|
||||
|
||||
(defun vcursor-scroll-up (&optional n)
|
||||
"Scroll up the vcursor window ARG lines or near full screen if none.
|
||||
The vcursor will always appear in an unselected window."
|
||||
|
||||
(interactive "P")
|
||||
(vcursor-window-funcall 'scroll-up n)
|
||||
)
|
||||
|
||||
(defun vcursor-scroll-down (&optional n)
|
||||
"Scroll down the vcursor window ARG lines or near-full screen if none.
|
||||
The vcursor will always appear in an unselected window."
|
||||
|
||||
(interactive "P")
|
||||
(vcursor-window-funcall 'scroll-down n)
|
||||
)
|
||||
|
||||
(defun vcursor-isearch-forward (&optional rep norecurs)
|
||||
"Perform forward incremental search in the virtual cursor window.
|
||||
The virtual cursor is moved to the resulting point; the ordinary
|
||||
cursor stays where it was."
|
||||
|
||||
(interactive "P")
|
||||
(vcursor-window-funcall 'isearch-forward rep norecurs)
|
||||
)
|
||||
|
||||
(defun vcursor-window-funcall (func &rest args)
|
||||
"Call FUNC with ARGS ... in a virtual cursor window.
|
||||
A window other than the currently-selected one will always be used.
|
||||
The virtual cursor is moved to the value of point when the function
|
||||
returns."
|
||||
|
||||
(vcursor-find-window t t)
|
||||
(let ((sw (selected-window)) text)
|
||||
;; We can't use save-window-excursion because that would restore
|
||||
;; the original display in the window we may want to alter.
|
||||
(unwind-protect
|
||||
(let ((here (point)))
|
||||
(select-window vcursor-window)
|
||||
(vcursor-locate)
|
||||
(apply func args)
|
||||
(if vcursor-copy-flag (setq text (buffer-substring here (point))))
|
||||
(vcursor-move (point)))
|
||||
(select-window sw))
|
||||
(if text (insert text)))
|
||||
(setq vcursor-last-command t)
|
||||
)
|
||||
|
||||
(defun vcursor-get-char-count (fn &rest args)
|
||||
"Apply FN to ARG1 ... and return the number of characters moved.
|
||||
Point is temporarily set to the virtual cursor position before FN is
|
||||
called.
|
||||
|
||||
This is called by most of the virtual-cursor copying commands to find
|
||||
out how much to copy."
|
||||
|
||||
(vcursor-check)
|
||||
(save-excursion
|
||||
(set-buffer (overlay-buffer vcursor-overlay))
|
||||
(let ((start (goto-char (overlay-start vcursor-overlay))))
|
||||
(- (progn (apply fn args) (point)) start)))
|
||||
)
|
||||
|
||||
;; Make sure the virtual cursor is active. Unless arg is non-nil,
|
||||
;; report an error if it is not.
|
||||
(defun vcursor-check (&optional arg)
|
||||
(cond
|
||||
((and (overlayp vcursor-overlay) (overlay-start vcursor-overlay))
|
||||
t)
|
||||
(arg nil)
|
||||
(t (error "The virtual cursor is not active now.")))
|
||||
)
|
||||
|
||||
(defun vcursor-disable (&optional arg)
|
||||
"Disable the virtual cursor.
|
||||
Next time you use it, it will start from point.
|
||||
|
||||
With a positive prefix ARG, the first window in cyclic order
|
||||
displaying the virtual cursor (or which was recently displaying the
|
||||
virutal cursor) will be deleted unless it's the selected
|
||||
window.
|
||||
|
||||
With a negative prefix argument, enable the virtual cursor: make it
|
||||
active at the same point as the real cursor.
|
||||
|
||||
Copying mode is always turned off: the next use of the vcursor will
|
||||
not copy text until you turn it on again."
|
||||
|
||||
(interactive "P")
|
||||
(if (overlayp vcursor-overlay)
|
||||
(progn
|
||||
(delete-overlay vcursor-overlay)
|
||||
(setq vcursor-overlay nil)))
|
||||
(cond
|
||||
((not (vcursor-find-window t)))
|
||||
((or (not arg) (< (prefix-numeric-value arg) 0)))
|
||||
((delete-window vcursor-window)))
|
||||
(and arg (< (prefix-numeric-value arg) 0)
|
||||
(progn
|
||||
(vcursor-move (point))
|
||||
(setq vcursor-window (selected-window))))
|
||||
(setq vcursor-copy-flag nil)
|
||||
)
|
||||
|
||||
(defun vcursor-other-window (n &optional all-frames)
|
||||
"Activate the virtual cursor in another window.
|
||||
This is the next window cylically after one currently showing the
|
||||
virtual cursor, or else after the current selected window. If there
|
||||
is no other window, the current window is split.
|
||||
|
||||
Arguments N and optional ALL-FRAMES are the same as with other-window.
|
||||
ALL-FRAMES is also used to decide whether to split the window."
|
||||
|
||||
(interactive "p")
|
||||
(if (if (fboundp 'oemacs-version)
|
||||
(one-window-p nil)
|
||||
(one-window-p nil all-frames))
|
||||
(display-buffer (current-buffer) t))
|
||||
(save-excursion
|
||||
(save-window-excursion
|
||||
;; We don't use fancy vcursor-find-window trickery, since we're
|
||||
;; quite happy to have the vcursor cycle back into the current
|
||||
;; window.
|
||||
(let ((sw (selected-window))
|
||||
(win (vcursor-find-window nil nil (not all-frames))))
|
||||
(if win (select-window win))
|
||||
;; else start from here
|
||||
(other-window n all-frames)
|
||||
(vcursor-disable -1))))
|
||||
)
|
||||
|
||||
(defun vcursor-compare-windows (&optional arg)
|
||||
"Call `compare-windows' in the vcursor window.
|
||||
This has the effect of comparing the vcursor window with whichever
|
||||
window `next-window' returns there, which may not be the selected one.
|
||||
|
||||
A prefix argument, if any, is passed to `compare-windows'."
|
||||
(interactive "P")
|
||||
(vcursor-window-funcall 'compare-windows arg))
|
||||
|
||||
(defun vcursor-next-line (arg)
|
||||
"Move the virtual cursor forward ARG lines."
|
||||
;; This is next-line rewritten for the vcursor. Maybe it would
|
||||
;; be easier simply to rewrite line-move.
|
||||
(interactive "p")
|
||||
(let (temporary-goal-column opoint text)
|
||||
(save-excursion
|
||||
(vcursor-locate)
|
||||
(setq temporary-goal-column
|
||||
(if (or (eq last-command 'vcursor-next-line)
|
||||
(eq last-command 'vcursor-previous-line))
|
||||
(progn
|
||||
(setq last-command 'next-line) ; trick line-move
|
||||
vcursor-temp-goal-column)
|
||||
(if (and track-eol (eolp)
|
||||
(or (not (bolp)) (eq last-command 'end-of-line)))
|
||||
9999
|
||||
(current-column)))
|
||||
opoint (point))
|
||||
(line-move arg)
|
||||
(and (eq opoint (point-max)) (eq opoint (point))
|
||||
(signal 'end-of-buffer nil))
|
||||
(if vcursor-copy-flag (setq text (buffer-substring opoint (point))))
|
||||
(vcursor-move (point))
|
||||
(setq vcursor-temp-goal-column temporary-goal-column
|
||||
vcursor-last-command t))
|
||||
(if text (insert text)))
|
||||
)
|
||||
|
||||
(defun vcursor-previous-line (arg)
|
||||
"Move the virtual cursor back ARG lines."
|
||||
(interactive "p")
|
||||
(vcursor-next-line (- arg))
|
||||
)
|
||||
|
||||
(defun vcursor-forward-char (arg)
|
||||
"Move the virtual cursor forward ARG characters."
|
||||
(interactive "p")
|
||||
(vcursor-relative-move 'forward-char arg)
|
||||
)
|
||||
|
||||
(defun vcursor-backward-char (arg)
|
||||
"Move the virtual cursor backward ARG characters."
|
||||
(interactive "p")
|
||||
(vcursor-relative-move 'backward-char arg)
|
||||
)
|
||||
|
||||
(defun vcursor-forward-word (arg)
|
||||
"Move the virtual cursor forward ARG words."
|
||||
(interactive "p")
|
||||
(vcursor-relative-move 'forward-word arg)
|
||||
)
|
||||
|
||||
(defun vcursor-backward-word (arg)
|
||||
"Move the virtual cursor backward ARG words."
|
||||
(interactive "p")
|
||||
(vcursor-relative-move 'backward-word arg)
|
||||
)
|
||||
|
||||
(defun vcursor-beginning-of-line (arg)
|
||||
"Move the virtual cursor to beginning of its current line.
|
||||
ARG is as for `beginning-of-line'."
|
||||
(interactive "P")
|
||||
(vcursor-relative-move 'beginning-of-line
|
||||
(if arg (prefix-numeric-value arg)))
|
||||
)
|
||||
|
||||
(defun vcursor-end-of-line (arg)
|
||||
"Move the virtual cursor to end of its current line.
|
||||
ARG is as for `end-of-line'."
|
||||
(interactive "P")
|
||||
(vcursor-relative-move 'end-of-line
|
||||
(if arg (prefix-numeric-value arg)))
|
||||
)
|
||||
|
||||
(defun vcursor-beginning-of-buffer (&optional arg)
|
||||
"Move the virtual cursor to the beginning of its buffer.
|
||||
ARG is as for beginning-of-buffer."
|
||||
(interactive "P")
|
||||
(vcursor-relative-move
|
||||
(lambda (arg)
|
||||
(goto-char (if arg (/ (* arg (- (point-max) (point-min))) 10)
|
||||
(point-min))))
|
||||
(if arg (prefix-numeric-value arg)))
|
||||
)
|
||||
|
||||
(defun vcursor-end-of-buffer (&optional arg)
|
||||
"Move the virtual cursor to the end of its buffer.
|
||||
ARG is as for end-of-buffer.
|
||||
|
||||
Actually, the vcursor is moved to the second from last character or it
|
||||
would be invisible."
|
||||
(interactive "P")
|
||||
(vcursor-relative-move
|
||||
(lambda (arg)
|
||||
(goto-char (if arg (- (point-max)
|
||||
(/ (* arg (- (point-max) (point-min))) 10))
|
||||
(point-max))))
|
||||
(if arg (prefix-numeric-value arg)))
|
||||
)
|
||||
|
||||
(defun vcursor-execute-command (cmd)
|
||||
"Execute COMMAND for the virtual cursor.
|
||||
COMMAND is called interactively. Not all commands (in fact, only a
|
||||
small subset) are useful."
|
||||
(interactive "CCommand: ")
|
||||
(let (text opoint)
|
||||
(save-excursion
|
||||
(vcursor-locate)
|
||||
(setq opoint (point))
|
||||
(call-interactively cmd)
|
||||
(if vcursor-copy-flag (setq text (buffer-substring opoint (point))))
|
||||
(vcursor-move (point)))
|
||||
(if text (insert text)))
|
||||
(setq vcursor-last-command t)
|
||||
)
|
||||
|
||||
(defun vcursor-execute-key (keys)
|
||||
"Execute the command bound to KEYS for the virtual cursor.
|
||||
The command found is called interactively, so prefix argument etc.
|
||||
are usable."
|
||||
|
||||
(interactive "kKey sequence: ")
|
||||
(let ((cmd (key-binding keys)))
|
||||
(if cmd (vcursor-execute-command (key-binding keys))))
|
||||
)
|
||||
|
||||
(defun vcursor-copy (arg)
|
||||
"Copy ARG characters from the virtual cursor position to point."
|
||||
(interactive "p")
|
||||
(vcursor-check)
|
||||
(insert
|
||||
(save-excursion
|
||||
(set-buffer (overlay-buffer vcursor-overlay))
|
||||
(let* ((ostart (overlay-start vcursor-overlay))
|
||||
(end (+ ostart arg)))
|
||||
(prog1
|
||||
(buffer-substring ostart end)
|
||||
(vcursor-move end)))))
|
||||
(setq vcursor-last-command t)
|
||||
)
|
||||
|
||||
(defun vcursor-copy-word (arg)
|
||||
"Copy ARG words from the virtual cursor position to point."
|
||||
(interactive "p")
|
||||
(vcursor-copy (vcursor-get-char-count 'forward-word arg))
|
||||
)
|
||||
|
||||
(defun vcursor-copy-line (arg)
|
||||
"Copy up to ARGth line after virtual cursor position.
|
||||
With no argument, copy to the end of the current line.
|
||||
|
||||
Behaviour with regard to newlines is similar (but not identical) to
|
||||
`kill-line'; the main difference is that whitespace at the end of the
|
||||
line is treated like ordinary characters."
|
||||
|
||||
(interactive "P")
|
||||
(let* ((num (prefix-numeric-value arg))
|
||||
(count (vcursor-get-char-count 'end-of-line num)))
|
||||
(vcursor-copy (if (or (= count 0) arg) (1+ count) count)))
|
||||
)
|
||||
|
||||
(defun vcursor-post-command ()
|
||||
(and vcursor-auto-disable (not vcursor-last-command)
|
||||
vcursor-overlay (vcursor-disable))
|
||||
(setq vcursor-last-command nil)
|
||||
)
|
||||
|
||||
(add-hook 'post-command-hook 'vcursor-post-command)
|
||||
|
||||
(provide 'vcursor)
|
||||
|
||||
;; vcursor.el ends here
|
||||
Loading…
Add table
Add a link
Reference in a new issue