16583
|
1 ;;; hscroll.el: Minor mode to automatically scroll truncated lines horizontally
|
|
2 ;;; Copyright (C) 1992, 1993, 1995, 1996 Free Software Foundation, Inc.
|
|
3
|
|
4 ;; Author: Wayne Mesard <wmesard@esd.sgi.com>
|
|
5 ;; Keywords: display
|
|
6
|
|
7 ;; This file is part of GNU Emacs.
|
|
8
|
|
9 ;; GNU Emacs is free software; you can redistribute it and/or modify
|
|
10 ;; it under the terms of the GNU General Public License as published by
|
|
11 ;; the Free Software Foundation; either version 2, or (at your option)
|
|
12 ;; any later version.
|
|
13
|
|
14 ;; GNU Emacs is distributed in the hope that it will be useful,
|
|
15 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
16 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
17 ;; GNU General Public License for more details.
|
|
18
|
|
19 ;; You should have received a copy of the GNU General Public License
|
|
20 ;; along with GNU Emacs; see the file COPYING. If not, write to the
|
|
21 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
|
22 ;; Boston, MA 02111-1307, USA.
|
|
23
|
|
24 ;;; Commentary:a
|
|
25 ;;
|
|
26 ;; Automatically scroll horizontally when the point moves off the
|
|
27 ;; left or right edge of the window.
|
|
28 ;;
|
|
29 ;; - Type "M-x hscroll-mode" to enable it in the current buffer.
|
|
30 ;; - Type "M-x hscroll-global-mode" to enable it in every buffer.
|
|
31 ;; - "turn-on-hscroll" is useful in mode hooks as in:
|
|
32 ;; (add-hook 'text-mode-hook 'turn-on-hscroll)
|
|
33 ;;
|
|
34 ;; - hscroll-margin controls how close the cursor can get to the edge
|
|
35 ;; of the window.
|
|
36 ;; - hscroll-step-percent controls how far to jump once we decide to do so.
|
|
37 ;;
|
|
38 ;; Most users won't want to mess with the other variables defined
|
|
39 ;; here. But they're all documented, and they all start with
|
|
40 ;; "hscroll-" if you're curious.
|
|
41 ;;
|
|
42 ;; Oh, you should also know that if you set the hscroll-margin and
|
|
43 ;; hscroll-step-percent large enough, you can get an interesting, but
|
|
44 ;; undesired ping-pong effect as the point bounces from one edge to
|
|
45 ;; the other.
|
|
46 ;;
|
|
47 ;; wmesard@sgi.com
|
|
48
|
|
49 ;;; Code:
|
|
50
|
|
51 ;;;
|
|
52 ;;; PUBLIC VARIABLES
|
|
53 ;;;
|
|
54
|
|
55 (defvar hscroll-version "2.2")
|
|
56
|
19420
|
57 (defgroup hscroll nil
|
|
58 "Minor mode to automatically scroll truncated lines horizontally."
|
|
59 :group 'editing)
|
|
60
|
|
61 (defcustom hscroll-margin 5
|
16583
|
62 "*How many columns away from the edge of the window point is allowed to get
|
19420
|
63 before HScroll will horizontally scroll the window."
|
|
64 :group 'hscroll
|
|
65 :type 'integer)
|
16583
|
66
|
19420
|
67 (defcustom hscroll-snap-threshold 30
|
16583
|
68 "*When point is this many columns (or less) from the left edge of the document,
|
|
69 don't do any horizontal scrolling. In other words, be biased towards the left
|
|
70 edge of the document.
|
19420
|
71 Set this variable to zero to disable this bias."
|
|
72 :group 'hscroll
|
|
73 :type 'integer)
|
16583
|
74
|
19420
|
75 (defcustom hscroll-step-percent 25
|
16583
|
76 "*How far away to place the point from the window's edge when scrolling.
|
19420
|
77 Expressed as a percentage of the window's width."
|
|
78 :group 'hscroll
|
|
79 :type 'integer)
|
16583
|
80
|
19420
|
81 (defcustom hscroll-mode-name " Hscr"
|
16583
|
82 "*Horizontal scrolling mode line indicator.
|
19420
|
83 Set this to nil to conserve valuable mode line space."
|
|
84 :group 'hscroll
|
|
85 :type 'string)
|
16583
|
86
|
|
87 (or (assq 'hscroll-mode minor-mode-alist)
|
|
88 (setq minor-mode-alist
|
|
89 (cons '(hscroll-mode hscroll-mode-name) minor-mode-alist)))
|
|
90
|
|
91
|
|
92 ;;;
|
|
93 ;;; PRIVATE VARIABLES
|
|
94 ;;;
|
|
95
|
|
96 (defvar hscroll-mode nil
|
|
97 "Non-nil if HScroll mode is enabled.")
|
|
98 (make-variable-buffer-local 'hscroll-mode)
|
|
99
|
|
100
|
|
101 (defvar hscroll-old-truncate-local nil)
|
|
102 (defvar hscroll-old-truncate-was-global nil)
|
|
103 (make-variable-buffer-local 'hscroll-old-truncate)
|
|
104 (make-variable-buffer-local 'hscroll-old-truncate-was-global)
|
|
105
|
|
106 (defvar hscroll-old-truncate-default nil)
|
|
107
|
|
108 ;;;
|
|
109 ;;; PUBLIC COMMANDS
|
|
110 ;;;
|
|
111
|
|
112 ;;;###autoload
|
|
113 (defun turn-on-hscroll ()
|
|
114 "Unconditionally turn on Hscroll mode in the current buffer."
|
|
115 (hscroll-mode 1))
|
|
116
|
|
117 ;;;###autoload
|
|
118 (defun hscroll-mode (&optional arg)
|
|
119 "Toggle HScroll mode in the current buffer.
|
|
120 With ARG, turn HScroll mode on if ARG is positive, off otherwise.
|
|
121 In HScroll mode, truncated lines will automatically scroll left or
|
|
122 right when point gets near either edge of the window.
|
|
123 See also \\[hscroll-global-mode]."
|
|
124 (interactive "P")
|
|
125 (make-local-hook 'post-command-hook)
|
|
126 (let ((newmode (if (null arg)
|
|
127 (not hscroll-mode)
|
|
128 (> (prefix-numeric-value arg) 0))))
|
|
129
|
|
130 (if newmode
|
|
131 ;; turn it on
|
|
132 (if (not hscroll-mode)
|
|
133 ;; it was off
|
|
134 (let ((localp (local-variable-p 'truncate-lines)))
|
|
135 (if localp
|
|
136 (setq hscroll-old-truncate-local truncate-lines))
|
|
137 (setq hscroll-old-truncate-was-global (not localp))
|
|
138 (setq truncate-lines t)
|
|
139 (add-hook 'post-command-hook
|
|
140 (function hscroll-window-maybe) nil t)
|
|
141 ))
|
|
142 ;; turn it off
|
|
143 (if hscroll-mode
|
|
144 ;; it was on
|
|
145 (progn
|
|
146 (if hscroll-old-truncate-was-global
|
|
147 (kill-local-variable 'truncate-lines)
|
|
148 (setq truncate-lines hscroll-old-truncate-local))
|
|
149 (if (not truncate-lines)
|
|
150 (set-window-hscroll (selected-window) 0))
|
|
151 (remove-hook 'post-command-hook
|
|
152 (function hscroll-window-maybe) t)
|
|
153 ))
|
|
154 )
|
|
155
|
|
156 (setq hscroll-mode newmode)
|
|
157 (force-mode-line-update nil)
|
|
158 ))
|
|
159
|
|
160
|
|
161 ;;;###autoload
|
|
162 (defun hscroll-global-mode (&optional arg)
|
|
163 "Toggle HScroll mode in all buffers.
|
|
164 With ARG, turn HScroll mode on if ARG is positive, off otherwise.
|
|
165 If a buffer ever has HScroll mode set locally (via \\[hscroll-mode]),
|
|
166 it will forever use the local value (i.e., \\[hscroll-global-mode]
|
|
167 will have no effect on it).
|
|
168 See also \\[hscroll-mode]."
|
|
169 (interactive "P")
|
|
170 (let* ((oldmode (default-value 'hscroll-mode))
|
|
171 (newmode (if (null arg)
|
|
172 (not oldmode)
|
|
173 (> (prefix-numeric-value arg) 0))))
|
|
174
|
|
175 (if newmode
|
|
176 ;; turn it on
|
|
177 (if (not hscroll-mode)
|
|
178 ;; it was off
|
|
179 (progn
|
|
180 (setq hscroll-old-truncate-default (default-value truncate-lines))
|
|
181 (setq hscroll-old-truncate-was-global t)
|
|
182 (setq-default truncate-lines t)
|
|
183 (add-hook 'post-command-hook (function hscroll-window-maybe))
|
|
184 ))
|
|
185 ;; turn it off
|
|
186 (if hscroll-mode
|
|
187 ;; it was on
|
|
188 (progn
|
|
189 (setq-default truncate-lines hscroll-old-truncate-default)
|
|
190 (remove-hook 'post-command-hook (function hscroll-window-maybe))
|
|
191 ))
|
|
192 )
|
|
193
|
|
194 (setq-default hscroll-mode newmode)
|
|
195 (force-mode-line-update t)
|
|
196 ))
|
|
197
|
|
198 (defun hscroll-window-maybe ()
|
|
199 "Scroll horizontally if point is off or nearly off the edge of the window.
|
|
200 This is called automatically when in HScroll mode, but it can be explicitly
|
|
201 invoked as well (i.e., it can be bound to a key)."
|
|
202 (interactive)
|
|
203 ;; Only consider scrolling if truncate-lines is true,
|
|
204 ;; the window is already scrolled or partial-widths is true and this is
|
|
205 ;; a partial width window. See display_text_line() in xdisp.c.
|
|
206 (if (and hscroll-mode
|
|
207 (or truncate-lines
|
|
208 (not (zerop (window-hscroll)))
|
|
209 (and truncate-partial-width-windows
|
|
210 (< (window-width) (frame-width)))))
|
|
211 (let ((linelen (save-excursion (end-of-line) (current-column)))
|
|
212 (rightmost-char (+ (window-width) (window-hscroll)))
|
|
213 )
|
|
214 (if (< (current-column) hscroll-snap-threshold)
|
|
215 (set-window-hscroll
|
|
216 (selected-window)
|
|
217 (- (window-hscroll)))
|
|
218 (if (>= (current-column)
|
|
219 (- rightmost-char hscroll-margin
|
|
220 ;; Off-by-one if the left edge is scrolled
|
|
221 (if (not (zerop (window-hscroll))) 1 0)
|
|
222 ;; Off by one if the right edge is scrolled
|
|
223 (if (> linelen rightmost-char) 1 0)
|
|
224 ))
|
|
225 ;; Scroll to the left a proportion of the window's width.
|
|
226 (set-window-hscroll
|
|
227 (selected-window)
|
|
228 (- (+ (current-column)
|
|
229 (/ (* (window-width) hscroll-step-percent) 100))
|
|
230 (window-width)))
|
|
231 (if (< (current-column) (+ (window-hscroll) hscroll-margin))
|
|
232 ;; Scroll to the right a proportion of the window's width.
|
|
233 (set-window-hscroll
|
|
234 (selected-window)
|
|
235 (- (current-column) (/ (* (window-width) hscroll-step-percent) 100)))
|
|
236 )))
|
|
237 )))
|
|
238
|
|
239 ;;;
|
|
240 ;;; It's not a bug, it's a *feature*
|
|
241 ;;;
|
|
242
|
|
243 (provide 'hscroll)
|
|
244
|
|
245 ;;; hscroll.el ends here
|