unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
* Furna's fisheye minor mode
@ 2004-01-20 15:00 Juha Vierinen
  2004-01-20 16:29 ` Stefan Monnier
  2004-01-21  9:21 ` Richard Stallman
  0 siblings, 2 replies; 5+ messages in thread
From: Juha Vierinen @ 2004-01-20 15:00 UTC (permalink / raw)


[-- Attachment #1: Type: text/plain, Size: 690 bytes --]

Hi,

I have attached a minor mode for emacs 21 that dynamically filters out 
stuff that is indented. It is a bit similar to hideshow, hidelines and 
outline, but it works on the indentation level instead of the semantics 
of some programming language. The mode is slow with very large files, 
because I couldn't figure out how to check if the point is in the 
visible region of the buffer. Also, the only way I could detect that the 
point had moved was by saving the point position and checking if it has 
changed in the post-command-hook.

The question is, what is the right way to check that the point has 
moved? How do I know if the point is in the visible region of the buffer?

juha

[-- Attachment #2: fisheye.el --]
[-- Type: text/plain, Size: 8874 bytes --]

;;; fisheye.el --- 
;;
;; Furna's fisheye mode. Nice for editing large source code files 
;;
;; Author: Juha Vierinen <jvierine @ tml spot hut spot fi>
;;                               (use your blind spot)
;;
;;; Commentary
;;
;; The simplest way to make fisheye work is to add the following
;; lines to your .emacs file:
;;
;; (autoload 'fisheye "fisheye" "Fisheye mode" t)
;;
;; and 'fisheye-minor-mode' to toggle on/off
;;
;; Internal functions mapped to key-strokes
;;
;; I recommend using spaces for intendation 
;; (setq indent-tabs-mode nil)
;;
;; Tested on Emacs 21.2.1 and 21.3.1
;; 
;; todo 
;; - better doi and lod functions (language specific)
;;
;; GPL
;;

(defcustom fisheye-minor-mode-hook nil
  "*Hook called when fisheye minor mode is activated or deactivated."
  :type 'hook
  :group 'fisheye
  :version "21.1")

;(defvar fisheye-minor-mode nil
;  "Non-nil if using fisheye mode as a minor mode of some other mode.
;Use the command `fisheye-minor-mode' to toggle or set this variable.")

(defvar fisheye-minor-mode-map nil
  "Keymap for fisheye minor mode.")

;;;###autoload
(define-minor-mode fisheye-minor-mode
  "Toggle fisheye minor mode.
   With ARG, turn fisheye minor mode on if ARG is positive, off otherwise.
   When fisheye minor mode is on, the menu bar is augmented with fisheye
   commands and the fisheye commands are enabled.
   
   The value '(fe) is added to `buffer-invisibility-spec'.

   The main commands are: `fisheye-point-moved' and 'fisheye-show-all-invisible'.

   Turning fisheye minor mode off reverts the menu bar and the
   variables to default values and disables the fisheye commands.

    Lastly, the normal hook `fisheye-minor-mode-hook' is run using `run-hooks'.

    Key bindings:
    \\{fisheye-minor-mode-map}"
  nil " Fisheye" nil
  (if fisheye-minor-mode
      (progn
        (set (make-local-variable 'line-move-ignore-invisible) t)
        ;; use '(fe . t) if you want ellipses for hidden overlays
	(add-to-invisibility-spec '(fe)) 
	(add-hook 'post-command-hook 'fisheye-yoho))
    (fisheye-show-all-invisible)
    (remove-from-invisibility-spec '(fe))
    (remove-hook 'post-command-hook 'fisheye-yoho))
  (run-hooks 'fisheye-minor-mode-hook))

;; internal variables
(defvar fisheye-old-point 1 "keeps track of the previous point placement.")
;(defvar fisheye-minor-mode 1 "is fisheye mode on or not")
(defvar fisheye-min-level-visible 1 "The level that cannot be hidden")
(defvar fisheye-max-level-detected 10 "The largest level of detail recognized")
(defvar fisheye-doi-visible 7 "The level that cannot be hidden")
(defvar fisheye-visible-area 20 "The visible area that is not folded (in lines)")
(defvar fisheye-inside-lodcount 0)
(defvar fisheye-tab-spaces 8 "tab equals eight spaces") 
(defvar fisheye-invisible-list-cursor 0 "An index indicating the position of the point in the invisible areas list") 
(defvar fisheye-invisible-areas-list () "List of invisible overlays used by fisheye-mode")

(defun fisheye-add-invisible-overlay (start end)
  "Add an overlay from `start' to `end' in the current buffer.  Push the
overlay onto the fisheye-invisible-areas-list list"
  (let ((overlay (make-overlay start end)))
    (setq fisheye-invisible-areas-list 
	  (fisheye-addn (+ (length fisheye-invisible-areas-list) 1) 
		fisheye-invisible-areas-list 
		overlay))
    (overlay-put overlay 'invisible '(fe))))

(defun fisheye-add-invisible-overlay-at (n start end)
  "Add an overlay from `start' to `end' in the current buffer.  Push the
overlay onto the fisheye-invisible-areas-list list"
  (let ((overlay (make-overlay start end)))
    (setq fisheye-invisible-areas-list (fisheye-addn n fisheye-invisible-areas-list overlay))
    (overlay-put overlay 'invisible '(fe))))

(defun fisheye-toggle ()
  "Toggle fisheye mode, show all hidden lines"
  (if (eq fisheye-minor-mode nil)
      (setq fisheye-minor-mode 1)
    (setq fisheye-minor-mode nil)
    (fisheye-show-all-invisible)))

(defun fisheye-yoho ()
  (if (and (not (equal fisheye-old-point (point)))
           (not (eq fisheye-minor-mode nil)))
      (fisheye-point-moved))
  (setq fisheye-old-point 
        (point)))

(defun fisheye-move (direction)
  "Move one step in some direction" 
  (let ((new-point (point))
	(start-position))
    (save-excursion
      (goto-char fisheye-old-point)
      (forward-line (* direction (+ fisheye-visible-area 1)))
      (if (< (fisheye-doi (point) fisheye-old-point)
	      fisheye-doi-visible)
	  (if (= direction 1)
	      (fisheye-delete-overlay-after fisheye-invisible-list-cursor)
	    (fisheye-delete-overlay-before fisheye-invisible-list-cursor)
	    (setq fisheye-invisible-list-cursor (- fisheye-invisible-list-cursor 1))))

      (goto-char fisheye-old-point)
      (forward-line (* direction (- fisheye-visible-area)))
      (if (>= (fisheye-doi (point) new-point)
	      fisheye-doi-visible)
	  ()
	(beginning-of-line)
	(setq start-position (point))
	(end-of-line)
	(fisheye-add-invisible-overlay-at (+ fisheye-invisible-list-cursor 1) start-position (+ 1 (point)))
	(if (= direction 1)
	    (setq fisheye-invisible-list-cursor (+ fisheye-invisible-list-cursor 1)))))))

(defun fisheye-delete-overlay-after (cursor)
  (if (> cursor (length fisheye-invisible-areas-list))
      ()
    (delete-overlay (nth cursor fisheye-invisible-areas-list))
    (setq fisheye-invisible-areas-list (fisheye-remn (+ cursor 1) fisheye-invisible-areas-list))))

(defun fisheye-delete-overlay-before (cursor)
  (if (< cursor 1)
      ()
    (delete-overlay (nth (- cursor 1) fisheye-invisible-areas-list))
    (setq fisheye-invisible-areas-list (fisheye-remn cursor fisheye-invisible-areas-list))))

(defun fisheye-point-moved ()
  "The point has moved, so we brute force the buffer, this is done initially, and also if the point has radically moved"
  (interactive)
  (if (and (not (eq fisheye-invisible-areas-list nil))
	   (= (fisheye-count-lines (point) fisheye-old-point) 1))
      (if  (> (- (point) fisheye-old-point) 0)
	  (fisheye-move 1)
	(fisheye-move -1))
    (if (> (fisheye-count-lines (point) fisheye-old-point) 0)
	(let ((focus-point (point))
	      (start-position)
	      (end-point (point-max)))
	  (save-excursion
	    (fisheye-show-all-invisible)
	    (setq fisheye-invisible-list-cursor 0)
	    (goto-char (point-min))
	    (while (and (save-excursion (end-of-line)
					(not (eobp)))
			(< (point) end-point))
	      (beginning-of-line)
	      (if (>= (fisheye-doi (point) focus-point) 
		      fisheye-doi-visible)
		  (forward-line 1)
		(setq start-position (point))
		(end-of-line)
		(fisheye-add-invisible-overlay start-position (+ 1 (point)))
		(if (< (point) focus-point)
		    (setq fisheye-invisible-list-cursor
			  (+ fisheye-invisible-list-cursor 1)))
		(forward-line 1))))))))

(defun fisheye-lod (current-point)
  "The relevance the level of detail of the current line. Override, if you want something special"
  (let ((level 1)
	(tmp-point))
    (save-excursion 
      (goto-char current-point)
      (beginning-of-line)
      ;; if plain newline, then level of detail is highest (should be filtered out)
      (if (eq (char-after (point)) 10)
	  (setq level fisheye-max-level-detected)
	(while (and (or (eq (char-after (point)) 32)
			(eq (char-after (point)) 9))
		    (< level fisheye-max-level-detected)
		    (not (eolp)))
	  (if (eq (char-after (point)) 32)
	      (setq level (+ level 1))
	    (setq level (+ level fisheye-tab-spaces)))
	  (goto-char (forward-point 1)))))
    level))

(defun fisheye-doi (current-point focus-point)
  "Degree of interest function. Simple window, with fixed size, also we display all sufficiently low level details (lines that have small enough lod, defined in fisheye-min-level-visible" 
  (let ((doi nil)
        (distance nil))
    (setq distance (fisheye-count-lines focus-point current-point))
    (if (< distance fisheye-visible-area)
        (setq doi fisheye-doi-visible)
      (setq doi (- (+ fisheye-doi-visible fisheye-min-level-visible)
                   (fisheye-lod current-point))))
    doi))

(defun fisheye-show-all-invisible ()
  "Show all hidden area, when fisheye is toggled off"
  (interactive)
  (mapcar (lambda (overlay) (delete-overlay overlay)) 
          fisheye-invisible-areas-list)
  (setq fisheye-invisible-areas-list ()))

(defun fisheye-remn (n l)
  (if (= n 1)
      (setq l (cdr l))
    (setcdr (nthcdr (- n 2) l)
	    (nthcdr n l)))
  l)

(defun fisheye-addn (n l o)
  (if (< n 2)
      (setq l (cons o l))
    (setcdr (nthcdr (- n 2) l)
	    (cons o (nthcdr (- n 1) l))))
  l)

(defun fisheye-count-lines (a b) 
  (let ((point-a)
	(point-b)
	(lines))
    (save-excursion 
      (goto-char a)
      (beginning-of-line)
      (setq point-a (point))
      (goto-char b)
      (beginning-of-line)
      (setq point-b (point))
      (setq lines (count-lines point-a point-b)))
    lines))

(provide 'fisheye)


[-- Attachment #3: Type: text/plain, Size: 141 bytes --]

_______________________________________________
Emacs-devel mailing list
Emacs-devel@gnu.org
http://mail.gnu.org/mailman/listinfo/emacs-devel

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: Furna's fisheye minor mode
  2004-01-20 15:00 Furna's fisheye minor mode Juha Vierinen
@ 2004-01-20 16:29 ` Stefan Monnier
  2004-01-21 10:37   ` Juha
  2004-01-21  9:21 ` Richard Stallman
  1 sibling, 1 reply; 5+ messages in thread
From: Stefan Monnier @ 2004-01-20 16:29 UTC (permalink / raw)
  Cc: emacs-devel

> I have attached a minor mode for emacs 21 that dynamically filters out stuff
> that is indented. It is a bit similar to hideshow, hidelines and outline,
> but it works on the indentation level instead of the semantics of some
> programming language.

Setting outline-regexp to "[ \t]*" does "the same", so I expect there are
other differences (just like there are differences between hs-minor-mode,
outline-minor-mode, as well as umpteen other variants).  Could you describe
what your mode does to make it easier to understand your code?

Most interesting would be to know "what does the user have to do to
hide/unhide parts of the text and to tell which parts to hide/unhide".

> The mode is slow with very large files,

I suppose it's slow because you use line-counts rather than
buffer positions.  I recommend you begin by removing fisheye-count-lines
and figure out how to get your code working again without using it.
That'll speed it up tremendously.

> because I couldn't figure out how to check if the point is in the visible
> region of the buffer.

How about using overlays-at and check whether one of the overlays at point
belongs to fisheye ?

> Also, the only way I could detect that the point had moved was by saving
> the point position and checking if it has changed in the
> post-command-hook.

Why do you need to detect it ?  Do you automatically hide/unhide parts of
the buffer based on the user's movement (like reveal-mode does) ?

> The question is, what is the right way to check that the point has moved?

Using post-command-hook sounds about right.  In many cases you can try to
answer "why do I need to know whether point has moved" in order to avoid
having to answer the first question, tho.


        Stefan

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: Furna's fisheye minor mode
  2004-01-20 15:00 Furna's fisheye minor mode Juha Vierinen
  2004-01-20 16:29 ` Stefan Monnier
@ 2004-01-21  9:21 ` Richard Stallman
  2004-01-21 10:12   ` Juha
  1 sibling, 1 reply; 5+ messages in thread
From: Richard Stallman @ 2004-01-21  9:21 UTC (permalink / raw)
  Cc: emacs-devel

How does this differ from C-x $?

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: Furna's fisheye minor mode
  2004-01-21  9:21 ` Richard Stallman
@ 2004-01-21 10:12   ` Juha
  0 siblings, 0 replies; 5+ messages in thread
From: Juha @ 2004-01-21 10:12 UTC (permalink / raw)


It's otherwise similar to selective display, but it automatically 
unhides everything around the point.

juha

Richard Stallman wrote:
> How does this differ from C-x $?

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: Furna's fisheye minor mode
  2004-01-20 16:29 ` Stefan Monnier
@ 2004-01-21 10:37   ` Juha
  0 siblings, 0 replies; 5+ messages in thread
From: Juha @ 2004-01-21 10:37 UTC (permalink / raw)


> Most interesting would be to know "what does the user have to do to
> hide/unhide parts of the text and to tell which parts to hide/unhide".

You can define the level on indentation for a high level feature, 
everything that has more is a low level feature. If the point is close 
enough, all levels of indentation are shown. Hiding and unhiding is done 
automatically as you move the point.

> I suppose it's slow because you use line-counts rather than
> buffer positions.  I recommend you begin by removing fisheye-count-lines
> and figure out how to get your code working again without using it.
> That'll speed it up tremendously.

Ok. I guess I could use the number of characters as a distance measure.

> the buffer based on the user's movement (like reveal-mode does) ?

reveal-mode? I'm running 21.2.1 and I don't have a reveal-mode.

> Using post-command-hook sounds about right.  In many cases you can try to
> answer "why do I need to know whether point has moved" in order to avoid
> having to answer the first question, tho.

It's the automatic hiding/unhiding that I want.

juha

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2004-01-21 10:37 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2004-01-20 15:00 Furna's fisheye minor mode Juha Vierinen
2004-01-20 16:29 ` Stefan Monnier
2004-01-21 10:37   ` Juha
2004-01-21  9:21 ` Richard Stallman
2004-01-21 10:12   ` Juha

Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).