;;; fusion.el --- CodeWright Fusion-style motion and text selection ;; Copyright (C) 1997 Kirill M. Katsnelson ;; Author: Kirill M. Katsnelson ;; Date written: 1997 ;; Keywords: keyboard selection region ;; Version: 1.2 ;; This file is part of XEmacs. ;; XEmacs 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. ;; XEmacs 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 XEmacs; see the file COPYING. If not, write to the Free ;; Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA ;; 02111-1307, USA. ;;; Synched up with: Not synched. ;;; Commentary: ;; Fusion provides emulation of cursor motion and shift-mark selection ;; compatible with CodeWright Fusion. ;; ;; CodeWright is a text editor with concepts close to emacs and ;; XEmacs, sold by Premia Corp. It has similar barenaked shell stuffed ;; with editing functionality using macro language, but unlike emacsen ;; it uses a set of C macros, so its macros are externally compiled. ;; ;; 'Fusion' is a mode of CodeWright which resembles closely the ;; behavior of Microsoft Developer Studio embedded editor. The correct ;; name for this package would be msvc-motion then; but, author's ;; opinion is that 'fusion' sounds better! ;; ;; Usage: ;; ------ ;; Put the one of the following lines into your .emacs file: ;; (fusion-set-mode t) ;; Load fusion and turn it on ;; or ;; (require 'fusion) ;; Load fusion and turn it off ;; ;; If you want that fusion mode does not appear neither on the ;; modeline nor in the minor mode menu, also add ;; (put 'fusion-mode :included nil) ;; ;; (this only makes sense if you turn on the mode programmatically: ;; in this case, there in no way to turn it on from the UI) ;; ;; [As of 21.0 beta 31, the mode indicator is not hidden on the ;; modeline. This probably will be fixed] ;;; ChangeLog ;; First written long ago ;; November 1997 : v1.2: converted into a minor mode. ;; March 1997 : First public release. ;;; Code: ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;; Set-up ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (defvar fusion-mode nil "Non-nil when fusion mode is enabled. Do not set this. You should call `fusion-set-mode' or `fusion-mode' instead.") ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;; Caret motion functions ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (defun fusion-up (&optional ARG) "Move up a line" (interactive "_p") ;; Awful unbelievable kludge. (setq this-command 'previous-line) (condition-case nil (previous-line ARG) (beginning-of-buffer nil))) (defun fusion-down (&optional ARG) "Move down a line" (interactive "_p") ;; Utter topmost kludge. (setq this-command 'next-line) (condition-case nil (next-line ARG) (end-of-buffer nil))) (defun fusion-left (&optional ARG) "Move left a character. Do not signal if sob is reached." (interactive "_p") (condition-case nil (backward-char ARG) (beginning-of-buffer nil))) (defun fusion-right (&optional ARG) "Move right a character. Do not signal if eob is reached." (interactive "_p") (condition-case nil (forward-char ARG) (end-of-buffer nil))) (defun fusion-home () "Go to the first non-blank in the line or to the line start. Moves to the line beginning if positioned on or left to the first non-blank character on the line. Moves to the first non-blank character if positioned right to such character or at the line beginning." (interactive "_") (if (zerop (current-column)) (back-to-indentation) (let ((oldpos (point))) (back-to-indentation) (if (<= oldpos (point)) (beginning-of-line))))) (defun fusion-end () "Go to the end of the current line." (interactive "_") (end-of-line)) ;This function returns amount of lines to scroll, based on current window size (defun fusion-scroll-lines () "This is an internal function of the fusion package" (max 1 (- (window-displayed-height) next-screen-context-lines))) (defun fusion-pageup (&optional ARG) "Move ARG (or 1) pages up. Stop exactly at the start of buffer." (interactive "_p") (condition-case nil (scroll-down (if (and ARG (> ARG 1)) ARG (fusion-scroll-lines))) (beginning-of-buffer (fusion-bob)))) (defun fusion-pagedown (&optional ARG) "Move ARG (or 1) pages down. Stop exactly at end of buffer." (interactive "_p") (condition-case nil (scroll-down (- (if (and ARG (> ARG 1)) ARG (fusion-scroll-lines)))) (end-of-buffer (fusion-sol-eob)))) (defun fusion-bob () "Go to the beginning of buffer." (interactive "_") (goto-char 0)) (defun fusion-sol-eob () "Go to the beginning of the last line of buffer." (interactive "_") (goto-char (point-max)) (beginning-of-line)) (defun fusion-eob () "Go to the end of buffer." (interactive "_") (goto-char (point-max))) (defun fusion-wordleft (&optional ARG) "Go to the beginning of the previous word" (interactive "_p") (condition-case nil (forward-word (- (or ARG 1))) (beginning-of-buffer nil))) (defun fusion-wordright (&optional ARG) "Go to the end of the next word" (interactive "_p") (condition-case nil (forward-word (or ARG 1)) (end-of-buffer nil))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;; Shift-arrows region mark functions ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;; This var stores point recorded by pre-command hook. ;; (defvar fusion-precommand-point 0 "This is an internal variable of the fusion package") ;; ;; This variable is set to t after zmacs-regions warning has ;; been reported to user ;; (defvar fusion-zmacs-regions-warned-p nil "This is an internal variable of the fusion package") ;; ;; This just stores before-command position, ;; to which we can possibly move mark in our ;; post-command hook ;; (defun fusion-precommand () "This is an internal function of the fusion package" (setq fusion-precommand-point (point))) ;; ;; The algorithm is as follows: ;; If position has changed AND the key is pressed, ;; AND this was a motion key, THEN: ;; IF region is currently active AND shift key ;; was up, then deactivate region; ;; IF region is inactive, AND shift key is down, ;; then set mark to the pre-command position ;; and activate the region. ;; (defun fusion-postcommand () "This is an internal function of the fusion package" (if zmacs-regions (when (and (key-press-event-p last-input-event) (memq (event-key last-input-event) '(left right up down home end prior next))) ; Trigger to issue a warning again if zmacs-regions will be re-disabled (setq fusion-zmacs-regions-warned-p nil) (let ((shift-down (memq 'shift (event-modifiers last-input-event)))) (when (and zmacs-region-active-p (not shift-down)) (zmacs-deactivate-region) (setq zmacs-region-stays nil)) (when (and (not zmacs-region-active-p) shift-down) (set-mark fusion-precommand-point) (zmacs-activate-region)))) (unless fusion-zmacs-regions-warned-p (setq fusion-zmacs-regions-warned-p t) (warn "Fusion style selection does not work unless zmacs-regions are enabled!")))) ;; ;; This function disables fusion keys in a minibuffer. ;; Hooks and thus shift-mark still works though. ;; (defun fusion-minibuffer-setup () "This is an internal function of the fusion package" (set (make-local-variable 'fusion-mode) nil)) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;; Toggle function ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;###autoload (defun fusion-mode () "Toggle fusion mode on and off. See also `fusion-set-mode'" (interactive) (let ((fn (if fusion-mode 'remove-hook 'add-hook))) (funcall fn 'pre-command-hook 'fusion-precommand) (funcall fn 'post-command-hook 'fusion-postcommand)) (setq fusion-mode (not fusion-mode)) (redraw-modeline t) fusion-mode) ;;;###autoload (defun fusion-set-mode (&optional on) "Turn fusion mode off when ON is nil, on otherwise See also `fusion-mode'" (when (or (and on (not fusion-mode)) (and (not on) fusion-mode)) (fusion-mode))) ; Guard against double init (unless (featurep 'fusion) (add-minor-mode 'fusion-mode " Fusn" (let ((map (make-keymap))) (define-key map 'up 'fusion-up) (define-key map 'down 'fusion-down) (define-key map 'left 'fusion-left) (define-key map 'right 'fusion-right) (define-key map 'prior 'fusion-pageup) (define-key map 'next 'fusion-pagedown) (define-key map 'home 'fusion-home) (define-key map 'end 'fusion-end) (define-key map '(control up) 'fusion-up) (define-key map '(control down) 'fusion-down) (define-key map '(control left) 'fusion-wordleft) (define-key map '(control right) 'fusion-wordright) (define-key map '(control prior) 'fusion-bob) (define-key map '(control next) 'fusion-sol-eob) (define-key map '(control home) 'fusion-bob) (define-key map '(control end) 'fusion-eob) map)) (add-hook 'minibuffer-setup-hook 'fusion-minibuffer-setup)) (provide 'fusion) ;;; fusion.el ends here