summaryrefslogtreecommitdiffstats
path: root/emacs.d/nxhtml/util/foldit.el
blob: 0ffacc35cca2b5d4b42b034482c2bb75879dfa89 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
;;; foldit.el --- Helpers for folding
;;
;; Author: Lennart Borgman (lennart O borgman A gmail O com)
;; Created: 2009-08-10 Mon
;; Version:
;; Last-Updated:
;; URL:
;; Keywords:
;; Compatibility:
;;
;; Features that might be required by this library:
;;
;;   None
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;;; Commentary:
;;
;; Defines `foldit-mode' which puts visual clues on hidden regions.
;; Does not do any folding itself but works with `outline-minor-mode'
;; and `hs-minor-mode'.
;;
;; Fix-me: reveal-mode does not work with this and I have no idea why
;; ...
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;;; Change log:
;;
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; 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 3, 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 this program; see the file COPYING.  If not, write to
;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth
;; Floor, Boston, MA 02110-1301, USA.
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;;; Code:

;; Fix-me: start-tag-beg/start-tag-end are workarounds for smaller
;; bugs in hs-minor-mode and outline-minor-mode. Maybe try to fix
;; them... - but there are a whole bunch of other invisibilty related
;; bugs that ought to be fixed first since otherwise it is impossible
;; to know where point goes after hiding/unhiding.

(eval-when-compile (require 'cl))
(eval-when-compile (require 'hideshow))
(eval-when-compile (require 'mumamo nil t))
(eval-when-compile (require 'outline))

(defsubst foldit-overlay-priority ()
  (1+ (or (and (boundp 'mlinks-link-overlay-priority)
               mlinks-link-overlay-priority)
          100)))

;;;###autoload
(defgroup foldit nil
  "Customization group for foldit folding helpers."
  :group 'nxhtml)

(defvar foldit-temp-at-point-ovl nil)
(make-variable-buffer-local 'foldit-temp-at-point-ovl)

;;;###autoload
(define-minor-mode foldit-mode
  "Minor mode providing visual aids for folding.
Shows some hints about what you have hidden and how to reveal it.

Supports `hs-minor-mode', `outline-minor-mode' and major modes
derived from `outline-mode'."
  :lighter nil
  (if foldit-mode
      (progn
        ;; Outline
        (add-hook 'outline-view-change-hook 'foldit-outline-change nil t)
        ;; Add our overlays
        (when (or (and (boundp 'outline-minor-mode) outline-minor-mode)
                  ;; Fix-me: mumamo
                  (derived-mode-p 'outline-mode)) (foldit-outline-change))
        ;; hs
        (unless (local-variable-p 'hs-set-up-overlay)
          (set (make-local-variable 'hs-set-up-overlay) 'foldit-hs-set-up-overlay))
        ;; Add our overlays
        (when (or (and (boundp 'hs-minor-mode) hs-minor-mode))
          (save-restriction
            (widen)
            (let (ovl)
              (dolist (ovl (overlays-in (point-min) (point-max)))
                (when (eq (overlay-get ovl 'invisible) 'hs)
                  (funcall hs-set-up-overlay ovl)))))))
    ;; Outline
    (remove-hook 'outline-view-change-hook 'foldit-outline-change t)
    ;; hs
    (when (and (local-variable-p 'hs-set-up-overlay)
               (eq hs-set-up-overlay 'foldit-hs-set-up-overlay))
      (kill-local-variable 'hs-set-up-overlay))
    ;; Remove our overlays
    (save-restriction
      (widen)
      (let (ovl prop)
        (dolist (ovl (overlays-in (point-min) (point-max)))
          (when (setq prop (overlay-get ovl 'foldit))
            (case prop
              ;;('display (overlay-put ovl 'display nil))
              ('foldit (delete-overlay ovl))
              (t (delete-overlay ovl))
              )))))))

(defcustom foldit-avoid '(org-mode)
  "List of major modes to avoid."
  :group 'foldit)

;;;###autoload
(define-globalized-minor-mode foldit-global-mode foldit-mode
  (lambda () (foldit-mode 1))
  :group 'foldit)

(defun foldit-hidden-line-str (hidden-lines type)
  "String to display for hidden lines.
HIDDEN-LINES are the number of lines and TYPE is a string
indicating how they were hidden."
  (propertize (format " ...(%d %slines)" hidden-lines type)
              'face 'shadow))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; Outline

(defvar foldit-outline-keymap
  (let ((map (make-sparse-keymap)))
    (define-key map "\r" 'foldit-outline-show-entry)
    (define-key map [down-mouse-1] 'foldit-outline-show-entry)
    (define-key map [S-tab]   'mlinks-backward-link)
    (define-key map [tab]     'mlinks-forward-link)
    (define-key map "\t"      'mlinks-forward-link)
    map))

(defun foldit-outline-change ()
  "Check outline overlays.
Run this in `outline-view-change-hook'."
  ;; We get the variables FROM and TO here from `outline-flag-region'
  ;; so let us use them. But O is hidden...
  (let* (from
         to
         num-lines
         ovl
         (tag ""))
    (cond
     ((and (boundp 'start)
           start
           (boundp 'end)
           end)
      (setq from start)
      (setq to   end))
     (t
      (setq from (point-min))
      (setq to   (point-max))))
    (dolist (ovl (overlays-in from to))
      (when (eq (overlay-get ovl 'invisible) 'outline)
        (setq num-lines (count-lines (overlay-start ovl) (overlay-end ovl)))
        (overlay-put ovl 'display (concat
                                   (propertize "+" 'face 'mode-line)
                                   ""
                                   tag (foldit-hidden-line-str num-lines "")))
        (overlay-put ovl 'foldit 'display) ;; Should be a list...
        (overlay-put ovl 'keymap foldit-outline-keymap)
        (overlay-put ovl 'face 'lazy-highlight)
        (overlay-put ovl 'mouse-face 'highlight)
        (overlay-put ovl 'help-echo "Press RET to show hidden part")
        (overlay-put ovl 'mlinks-link t)
        (overlay-put ovl 'priority (foldit-overlay-priority))
        (mumamo-with-buffer-prepared-for-jit-lock
         (let* ((start-tag-beg (overlay-start ovl))
                (start-tag-end start-tag-beg))
           (put-text-property start-tag-beg (+ start-tag-beg 1)
                              'foldit-tag-end (copy-marker start-tag-end))))
        ))))

(defvar foldit-outline-hide-again-keymap
  (let ((map (make-sparse-keymap)))
    (define-key map "\r" 'foldit-outline-hide-again)
    (define-key map [down-mouse-1] 'foldit-outline-hide-again)
    (define-key map [S-tab]   'mlinks-backward-link)
    (define-key map [tab]     'mlinks-forward-link)
    (define-key map "\t"      'mlinks-forward-link)
    map))

(defun foldit-outline-show-entry ()
  "Show hidden entry."
  (interactive)
  (let ((tag-end (get-text-property (point) 'foldit-tag-end)))
    (show-entry)
    (mumamo-with-buffer-prepared-for-jit-lock
     (set-text-properties (point) (+ (point) 2) 'foldit-tag-end))
    (when tag-end (goto-char tag-end))
    (foldit-add-temp-at-point-overlay "-"
                                      foldit-outline-hide-again-keymap
                                      "Press RET to hide again")))

(defun foldit-outline-hide-again ()
  "Hide entry again."
  (interactive)
  (when (overlayp foldit-temp-at-point-ovl)
    (delete-overlay foldit-temp-at-point-ovl))
  (hide-entry))


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; Hide/Show

(defvar foldit-hs-start-tag-end-func 'foldit-hs-default-start-tag-end)
(make-variable-buffer-local 'foldit-hs-start-tag-end-func)
(put 'foldit-hs-start-tag-end-func 'permanent-local t)

(defun foldit-hs-default-start-tag-end (beg)
  "Find end of hide/show tag beginning at BEG."
  (min (+ beg 65)
       (save-excursion
         (goto-char beg)
         (line-end-position))))

(defvar foldit-hs-keymap
  (let ((map (make-sparse-keymap)))
    (define-key map "\r" 'foldit-hs-show-block)
    (define-key map [down-mouse-1] 'foldit-hs-show-block)
    (define-key map [S-tab]   'mlinks-backward-link)
    (define-key map [tab]     'mlinks-forward-link)
    (define-key map "\t"      'mlinks-forward-link)
    map))

(defvar foldit-hs-hide-again-keymap
  (let ((map (make-sparse-keymap)))
    (define-key map "\r" 'foldit-hs-hide-again)
    (define-key map [down-mouse-1] 'foldit-hs-hide-again)
    (define-key map [S-tab]   'mlinks-backward-link)
    (define-key map [tab]     'mlinks-forward-link)
    (define-key map "\t"      'mlinks-forward-link)
    map))

(defun foldit-hs-set-up-overlay (ovl)
  "Set up overlay OVL for hide/show."
  (let* ((num-lines (count-lines (overlay-start ovl) (overlay-end ovl)))
         (here (point))
         (start-tag-beg (overlay-start ovl))
         (start-tag-end (funcall foldit-hs-start-tag-end-func start-tag-beg))
         (tag (buffer-substring start-tag-beg start-tag-end)))
    (goto-char here)
    ;;(overlay-put ovl 'isearch-open-invisible t)
    (overlay-put ovl 'display (concat
                               (propertize "+" 'face 'mode-line)
                               " "
                               tag (foldit-hidden-line-str num-lines "h")))
    (overlay-put ovl 'foldit 'display)
    (overlay-put ovl 'keymap foldit-hs-keymap)
    (overlay-put ovl 'face 'next-error)
    (overlay-put ovl 'face 'lazy-highlight)
    (overlay-put ovl 'mouse-face 'highlight)
    (overlay-put ovl 'help-echo "Press RET to show hidden part")
    (overlay-put ovl 'mlinks-link t)
    (overlay-put ovl 'priority (foldit-overlay-priority))
    (mumamo-with-buffer-prepared-for-jit-lock
     (put-text-property start-tag-beg (+ start-tag-beg 1)
                        'foldit-tag-end (copy-marker start-tag-end)))))

(defun foldit-hs-show-block ()
  "Show hidden block."
  (interactive)
  (let ((tag-end (get-text-property (point) 'foldit-tag-end)))
    (hs-show-block)
    (mumamo-with-buffer-prepared-for-jit-lock
     (set-text-properties (point) (+ (point) 2) 'foldit-tag-end))
    (when tag-end (goto-char tag-end))
    (foldit-add-temp-at-point-overlay "-"
                                      foldit-hs-hide-again-keymap
                                    "Press RET to hide again")))

(defun foldit-hs-hide-again ()
  "Hide hide/show block again."
  (interactive)
  (when (overlayp foldit-temp-at-point-ovl)
    (delete-overlay foldit-temp-at-point-ovl))
  (hs-hide-block))


;;; Fix-me: break out this
;; >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
(defun foldit-add-temp-at-point-overlay (marker keymap msg)
  "Add a temporary overlay with a marker MARKER and a keymap KEYMAP.
The overlay is also given the help echo MSG.

This overlay is removed as soon as point moves from current point."
  (let ((ovl (make-overlay (point) (1+ (point))))
        (real (buffer-substring (point) (1+ (point)))))
    (overlay-put ovl 'isearch-open-invisible t)
    (overlay-put ovl 'display (concat
                               (propertize marker 'face 'mode-line)
                               " "
                               msg
                               real))
    (overlay-put ovl 'foldit 'foldit)
    (overlay-put ovl 'keymap keymap)
    (overlay-put ovl 'face 'lazy-highlight)
    (overlay-put ovl 'mouse-face 'highlight)
    (overlay-put ovl 'help-echo msg)
    (overlay-put ovl 'mlinks-link t)
    (overlay-put ovl 'priority (foldit-overlay-priority))
    (setq foldit-temp-at-point-ovl ovl)
    (add-hook 'post-command-hook
              'foldit-remove-temp-at-point-overlay
              nil t)))

(defun foldit-remove-temp-at-point-overlay ()
  "Remove overlay made by `foldit-add-temp-at-point-overlay'."
  (condition-case err
      (unless (and foldit-temp-at-point-ovl
                   (overlay-buffer foldit-temp-at-point-ovl)
                   (= (overlay-start foldit-temp-at-point-ovl)
                      (point)))
        (delete-overlay foldit-temp-at-point-ovl)
        (setq foldit-temp-at-point-ovl nil)
        (remove-hook 'post-command-hook 'foldit-remove-temp-at-point-overlay t)
        )
    (error (message "foldit-remove-temp-at-point-overlay: %s"
                    (propertize (error-message-string err))))))
;; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<



;; (defun put-before-on-invis ()
;;   (let* (o
;;          (io (catch 'io
;;                (dolist (o (overlays-at (1+ (point))))
;;                  (when (overlay-get o 'invisible)
;;                    (throw 'io o)))))
;;          (str (propertize "IOSTRING"
;;                           'face 'secondary-selection
;;                           )))
;;     (overlay-put io 'before-string str)
;;     ;;(overlay-put io 'display "display")
;;     (overlay-put io 'display nil)
;;     ;;(overlay-put io 'after-string "AFTER")
;;     ))

(provide 'foldit)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; foldit.el ends here