Homepage: https://www.gnu.org/software/emacs
Author: Peter Stephenson
Manipulate an alternative ("virtual") cursor
Latest changes ============== - *IMPORTANT* `vcursor-key-bindings' is now nil by default, to avoid side-effects when the package is loaded. This means no keys are bound by default. Use customize to change it to t to restore the old behavior. (If you do it by hand in .emacs, it must come before vcursor is loaded.) - You can alter the main variables and the vcursor face via M-x customize: go to the Editing group and find Vcursor. - `vcursor-auto-disable' can now be 'copy (actually any value not nil or t), which means that copying from the vcursor will be turned off after any operation not involving the vcursor, but the vcursor itself will be left alone. - works on dumb terminals - new keymap vcursor-map for binding to a prefix key - `vcursor-compare-windows' substantially improved - `vcursor-execute-{key,command}' much better about using the right keymaps and arranging for the correct windows to be used - `vcursor-window-funcall' can call functions interactively - `vcursor-interpret-input' for special effects Introduction ============ Virtual cursor commands. I got this idea from the old BBC micro. You need a window system for the best effects. This is much easier to use than the instructions are to read. First, you need to let vcursor define some keys: setting vcursor-key-bindings to t before loading, or by customize, will define various keys with the prefix C-S. You'll have to read further if you don't want this. Then 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"). There is also a keymap which you can bind to a prefix key, which may give some more intuitive alternatives in some cases, see `The vcursor keymap' below. 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 behavior 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 give 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 set it to non-nil but not t, then the vcursor itself will remain active, but copying will be turned off, so that the next time the vcursor is moved no text is copied over. Experience shows that this setting is particularly useful. 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.) vcursor-compare-windows is now a reliable adaption of compare-windows, which compares between point in the current buffer and the vcursor location in the other one. It is an error if vcursor is not set, however it will be brought up in another window if it is not currently visible. The prefix argument acts just like compare-windows, ignoring whitespace if set. (In versions before 1.6, this simply called compare-windows, which was much less likely to pick the two windows you wanted.) 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. This has many uses not necessarily related to moving the vcursor itself; it can do essentially everything that the \C-x 4 series of commands can do and a lot more. Note, however, that a new window is not used if the vcursor is visible in the current one: this can lead to some strange effects, but it is preferable to making a new window every time the vcursor is moved in this may. C-S-f10 (C-S-x) (vcursor-execute-command) behaves the same way but you enter the name of the command. To do anything really 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). Key bindings ============ 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 traveled) 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. Usage on dumb terminals ======================= If Emacs has set the variable window-system to nil, vcursor will assume that overlays cannot be displayed in a different face, and will instead use a string (the variable vcursor-string, by default "**>") to show its position. This was first implemented in Emacs 19.29. Unlike the old-fashioned overlay arrow (as used by debuggers), this appears between existing text, which can make it hard to read if you're not used to it. (This seemed the better option here.) This means moving the vcursor up and down is a very efficient way of locating it! Everything else should function as expected, but there is no way to get an easy key binding for the vcursor keys on a generic terminal. Consequently a special keymap is defined for you to use traditional methods: the keymap, however, is available on any terminal type. The vcursor keymap ================== In addition to any other bindings, vcursor-map contains key definitions for handling the vcursor. You should assign this to a prefix key in the usual way, e.g. (global-set-key [f14] vcursor-map) and also as usual \C-h in this map will list the key definitions, which are designed to be easy to remember. A special feature is provided by (vcursor-use-vcursor-map), bound to t in that keymap. With this in effect, the main keymap is overridden by the vcursor map, so keys like \C-p and so on move the vcursor instead. Remember how to turn it off (type t), or you are in serious trouble! Note that the cursor keys are not bound by default in this keymap and will continue to move the ordinary cursor. Interpreted input ================= Just occasionally, you may want to pretend the strings copied from the vcursor position are to be interpreted as if you had typed them from the keyboard. Normally, they will just insert themselves anyway, but in some modes (Info and calc for example) typing ordinary characters does something else. To get this effect, set vcursor-interpret-input to t. This is normally not a good idea as interpreting input is very much slower than copying text. 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 enhancements: 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.