1;;; yatexsec.el --- YaTeX sectioning browser 2;;; 3;;; (c) 1994-2017 by HIROSE Yuuji [yuuji@yatex.org] 4;;; Last modified Wed May 30 13:29:50 2018 on firestorm 5;;; $Id: yatexsec.el,v a58a35eac93f 2018-07-31 08:21 +0900 yuuji $ 6 7;;; Code: 8(defvar YaTeX-sectioning-level 9 '(("part" . 0) 10 ("chapter" . 1) 11 ("section" . 2) 12 ("subsection" . 3) 13 ("subsubsection" . 4) 14 ("paragraph" . 5) 15 ("subparagraph" . 6)) 16 "*Alist of LaTeX's sectioning command and its level. 17This value must be written in numerically ascending order and consecutive. 18Needn't define the level of `*' commands such as `section*'.") 19 20(defvar YaTeX-sectioning-max-level 21 (cdr (nth (1- (length YaTeX-sectioning-level)) YaTeX-sectioning-level)) 22 "*The heighest(numerically) level of sectioning command. 23This must be the heighest number in YaTeX-sectioning-level.") 24 25(defun YaTeX-sectioning-map-hide (map) 26 (let ((ch ?0)) 27 (while (<= ch ?9) 28 (define-key map (char-to-string ch) 'YaTeX-sectioning-hide) 29 (setq ch (1+ ch)))) 30) 31 32(defvar YaTeX-sectioning-minibuffer-map nil 33 "Key map used in minibuffer for sectioning.") 34(if YaTeX-sectioning-minibuffer-map nil 35 (setq YaTeX-sectioning-minibuffer-map 36 (copy-keymap minibuffer-local-completion-map)) 37 (define-key YaTeX-sectioning-minibuffer-map "\C-p" 38 'YaTeX-sectioning-up) 39 (define-key YaTeX-sectioning-minibuffer-map "\C-e" 40 'YaTeX-sectioning-up) 41 (define-key YaTeX-sectioning-minibuffer-map "\C-i" 42 'YaTeX-minibuffer-complete) 43 (define-key YaTeX-sectioning-minibuffer-map " " 44 'YaTeX-minibuffer-complete) 45 (define-key YaTeX-sectioning-minibuffer-map "\C-n" 46 'YaTeX-sectioning-down) 47 (define-key YaTeX-sectioning-minibuffer-map "\C-x" 48 'YaTeX-sectioning-down) 49 (define-key YaTeX-sectioning-minibuffer-map "\C-v" 50 'YaTeX-sectioning-scroll-up) 51 (define-key YaTeX-sectioning-minibuffer-map "\C-c" 52 'YaTeX-sectioning-scroll-up) 53 (define-key YaTeX-sectioning-minibuffer-map "\M-v" 54 'YaTeX-sectioning-scroll-down) 55 (define-key YaTeX-sectioning-minibuffer-map "\C-r" 56 'YaTeX-sectioning-scroll-down) 57 (define-key YaTeX-sectioning-minibuffer-map "\C-w" 58 (function (lambda () (interactive) (YaTeX-sectioning-scroll-down 1)))) 59 (define-key YaTeX-sectioning-minibuffer-map "\C-z" 60 (function (lambda () (interactive) (YaTeX-sectioning-scroll-up 1)))) 61 (define-key YaTeX-sectioning-minibuffer-map "\C-l" 62 'YaTeX-sectioning-recenter) 63 (define-key YaTeX-sectioning-minibuffer-map "?" 64 'YaTeX-sectioning-help) 65 (YaTeX-sectioning-map-hide YaTeX-sectioning-minibuffer-map) 66) 67 68(defvar YaTeX-sectioning-buffer-map nil 69 "Key map used in YaTeX-sectioning-buffer.") 70(if YaTeX-sectioning-buffer-map nil 71 (setq YaTeX-sectioning-buffer-map (make-sparse-keymap)) 72 (define-key YaTeX-sectioning-buffer-map " " 'YaTeX-sectioning-buffer-jump) 73 (define-key YaTeX-sectioning-buffer-map "." 'YaTeX-sectioning-buffer-show) 74 (define-key YaTeX-sectioning-buffer-map (concat YaTeX-prefix "\C-c") 75 'YaTeX-sectioning-buffer-jump) 76 (define-key YaTeX-sectioning-buffer-map "u" 'YaTeX-shift-section-up) 77 (define-key YaTeX-sectioning-buffer-map "d" 'YaTeX-shift-section-down) 78 (define-key YaTeX-sectioning-buffer-map "U" 'YaTeX-shift-section-up-region) 79 (define-key YaTeX-sectioning-buffer-map "D" 'YaTeX-shift-section-down-region) 80 (define-key YaTeX-sectioning-buffer-map "s" 'YaTeX-sync-section-buffer) 81 (define-key YaTeX-sectioning-buffer-map "n" 82 'YaTeX-sectioning-buffer-next-line) 83 (define-key YaTeX-sectioning-buffer-map "p" 84 'YaTeX-sectioning-buffer-prev-line) 85 (define-key YaTeX-sectioning-buffer-map "h" 'describe-mode) 86 (define-key YaTeX-sectioning-buffer-map "o" 'other-window) 87 (define-key YaTeX-sectioning-buffer-map "-" 'shrink-window) 88 (define-key YaTeX-sectioning-buffer-map "+" 'enlarge-window) 89 (define-key YaTeX-sectioning-buffer-map "q" 'delete-window) 90 (define-key YaTeX-sectioning-buffer-map "\C-_" 'YaTeX-shift-section-undo) 91 (and YaTeX-emacs-19 (boundp 'window-system) (eq window-system 'x) 92 (define-key YaTeX-sectioning-buffer-map [?\C-/] 93 'YaTeX-shift-section-undo)) 94 (YaTeX-sectioning-map-hide YaTeX-sectioning-buffer-map) 95) 96 97(defun YaTeX-sectioning-mode () 98 "Mode for browsing document's sectioning structure. 99\\[YaTeX-shift-section-up] Shift up a sectioning command 100\\[YaTeX-shift-section-down] Shift down a sectioning command 101\\[YaTeX-shift-section-up-region] Shift up sectioning commands in region 102\\[YaTeX-shift-section-down-region] Shift down sectioning commands in region 103\\[YaTeX-shift-section-undo] Undo changes of shifting 104\\[YaTeX-sync-section-buffer] Synchronize sectioning buffer with source 105\\[YaTeX-sectioning-buffer-next-line] Next line 106\\[YaTeX-sectioning-buffer-prev-line] Previous line 107\\[YaTeX-sectioning-buffer-jump] Previous line 108\\[YaTeX-sectioning-buffer-show] Show curresponding source line 109" 110 (interactive) 111 (setq major-mode 'YaTeX-sectioning-mode 112 mode-name "sectioning") 113 (use-local-map YaTeX-sectioning-buffer-map) 114) 115 116(defvar YaTeX-sectioning-buffer-parent nil) 117(defun YaTeX-sectioning-buffer-jump-internal (&optional keep) 118 (let ((p (point)) ;save-excursion is NG because 119 ptn ln) ;this function should switch buffer 120 (beginning-of-line) 121 (if (re-search-forward YaTeX-sectioning-regexp) 122 (progn 123 (save-restriction 124 (narrow-to-region (point-beginning-of-line) (point-end-of-line)) 125 (setq ptn (buffer-substring 126 (1- (match-beginning 0)) 127 (progn (skip-chars-forward "^}") (1+ (point)))) 128 ln (buffer-substring 129 (progn (search-forward "line:") (match-end 0)) 130 (progn (skip-chars-forward "0-9") (point))))) 131 (goto-char p) 132 (YaTeX-showup-buffer YaTeX-sectioning-buffer-parent nil t) 133 (or 134 (and ln (string< "" ln) 135 (progn 136 (goto-char (point-min)) 137 (forward-line (max 0 (- (YaTeX-str2int ln) 2))) 138 (and 139 (search-forward ptn nil t) 140 (goto-char (match-beginning 0))))) 141 (progn 142 (goto-char (point-max)) 143 (search-backward ptn))) 144 (if keep (goto-buffer-window YaTeX-sectioning-buffer)) 145 (current-buffer)) 146 nil))) 147 148(defun YaTeX-sectioning-buffer-jump (&optional keep) 149 "Goto corresponding sectioning unit with current line in the next window. 150If optional argument KEEP is non-nil, only shows the line." 151 (interactive) 152 (if (and YaTeX-sectioning-buffer-parent 153 (get-buffer YaTeX-sectioning-buffer-parent)) 154 (YaTeX-sectioning-buffer-jump-internal keep) 155 (message "No line number expression.")) 156) 157 158(defun YaTeX-sectioning-buffer-show () 159 "Show corresponding sectioning unit with current line." 160 (interactive) 161 (YaTeX-sectioning-buffer-jump-internal t) 162) 163 164(defun YaTeX-sectioning-hide-under (n) 165 "Hide sectioning commands under level N." 166 (let ((cw (selected-window))) 167 (YaTeX-showup-buffer YaTeX-sectioning-buffer nil t) 168 (if (>= n YaTeX-sectioning-max-level) 169 (progn 170 (set-selective-display nil) 171 (message "Show all.")) 172 (set-selective-display (1+ n)) 173 (if (rassq n YaTeX-sectioning-level) 174 (message "Hide lower than %s" (car (rassq n YaTeX-sectioning-level))) 175 (message ""))) 176 (if (numberp selective-display) 177 (setq mode-name (format "level %d" (1- selective-display))) 178 (setq mode-name (format "all"))) 179 (select-window cw)) 180) 181(defun YaTeX-sectioning-hide () 182 "Call YaTeX-sectioning-hide-under with argument according to pressed key." 183 (interactive) 184 (YaTeX-sectioning-hide-under (- (YaTeX-last-key) ?0))) 185 186(defun YaTeX-sectioning-help () 187 "Show help of sectioning." 188 (interactive) 189 (let ((cw (selected-window)) sb (hb (get-buffer-create "*Help*"))) 190 (unwind-protect 191 (progn 192 (other-window 1) 193 (setq sb (current-buffer)) 194 (switch-to-buffer hb) 195 (setq buffer-read-only nil) ;; Emacs26 196 (erase-buffer) 197 (insert "===== View sectioning ===== 198C-p Up sectioning level. 0 Show only \\part, 199C-n Down sectioning level. 1 and \\chapter, 200C-v Scroll up *Sectioning line* buffer. 2 and \\section, 201M-v Scroll down *Sectioning line* buffer. 3 and \\subsection, 202C-z Scroll up by 1 line. 4 and \\subsubsection, 203C-w Scroll down by 1 line. 5 and \\paragraph. 204SPC Complete word. 6 Show all. 205TAB Complete word. 206C-l Recenter recent line. 207RET Select. 208==== End of HELP ===== 209") 210 (set-buffer-modified-p nil) 211 (goto-char (point-min)) 212 (momentary-string-display "" (point-min))) 213 (bury-buffer hb) 214 (switch-to-buffer sb) 215 (select-window cw))) 216) 217 218(defun YaTeX-sectioning-up (n) 219 "Up section level. 220Refers the YaTeX-read-section-in-minibuffer's local variable minibuffer-start." 221 (interactive "p") 222 (if (eq (selected-window) (minibuffer-window)) 223 (let*((command (YaTeX-minibuffer-string)) 224 (aster (and (string< "" command) 225 (equal (substring command -1) "*"))) 226 (command (if aster (substring command 0 -1) command)) 227 (alist YaTeX-sectioning-level) 228 (level 0)) 229 (or (assoc command alist) (error "No such sectioning command.")) 230 (while (not (string= (car (nth level alist)) command)) 231 (setq level (1+ level))) ;I want to use `member'.... 232 (setq level (- level n)) 233 (if (or (< level 0) (>= level (length alist))) 234 (ding) 235 (YaTeX-minibuffer-erase) 236 (insert (concat (car (nth level alist)) (if aster "*" "")))))) 237) 238 239(defun YaTeX-sectioning-down (n) 240 "Down section level." 241 (interactive "p") 242 (YaTeX-sectioning-up (- n)) 243) 244 245(defun YaTeX-sectioning-scroll-up (n) 246 (interactive "P") 247 (let ((section-buffer YaTeX-sectioning-buffer) 248 (cw (selected-window))) 249 (YaTeX-showup-buffer section-buffer nil t) 250 (unwind-protect 251 (scroll-up (or n (- (window-height) 2))) 252 (select-window cw))) 253) 254 255(defun YaTeX-sectioning-scroll-down (n) 256 (interactive "P") 257 (let ((section-buffer YaTeX-sectioning-buffer) 258 (cw (selected-window))) 259 (YaTeX-showup-buffer section-buffer nil t) 260 (unwind-protect 261 (scroll-down (or n (- (window-height) 2))) 262 (select-window cw))) 263) 264 265(defun YaTeX-sectioning-recenter (arg) 266 "Recenter `<<--' line" 267 (interactive "P") 268 (let ((cw (selected-window))) 269 (unwind-protect 270 (progn 271 (YaTeX-showup-buffer YaTeX-sectioning-buffer nil t) 272 (or (search-forward "<<--" nil t) 273 (search-backward "<<--" nil)) 274 (recenter (or arg (/ (window-height) 2)))) 275 (select-window cw))) 276) 277 278(defvar YaTeX-sectioning-minibuffer " *sectioning*" 279 "Miniuffer used for sectioning") 280;;;###autoload 281(defun YaTeX-read-section-in-minibuffer (prompt table &optional default delim) 282 (interactive) 283 (let ((minibuffer-completion-table table)) 284 (read-from-minibuffer 285 prompt default YaTeX-sectioning-minibuffer-map)) 286) 287 288(defun YaTeX-get-sectioning-level () 289 "Get section-level on the cursor." 290 (cdr-safe (assoc (buffer-substring 291 (point) 292 (progn (skip-chars-forward "a-z") (point))) 293 YaTeX-sectioning-level)) 294) 295 296(defvar YaTeX-sectioning-buffer "*Sectioning lines*") 297(defvar YaTeX-sectioning-indent 1) 298(defun YaTeX-collect-sections () 299 "Collect all the lines which contains sectioning command." 300 (let ((cw (selected-window)) level indent begp (prevp 1) (prevl 1) 301 (pattern (concat YaTeX-ec-regexp 302 "\\(" YaTeX-sectioning-regexp "\\)\\*?{")) 303 (cb (current-buffer))) 304 (save-excursion 305 (set-buffer (get-buffer-create YaTeX-sectioning-buffer)) 306 (setq buffer-read-only nil) 307 (erase-buffer) 308 (set-buffer cb) 309 (YaTeX-showup-buffer YaTeX-sectioning-buffer) ;show buffer 310 (goto-char (point-min)) 311 (let ((standard-output (get-buffer YaTeX-sectioning-buffer))) 312 (while (re-search-forward pattern nil t) 313 (goto-char (1+ (match-beginning 0))) 314 (setq level (YaTeX-get-sectioning-level) 315 begp (match-beginning 0)) 316 ;;(beginning-of-line) 317 ;;(skip-chars-forward " \t") 318 (setq indent (format "%%%ds" (* level YaTeX-sectioning-indent))) 319 (princ (format indent "")) 320 (if (YaTeX-on-comment-p) (princ "%")) 321 (princ (buffer-substring begp (progn (forward-list 1) (point)))) 322 (setq prevl (+ prevl (count-lines prevp (point)) -1) 323 prevp (point)) 324 (princ (format " (line:%d)" prevl)) 325 (princ "\n"))) 326 (set-buffer YaTeX-sectioning-buffer) 327 (make-local-variable 'YaTeX-sectioning-buffer-parent) 328 (YaTeX-sectioning-mode) 329 (use-local-map YaTeX-sectioning-buffer-map) 330 (setq YaTeX-sectioning-buffer-parent cb) 331 (if (numberp selective-display) 332 (setq mode-name (format "level %d" (1- selective-display)))) 333 YaTeX-sectioning-buffer)) 334) 335 336(defvar YaTeX-pending-undo nil) 337(defun YaTeX-section-overview () 338 "Show section overview. Return the nearest sectioning command." 339 (interactive) 340 (let ((cw (selected-window)) (ln (count-lines (point-min) (point))) 341 (pattern "(line:\\([0-9]+\\))") 342 secbuf (command "")) 343 (save-excursion 344 (setq secbuf (YaTeX-collect-sections)) 345 (YaTeX-showup-buffer secbuf nil t) 346 (set-buffer secbuf) 347 (goto-char (point-max)) 348 (while (re-search-backward pattern nil t) 349 (if (< ln (YaTeX-str2int (YaTeX-match-string 1))) nil 350 (beginning-of-line) 351 (search-forward YaTeX-ec) 352 (looking-at YaTeX-TeX-token-regexp) 353 (setq command (YaTeX-match-string 0)) 354 (end-of-line) 355 (insert " <<--") 356 (setq pattern (concat "HackyRegexp" "ForFailure")))) 357 (set-buffer-modified-p nil) 358 (setq buffer-read-only t buffer-undo-list nil) 359 (make-local-variable 'YaTeX-pending-undo) 360 (forward-line 1) 361 (if (eobp) (recenter -1) (recenter -3)) 362 (select-window cw) 363 command)) 364) 365 366;;;###autoload 367(defun YaTeX-make-section-with-overview () 368 "Input sectining command with previous overview." 369 (interactive) 370 (insert 371 YaTeX-ec 372 (YaTeX-read-section-in-minibuffer 373 "Sectioning(Up=C-p, Down=C-n, Help=?): " 374 YaTeX-sectioning-level (YaTeX-section-overview)) 375 "{}") 376 (forward-char -1) 377) 378 379(defun YaTeX-shifted-section (sc n) 380 "Get SC's N-shifted sectioning command." 381 (let (lv) 382 (setq lv (- (cdr (assoc sc YaTeX-sectioning-level)) n) 383 lv (max (min YaTeX-sectioning-max-level lv) 0)) 384 (car (nth lv YaTeX-sectioning-level))) 385) 386 387(defun YaTeX-shift-section-up (n) 388 "Shift sectioning command down by level N." 389 (interactive "p") 390 (let ((cb (current-buffer)) sc nsc lv) 391 (if (and YaTeX-sectioning-buffer-parent 392 (get-buffer YaTeX-sectioning-buffer-parent) 393 (save-excursion 394 (beginning-of-line) 395 (skip-chars-forward "^\\\\" (point-end-of-line)) 396 (YaTeX-on-section-command-p YaTeX-sectioning-regexp))) 397 (save-excursion 398 (or (buffer-name (get-buffer YaTeX-sectioning-buffer-parent)) 399 (error "This buffer is obsolete.")) 400 (setq nsc (YaTeX-shifted-section (YaTeX-match-string 1) n)) 401 (YaTeX-sectioning-buffer-jump-internal) 402 (undo-boundary) 403 (goto-char (match-beginning 0)) 404 (skip-chars-forward "\\\\") 405 (delete-region 406 (point) (progn (skip-chars-forward "^*{") (point))) 407 (insert nsc) 408 (undo-boundary) 409 ;; Return to *Sectioning Lines* buffer 410 (select-window (get-buffer-window cb)) 411 (beginning-of-line) 412 (let (buffer-read-only) 413 (delete-region 414 (point) (progn (skip-chars-forward " \t") (point))) 415 (indent-to-column (* (cdr (assoc nsc YaTeX-sectioning-level)) 416 YaTeX-sectioning-indent)) 417 (skip-chars-forward "^\\\\") 418 (delete-region 419 (1+ (point)) (progn (skip-chars-forward "^*{") (point))) 420 (insert nsc) 421 (undo-boundary)) 422 (set-buffer-modified-p nil) 423 (setq YaTeX-pending-undo pending-undo-list) 424 ))) 425) 426(defun YaTeX-shift-section-down (n) 427 "Shift sectioning command down by level N." 428 (interactive "p") 429 (YaTeX-shift-section-up (- n)) 430) 431(defun YaTeX-shift-section-undo (arg) 432 "Undo YaTeX-shift-section-up/down." 433 (interactive "p") 434 (and YaTeX-sectioning-buffer-parent 435 (get-buffer YaTeX-sectioning-buffer-parent) 436 (equal (current-buffer) (get-buffer YaTeX-sectioning-buffer)) 437 (let ((cb (current-buffer)) 438 (lc (if (eq last-command 'YaTeX-shift-section-undo) 'undo t))) 439 (let ((pending-undo-list YaTeX-pending-undo) 440 buffer-read-only (last-command lc)) 441 (undo arg) 442 (setq YaTeX-pending-undo pending-undo-list)) 443 (YaTeX-showup-buffer YaTeX-sectioning-buffer-parent) 444 (goto-buffer-window YaTeX-sectioning-buffer-parent) 445 (undo-boundary) 446 (let ((last-command lc) 447 (pending-undo-list 448 (if (eq lc 'undo) YaTeX-pending-undo pending-undo-list))) 449 (undo arg) 450 (setq YaTeX-pending-undo pending-undo-list)) 451 (goto-buffer-window cb) 452 (setq this-command 'YaTeX-shift-section-undo))) 453) 454(defun YaTeX-sync-section-buffer () 455 "Synchronize *Sectioning Lines* buffer with parent buffer." 456 (interactive) 457 (if (and YaTeX-sectioning-buffer-parent 458 (get-buffer YaTeX-sectioning-buffer-parent)) 459 (let ((cb (current-buffer)) (p (point))) 460 (set-buffer (get-buffer YaTeX-sectioning-buffer-parent)) 461 (YaTeX-section-overview) 462 (switch-to-buffer cb) 463 (goto-char p))) 464) 465(defun YaTeX-shift-section-up-region (beg end n) 466 "Shift sectioning commands in region down by level N." 467 (interactive "r\np") 468 (or YaTeX-sectioning-buffer-parent 469 (get-buffer YaTeX-sectioning-buffer-parent) 470 (error "Can't find corresponding LaTeX buffer")) 471 (save-excursion 472 (goto-char beg) 473 (let ((cb (current-buffer)) nsc from to repllist (e (make-marker))) 474 (set-marker e end) 475 (while (progn (skip-chars-forward "^\\\\") (< (point) e)) 476 (YaTeX-on-section-command-p YaTeX-sectioning-regexp) 477 (setq from (YaTeX-match-string 0) 478 nsc (YaTeX-shifted-section (YaTeX-match-string 1) n)) 479 (goto-char (match-beginning 0)) 480 (let (buffer-read-only) 481 ;(delete-region (point) (progn (beginning-of-line) (point))) 482 (delete-region (progn (beginning-of-line) (point)) 483 (progn (skip-chars-forward " \t") (point))) 484 (indent-to-column (cdr (assoc nsc YaTeX-sectioning-level))) 485 (delete-region 486 (progn (skip-chars-forward "%\\\\") (point)) 487 (progn (skip-chars-forward "^*{") (point))) 488 (insert nsc)) 489 (YaTeX-on-section-command-p YaTeX-sectioning-regexp) 490 (setq to (YaTeX-match-string 0) 491 repllist (cons (cons from to) repllist)) 492 (forward-line 1)) 493 (YaTeX-showup-buffer YaTeX-sectioning-buffer-parent) 494 (goto-buffer-window YaTeX-sectioning-buffer-parent) 495 (save-excursion 496 (goto-char (point-max)) 497 (undo-boundary) 498 (while repllist 499 (if (search-backward (car (car repllist)) nil t) 500 (progn 501 (goto-char (match-beginning 0)) ;confirm 502 (delete-region (point) (match-end 0)) 503 (insert (cdr (car repllist))) 504 (goto-char (match-beginning 0)))) 505 (setq repllist (cdr repllist)))) 506 (goto-buffer-window cb))) 507) 508(defun YaTeX-shift-section-down-region (beg end n) 509 "Shift sectioning commands in region down by level N." 510 (interactive "r\np") 511 (YaTeX-shift-section-up-region beg end (- n)) 512) 513(defun YaTeX-sectioning-buffer-next-line (n) 514 "Move to next line in *Sectioning Lines* buffer." 515 (interactive "p") 516 (forward-line n) 517 (skip-chars-forward " \t%") 518) 519(defun YaTeX-sectioning-buffer-prev-line (n) 520 "Move to previous line in *Sectioning Lines* buffer." 521 (interactive "p") 522 (YaTeX-sectioning-buffer-next-line (- n)) 523) 524(provide 'yatexsec) 525