From b8f1c989957e96767993d0fc21ced894e3445489 Mon Sep 17 00:00:00 2001 From: David Aspinall Date: Sun, 6 Sep 2009 13:24:17 +0000 Subject: Cleanup code and use define-minor-mode. --- lib/holes.el | 689 ++++++++++++++++++++++++----------------------------------- 1 file changed, 279 insertions(+), 410 deletions(-) diff --git a/lib/holes.el b/lib/holes.el index 0865cd4c..40bad9a0 100644 --- a/lib/holes.el +++ b/lib/holes.el @@ -10,6 +10,8 @@ ;; Credits also to Stefan Monnier for great help in making this file ;; cleaner. ;; +;; Further cleanups by David Aspinall. +;; ;; This software is free software; you can redistribute it and/or ;; modify it under the terms of the GNU General Public ;; License version 2, as published by the Free Software Foundation. @@ -25,134 +27,58 @@ ;; ;;; Commentary: -;; See documentation in variable holes-doc. - -;;; History: ;; +;; See documentation of `holes-mode'. -(eval-when-compile (require 'span)) -(require 'cl) - -;;; Help: - -(defvar holes-doc nil - "The mode `holes-mode' is meant to help program editing. -It is useful to build complicated expressions by copy pasting several -peaces of text from different parts of a buffer (or even from -different buffers). - - HOLES - -A hole is a piece of (highlighted) text that may be replaced by -another part of text later. There is no information stored on the -file for holes, so you can save and modify files containing holes with -no harm... You can even insert or delete characters inside holes like -any other characters. - - USE - -At any time only one particular hole, called \"active\", can be -\"filled\". Holes can be in several buffers but there is always one or -zero active hole globally. It is highlighted with a different color. - -Functions described below have default shortcuts when `holes-mode' is -on that you can customize. - -TO DEFINE A HOLE, two methods: - - o Select a region with keyboard or mouse, then use - \\[holes-set-make-active-hole]. If the selected region is empty, - then a hole containing # is created at point. - - o Select text with mouse while pressing ctrl and meta (`C-M-select'). - If the selected region is empty (i.e. if you just click while - pressing ctrl+meta), then a hole containing # is created. - -TO ACTIVATE A HOLE, click on it with the button 1 of your mouse. The -previous active hole will be deactivated. - -TO FORGET A HOLE without deleting its text, click on it with the -button 2 (middle) of your mouse. - -TO DESTROY A HOLE and delete its text, click on it with the button 3 -of your mouse. - -TO FILL A HOLE with a text selection, first make sure it is active, -then two methods: - - o Select text with keyboard or mouse and hit - \\[holes-replace-update-active-hole] - - o Select text with mouse while pressing ctrl, meta and shift - (`C-M-S-select'). This is a - generalization of the `mouse-track-insert' feature of XEmacs. This - method allows you to fill different holes faster than with the usual - copy-paste method. - -After replacement the next hole is automatically made active so you -can fill it immediately by hitting again -\\[holes-replace-update-active-hole] or `C-M-S-select'. - -TO JUMP TO THE ACTIVE HOLE, just hit -\\[holes-set-point-next-hole-destroy]. You must -be in the buffer containing the active hole. the point will move to -the active hole, and the active hole will be destroyed so you can type -something to put at its place. The following hole is automatically -made active, so you can hit \\[holes-set-point-next-hole-destroy] -again. - -It is useful in combination with abbreviations. For example in -`coq-mode' \"fix\" is an abbreviation for Fixpoint # (# : #) {struct #} : -# := #, where each # is a hole. Then hitting -\\[holes-set-point-next-hole-destroy] goes from one hole to the -following and you can fill-in each hole very quickly. - -COMBINING HOLES AND SKELETONS - -`holes' minor mode is made to work with minor mode `skeleton' minor -mode. For the moment only Emacs version of `skeleton' is compatible -with `holes', not XEmacs's. When you insert a skeleton, each -interesting position will be replaced by a hole. - - KNOWN BUGS - - o Don't try to make overlapping holes, it doesn't work. (what would -it mean anyway?) - - o With Emacs, cutting or pasting a hole wil not produce new -holes, and undoing on holes cannot make holes re-appear. With XEmacs -it will, but if you copy paste the active hole, you will get several -holes highlighted as the active one (whereas only one of them really -is), which is annoying. -") +(eval-when-compile + (require 'span)) +(require 'cl) ;;; Code: +;;; ;;; initialization -(defvar holes-default-hole (make-detached-span) +;;; + +(defvar holes-default-hole + (let ((ol (make-overlay 0 0))) + (delete-overlay ol) ol) "An empty detached hole used as the default hole. You should not use this variable.") -(span-detach holes-default-hole) + (defvar holes-active-hole holes-default-hole "The current active hole. There can be only one active hole at a time, and this is this one. This is not buffer local.") -;;; end initialization -;;;customizable + +;;; +;;; Customizable +;;; + +(defgroup holes nil + "Customization for Holes minor mode." + :prefix "holes-" + :group 'editing) + (defcustom holes-empty-hole-string "#" - "String to be inserted for empty hole (don't put an empty string).") + "String to be inserted for empty hole (don't put an empty string)." + :type 'string + :group 'holes) (defcustom holes-empty-hole-regexp "#\\|@{\\([^{}]*\\)}" "Regexp denoting a hole in abbrevs. Subgroup 1 is treated specially: if it matches, it is assumed that everything before it and after it in the regexp matches delimiters -which should be removed when making the text into a hole.") +which should be removed when making the text into a hole." + :type 'regexp + :group 'holes) -(defcustom holes-search-limit 1000 - "Number of chars to look forward when looking for the next hole, unused for now.") ;unused for the moment +;(defcustom holes-search-limit 1000 +; "Number of chars to look forward when looking for the next hole, unused for now.") +;unused for the moment ;; The following is customizable by a command of the form: ;;for dark background @@ -170,7 +96,8 @@ which should be removed when making the text into a hole.") :background "darkred" :foreground "white") (((class color) (background light)) :background "paleVioletRed" :foreground "black")) - "Font Lock face used to highlight the active hole.") + "Font Lock face used to highlight the active hole." + :group 'holes) (defface inactive-hole-face '((((class grayscale) (background light)) :background "lightgrey") @@ -179,137 +106,150 @@ which should be removed when making the text into a hole.") :background "mediumblue" :foreground "white") (((class color) (background light)) :background "lightsteelblue" :foreground "black")) - "Font Lock face used to highlight the active hole.") + "Font Lock face used to highlight the active hole." + :group 'holes) + +;;; +;;; Keymaps +;;; + +(defvar hole-map + (let ((map (make-sparse-keymap))) + (define-key map [(mouse-1)] 'holes-mouse-set-active-hole) + (define-key map [(mouse-3)] 'holes-mouse-destroy-hole) + (define-key map [(mouse-2)] 'holes-mouse-forget-hole) + map) + "Keymap to use on the holes's overlays. +This keymap is used only when point is on a hole. +See `holes-mode-map' for the keymap of `holes-mode'.") + +(defvar holes-mode-map + (let ((map (make-sparse-keymap))) + (define-key map [(control c) (h)] 'holes-set-make-active-hole) + (define-key map [(control c) (control y)] 'holes-replace-update-active-hole) + (define-key map [(control meta down-mouse-1)] + 'holes-mouse-set-make-active-hole) + (define-key map [(control meta shift down-mouse-1)] + 'holes-mouse-replace-active-hole) + (define-key map [(control c) (control j)] + 'holes-set-point-next-hole-destroy) + map) + "Keymap of `holes-mode'. -;;; end customizable +This one is active whenever we are on a buffer where `holes-mode' is active. +This is not the keymap used on holes's overlay (see `hole-map' instead).") + + +;;;(global-set-key [(control meta **WRONG** space ) ] 'holes-set-active-hole-next) + + + +;;; +;;; Utility functions +;;; (defun holes-region-beginning-or-nil () - "Internal." + "Return the beginning of the acitve region, or nil." (and mark-active (region-beginning))) (defun holes-region-end-or-nil () - "Internal." + "Return the end of the acitve region, or nil." (and mark-active (region-end))) (defun holes-copy-active-region () - "Internal." + "Copy and retuurn the active region." (assert mark-active nil "the region is not active now.") (copy-region-as-kill (region-beginning) (region-end)) (car kill-ring)) -(defun holes-is-hole-p (SPAN) - ;; checkdoc-params: (SPAN) - "Internal." - (span-property SPAN 'hole)) +(defun holes-is-hole-p (span) + "Non-nil if SPAN is a HOLE." + (span-property span 'hole)) -(defun holes-hole-start-position (HOLE) - ;; checkdoc-params: (HOLE) - "Internal." - (assert (holes-is-hole-p HOLE) t "holes-hole-start-position: %s is not a hole") - (span-start HOLE)) +(defun holes-hole-start-position (hole) + "Return start position of HOLE." + (assert (holes-is-hole-p hole) t + "holes-hole-start-position: %s is not a hole") + (span-start hole)) -(defun holes-hole-end-position (HOLE) - ;; checkdoc-params: (HOLE) - "Internal." - (assert (holes-is-hole-p HOLE) t "holes-hole-end-position: %s is not a hole") - (span-end HOLE) - ) +(defun holes-hole-end-position (hole) + "Return end position of HOLE." + (assert (holes-is-hole-p hole) t "holes-hole-end-position: %s is not a hole") + (span-end hole)) -(defun holes-hole-buffer (HOLE) - ;; checkdoc-params: (HOLE) +(defun holes-hole-buffer (hole) + "Return the buffer of HOLE." "Internal." - (assert (holes-is-hole-p HOLE) t "holes-hole-buffer: %s is not a hole") - (span-buffer HOLE) - ) + (assert (holes-is-hole-p hole) t "holes-hole-buffer: %s is not a hole") + (span-buffer hole)) (defun holes-hole-at (&optional pos) - "Return the hole (an span) at POS in current buffer. + "Return the hole (a span) at POS in current buffer. If pos is not in a hole raises an error." - (span-at (or pos (point)) 'hole) - ) - + (span-at (or pos (point)) 'hole)) (defun holes-active-hole-exist-p () - "Return t if the active hole exists and is not empty (ie detached). Use this to know if the active hole is set and usable (don't use the active-hole-marker variable)." - - (not (span-detached-p holes-active-hole)) - ) + (not (span-detached-p holes-active-hole))) (defun holes-active-hole-start-position () "Return the position of the start of the active hole. See `active-hole-buffer' to get its buffer. Returns an error if active hole doesn't exist (the marker is set to nothing)." - (assert (holes-active-hole-exist-p) t "holes-active-hole-start-position: no active hole") - (holes-hole-start-position holes-active-hole) - ) + (holes-hole-start-position holes-active-hole)) (defun holes-active-hole-end-position () "Return the position of the start of the active hole. See `active-hole-buffer' to get its buffer. Returns an error if active hole doesn't exist (the marker is set to nothing)." - (assert (holes-active-hole-exist-p) t "holes-active-hole-end-position: no active hole") - (holes-hole-end-position holes-active-hole) - ) + (holes-hole-end-position holes-active-hole)) (defun holes-active-hole-buffer () - "Return the buffer containing the active hole. Raise an error if the active hole is not set. Don't care if the active hole is empty." - (assert (holes-active-hole-exist-p) t "holes-active-hole-buffer: no active hole") - (holes-hole-buffer holes-active-hole) - ) + (holes-hole-buffer holes-active-hole)) (defun holes-goto-active-hole () - "Set point to active hole. Raises an error if active-hole is not set." - (interactive) (assert (holes-active-hole-exist-p) t "holes-goto-active-hole: no active hole") - (goto-char (holes-active-hole-start-position)) - ) + (goto-char (holes-active-hole-start-position))) -(defun holes-highlight-hole-as-active (HOLE) +(defun holes-highlight-hole-as-active (hole) "Highlight a HOLE with the `active-hole-face'. DON'T USE this as it would break synchronization (non active hole highlighted)." - - (assert (holes-is-hole-p HOLE) t + (assert (holes-is-hole-p hole) t "holes-highlight-hole-as-active: %s is not a hole") - (set-span-face HOLE 'active-hole-face) - ) + (set-span-face hole 'active-hole-face)) -(defun holes-highlight-hole (HOLE) +(defun holes-highlight-hole (hole) "Highlight a HOLE with the not active face. DON'T USE this as it would break synchronization (active hole non highlighted)." - - (assert (holes-is-hole-p HOLE) t + (assert (holes-is-hole-p hole) t "holes-highlight-hole: %s is not a hole") - (set-span-face HOLE 'inactive-hole-face) - ) - + (set-span-face hole 'inactive-hole-face)) (defun holes-disable-active-hole () "Disable the active hole. The goal remains but is not the active one anymore. Does nothing if the active hole is already disable." - (if (not (holes-active-hole-exist-p)) () ;; HACK: normal hole color, this way undo will show this hole @@ -317,138 +257,102 @@ the active hole is already disable." ;; the active hole, but it doesn't, so we put the 'not active' ;; color. (holes-highlight-hole holes-active-hole) - (setq holes-active-hole holes-default-hole) - ) - ) - - - -(defun holes-set-active-hole (HOLE) + (setq holes-active-hole holes-default-hole))) +(defun holes-set-active-hole (hole) "Set active hole to HOLE. Error if HOLE is not a hole." - - (assert (holes-is-hole-p HOLE) t + (assert (holes-is-hole-p hole) t "holes-set-active-hole: %s is not a hole") - (if (holes-active-hole-exist-p) (holes-highlight-hole holes-active-hole)) - (setq holes-active-hole HOLE) - (holes-highlight-hole-as-active holes-active-hole) - ) - + (if (holes-active-hole-exist-p) + (holes-highlight-hole holes-active-hole)) + (setq holes-active-hole hole) + (holes-highlight-hole-as-active holes-active-hole)) (defun holes-is-in-hole-p (&optional pos) "Return non-nil if POS (default: point) is in a hole, nil otherwise." - (holes-hole-at pos) - ) - - + (holes-hole-at pos)) (defun holes-make-hole (start end) "Make and return an (span) hole from START to END." (let ((ext (span-make start end))) (set-span-properties - ext `( - hole t + ext `(hole t mouse-face highlight priority 100 ;; what should I put here? I want big priority face secondary-selection start-open nil end-open t duplicable t - ;; unique t - ;; really disappear if empty: - evaporate t ;; Emacs - detachable t ;; XEmacs + evaporate t ;; really disappear if empty ;; pointer frame-icon-glyph + keymap ,hole-map help-echo "this is a \"hole\", button 2 to forget, button 3 to destroy, button 1 to make active" - 'balloon-help "this is a \"hole\", button 2 to forget, button 3 to destroy, button 1 to make active" - )) - - (set-span-keymap ext hole-map) - ext - ) - ) + 'balloon-help "this is a \"hole\", button 2 to forget, button 3 to destroy, button 1 to make active")) + ext)) (defun holes-make-hole-at (&optional start end) "Make a hole from START to END. If no arg default hole after point. If only one arg: error. Return the span." (interactive) - (let* ((rstart (or start (holes-region-beginning-or-nil) (point))) (rend (or end (holes-region-end-or-nil) (point)))) (if (eq rstart rend) (progn (goto-char rstart) (insert holes-empty-hole-string) - (setq rend (point)) - ) - ) - (holes-make-hole rstart rend) - ) - ) - + (setq rend (point)))) + (holes-make-hole rstart rend))) -(defun holes-clear-hole (HOLE) - ; checkdoc-params: (HOLE) - "Internal." - (assert (holes-is-hole-p HOLE) t +(defun holes-clear-hole (hole) + "Clear the HOLE." + (assert (holes-is-hole-p hole) t "holes-clear-hole: %s is not a hole") - - (if (and (holes-active-hole-exist-p) (eq holes-active-hole HOLE)) - (holes-disable-active-hole) - ) - (span-delete HOLE) - ) + (if (and (holes-active-hole-exist-p) + (eq holes-active-hole hole)) + (holes-disable-active-hole)) + (span-delete hole)) (defun holes-clear-hole-at (&optional pos) "Clear hole at POS (default=point)." (interactive) (if (not (holes-is-in-hole-p (or pos (point)))) (error "Holes-clear-hole-at: no hole here")) - (holes-clear-hole (holes-hole-at (or pos (point)))) - ) + (holes-clear-hole (holes-hole-at (or pos (point))))) -(defun holes-map-holes (FUNCTION &optional OBJECT FROM TO) - ; checkdoc-params: (FUNCTION OBJECT FROM TO) - "Internal." - (fold-spans FUNCTION OBJECT FROM TO nil nil 'hole) - ) - +(defun holes-map-holes (function &optional object from to) + "Map function FUNCTION across holes." + (fold-spans function object from to nil nil 'hole)) - -(defun holes-mapcar-holes (FUNCTION &optional FROM TO PROP) - ; checkdoc-params: (FUNCTION FROM TO PROP) - "Internal." - (span-mapcar-spans FUNCTION FROM TO 'hole) - ) +(defun holes-mapcar-holes (function &optional from to prop) + "Map function FUNCTION across spans." + (span-mapcar-spans function from to 'hole)) (defun holes-clear-all-buffer-holes (&optional start end) "Clear all holes leaving their contents. Operate betwenn START and END if non nil." (interactive) (holes-disable-active-hole) - (holes-mapcar-holes 'holes-clear-hole (or start (point-min)) (or end (point-max)) 'hole) - ) - - + (holes-mapcar-holes + 'holes-clear-hole (or start (point-min)) (or end (point-max)) + 'hole)) ;;; limit ? -(defun holes-next (pos BUFFER) +(defun holes-next (pos buffer) "Return the first hole after POS in BUFFER. Or after the hole at pos if there is one (default pos=point). If no hole found, return nil." - (holes-map-holes '(lambda (h x) (and (holes-is-hole-p h) h)) BUFFER pos) - ) + (holes-map-holes + '(lambda (h x) (and (holes-is-hole-p h) h)) buffer pos)) (defun holes-next-after-active-hole () "Internal." (assert (holes-active-hole-exist-p) t "next-active-hole: no active hole") (holes-next (holes-active-hole-end-position) - (holes-active-hole-buffer)) - ) + (holes-active-hole-buffer))) (defun holes-set-active-hole-next (&optional buffer pos) "Set the active hole in BUFFER to the first hole after POS. @@ -458,10 +362,7 @@ Default pos = point and buffer = current." (or buffer (current-buffer))))) (if nxthole (holes-set-active-hole nxthole) - (holes-disable-active-hole) - ) - ) - ) + (holes-disable-active-hole)))) ;;;(defun holes-set-active-hole-next-after-active () ;; "sets the active hole to the first hole after active @@ -476,12 +377,11 @@ Default pos = point and buffer = current." "Erase chars between START and END, and replace them with STR." (with-current-buffer (or buffer (current-buffer)) (goto-char end) - ;; Insert before deleting, so the markers at `start' and `end' don't get - ;; mixed up together. + ;; Insert before deleting, so the markers at `start' and `end' + ;; don't get mixed up together. (insert str) (delete-region start end))) - (defun holes-replace (str &optional thehole) "Replace the current hole by STR, replace THEHOLE instead if given. Do not use this, it breaks the right colorization of the active @@ -504,23 +404,18 @@ goal(FIXME?). Use `replace-active-hole' instead." (span-buffer exthole) ) (span-detach exthole) ;; this seems necessary for span overlays, - ;; where the buffer attached to the span is - ;; not removed automatically by the fact - ;; that the span is removed from the buffer - ;; (holes-replace-segment should perhaps - ;; take care of that) - ) - ) - ) + ;; where the buffer attached to the span is not removed + ;; automatically by the fact that the span is removed from the + ;; buffer (holes-replace-segment should perhaps take care of + ;; that) + ))) (defun holes-replace-active-hole (&optional str) "Replace the active hole by STR, if no str is given, then put the selection instead." - (if (not (holes-active-hole-exist-p)) () + (if (not (holes-active-hole-exist-p)) nil (holes-replace (or str (current-kill 0) (error "Nothing to put in hole")) - holes-active-hole) - )) - + holes-active-hole))) (defun holes-replace-update-active-hole (&optional str) "Replace the active hole by STR. @@ -529,26 +424,22 @@ following hole if it exists." (interactive) (assert (holes-active-hole-exist-p) t "holes-replace-update-active-hole: no active hole") - (if (not (holes-active-hole-exist-p)) - () - (let ((nxthole (holes-next-after-active-hole))) - (holes-replace-active-hole - (or str - (and mark-active (holes-copy-active-region)) - (current-kill 0) (error "Nothing to put in hole"))) - (if nxthole (holes-set-active-hole nxthole) - (setq holes-active-hole holes-default-hole)) - ) - ) - ) - + (if (holes-active-hole-exist-p) + (let ((nxthole (holes-next-after-active-hole))) + (holes-replace-active-hole + (or str + (and mark-active + (holes-copy-active-region)) + (current-kill 0) + (error "Nothing to put in hole"))) + (if nxthole (holes-set-active-hole nxthole) + (setq holes-active-hole holes-default-hole))))) (defun holes-delete-update-active-hole () "Deletes the active hole and supresses its content. Sets `holes-active-hole' to the next hole if it exists." (interactive) - (holes-replace-update-active-hole "") - ) + (holes-replace-update-active-hole "")) ;;;###autoload @@ -556,8 +447,7 @@ Sets `holes-active-hole' to the next hole if it exists." "Make a new hole between START and END or at point, and make it active." (interactive) - (holes-set-active-hole (holes-make-hole-at start end)) - ) + (holes-set-active-hole (holes-make-hole-at start end))) ;; mouse stuff, I want to make something close to `mouse-track-insert' @@ -568,40 +458,13 @@ Sets `holes-active-hole' to the next hole if it exists." ;; have nearly the same meaning for me. So I define this ;; track-mouse-selection. -(eval-and-compile - (cond - ;; XEmacs's mouse-track. - ((fboundp 'mouse-track) - (defalias 'holes-track-mouse-selection 'mouse-track) - (defsubst holes-track-mouse-clicks () - "see `mouse-track-click-count'" - mouse-track-click-count)) - ;; Emacs-22's mouse-drag-track. - ((fboundp 'mouse-drag-track) - (defalias 'holes-track-mouse-selection 'mouse-drag-track) - (defsubst holes-track-mouse-clicks () - "see `mouse-track-click-count'" - (+ mouse-selection-click-count 1))) - ;; Emacs<22 - ((fboundp 'mouse-drag-region) - (defun holes-track-mouse-selection (event) - ;; Emacs-21's mouse-drag-region has a bug that makes it behave more or - ;; less like we want it as long as transient-mark-mode is active. - (let ((transient-mark-mode nil)) - (mouse-drag-region event))) - (defsubst holes-track-mouse-clicks () - "see `mouse-selection-click-count'" - (+ mouse-selection-click-count 1))) - (t - (unless noninteractive - ;; da: ^^^^ avoid error in "make doc" (mouse functions undefined?) - (error - "Your (X)Emacs version is not compatible with holes (too old or - new version?), sorry"))))) +(defalias 'holes-track-mouse-selection 'mouse-drag-track) +(defsubst holes-track-mouse-clicks () + "See `mouse-track-click-count'" + (+ mouse-selection-click-count 1)) (defun holes-mouse-replace-active-hole (event) - ; checkdoc-params: (event) - "Internal." + "Replace the active hole with one under mouse EVENT." (interactive "*e") (holes-track-mouse-selection event) (save-excursion @@ -612,66 +475,46 @@ Sets `holes-active-hole' to the next hole if it exists." (if (not mark-active) (error "Nothing to put in hole") (holes-replace-update-active-hole (current-kill 0)) - (message "hole replaced") - ) - ) - ) - ;; (zmacs-deactivate-region) - ) + (message "hole replaced"))))) -(defun holes-destroy-hole (&optional SPAN) - ; checkdoc-params: (SPAN) - "Internal." +(defun holes-destroy-hole (&optional span) + "Destroy the hole SPAN." (interactive) - (let* ((sp (or SPAN (holes-hole-at (point)) (error "No hole to destroy")))) + (let* ((sp (or span (holes-hole-at (point)) + (error "No hole to destroy")))) (save-excursion (if (and (holes-active-hole-exist-p) (eq sp holes-active-hole)) (holes-disable-active-hole)) (holes-replace "" sp) - (span-detach sp) - ) - (message "hole killed") - ) - ) + (span-detach sp)) + (message "hole killed"))) -(defun holes-hole-at-event (event) - ; checkdoc-params: (event) - "Internal." +(defsubst holes-hole-at-event (event) + "Return the hole at EVENT." (span-at-event event 'hole)) (defun holes-mouse-destroy-hole (event) - ; checkdoc-params: (event) - "Internal." + "Destroy the hole at EVENT." (interactive "*e") - (holes-destroy-hole (holes-hole-at-event event)) - ) - + (holes-destroy-hole (holes-hole-at-event event))) ;;;(span-at-event EVENT &optional PROPERTY BEFORE AT-FLAG) ;;comprend pas?? (defun holes-mouse-forget-hole (event) - ; checkdoc-params: (event) - "Internal." + "Delete and deactivate the hole at EVENT." (interactive "*e") (save-excursion (let ((ext (holes-hole-at-event event))) (if (eq ext holes-active-hole) (holes-disable-active-hole)) - (span-detach ext) - ) - ) - (message "hole deleted") - ) - - + (span-detach ext))) + (message "hole deleted")) (defun holes-mouse-set-make-active-hole (event) - ; checkdoc-params: (event) - "Internal." + "Make a new hole at EVENT click activate it." (interactive "*e") - ;;(set-mark (point)) (holes-track-mouse-selection event) (if (and (eq (holes-track-mouse-clicks) 1) @@ -683,22 +526,15 @@ Sets `holes-active-hole' to the next hole if it exists." (let ((ext (holes-hole-at-event event))) (if (and ext (holes-is-hole-p ext)) (error "Already a hole here") - (holes-set-active-hole (holes-make-hole-at))) - ) - ) - ) - ) + (holes-set-active-hole (holes-make-hole-at))))))) (defun holes-mouse-set-active-hole (event) - ; checkdoc-params: (event) - "Internal." + "Make the hole at EVENT click active." (interactive "*e") (let ((ext (holes-hole-at-event event))) (if (and ext (holes-is-hole-p ext)) (holes-set-active-hole ext) - (error "No hole here")) - ) - ) + (error "No hole here")))) (defun holes-set-point-next-hole-destroy () @@ -709,45 +545,8 @@ Destroy it and makes the next hole active if any." (assert (eq (current-buffer) (holes-active-hole-buffer)) nil "active hole not in this buffer") (holes-goto-active-hole) - (holes-delete-update-active-hole) - ) - + (holes-delete-update-active-hole)) -;;; Customizable key bindings - - - -(defvar hole-map - (let ((map (make-sparse-keymap))) - (define-key map [(mouse-1)] 'holes-mouse-set-active-hole) - (define-key map [(mouse-3)] 'holes-mouse-destroy-hole) - (define-key map [(mouse-2)] 'holes-mouse-forget-hole) - map) - "Keymap to use on the holes's overlays. -This keymap is used only when - on a hole. See `holes-mode-map' for the keymap of `holes-mode'.") - -(defvar holes-mode-map - (let ((map (make-sparse-keymap))) - (define-key map [(control c) (h)] 'holes-set-make-active-hole) - (define-key map [(control c) (control y)] 'holes-replace-update-active-hole) - (define-key map [(control meta down-mouse-1)] 'holes-mouse-set-make-active-hole) - (define-key map [(control meta shift down-mouse-1)] 'holes-mouse-replace-active-hole) - (define-key map [(control c) (control j)] 'holes-set-point-next-hole-destroy) - map) - "Keymap of `holes-mode'. -This is not the keymap used on holes's overlay - (see `hole-map' instead). This one is active whenever we are on a - buffer where `holes-mode' is active.") - -(or (assq 'holes-mode minor-mode-map-alist) - (push (cons 'holes-mode holes-mode-map) - minor-mode-map-alist)) - -;;;(global-set-key [(control meta **WRONG** space ) ] 'holes-set-active-hole-next) - - -;;;;;;;;;;; End Customizable key bindings ;;;;; ;; utilities to be used in conjunction with abbrevs. ;; The idea is to put abbrevs of the form: @@ -835,29 +634,99 @@ become holes." (setq last-abbrev-location pos) (holes-abbrev-complete))) -(defvar holes-mode nil - "Is equal to t if holes mode is on, nil otherwise.") -(make-variable-buffer-local 'holes-mode) - -;; FIXME: Use define-minor-mode, or at least add-minor-mode. ;;;###autoload -(defun holes-mode (&optional arg) - "If ARG is nil, then toggle holes mode on/off. -If arg is positive, then turn holes mode on. If arg is negative, then -turn it off." - (interactive) - (setq holes-mode (if (null arg) (not holes-mode) - (> (prefix-numeric-value arg) 0))) - (cond - (holes-mode - (add-hook 'skeleton-end-hook 'holes-skeleton-end-hook nil t)) - (t - (remove-hook 'skeleton-end-hook 'holes-skeleton-end-hook t))) - (run-hooks 'holes-mode-hook)) +(define-minor-mode holes-mode + "Toggle Holes minor mode. +With arg, turn Outline minor mode on if arg is positive, off otherwise. + +The mode `holes-mode' is meant to help program editing. It is +useful to build complicated expressions by copy pasting several +peices of text from different parts of a buffer (or even from +different buffers). + +HOLES + +A hole is a piece of (highlighted) text that may be replaced by +another part of text later. There is no information stored on the +file for holes, so you can save and modify files containing holes with +no harm... You can even insert or delete characters inside holes like +any other characters. + +USE + +At any time only one particular hole, called \"active\", can be +\"filled\". Holes can be in several buffers but there is always one or +zero active hole globally. It is highlighted with a different color. + +Functions described below have default shortcuts when `holes-mode' is +on that you can customize. + +TO DEFINE A HOLE, two methods: + + o Select a region with keyboard or mouse, then use + \\[holes-set-make-active-hole]. If the selected region is empty, + then a hole containing # is created at point. + + o Select text with mouse while pressing ctrl and meta (`C-M-select'). + If the selected region is empty (i.e. if you just click while + pressing ctrl+meta), then a hole containing # is created. + +TO ACTIVATE A HOLE, click on it with the button 1 of your mouse. The +previous active hole will be deactivated. + +TO FORGET A HOLE without deleting its text, click on it with the +button 2 (middle) of your mouse. + +TO DESTROY A HOLE and delete its text, click on it with the button 3 +of your mouse. + +TO FILL A HOLE with a text selection, first make sure it is active, +then two methods: + + o Select text with keyboard or mouse and hit + \\[holes-replace-update-active-hole] -(or (assq 'holes-mode minor-mode-alist) - (setq minor-mode-alist - (cons '(holes-mode " Holes") minor-mode-alist))) + o Select text with mouse while pressing ctrl, meta and shift + (`C-M-S-select'). This is a + generalization of the `mouse-track-insert' feature of XEmacs. This + method allows you to fill different holes faster than with the usual + copy-paste method. + +After replacement the next hole is automatically made active so you +can fill it immediately by hitting again +\\[holes-replace-update-active-hole] or `C-M-S-select'. + +TO JUMP TO THE ACTIVE HOLE, just hit +\\[holes-set-point-next-hole-destroy]. You must +be in the buffer containing the active hole. the point will move to +the active hole, and the active hole will be destroyed so you can type +something to put at its place. The following hole is automatically +made active, so you can hit \\[holes-set-point-next-hole-destroy] +again. + +It is useful in combination with abbreviations. For example in +`coq-mode' \"fix\" is an abbreviation for Fixpoint # (# : #) {struct #} : +# := #, where each # is a hole. Then hitting +\\[holes-set-point-next-hole-destroy] goes from one hole to the +following and you can fill-in each hole very quickly. + +COMBINING HOLES AND SKELETONS + +`holes' minor mode is made to work with minor mode `skeleton' minor +mode. + +KNOWN BUGS + + o Don't try to make overlapping holes, it doesn't work. (what would +it mean anyway?) + + o Cutting or pasting a hole will not produce new holes, and +undoing on holes cannot make holes re-appear." + nil " Holes" holes-mode-map + :group 'holes + (if holes-mode + (add-hook 'skeleton-end-hook 'holes-skeleton-end-hook nil t) + (remove-hook 'skeleton-end-hook 'holes-skeleton-end-hook t))) (provide 'holes) -- cgit v1.2.3