| 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 |
(defgroup picture nil |
|---|
| 37 |
"Picture mode --- editing using quarter-plane screen model." |
|---|
| 38 |
:prefix "picture-" |
|---|
| 39 |
:group 'editing) |
|---|
| 40 |
|
|---|
| 41 |
(defcustom picture-rectangle-ctl ?+ |
|---|
| 42 |
"*Character `picture-draw-rectangle' uses for top left corners." |
|---|
| 43 |
:type 'character |
|---|
| 44 |
:group 'picture) |
|---|
| 45 |
(defcustom picture-rectangle-ctr ?+ |
|---|
| 46 |
"*Character `picture-draw-rectangle' uses for top right corners." |
|---|
| 47 |
:type 'character |
|---|
| 48 |
:group 'picture) |
|---|
| 49 |
(defcustom picture-rectangle-cbr ?+ |
|---|
| 50 |
"*Character `picture-draw-rectangle' uses for bottom right corners." |
|---|
| 51 |
:type 'character |
|---|
| 52 |
:group 'picture) |
|---|
| 53 |
(defcustom picture-rectangle-cbl ?+ |
|---|
| 54 |
"*Character `picture-draw-rectangle' uses for bottom left corners." |
|---|
| 55 |
:type 'character |
|---|
| 56 |
:group 'picture) |
|---|
| 57 |
(defcustom picture-rectangle-v ?| |
|---|
| 58 |
"*Character `picture-draw-rectangle' uses for vertical lines." |
|---|
| 59 |
:type 'character |
|---|
| 60 |
:group 'picture) |
|---|
| 61 |
(defcustom picture-rectangle-h ?- |
|---|
| 62 |
"*Character `picture-draw-rectangle' uses for horizontal lines." |
|---|
| 63 |
:type 'character |
|---|
| 64 |
:group 'picture) |
|---|
| 65 |
|
|---|
| 66 |
|
|---|
| 67 |
|
|---|
| 68 |
|
|---|
| 69 |
|
|---|
| 70 |
|
|---|
| 71 |
|
|---|
| 72 |
(defvar picture-desired-column 0) |
|---|
| 73 |
|
|---|
| 74 |
|
|---|
| 75 |
|
|---|
| 76 |
|
|---|
| 77 |
(defun picture-update-desired-column (adjust-to-current) |
|---|
| 78 |
(let ((current-column (current-column))) |
|---|
| 79 |
(if (or adjust-to-current |
|---|
| 80 |
(< picture-desired-column (1- current-column)) |
|---|
| 81 |
(> picture-desired-column (1+ current-column))) |
|---|
| 82 |
(setq picture-desired-column current-column)) |
|---|
| 83 |
current-column)) |
|---|
| 84 |
|
|---|
| 85 |
(defun picture-beginning-of-line (&optional arg) |
|---|
| 86 |
"Position point at the beginning of the line. |
|---|
| 87 |
With ARG not nil, move forward ARG - 1 lines first. |
|---|
| 88 |
If scan reaches end of buffer, stop there without error." |
|---|
| 89 |
(interactive "P") |
|---|
| 90 |
(if arg (forward-line (1- (prefix-numeric-value arg)))) |
|---|
| 91 |
(beginning-of-line) |
|---|
| 92 |
(setq picture-desired-column 0)) |
|---|
| 93 |
|
|---|
| 94 |
(defun picture-end-of-line (&optional arg) |
|---|
| 95 |
"Position point after last non-blank character on current line. |
|---|
| 96 |
With ARG not nil, move forward ARG - 1 lines first. |
|---|
| 97 |
If scan reaches end of buffer, stop there without error." |
|---|
| 98 |
(interactive "P") |
|---|
| 99 |
(if arg (forward-line (1- (prefix-numeric-value arg)))) |
|---|
| 100 |
(beginning-of-line) |
|---|
| 101 |
(skip-chars-backward " \t" (prog1 (point) (end-of-line))) |
|---|
| 102 |
(setq picture-desired-column (current-column))) |
|---|
| 103 |
|
|---|
| 104 |
(defun picture-forward-column (arg &optional interactive) |
|---|
| 105 |
"Move cursor right, making whitespace if necessary. |
|---|
| 106 |
With argument, move that many columns." |
|---|
| 107 |
(interactive "p\nd") |
|---|
| 108 |
(let (deactivate-mark) |
|---|
| 109 |
(picture-update-desired-column interactive) |
|---|
| 110 |
(setq picture-desired-column (max 0 (+ picture-desired-column arg))) |
|---|
| 111 |
(let ((current-column (move-to-column picture-desired-column t))) |
|---|
| 112 |
(if (and (> current-column picture-desired-column) |
|---|
| 113 |
(< arg 0)) |
|---|
| 114 |
|
|---|
| 115 |
|
|---|
| 116 |
(forward-char -1))))) |
|---|
| 117 |
|
|---|
| 118 |
(defun picture-backward-column (arg &optional interactive) |
|---|
| 119 |
"Move cursor left, making whitespace if necessary. |
|---|
| 120 |
With argument, move that many columns." |
|---|
| 121 |
(interactive "p\nd") |
|---|
| 122 |
(picture-update-desired-column interactive) |
|---|
| 123 |
(picture-forward-column (- arg))) |
|---|
| 124 |
|
|---|
| 125 |
(defun picture-move-down (arg) |
|---|
| 126 |
"Move vertically down, making whitespace if necessary. |
|---|
| 127 |
With argument, move that many lines." |
|---|
| 128 |
(interactive "p") |
|---|
| 129 |
(let (deactivate-mark) |
|---|
| 130 |
(picture-update-desired-column nil) |
|---|
| 131 |
(picture-newline arg) |
|---|
| 132 |
(let ((current-column (move-to-column picture-desired-column t))) |
|---|
| 133 |
(if (> current-column picture-desired-column) |
|---|
| 134 |
(forward-char -1))))) |
|---|
| 135 |
|
|---|
| 136 |
(defvar picture-vertical-step 0 |
|---|
| 137 |
"Amount to move vertically after text character in Picture mode.") |
|---|
| 138 |
|
|---|
| 139 |
(defvar picture-horizontal-step 1 |
|---|
| 140 |
"Amount to move horizontally after text character in Picture mode.") |
|---|
| 141 |
|
|---|
| 142 |
(defun picture-move-up (arg) |
|---|
| 143 |
"Move vertically up, making whitespace if necessary. |
|---|
| 144 |
With argument, move that many lines." |
|---|
| 145 |
(interactive "p") |
|---|
| 146 |
(picture-update-desired-column nil) |
|---|
| 147 |
(picture-move-down (- arg))) |
|---|
| 148 |
|
|---|
| 149 |
(defun picture-movement-right () |
|---|
| 150 |
"Move right after self-inserting character in Picture mode." |
|---|
| 151 |
(interactive) |
|---|
| 152 |
(picture-set-motion 0 1)) |
|---|
| 153 |
|
|---|
| 154 |
(defun picture-movement-left () |
|---|
| 155 |
"Move left after self-inserting character in Picture mode." |
|---|
| 156 |
(interactive) |
|---|
| 157 |
(picture-set-motion 0 -1)) |
|---|
| 158 |
|
|---|
| 159 |
(defun picture-movement-up () |
|---|
| 160 |
"Move up after self-inserting character in Picture mode." |
|---|
| 161 |
(interactive) |
|---|
| 162 |
(picture-set-motion -1 0)) |
|---|
| 163 |
|
|---|
| 164 |
(defun picture-movement-down () |
|---|
| 165 |
"Move down after self-inserting character in Picture mode." |
|---|
| 166 |
(interactive) |
|---|
| 167 |
(picture-set-motion 1 0)) |
|---|
| 168 |
|
|---|
| 169 |
(defun picture-movement-nw (&optional arg) |
|---|
| 170 |
"Move up and left after self-inserting character in Picture mode. |
|---|
| 171 |
With prefix argument, move up and two-column left." |
|---|
| 172 |
(interactive "P") |
|---|
| 173 |
(picture-set-motion -1 (if arg -2 -1))) |
|---|
| 174 |
|
|---|
| 175 |
(defun picture-movement-ne (&optional arg) |
|---|
| 176 |
"Move up and right after self-inserting character in Picture mode. |
|---|
| 177 |
With prefix argument, move up and two-column right." |
|---|
| 178 |
(interactive "P") |
|---|
| 179 |
(picture-set-motion -1 (if arg 2 1))) |
|---|
| 180 |
|
|---|
| 181 |
(defun picture-movement-sw (&optional arg) |
|---|
| 182 |
"Move down and left after self-inserting character in Picture mode. |
|---|
| 183 |
With prefix argument, move down and two-column left." |
|---|
| 184 |
(interactive "P") |
|---|
| 185 |
(picture-set-motion 1 (if arg -2 -1))) |
|---|
| 186 |
|
|---|
| 187 |
(defun picture-movement-se (&optional arg) |
|---|
| 188 |
"Move down and right after self-inserting character in Picture mode. |
|---|
| 189 |
With prefix argument, move down and two-column right." |
|---|
| 190 |
(interactive "P") |
|---|
| 191 |
(picture-set-motion 1 (if arg 2 1))) |
|---|
| 192 |
|
|---|
| 193 |
(defun picture-set-motion (vert horiz) |
|---|
| 194 |
"Set VERTICAL and HORIZONTAL increments for movement in Picture mode. |
|---|
| 195 |
The mode line is updated to reflect the current direction." |
|---|
| 196 |
(setq picture-vertical-step vert |
|---|
| 197 |
picture-horizontal-step horiz) |
|---|
| 198 |
(setq mode-name |
|---|
| 199 |
(format "Picture:%s" |
|---|
| 200 |
(nth (+ 2 (% horiz 3) (* 5 (1+ (% vert 2)))) |
|---|
| 201 |
'(wnw nw up ne ene Left left none right Right |
|---|
| 202 |
wsw sw down se ese)))) |
|---|
| 203 |
(force-mode-line-update) |
|---|
| 204 |
(message "")) |
|---|
| 205 |
|
|---|
| 206 |
(defun picture-move () |
|---|
| 207 |
"Move in direction of `picture-vertical-step' and `picture-horizontal-step'." |
|---|
| 208 |
(if (/= picture-vertical-step 0) |
|---|
| 209 |
(picture-move-down picture-vertical-step)) |
|---|
| 210 |
(if (/= picture-horizontal-step 0) |
|---|
| 211 |
(picture-forward-column picture-horizontal-step))) |
|---|
| 212 |
|
|---|
| 213 |
(defun picture-motion (arg) |
|---|
| 214 |
"Move point in direction of current picture motion in Picture mode. |
|---|
| 215 |
With ARG do it that many times. Useful for delineating rectangles in |
|---|
| 216 |
conjunction with diagonal picture motion. |
|---|
| 217 |
Do \\[command-apropos] picture-movement to see commands which control motion." |
|---|
| 218 |
(interactive "p") |
|---|
| 219 |
(picture-move-down (* arg picture-vertical-step)) |
|---|
| 220 |
(picture-forward-column (* arg picture-horizontal-step))) |
|---|
| 221 |
|
|---|
| 222 |
(defun picture-motion-reverse (arg) |
|---|
| 223 |
"Move point in direction opposite of current picture motion in Picture mode. |
|---|
| 224 |
With ARG do it that many times. Useful for delineating rectangles in |
|---|
| 225 |
conjunction with diagonal picture motion. |
|---|
| 226 |
Do \\[command-apropos] picture-movement to see commands which control motion." |
|---|
| 227 |
(interactive "p") |
|---|
| 228 |
(picture-motion (- arg))) |
|---|
| 229 |
|
|---|
| 230 |
(defun picture-mouse-set-point (event) |
|---|
| 231 |
"Move point to the position clicked on, making whitespace if necessary." |
|---|
| 232 |
(interactive "e") |
|---|
| 233 |
(let* ((pos (posn-col-row (event-start event))) |
|---|
| 234 |
(x (car pos)) |
|---|
| 235 |
(y (cdr pos)) |
|---|
| 236 |
(current-row (count-lines (window-start) (line-beginning-position)))) |
|---|
| 237 |
(unless (equal x (current-column)) |
|---|
| 238 |
(picture-forward-column (- x (current-column)))) |
|---|
| 239 |
(unless (equal y current-row) |
|---|
| 240 |
(picture-move-down (- y current-row))))) |
|---|
| 241 |
|
|---|
| 242 |
|
|---|
| 243 |
|
|---|
| 244 |
|
|---|
| 245 |
(defun picture-insert (ch arg) |
|---|
| 246 |
(let* ((width (char-width ch)) |
|---|
| 247 |
|
|---|
| 248 |
|
|---|
| 249 |
(picture-horizontal-step |
|---|
| 250 |
(if (and (= picture-vertical-step 0) |
|---|
| 251 |
(> width 1) |
|---|
| 252 |
(< (abs picture-horizontal-step) 2)) |
|---|
| 253 |
(* picture-horizontal-step 2) |
|---|
| 254 |
picture-horizontal-step))) |
|---|
| 255 |
(while (> arg 0) |
|---|
| 256 |
(setq arg (1- arg)) |
|---|
| 257 |
(if (/= picture-desired-column (current-column)) |
|---|
| 258 |
(move-to-column picture-desired-column t)) |
|---|
| 259 |
(let ((col (+ picture-desired-column width))) |
|---|
| 260 |
(or (eolp) |
|---|
| 261 |
(let ((pos (point))) |
|---|
| 262 |
(move-to-column col t) |
|---|
| 263 |
(delete-region pos (point))))) |
|---|
| 264 |
(insert ch) |
|---|
| 265 |
(forward-char -1) |
|---|
| 266 |
(picture-move)))) |
|---|
| 267 |
|
|---|
| 268 |
(defun picture-self-insert (arg) |
|---|
| 269 |
"Insert this character in place of character previously at the cursor. |
|---|
| 270 |
The cursor then moves in the direction you previously specified |
|---|
| 271 |
with the commands `picture-movement-right', `picture-movement-up', etc. |
|---|
| 272 |
Do \\[command-apropos] `picture-movement' to see those commands." |
|---|
| 273 |
(interactive "p") |
|---|
| 274 |
(picture-update-desired-column (not (eq this-command last-command))) |
|---|
| 275 |
(picture-insert last-command-event arg)) |
|---|
| 276 |
|
|---|
| 277 |
(defun picture-clear-column (arg) |
|---|
| 278 |
"Clear out ARG columns after point without moving." |
|---|
| 279 |
(interactive "p") |
|---|
| 280 |
(let* ((original-col (current-column)) |
|---|
| 281 |
(target-col (max 0 (+ original-col arg))) |
|---|
| 282 |
pos) |
|---|
| 283 |
(move-to-column target-col t) |
|---|
| 284 |
(setq pos (point)) |
|---|
| 285 |
(move-to-column original-col) |
|---|
| 286 |
(delete-region pos (point)) |
|---|
| 287 |
(save-excursion |
|---|
| 288 |
(indent-to (max target-col original-col)))) |
|---|
| 289 |
(setq picture-desired-column (current-column))) |
|---|
| 290 |
|
|---|
| 291 |
(defun picture-backward-clear-column (arg) |
|---|
| 292 |
"Clear out ARG columns before point, moving back over them." |
|---|
| 293 |
(interactive "p") |
|---|
| 294 |
(picture-clear-column (- arg))) |
|---|
| 295 |
|
|---|
| 296 |
(defun picture-clear-line (arg) |
|---|
| 297 |
"Clear out rest of line; if at end of line, advance to next line. |
|---|
| 298 |
Cleared-out line text goes into the kill ring, as do newlines that are |
|---|
| 299 |
advanced over. With argument, clear out (and save in kill ring) that |
|---|
| 300 |
many lines." |
|---|
| 301 |
(interactive "P") |
|---|
| 302 |
(if arg |
|---|
| 303 |
(progn |
|---|
| 304 |
(setq arg (prefix-numeric-value arg)) |
|---|
| 305 |
(kill-line arg) |
|---|
| 306 |
(newline (if (> arg 0) arg (- arg)))) |
|---|
| 307 |
(if (looking-at "[ \t]*$") |
|---|
| 308 |
(kill-ring-save (point) (progn (forward-line 1) (point))) |
|---|
| 309 |
(kill-region (point) (progn (end-of-line) (point)))))) |
|---|
| 310 |
|
|---|
| 311 |
(defun picture-newline (arg) |
|---|
| 312 |
"Move to the beginning of the following line. |
|---|
| 313 |
With argument, moves that many lines (up, if negative argument); |
|---|
| 314 |
always moves to the beginning of a line." |
|---|
| 315 |
(interactive "p") |
|---|
| 316 |
(if (< arg 0) |
|---|
| 317 |
(forward-line arg) |
|---|
| 318 |
(while (> arg 0) |
|---|
| 319 |
(end-of-line) |
|---|
| 320 |
(if (eobp) (newline) (forward-char 1)) |
|---|
| 321 |
(setq arg (1- arg))))) |
|---|
| 322 |
|
|---|
| 323 |
(defun picture-open-line (arg) |
|---|
| 324 |
"Insert an empty line after the current line. |
|---|
| 325 |
With positive argument insert that many lines." |
|---|
| 326 |
(interactive "p") |
|---|
| 327 |
(save-excursion |
|---|
| 328 |
(end-of-line) |
|---|
| 329 |
(open-line arg))) |
|---|
| 330 |
|
|---|
| 331 |
(defun picture-duplicate-line () |
|---|
| 332 |
"Insert a duplicate of the current line, below it." |
|---|
| 333 |
(interactive) |
|---|
| 334 |
(save-excursion |
|---|
| 335 |
(let ((contents |
|---|
| 336 |
(buffer-substring |
|---|
| 337 |
(progn (beginning-of-line) (point)) |
|---|
| 338 |
(progn (picture-newline 1) (point))))) |
|---|
| 339 |
(forward-line -1) |
|---|
| 340 |
(insert contents)))) |
|---|
| 341 |
|
|---|
| 342 |
|
|---|
| 343 |
(defun picture-replace-match (newtext fixedcase literal) |
|---|
| 344 |
(let (ocolumn change pos) |
|---|
| 345 |
(goto-char (setq pos (match-end 0))) |
|---|
| 346 |
(setq ocolumn (current-column)) |
|---|
| 347 |
|
|---|
| 348 |
(let ((buffer-undo-list nil) |
|---|
| 349 |
list1) |
|---|
| 350 |
(replace-match newtext fixedcase literal) |
|---|
| 351 |
(setq change (- (current-column) ocolumn)) |
|---|
| 352 |
(setq list1 buffer-undo-list) |
|---|
| 353 |
(while list1 |
|---|
| 354 |
(setq list1 (primitive-undo 1 list1)))) |
|---|
| 355 |
(goto-char pos) |
|---|
| 356 |
(if (> change 0) |
|---|
| 357 |
(delete-region (point) |
|---|
| 358 |
(progn |
|---|
| 359 |
(move-to-column (+ change (current-column)) t) |
|---|
| 360 |
(point)))) |
|---|
| 361 |
(replace-match newtext fixedcase literal) |
|---|
| 362 |
(if (< change 0) |
|---|
| 363 |
(insert-char ?\s (- change))))) |
|---|
| 364 |
|
|---|
| 365 |
|
|---|
| 366 |
|
|---|
| 367 |
(defcustom picture-tab-chars "!-~" |
|---|
| 368 |
"*A character set which controls behavior of commands. |
|---|
| 369 |
\\[picture-set-tab-stops] and \\[picture-tab-search]. It is NOT a |
|---|
| 370 |
regular expression, any regexp special characters will be quoted. |
|---|
| 371 |
It defines a set of \"interesting characters\" to look for when setting |
|---|
| 372 |
\(or searching for) tab stops, initially \"!-~\" (all printing characters). |
|---|
| 373 |
For example, suppose that you are editing a table which is formatted thus: |
|---|
| 374 |
| foo | bar + baz | 23 * |
|---|
| 375 |
| bubbles | and + etc | 97 * |
|---|
| 376 |
and that `picture-tab-chars' is \"|+*\". Then invoking |
|---|
| 377 |
\\[picture-set-tab-stops] on either of the previous lines would result |
|---|
| 378 |
in the following tab stops |
|---|
| 379 |
: : : : |
|---|
| 380 |
Another example - \"A-Za-z0-9\" would produce the tab stops |
|---|
| 381 |
: : : : |
|---|
| 382 |
|
|---|
| 383 |
Note that if you want the character `-' to be in the set, it must be |
|---|
| 384 |
included in a range or else appear in a context where it cannot be |
|---|
| 385 |
taken for indicating a range (e.g. \"-A-Z\" declares the set to be the |
|---|
| 386 |
letters `A' through `Z' and the character `-'). If you want the |
|---|
| 387 |
character `\\' in the set it must be preceded by itself: \"\\\\\". |
|---|
| 388 |
|
|---|
| 389 |
The command \\[picture-tab-search] is defined to move beneath (or to) a |
|---|
| 390 |
character belonging to this set independent of the tab stops list." |
|---|
| 391 |
:type 'string |
|---|
| 392 |
:group 'picture) |
|---|
| 393 |
|
|---|
| 394 |
(defun picture-set-tab-stops (&optional arg) |
|---|
| 395 |
"Set value of `tab-stop-list' according to context of this line. |
|---|
| 396 |
This controls the behavior of \\[picture-tab]. A tab stop is set at |
|---|
| 397 |
every column occupied by an \"interesting character\" that is preceded |
|---|
| 398 |
by whitespace. Interesting characters are defined by the variable |
|---|
| 399 |
`picture-tab-chars', see its documentation for an example of usage. |
|---|
| 400 |
With ARG, just (re)set `tab-stop-list' to its default value. The tab |
|---|
| 401 |
stops computed are displayed in the minibuffer with `:' at each stop." |
|---|
| 402 |
(interactive "P") |
|---|
| 403 |
(save-excursion |
|---|
| 404 |
(let (tabs) |
|---|
| 405 |
(if arg |
|---|
| 406 |
(setq tabs (default-value 'tab-stop-list)) |
|---|
| 407 |
(let ((regexp (concat "[ \t]+[" (regexp-quote picture-tab-chars) "]"))) |
|---|
| 408 |
(beginning-of-line) |
|---|
| 409 |
(let ((bol (point))) |
|---|
| 410 |
(end-of-line) |
|---|
| 411 |
(while (re-search-backward regexp bol t) |
|---|
| 412 |
(skip-chars-forward " \t") |
|---|
| 413 |
(setq tabs (cons (current-column) tabs))) |
|---|
| 414 |
(if (null tabs) |
|---|
| 415 |
(error "No characters in set %s on this line" |
|---|
| 416 |
(regexp-quote picture-tab-chars)))))) |
|---|
| 417 |
(setq tab-stop-list tabs) |
|---|
| 418 |
(let ((blurb (make-string (1+ (nth (1- (length tabs)) tabs)) ?\ ))) |
|---|
| 419 |
(while tabs |
|---|
| 420 |
(aset blurb (car tabs) ?:) |
|---|
| 421 |
(setq tabs (cdr tabs))) |
|---|
| 422 |
(message blurb))))) |
|---|
| 423 |
|
|---|
| 424 |
(defun picture-tab-search (&optional arg) |
|---|
| 425 |
"Move to column beneath next interesting char in previous line. |
|---|
| 426 |
With ARG move to column occupied by next interesting character in this |
|---|
| 427 |
line. The character must be preceded by whitespace. |
|---|
| 428 |
\"interesting characters\" are defined by variable `picture-tab-chars'. |
|---|
| 429 |
If no such character is found, move to beginning of line." |
|---|
| 430 |
(interactive "P") |
|---|
| 431 |
(let ((target (current-column))) |
|---|
| 432 |
(save-excursion |
|---|
| 433 |
(if (and (not arg) |
|---|
| 434 |
(progn |
|---|
| 435 |
(beginning-of-line) |
|---|
| 436 |
(skip-chars-backward |
|---|
| 437 |
(concat "^" (regexp-quote picture-tab-chars)) |
|---|
| 438 |
(point-min)) |
|---|
| 439 |
(not (bobp)))) |
|---|
| 440 |
(move-to-column target)) |
|---|
| 441 |
(if (re-search-forward |
|---|
| 442 |
(concat "[ \t]+[" (regexp-quote picture-tab-chars) "]") |
|---|
| 443 |
(save-excursion (end-of-line) (point)) |
|---|
| 444 |
'move) |
|---|
| 445 |
(setq target (1- (current-column))) |
|---|
| 446 |
(setq target nil))) |
|---|
| 447 |
(if target |
|---|
| 448 |
(move-to-column target t) |
|---|
| 449 |
(beginning-of-line)))) |
|---|
| 450 |
|
|---|
| 451 |
(defun picture-tab (&optional arg) |
|---|
| 452 |
"Tab transparently (just move point) to next tab stop. |
|---|
| 453 |
With prefix arg, overwrite the traversed text with spaces. The tab stop |
|---|
| 454 |
list can be changed by \\[picture-set-tab-stops] and \\[edit-tab-stops]. |
|---|
| 455 |
See also documentation for variable `picture-tab-chars'." |
|---|
| 456 |
(interactive "P") |
|---|
| 457 |
(let* ((opoint (point))) |
|---|
| 458 |
(move-to-tab-stop) |
|---|
| 459 |
(if arg |
|---|
| 460 |
(let (indent-tabs-mode |
|---|
| 461 |
(column (current-column))) |
|---|
| 462 |
(delete-region opoint (point)) |
|---|
| 463 |
(indent-to column))))) |
|---|
| 464 |
|
|---|
| 465 |
|
|---|
| 466 |
|
|---|
| 467 |
(defvar picture-killed-rectangle nil |
|---|
| 468 |
"Rectangle killed or copied by \\[picture-clear-rectangle] in Picture mode. |
|---|
| 469 |
The contents can be retrieved by \\[picture-yank-rectangle]") |
|---|
| 470 |
|
|---|
| 471 |
(defun picture-clear-rectangle (start end &optional killp) |
|---|
| 472 |
"Clear and save rectangle delineated by point and mark. |
|---|
| 473 |
The rectangle is saved for yanking by \\[picture-yank-rectangle] and replaced |
|---|
| 474 |
with whitespace. The previously saved rectangle, if any, is lost. With |
|---|
| 475 |
prefix argument, the rectangle is actually killed, shifting remaining text." |
|---|
| 476 |
(interactive "r\nP") |
|---|
| 477 |
(setq picture-killed-rectangle (picture-snarf-rectangle start end killp))) |
|---|
| 478 |
|
|---|
| 479 |
(defun picture-clear-rectangle-to-register (start end register &optional killp) |
|---|
| 480 |
"Clear rectangle delineated by point and mark into REGISTER. |
|---|
| 481 |
The rectangle is saved in REGISTER and replaced with whitespace. With |
|---|
| 482 |
prefix argument, the rectangle is actually killed, shifting remaining text." |
|---|
| 483 |
(interactive "r\ncRectangle to register: \nP") |
|---|
| 484 |
(set-register register (picture-snarf-rectangle start end killp))) |
|---|
| 485 |
|
|---|
| 486 |
(defun picture-snarf-rectangle (start end &optional killp) |
|---|
| 487 |
(let ((column (current-column)) |
|---|
| 488 |
(indent-tabs-mode nil)) |
|---|
| 489 |
(prog1 (save-excursion |
|---|
| 490 |
(if killp |
|---|
| 491 |
(delete-extract-rectangle start end) |
|---|
| 492 |
(prog1 (extract-rectangle start end) |
|---|
| 493 |
(clear-rectangle start end)))) |
|---|
| 494 |
(move-to-column column t)))) |
|---|
| 495 |
|
|---|
| 496 |
(defun picture-yank-rectangle (&optional insertp) |
|---|
| 497 |
"Overlay rectangle saved by \\[picture-clear-rectangle] |
|---|
| 498 |
The rectangle is positioned with upper left corner at point, overwriting |
|---|
| 499 |
existing text. With prefix argument, the rectangle is inserted instead, |
|---|
| 500 |
shifting existing text. Leaves mark at one corner of rectangle and |
|---|
| 501 |
point at the other (diagonally opposed) corner." |
|---|
| 502 |
(interactive "P") |
|---|
| 503 |
(if (not (consp picture-killed-rectangle)) |
|---|
| 504 |
(error "No rectangle saved") |
|---|
| 505 |
(picture-insert-rectangle picture-killed-rectangle insertp))) |
|---|
| 506 |
|
|---|
| 507 |
(defun picture-yank-at-click (click arg) |
|---|
| 508 |
"Insert the last killed rectangle at the position clicked on. |
|---|
| 509 |
Also move point to one end of the text thus inserted (normally the end). |
|---|
| 510 |
Prefix arguments are interpreted as with \\[yank]. |
|---|
| 511 |
If `mouse-yank-at-point' is non-nil, insert at point |
|---|
| 512 |
regardless of where you click." |
|---|
| 513 |
(interactive "e\nP") |
|---|
| 514 |
(or mouse-yank-at-point (mouse-set-point click)) |
|---|
| 515 |
(picture-yank-rectangle arg)) |
|---|
| 516 |
|
|---|
| 517 |
(defun picture-yank-rectangle-from-register (register &optional insertp) |
|---|
| 518 |
"Overlay rectangle saved in REGISTER. |
|---|
| 519 |
The rectangle is positioned with upper left corner at point, overwriting |
|---|
| 520 |
existing text. With prefix argument, the rectangle is |
|---|
| 521 |
inserted instead, shifting existing text. Leaves mark at one corner |
|---|
| 522 |
of rectangle and point at the other (diagonally opposed) corner." |
|---|
| 523 |
(interactive "cRectangle from register: \nP") |
|---|
| 524 |
(let ((rectangle (get-register register))) |
|---|
| 525 |
(if (not (consp rectangle)) |
|---|
| 526 |
(error "Register %c does not contain a rectangle" register) |
|---|
| 527 |
(picture-insert-rectangle rectangle insertp)))) |
|---|
| 528 |
|
|---|
| 529 |
(defun picture-insert-rectangle (rectangle &optional insertp) |
|---|
| 530 |
"Overlay RECTANGLE with upper left corner at point. |
|---|
| 531 |
Optional argument INSERTP, if non-nil causes RECTANGLE to be inserted. |
|---|
| 532 |
Leaves the region surrounding the rectangle." |
|---|
| 533 |
(let ((indent-tabs-mode nil)) |
|---|
| 534 |
(if (not insertp) |
|---|
| 535 |
(save-excursion |
|---|
| 536 |
(delete-rectangle (point) |
|---|
| 537 |
(progn |
|---|
| 538 |
(picture-forward-column (length (car rectangle))) |
|---|
| 539 |
(picture-move-down (1- (length rectangle))) |
|---|
| 540 |
(point))))) |
|---|
| 541 |
(push-mark) |
|---|
| 542 |
(insert-rectangle rectangle))) |
|---|
| 543 |
|
|---|
| 544 |
(defun picture-current-line () |
|---|
| 545 |
"Return the vertical position of point. Top line is 1." |
|---|
| 546 |
(+ (count-lines (point-min) (point)) |
|---|
| 547 |
(if (= (current-column) 0) 1 0))) |
|---|
| 548 |
|
|---|
| 549 |
(defun picture-draw-rectangle (start end) |
|---|
| 550 |
"Draw a rectangle around region." |
|---|
| 551 |
(interactive "*r") |
|---|
| 552 |
(let* ((sl (picture-current-line)) |
|---|
| 553 |
(sc (current-column)) |
|---|
| 554 |
(pvs picture-vertical-step) |
|---|
| 555 |
(phs picture-horizontal-step) |
|---|
| 556 |
(c1 (progn (goto-char start) (current-column))) |
|---|
| 557 |
(r1 (picture-current-line)) |
|---|
| 558 |
(c2 (progn (goto-char end) (current-column))) |
|---|
| 559 |
(r2 (picture-current-line)) |
|---|
| 560 |
(right (max c1 c2)) |
|---|
| 561 |
(left (min c1 c2)) |
|---|
| 562 |
(top (min r1 r2)) |
|---|
| 563 |
(bottom (max r1 r2))) |
|---|
| 564 |
(goto-line top) |
|---|
| 565 |
(move-to-column left t) |
|---|
| 566 |
(picture-update-desired-column t) |
|---|
| 567 |
|
|---|
| 568 |
(picture-movement-right) |
|---|
| 569 |
(picture-insert picture-rectangle-ctl 1) |
|---|
| 570 |
(picture-insert picture-rectangle-h (- right picture-desired-column)) |
|---|
| 571 |
|
|---|
| 572 |
(picture-movement-down) |
|---|
| 573 |
(picture-insert picture-rectangle-ctr 1) |
|---|
| 574 |
(picture-insert picture-rectangle-v (- bottom (picture-current-line))) |
|---|
| 575 |
|
|---|
| 576 |
(picture-movement-left) |
|---|
| 577 |
(picture-insert picture-rectangle-cbr 1) |
|---|
| 578 |
(picture-insert picture-rectangle-h (- picture-desired-column left)) |
|---|
| 579 |
|
|---|
| 580 |
(picture-movement-up) |
|---|
| 581 |
(picture-insert picture-rectangle-cbl 1) |
|---|
| 582 |
(picture-insert picture-rectangle-v (- (picture-current-line) top)) |
|---|
| 583 |
|
|---|
| 584 |
(picture-set-motion pvs phs) |
|---|
| 585 |
(goto-line sl) |
|---|
| 586 |
(move-to-column sc t))) |
|---|
| 587 |
|
|---|
| 588 |
|
|---|
| 589 |
|
|---|
| 590 |
|
|---|
| 591 |
(defvar picture-mode-map nil) |
|---|
| 592 |
|
|---|
| 593 |
(defun picture-substitute (oldfun newfun) |
|---|
| 594 |
(define-key picture-mode-map (vector 'remap oldfun) newfun)) |
|---|
| 595 |
|
|---|
| 596 |
(if (not picture-mode-map) |
|---|
| 597 |
(progn |
|---|
| 598 |
(setq picture-mode-map (make-keymap)) |
|---|
| 599 |
(picture-substitute 'self-insert-command 'picture-self-insert) |
|---|
| 600 |
(picture-substitute 'completion-separator-self-insert-command |
|---|
| 601 |
'picture-self-insert) |
|---|
| 602 |
(picture-substitute 'completion-separator-self-insert-autofilling |
|---|
| 603 |
'picture-self-insert) |
|---|
| 604 |
(picture-substitute 'forward-char 'picture-forward-column) |
|---|
| 605 |
(picture-substitute 'backward-char 'picture-backward-column) |
|---|
| 606 |
(picture-substitute 'delete-char 'picture-clear-column) |
|---|
| 607 |
|
|---|
| 608 |
(picture-substitute 'backward-delete-char-untabify 'picture-backward-clear-column) |
|---|
| 609 |
(picture-substitute 'delete-backward-char 'picture-backward-clear-column) |
|---|
| 610 |
(picture-substitute 'kill-line 'picture-clear-line) |
|---|
| 611 |
(picture-substitute 'open-line 'picture-open-line) |
|---|
| 612 |
(picture-substitute 'newline 'picture-newline) |
|---|
| 613 |
(picture-substitute 'newline-and-indent 'picture-duplicate-line) |
|---|
| 614 |
(picture-substitute 'next-line 'picture-move-down) |
|---|
| 615 |
(picture-substitute 'previous-line 'picture-move-up) |
|---|
| 616 |
(picture-substitute 'beginning-of-line 'picture-beginning-of-line) |
|---|
| 617 |
(picture-substitute 'end-of-line 'picture-end-of-line) |
|---|
| 618 |
(picture-substitute 'mouse-set-point 'picture-mouse-set-point) |
|---|
| 619 |
|
|---|
| 620 |
(define-key picture-mode-map "\C-c\C-d" 'delete-char) |
|---|
| 621 |
(define-key picture-mode-map "\e\t" 'picture-toggle-tab-state) |
|---|
| 622 |
(define-key picture-mode-map "\t" 'picture-tab) |
|---|
| 623 |
(define-key picture-mode-map "\e\t" 'picture-tab-search) |
|---|
| 624 |
(define-key picture-mode-map "\C-c\t" 'picture-set-tab-stops) |
|---|
| 625 |
(define-key picture-mode-map "\C-c\C-k" 'picture-clear-rectangle) |
|---|
| 626 |
(define-key picture-mode-map "\C-c\C-w" 'picture-clear-rectangle-to-register) |
|---|
| 627 |
(define-key picture-mode-map "\C-c\C-y" 'picture-yank-rectangle) |
|---|
| 628 |
(define-key picture-mode-map "\C-c\C-x" 'picture-yank-rectangle-from-register) |
|---|
| 629 |
(define-key picture-mode-map "\C-c\C-r" 'picture-draw-rectangle) |
|---|
| 630 |
(define-key picture-mode-map "\C-c\C-c" 'picture-mode-exit) |
|---|
| 631 |
(define-key picture-mode-map "\C-c\C-f" 'picture-motion) |
|---|
| 632 |
(define-key picture-mode-map "\C-c\C-b" 'picture-motion-reverse) |
|---|
| 633 |
(define-key picture-mode-map "\C-c<" 'picture-movement-left) |
|---|
| 634 |
(define-key picture-mode-map "\C-c>" 'picture-movement-right) |
|---|
| 635 |
(define-key picture-mode-map "\C-c^" 'picture-movement-up) |
|---|
| 636 |
(define-key picture-mode-map "\C-c." 'picture-movement-down) |
|---|
| 637 |
(define-key picture-mode-map "\C-c`" 'picture-movement-nw) |
|---|
| 638 |
(define-key picture-mode-map "\C-c'" 'picture-movement-ne) |
|---|
| 639 |
(define-key picture-mode-map "\C-c/" 'picture-movement-sw) |
|---|
| 640 |
(define-key picture-mode-map "\C-c\\" 'picture-movement-se) |
|---|
| 641 |
(define-key picture-mode-map [(control ?c) left] 'picture-movement-left) |
|---|
| 642 |
(define-key picture-mode-map [(control ?c) right] 'picture-movement-right) |
|---|
| 643 |
(define-key picture-mode-map [(control ?c) up] 'picture-movement-up) |
|---|
| 644 |
(define-key picture-mode-map [(control ?c) down] 'picture-movement-down) |
|---|
| 645 |
(define-key picture-mode-map [(control ?c) home] 'picture-movement-nw) |
|---|
| 646 |
(define-key picture-mode-map [(control ?c) prior] 'picture-movement-ne) |
|---|
| 647 |
(define-key picture-mode-map [(control ?c) end] 'picture-movement-sw) |
|---|
| 648 |
(define-key picture-mode-map [(control ?c) next] 'picture-movement-se))) |
|---|
| 649 |
|
|---|
| 650 |
(defcustom picture-mode-hook nil |
|---|
| 651 |
"If non-nil, its value is called on entry to Picture mode. |
|---|
| 652 |
Picture mode is invoked by the command \\[picture-mode]." |
|---|
| 653 |
:type 'hook |
|---|
| 654 |
:group 'picture) |
|---|
| 655 |
|
|---|
| 656 |
(defvar picture-mode-old-local-map) |
|---|
| 657 |
(defvar picture-mode-old-mode-name) |
|---|
| 658 |
(defvar picture-mode-old-major-mode) |
|---|
| 659 |
(defvar picture-mode-old-truncate-lines) |
|---|
| 660 |
|
|---|
| 661 |
|
|---|
| 662 |
(defun picture-mode () |
|---|
| 663 |
"Switch to Picture mode, in which a quarter-plane screen model is used. |
|---|
| 664 |
\\<picture-mode-map> |
|---|
| 665 |
Printing characters replace instead of inserting themselves with motion |
|---|
| 666 |
afterwards settable by these commands: |
|---|
| 667 |
|
|---|
| 668 |
Move left after insertion: \\[picture-movement-left] |
|---|
| 669 |
Move right after insertion: \\[picture-movement-right] |
|---|
| 670 |
Move up after insertion: \\[picture-movement-up] |
|---|
| 671 |
Move down after insertion: \\[picture-movement-down] |
|---|
| 672 |
|
|---|
| 673 |
Move northwest (nw) after insertion: \\[picture-movement-nw] |
|---|
| 674 |
Move northeast (ne) after insertion: \\[picture-movement-ne] |
|---|
| 675 |
Move southwest (sw) after insertion: \\[picture-movement-sw] |
|---|
| 676 |
Move southeast (se) after insertion: \\[picture-movement-se] |
|---|
| 677 |
|
|---|
| 678 |
Move westnorthwest (wnw) after insertion: C-u \\[picture-movement-nw] |
|---|
| 679 |
Move eastnortheast (ene) after insertion: C-u \\[picture-movement-ne] |
|---|
| 680 |
Move westsouthwest (wsw) after insertion: C-u \\[picture-movement-sw] |
|---|
| 681 |
Move eastsoutheast (ese) after insertion: C-u \\[picture-movement-se] |
|---|
| 682 |
|
|---|
| 683 |
The current direction is displayed in the mode line. The initial |
|---|
| 684 |
direction is right. Whitespace is inserted and tabs are changed to |
|---|
| 685 |
spaces when required by movement. You can move around in the buffer |
|---|
| 686 |
with these commands: |
|---|
| 687 |
|
|---|
| 688 |
Move vertically to SAME column in previous line: \\[picture-move-down] |
|---|
| 689 |
Move vertically to SAME column in next line: \\[picture-move-up] |
|---|
| 690 |
Move to column following last |
|---|
| 691 |
non-whitespace character: \\[picture-end-of-line] |
|---|
| 692 |
Move right, inserting spaces if required: \\[picture-forward-column] |
|---|
| 693 |
Move left changing tabs to spaces if required: \\[picture-backward-column] |
|---|
| 694 |
Move in direction of current picture motion: \\[picture-motion] |
|---|
| 695 |
Move opposite to current picture motion: \\[picture-motion-reverse] |
|---|
| 696 |
Move to beginning of next line: \\[next-line] |
|---|
| 697 |
|
|---|
| 698 |
You can edit tabular text with these commands: |
|---|
| 699 |
|
|---|
| 700 |
Move to column beneath (or at) next interesting |
|---|
| 701 |
character (see variable `picture-tab-chars'): \\[picture-tab-search] |
|---|
| 702 |
Move to next stop in tab stop list: \\[picture-tab] |
|---|
| 703 |
Set tab stops according to context of this line: \\[picture-set-tab-stops] |
|---|
| 704 |
(With ARG, resets tab stops to default value.) |
|---|
| 705 |
Change the tab stop list: \\[edit-tab-stops] |
|---|
| 706 |
|
|---|
| 707 |
You can manipulate text with these commands: |
|---|
| 708 |
Clear ARG columns after point without moving: \\[picture-clear-column] |
|---|
| 709 |
Delete char at point: \\[delete-char] |
|---|
| 710 |
Clear ARG columns backward: \\[picture-backward-clear-column] |
|---|
| 711 |
Clear ARG lines, advancing over them: \\[picture-clear-line] |
|---|
| 712 |
(the cleared text is saved in the kill ring) |
|---|
| 713 |
Open blank line(s) beneath current line: \\[picture-open-line] |
|---|
| 714 |
|
|---|
| 715 |
You can manipulate rectangles with these commands: |
|---|
| 716 |
Clear a rectangle and save it: \\[picture-clear-rectangle] |
|---|
| 717 |
Clear a rectangle, saving in a named register: \\[picture-clear-rectangle-to-register] |
|---|
| 718 |
Insert currently saved rectangle at point: \\[picture-yank-rectangle] |
|---|
| 719 |
Insert rectangle from named register: \\[picture-yank-rectangle-from-register] |
|---|
| 720 |
Draw a rectangular box around mark and point: \\[picture-draw-rectangle] |
|---|
| 721 |
Copies a rectangle to a register: \\[copy-rectangle-to-register] |
|---|
| 722 |
Undo effects of rectangle overlay commands: \\[advertised-undo] |
|---|
| 723 |
|
|---|
| 724 |
You can return to the previous mode with \\[picture-mode-exit], which |
|---|
| 725 |
also strips trailing whitespace from every line. Stripping is suppressed |
|---|
| 726 |
by supplying an argument. |
|---|
| 727 |
|
|---|
| 728 |
Entry to this mode calls the value of `picture-mode-hook' if non-nil. |
|---|
| 729 |
|
|---|
| 730 |
Note that Picture mode commands will work outside of Picture mode, but |
|---|
| 731 |
they are not defaultly assigned to keys." |
|---|
| 732 |
(interactive) |
|---|
| 733 |
(if (eq major-mode 'picture-mode) |
|---|
| 734 |
(error "You are already editing a picture") |
|---|
| 735 |
(set (make-local-variable 'picture-mode-old-local-map) (current-local-map)) |
|---|
| 736 |
(use-local-map picture-mode-map) |
|---|
| 737 |
(set (make-local-variable 'picture-mode-old-mode-name) mode-name) |
|---|
| 738 |
(set (make-local-variable 'picture-mode-old-major-mode) major-mode) |
|---|
| 739 |
(setq major-mode 'picture-mode) |
|---|
| 740 |
(set (make-local-variable 'picture-killed-rectangle) nil) |
|---|
| 741 |
(set (make-local-variable 'tab-stop-list) (default-value 'tab-stop-list)) |
|---|
| 742 |
(set (make-local-variable 'picture-tab-chars) |
|---|
| 743 |
(default-value 'picture-tab-chars)) |
|---|
| 744 |
(make-local-variable 'picture-vertical-step) |
|---|
| 745 |
(make-local-variable 'picture-horizontal-step) |
|---|
| 746 |
(set (make-local-variable 'picture-mode-old-truncate-lines) truncate-lines) |
|---|
| 747 |
(setq truncate-lines t) |
|---|
| 748 |
(picture-set-motion 0 1) |
|---|
| 749 |
|
|---|
| 750 |
|
|---|
| 751 |
(run-hooks 'edit-picture-hook 'picture-mode-hook) |
|---|
| 752 |
(message "Type %s in this buffer to return it to %s mode." |
|---|
| 753 |
(substitute-command-keys "\\[picture-mode-exit]") |
|---|
| 754 |
picture-mode-old-mode-name))) |
|---|
| 755 |
|
|---|
| 756 |
|
|---|
| 757 |
(defalias 'edit-picture 'picture-mode) |
|---|
| 758 |
|
|---|
| 759 |
(defun picture-mode-exit (&optional nostrip) |
|---|
| 760 |
"Undo `picture-mode' and return to previous major mode. |
|---|
| 761 |
With no argument, strip whitespace from end of every line in Picture buffer; |
|---|
| 762 |
otherwise, just return to previous mode. |
|---|
| 763 |
Runs `picture-mode-exit-hook' at the end." |
|---|
| 764 |
(interactive "P") |
|---|
| 765 |
(if (not (eq major-mode 'picture-mode)) |
|---|
| 766 |
(error "You aren't editing a Picture") |
|---|
| 767 |
(if (not nostrip) (delete-trailing-whitespace)) |
|---|
| 768 |
(setq mode-name picture-mode-old-mode-name) |
|---|
| 769 |
(use-local-map picture-mode-old-local-map) |
|---|
| 770 |
(setq major-mode picture-mode-old-major-mode) |
|---|
| 771 |
(kill-local-variable 'tab-stop-list) |
|---|
| 772 |
(setq truncate-lines picture-mode-old-truncate-lines) |
|---|
| 773 |
(force-mode-line-update) |
|---|
| 774 |
(run-hooks 'picture-mode-exit-hook))) |
|---|
| 775 |
|
|---|
| 776 |
(provide 'picture) |
|---|
| 777 |
|
|---|
| 778 |
|
|---|
| 779 |
|
|---|
| 780 |
|
|---|