(init_filelock): Add missing semicolon.
[bpt/emacs.git] / lisp / textmodes / picture.el
CommitLineData
6594deb0
ER
1;;; picture.el --- "Picture mode" -- editing using quarter-plane screen model.
2
8f1204db 3;; Copyright (C) 1985, 1994 Free Software Foundation, Inc.
3a801d0c 4
e5167999
ER
5;; Author: K. Shane Hartman
6;; Maintainer: FSF
695d13c7
BP
7
8;; This file is part of GNU Emacs.
9
10;; GNU Emacs is free software; you can redistribute it and/or modify
11;; it under the terms of the GNU General Public License as published by
e5167999 12;; the Free Software Foundation; either version 2, or (at your option)
695d13c7
BP
13;; any later version.
14
15;; GNU Emacs is distributed in the hope that it will be useful,
16;; but WITHOUT ANY WARRANTY; without even the implied warranty of
17;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18;; GNU General Public License for more details.
19
20;; You should have received a copy of the GNU General Public License
21;; along with GNU Emacs; see the file COPYING. If not, write to
22;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
23
edbd2f74
ER
24;;; Commentary:
25
26;; This code provides the picture-mode commands documented in the Emacs
27;; manual. The screen is treated as a semi-infinite quarter-plane with
28;; support for rectangle operations and `etch-a-sketch' character
29;; insertion in any of eight directions.
30
e5167999 31;;; Code:
695d13c7 32
695d13c7
BP
33(defun move-to-column-force (column)
34 "Move to column COLUMN in current line.
35Differs from `move-to-column' in that it creates or modifies whitespace
36if necessary to attain exactly the specified column."
c45a6306 37 (or (natnump column) (setq column 0))
695d13c7
BP
38 (move-to-column column)
39 (let ((col (current-column)))
40 (if (< col column)
41 (indent-to column)
42 (if (and (/= col column)
43 (= (preceding-char) ?\t))
44 (let (indent-tabs-mode)
45 (delete-char -1)
46 (indent-to col)
ca9c7579 47 (move-to-column column))))
eb8c3be9 48 ;; This call will go away when Emacs gets real horizontal autoscrolling
ca9c7579 49 (hscroll-point-visible)))
695d13c7
BP
50
51\f
52;; Picture Movement Commands
53
ca9c7579
ER
54(defun picture-beginning-of-line (&optional arg)
55 "Position point at the beginning of the line.
56With ARG not nil, move forward ARG - 1 lines first.
57If scan reaches end of buffer, stop there without error."
58 (interactive "P")
59 (if arg (forward-line (1- (prefix-numeric-value arg))))
60 (beginning-of-line)
eb8c3be9 61 ;; This call will go away when Emacs gets real horizontal autoscrolling
ca9c7579
ER
62 (hscroll-point-visible))
63
695d13c7
BP
64(defun picture-end-of-line (&optional arg)
65 "Position point after last non-blank character on current line.
66With ARG not nil, move forward ARG - 1 lines first.
67If scan reaches end of buffer, stop there without error."
68 (interactive "P")
69 (if arg (forward-line (1- (prefix-numeric-value arg))))
70 (beginning-of-line)
ca9c7579 71 (skip-chars-backward " \t" (prog1 (point) (end-of-line)))
eb8c3be9 72 ;; This call will go away when Emacs gets real horizontal autoscrolling
ca9c7579 73 (hscroll-point-visible))
695d13c7
BP
74
75(defun picture-forward-column (arg)
76 "Move cursor right, making whitespace if necessary.
77With argument, move that many columns."
78 (interactive "p")
ad8fb8ae
KH
79 (let ((target-column (+ (current-column) arg)))
80 (move-to-column-force target-column)
81 ;; Picture mode isn't really suited to multi-column characters,
82 ;; but we might as well let the user move across them.
83 (and (< arg 0)
84 (> (current-column) target-column)
85 (forward-char -1))))
695d13c7
BP
86
87(defun picture-backward-column (arg)
88 "Move cursor left, making whitespace if necessary.
89With argument, move that many columns."
90 (interactive "p")
ad8fb8ae 91 (picture-forward-column (- arg)))
695d13c7
BP
92
93(defun picture-move-down (arg)
94 "Move vertically down, making whitespace if necessary.
95With argument, move that many lines."
96 (interactive "p")
97 (let ((col (current-column)))
98 (picture-newline arg)
99 (move-to-column-force col)))
100
101(defconst picture-vertical-step 0
102 "Amount to move vertically after text character in Picture mode.")
103
104(defconst picture-horizontal-step 1
105 "Amount to move horizontally after text character in Picture mode.")
106
107(defun picture-move-up (arg)
108 "Move vertically up, making whitespace if necessary.
109With argument, move that many lines."
110 (interactive "p")
111 (picture-move-down (- arg)))
112
113(defun picture-movement-right ()
114 "Move right after self-inserting character in Picture mode."
115 (interactive)
116 (picture-set-motion 0 1))
117
118(defun picture-movement-left ()
119 "Move left after self-inserting character in Picture mode."
120 (interactive)
121 (picture-set-motion 0 -1))
122
123(defun picture-movement-up ()
124 "Move up after self-inserting character in Picture mode."
125 (interactive)
126 (picture-set-motion -1 0))
127
128(defun picture-movement-down ()
129 "Move down after self-inserting character in Picture mode."
130 (interactive)
131 (picture-set-motion 1 0))
132
133(defun picture-movement-nw ()
134 "Move up and left after self-inserting character in Picture mode."
135 (interactive)
136 (picture-set-motion -1 -1))
137
138(defun picture-movement-ne ()
139 "Move up and right after self-inserting character in Picture mode."
140 (interactive)
141 (picture-set-motion -1 1))
142
143(defun picture-movement-sw ()
144 "Move down and left after self-inserting character in Picture mode."
145 (interactive)
146 (picture-set-motion 1 -1))
147
148(defun picture-movement-se ()
149 "Move down and right after self-inserting character in Picture mode."
150 (interactive)
151 (picture-set-motion 1 1))
152
153(defun picture-set-motion (vert horiz)
154 "Set VERTICAL and HORIZONTAL increments for movement in Picture mode.
155The mode line is updated to reflect the current direction."
156 (setq picture-vertical-step vert
157 picture-horizontal-step horiz)
158 (setq mode-name
159 (format "Picture:%s"
160 (car (nthcdr (+ 1 (% horiz 2) (* 3 (1+ (% vert 2))))
161 '(nw up ne left none right sw down se)))))
162 ;; Kludge - force the mode line to be updated. Is there a better
163 ;; way to this?
164 (set-buffer-modified-p (buffer-modified-p))
165 (message ""))
166
167(defun picture-move ()
168 "Move in direction of `picture-vertical-step' and `picture-horizontal-step'."
169 (picture-move-down picture-vertical-step)
170 (picture-forward-column picture-horizontal-step))
171
172(defun picture-motion (arg)
173 "Move point in direction of current picture motion in Picture mode.
174With ARG do it that many times. Useful for delineating rectangles in
175conjunction with diagonal picture motion.
176Do \\[command-apropos] picture-movement to see commands which control motion."
177 (interactive "p")
178 (picture-move-down (* arg picture-vertical-step))
179 (picture-forward-column (* arg picture-horizontal-step)))
180
181(defun picture-motion-reverse (arg)
182 "Move point in direction opposite of current picture motion in Picture mode.
183With ARG do it that many times. Useful for delineating rectangles in
184conjunction with diagonal picture motion.
185Do \\[command-apropos] `picture-movement' to see commands which control motion."
186 (interactive "p")
187 (picture-motion (- arg)))
188
189\f
190;; Picture insertion and deletion.
191
192(defun picture-self-insert (arg)
193 "Insert this character in place of character previously at the cursor.
194The cursor then moves in the direction you previously specified
195with the commands `picture-movement-right', `picture-movement-up', etc.
196Do \\[command-apropos] `picture-movement' to see those commands."
197 (interactive "p")
198 (while (> arg 0)
199 (setq arg (1- arg))
200 (move-to-column-force (1+ (current-column)))
201 (delete-char -1)
202 (insert last-input-char)
203 (forward-char -1)
204 (picture-move)))
205
206(defun picture-clear-column (arg)
207 "Clear out ARG columns after point without moving."
208 (interactive "p")
209 (let* ((opoint (point))
210 (original-col (current-column))
211 (target-col (+ original-col arg)))
212 (move-to-column-force target-col)
213 (delete-region opoint (point))
214 (save-excursion
215 (indent-to (max target-col original-col)))))
216
217(defun picture-backward-clear-column (arg)
218 "Clear out ARG columns before point, moving back over them."
219 (interactive "p")
220 (picture-clear-column (- arg)))
221
222(defun picture-clear-line (arg)
223 "Clear out rest of line; if at end of line, advance to next line.
224Cleared-out line text goes into the kill ring, as do newlines that are
225advanced over. With argument, clear out (and save in kill ring) that
226many lines."
227 (interactive "P")
228 (if arg
229 (progn
230 (setq arg (prefix-numeric-value arg))
231 (kill-line arg)
232 (newline (if (> arg 0) arg (- arg))))
233 (if (looking-at "[ \t]*$")
234 (kill-ring-save (point) (progn (forward-line 1) (point)))
235 (kill-region (point) (progn (end-of-line) (point))))))
236
237(defun picture-newline (arg)
238 "Move to the beginning of the following line.
239With argument, moves that many lines (up, if negative argument);
240always moves to the beginning of a line."
241 (interactive "p")
242 (if (< arg 0)
243 (forward-line arg)
244 (while (> arg 0)
245 (end-of-line)
246 (if (eobp) (newline) (forward-char 1))
ca9c7579 247 (setq arg (1- arg))))
eb8c3be9 248 ;; This call will go away when Emacs gets real horizontal autoscrolling
ca9c7579 249 (hscroll-point-visible))
695d13c7
BP
250
251(defun picture-open-line (arg)
252 "Insert an empty line after the current line.
253With positive argument insert that many lines."
254 (interactive "p")
255 (save-excursion
256 (end-of-line)
ca9c7579 257 (open-line arg))
eb8c3be9 258 ;; This call will go away when Emacs gets real horizontal autoscrolling
ca9c7579 259 (hscroll-point-visible))
695d13c7
BP
260
261(defun picture-duplicate-line ()
262 "Insert a duplicate of the current line, below it."
263 (interactive)
264 (save-excursion
265 (let ((contents
266 (buffer-substring
267 (progn (beginning-of-line) (point))
268 (progn (picture-newline 1) (point)))))
269 (forward-line -1)
270 (insert contents))))
271
5c927015
RS
272;; Like replace-match, but overwrites.
273(defun picture-replace-match (newtext fixedcase literal)
274 (let (ocolumn change pos)
275 (goto-char (setq pos (match-end 0)))
276 (setq ocolumn (current-column))
277 ;; Make the replacement and undo it, to see how it changes the length.
278 (let ((buffer-undo-list nil)
279 list1)
280 (replace-match newtext fixedcase literal)
281 (setq change (- (current-column) ocolumn))
282 (setq list1 buffer-undo-list)
283 (while list1
284 (setq list1 (primitive-undo 1 list1))))
285 (goto-char pos)
286 (if (> change 0)
287 (delete-region (point)
288 (progn
289 (move-to-column-force (+ change (current-column)))
290 (point))))
291 (replace-match newtext fixedcase literal)
292 (if (< change 0)
293 (insert-char ?\ (- change)))))
695d13c7
BP
294\f
295;; Picture Tabs
296
297(defvar picture-tab-chars "!-~"
298 "*A character set which controls behavior of commands
299\\[picture-set-tab-stops] and \\[picture-tab-search]. It is NOT a
300regular expression, any regexp special characters will be quoted.
301It defines a set of \"interesting characters\" to look for when setting
302\(or searching for) tab stops, initially \"!-~\" (all printing characters).
303For example, suppose that you are editing a table which is formatted thus:
304| foo | bar + baz | 23 *
305| bubbles | and + etc | 97 *
306and that `picture-tab-chars' is \"|+*\". Then invoking
307\\[picture-set-tab-stops] on either of the previous lines would result
308in the following tab stops
309 : : : :
310Another example - \"A-Za-z0-9\" would produce the tab stops
311 : : : :
312
313Note that if you want the character `-' to be in the set, it must be
314included in a range or else appear in a context where it cannot be
315taken for indicating a range (e.g. \"-A-Z\" declares the set to be the
316letters `A' through `Z' and the character `-'). If you want the
317character `\\' in the set it must be preceded by itself: \"\\\\\".
318
319The command \\[picture-tab-search] is defined to move beneath (or to) a
320character belonging to this set independent of the tab stops list.")
321
322(defun picture-set-tab-stops (&optional arg)
323 "Set value of `tab-stop-list' according to context of this line.
324This controls the behavior of \\[picture-tab]. A tab stop is set at
325every column occupied by an \"interesting character\" that is preceded
326by whitespace. Interesting characters are defined by the variable
327`picture-tab-chars', see its documentation for an example of usage.
328With ARG, just (re)set `tab-stop-list' to its default value. The tab
329stops computed are displayed in the minibuffer with `:' at each stop."
330 (interactive "P")
331 (save-excursion
332 (let (tabs)
333 (if arg
334 (setq tabs (default-value 'tab-stop-list))
335 (let ((regexp (concat "[ \t]+[" (regexp-quote picture-tab-chars) "]")))
336 (beginning-of-line)
337 (let ((bol (point)))
338 (end-of-line)
339 (while (re-search-backward regexp bol t)
340 (skip-chars-forward " \t")
341 (setq tabs (cons (current-column) tabs)))
342 (if (null tabs)
343 (error "No characters in set %s on this line."
344 (regexp-quote picture-tab-chars))))))
345 (setq tab-stop-list tabs)
346 (let ((blurb (make-string (1+ (nth (1- (length tabs)) tabs)) ?\ )))
347 (while tabs
348 (aset blurb (car tabs) ?:)
349 (setq tabs (cdr tabs)))
350 (message blurb)))))
351
352(defun picture-tab-search (&optional arg)
353 "Move to column beneath next interesting char in previous line.
354With ARG move to column occupied by next interesting character in this
355line. The character must be preceded by whitespace.
356\"interesting characters\" are defined by variable `picture-tab-chars'.
357If no such character is found, move to beginning of line."
358 (interactive "P")
359 (let ((target (current-column)))
360 (save-excursion
361 (if (and (not arg)
362 (progn
363 (beginning-of-line)
364 (skip-chars-backward
365 (concat "^" (regexp-quote picture-tab-chars))
366 (point-min))
367 (not (bobp))))
368 (move-to-column target))
369 (if (re-search-forward
370 (concat "[ \t]+[" (regexp-quote picture-tab-chars) "]")
371 (save-excursion (end-of-line) (point))
372 'move)
373 (setq target (1- (current-column)))
374 (setq target nil)))
375 (if target
376 (move-to-column-force target)
377 (beginning-of-line))))
378
379(defun picture-tab (&optional arg)
380 "Tab transparently (just move point) to next tab stop.
381With prefix arg, overwrite the traversed text with spaces. The tab stop
382list can be changed by \\[picture-set-tab-stops] and \\[edit-tab-stops].
383See also documentation for variable `picture-tab-chars'."
384 (interactive "P")
385 (let* ((opoint (point)))
386 (move-to-tab-stop)
387 (if arg
388 (let (indent-tabs-mode
389 (column (current-column)))
390 (delete-region opoint (point))
391 (indent-to column)))))
392\f
393;; Picture Rectangles
394
395(defconst picture-killed-rectangle nil
396 "Rectangle killed or copied by \\[picture-clear-rectangle] in Picture mode.
397The contents can be retrieved by \\[picture-yank-rectangle]")
398
399(defun picture-clear-rectangle (start end &optional killp)
400 "Clear and save rectangle delineated by point and mark.
401The rectangle is saved for yanking by \\[picture-yank-rectangle] and replaced
402with whitespace. The previously saved rectangle, if any, is lost. With
403prefix argument, the rectangle is actually killed, shifting remaining text."
404 (interactive "r\nP")
405 (setq picture-killed-rectangle (picture-snarf-rectangle start end killp)))
406
407(defun picture-clear-rectangle-to-register (start end register &optional killp)
408 "Clear rectangle delineated by point and mark into REGISTER.
409The rectangle is saved in REGISTER and replaced with whitespace. With
410prefix argument, the rectangle is actually killed, shifting remaining text."
411 (interactive "r\ncRectangle to register: \nP")
412 (set-register register (picture-snarf-rectangle start end killp)))
413
414(defun picture-snarf-rectangle (start end &optional killp)
415 (let ((column (current-column))
416 (indent-tabs-mode nil))
417 (prog1 (save-excursion
418 (if killp
419 (delete-extract-rectangle start end)
420 (prog1 (extract-rectangle start end)
421 (clear-rectangle start end))))
422 (move-to-column-force column))))
423
424(defun picture-yank-rectangle (&optional insertp)
425 "Overlay rectangle saved by \\[picture-clear-rectangle]
426The rectangle is positioned with upper left corner at point, overwriting
427existing text. With prefix argument, the rectangle is inserted instead,
428shifting existing text. Leaves mark at one corner of rectangle and
429point at the other (diagonally opposed) corner."
430 (interactive "P")
431 (if (not (consp picture-killed-rectangle))
432 (error "No rectangle saved.")
433 (picture-insert-rectangle picture-killed-rectangle insertp)))
434
2ee658c3
RS
435(defun picture-yank-at-click (click arg)
436 "Insert the last killed rectangle at the position clicked on.
437Also move point to one end of the text thus inserted (normally the end).
438Prefix arguments are interpreted as with \\[yank].
439If `mouse-yank-at-point' is non-nil, insert at point
440regardless of where you click."
441 (interactive "e\nP")
442 (or mouse-yank-at-point (mouse-set-point click))
443 (picture-yank-rectangle arg))
444
695d13c7
BP
445(defun picture-yank-rectangle-from-register (register &optional insertp)
446 "Overlay rectangle saved in REGISTER.
447The rectangle is positioned with upper left corner at point, overwriting
448existing text. With prefix argument, the rectangle is
449inserted instead, shifting existing text. Leaves mark at one corner
450of rectangle and point at the other (diagonally opposed) corner."
451 (interactive "cRectangle from register: \nP")
452 (let ((rectangle (get-register register)))
453 (if (not (consp rectangle))
454 (error "Register %c does not contain a rectangle." register)
455 (picture-insert-rectangle rectangle insertp))))
456
457(defun picture-insert-rectangle (rectangle &optional insertp)
458 "Overlay RECTANGLE with upper left corner at point.
459Optional argument INSERTP, if non-nil causes RECTANGLE to be inserted.
460Leaves the region surrounding the rectangle."
461 (let ((indent-tabs-mode nil))
462 (if (not insertp)
463 (save-excursion
464 (delete-rectangle (point)
465 (progn
466 (picture-forward-column (length (car rectangle)))
467 (picture-move-down (1- (length rectangle)))
468 (point)))))
469 (push-mark)
470 (insert-rectangle rectangle)))
471
472\f
473;; Picture Keymap, entry and exit points.
474
475(defconst picture-mode-map nil)
476
ca9c7579
ER
477(defun picture-substitute (oldfun newfun)
478 (substitute-key-definition oldfun newfun picture-mode-map global-map))
479
695d13c7
BP
480(if (not picture-mode-map)
481 (let ((i ?\ ))
482 (setq picture-mode-map (make-keymap))
483 (while (< i ?\177)
c4fc49b6 484 (define-key picture-mode-map (make-string 1 i) 'picture-self-insert)
695d13c7 485 (setq i (1+ i)))
ca9c7579
ER
486
487 (picture-substitute 'forward-char 'picture-forward-column)
488 (picture-substitute 'backward-char 'picture-backward-column)
489 (picture-substitute 'delete-char 'picture-clear-column)
47bad81c 490 ;; There are two possibilities for what is normally on DEL.
ca9c7579 491 (picture-substitute 'backward-delete-char-untabify 'picture-backward-clear-column)
47bad81c 492 (picture-substitute 'delete-backward-char 'picture-backward-clear-column)
ca9c7579
ER
493 (picture-substitute 'kill-line 'picture-clear-line)
494 (picture-substitute 'open-line 'picture-open-line)
495 (picture-substitute 'newline 'picture-newline)
496 (picture-substitute 'newline-andindent 'picture-duplicate-line)
497 (picture-substitute 'next-line 'picture-move-down)
498 (picture-substitute 'previous-line 'picture-move-up)
499 (picture-substitute 'beginning-of-line 'picture-beginning-of-line)
500 (picture-substitute 'end-of-line 'picture-end-of-line)
501
695d13c7 502 (define-key picture-mode-map "\C-c\C-d" 'delete-char)
695d13c7
BP
503 (define-key picture-mode-map "\e\t" 'picture-toggle-tab-state)
504 (define-key picture-mode-map "\t" 'picture-tab)
505 (define-key picture-mode-map "\e\t" 'picture-tab-search)
506 (define-key picture-mode-map "\C-c\t" 'picture-set-tab-stops)
507 (define-key picture-mode-map "\C-c\C-k" 'picture-clear-rectangle)
508 (define-key picture-mode-map "\C-c\C-w" 'picture-clear-rectangle-to-register)
509 (define-key picture-mode-map "\C-c\C-y" 'picture-yank-rectangle)
510 (define-key picture-mode-map "\C-c\C-x" 'picture-yank-rectangle-from-register)
511 (define-key picture-mode-map "\C-c\C-c" 'picture-mode-exit)
512 (define-key picture-mode-map "\C-c\C-f" 'picture-motion)
513 (define-key picture-mode-map "\C-c\C-b" 'picture-motion-reverse)
514 (define-key picture-mode-map "\C-c<" 'picture-movement-left)
515 (define-key picture-mode-map "\C-c>" 'picture-movement-right)
516 (define-key picture-mode-map "\C-c^" 'picture-movement-up)
517 (define-key picture-mode-map "\C-c." 'picture-movement-down)
518 (define-key picture-mode-map "\C-c`" 'picture-movement-nw)
519 (define-key picture-mode-map "\C-c'" 'picture-movement-ne)
520 (define-key picture-mode-map "\C-c/" 'picture-movement-sw)
521 (define-key picture-mode-map "\C-c\\" 'picture-movement-se)))
522
ca9c7579
ER
523(defvar picture-mode-hook nil
524 "If non-nil, its value is called on entry to Picture mode.
525Picture mode is invoked by the command \\[picture-mode].")
695d13c7 526
c4fc49b6
RS
527(defvar picture-mode-old-local-map)
528(defvar picture-mode-old-mode-name)
529(defvar picture-mode-old-major-mode)
b9911289 530(defvar picture-mode-old-truncate-lines)
c4fc49b6 531
7229064d 532;;;###autoload
ca9c7579 533(defun picture-mode ()
695d13c7
BP
534 "Switch to Picture mode, in which a quarter-plane screen model is used.
535Printing characters replace instead of inserting themselves with motion
536afterwards settable by these commands:
537 C-c < Move left after insertion.
538 C-c > Move right after insertion.
539 C-c ^ Move up after insertion.
540 C-c . Move down after insertion.
541 C-c ` Move northwest (nw) after insertion.
542 C-c ' Move northeast (ne) after insertion.
543 C-c / Move southwest (sw) after insertion.
544 C-c \\ Move southeast (se) after insertion.
545The current direction is displayed in the mode line. The initial
546direction is right. Whitespace is inserted and tabs are changed to
547spaces when required by movement. You can move around in the buffer
548with these commands:
ca9c7579
ER
549 \\[picture-move-down] Move vertically to SAME column in previous line.
550 \\[picture-move-up] Move vertically to SAME column in next line.
551 \\[picture-end-of-line] Move to column following last non-whitespace character.
552 \\[picture-forward-column] Move right inserting spaces if required.
553 \\[picture-backward-column] Move left changing tabs to spaces if required.
695d13c7
BP
554 C-c C-f Move in direction of current picture motion.
555 C-c C-b Move in opposite direction of current picture motion.
556 Return Move to beginning of next line.
557You can edit tabular text with these commands:
558 M-Tab Move to column beneath (or at) next interesting character.
559 `Indents' relative to a previous line.
560 Tab Move to next stop in tab stop list.
561 C-c Tab Set tab stops according to context of this line.
562 With ARG resets tab stops to default (global) value.
563 See also documentation of variable picture-tab-chars
564 which defines \"interesting character\". You can manually
565 change the tab stop list with command \\[edit-tab-stops].
566You can manipulate text with these commands:
567 C-d Clear (replace) ARG columns after point without moving.
568 C-c C-d Delete char at point - the command normally assigned to C-d.
ca9c7579
ER
569 \\[picture-backward-clear-column] Clear (replace) ARG columns before point, moving back over them.
570 \\[picture-clear-line] Clear ARG lines, advancing over them. The cleared
695d13c7 571 text is saved in the kill ring.
ca9c7579 572 \\[picture-open-line] Open blank line(s) beneath current line.
695d13c7
BP
573You can manipulate rectangles with these commands:
574 C-c C-k Clear (or kill) a rectangle and save it.
575 C-c C-w Like C-c C-k except rectangle is saved in named register.
576 C-c C-y Overlay (or insert) currently saved rectangle at point.
577 C-c C-x Like C-c C-y except rectangle is taken from named register.
578 \\[copy-rectangle-to-register] Copies a rectangle to a register.
579 \\[advertised-undo] Can undo effects of rectangle overlay commands
580 commands if invoked soon enough.
581You can return to the previous mode with:
582 C-c C-c Which also strips trailing whitespace from every line.
583 Stripping is suppressed by supplying an argument.
584
ca9c7579 585Entry to this mode calls the value of picture-mode-hook if non-nil.
695d13c7
BP
586
587Note that Picture mode commands will work outside of Picture mode, but
588they are not defaultly assigned to keys."
589 (interactive)
ca9c7579
ER
590 (if (eq major-mode 'picture-mode)
591 (error "You are already editing a picture.")
695d13c7
BP
592 (make-local-variable 'picture-mode-old-local-map)
593 (setq picture-mode-old-local-map (current-local-map))
594 (use-local-map picture-mode-map)
595 (make-local-variable 'picture-mode-old-mode-name)
596 (setq picture-mode-old-mode-name mode-name)
597 (make-local-variable 'picture-mode-old-major-mode)
598 (setq picture-mode-old-major-mode major-mode)
ca9c7579 599 (setq major-mode 'picture-mode)
695d13c7
BP
600 (make-local-variable 'picture-killed-rectangle)
601 (setq picture-killed-rectangle nil)
602 (make-local-variable 'tab-stop-list)
603 (setq tab-stop-list (default-value 'tab-stop-list))
604 (make-local-variable 'picture-tab-chars)
605 (setq picture-tab-chars (default-value 'picture-tab-chars))
606 (make-local-variable 'picture-vertical-step)
607 (make-local-variable 'picture-horizontal-step)
b9911289
RS
608 (make-local-variable 'picture-mode-old-truncate-lines)
609 (setq picture-mode-old-truncate-lines truncate-lines)
ca9c7579 610 (setq truncate-lines t)
695d13c7 611 (picture-set-motion 0 1)
ca9c7579 612
e0dad66e
RS
613 ;; edit-picture-hook is what we used to run, picture-mode-hook is in doc.
614 (run-hooks 'edit-picture-hook 'picture-mode-hook)
695d13c7
BP
615 (message
616 (substitute-command-keys
617 "Type \\[picture-mode-exit] in this buffer to return it to %s mode.")
618 picture-mode-old-mode-name)))
619
6503cec3 620;;;###autoload
ca9c7579 621(defalias 'edit-picture 'picture-mode)
695d13c7
BP
622
623(defun picture-mode-exit (&optional nostrip)
ca9c7579 624 "Undo picture-mode and return to previous major mode.
695d13c7
BP
625With no argument strips whitespace from end of every line in Picture buffer
626 otherwise just return to previous mode."
627 (interactive "P")
ca9c7579 628 (if (not (eq major-mode 'picture-mode))
695d13c7
BP
629 (error "You aren't editing a Picture.")
630 (if (not nostrip) (picture-clean))
631 (setq mode-name picture-mode-old-mode-name)
632 (use-local-map picture-mode-old-local-map)
633 (setq major-mode picture-mode-old-major-mode)
634 (kill-local-variable 'tab-stop-list)
b9911289 635 (setq truncate-lines picture-mode-old-truncate-lines)
695d13c7
BP
636 ;; Kludge - force the mode line to be updated. Is there a better
637 ;; way to do this?
638 (set-buffer-modified-p (buffer-modified-p))))
639
640(defun picture-clean ()
641 "Eliminate whitespace at ends of lines."
642 (save-excursion
643 (goto-char (point-min))
644 (while (re-search-forward "[ \t][ \t]*$" nil t)
645 (delete-region (match-beginning 0) (point)))))
49116ac0
JB
646
647(provide 'picture)
648
6594deb0 649;;; picture.el ends here