yuuji@287: ;;; yatexhie.el --- YaTeX hierarchy browser yuuji@287: ;;; yuuji@294: ;;; (c)1995-2013 by HIROSE Yuuji [yuuji@yatex.org] yuuji@353: ;;; Last modified Sun Dec 21 14:05:20 2014 on firestorm yuuji@366: ;;; $Id$ yuuji@52: yuuji@287: ;;; Code: yuuji@52: ;; ----- Customizable variables ----- yuuji@53: (defvar YaTeX-hierarchy-ignore-heading-regexp yuuji@53: "\\$[A-Z][a-z]+: .* \\$\\|-\\*- .* -\\*-" yuuji@53: "*Regexp of lines to ignore as files' headline.") yuuji@52: yuuji@52: ;; ----- General variables ----- yuuji@52: (defvar YaTeX-default-TeX-extensions "\\.\\(tex\\|sty\\)") yuuji@52: (defvar YaTeX-hierarchy-current-main nil) yuuji@52: (defvar YaTeX-hierarchy-buffer-message yuuji@52: (concat yuuji@53: "n)ext p)rev N)extsame P)revsame u)p K)illbuf RET)select" yuuji@53: (if (and YaTeX-emacs-19 window-system) " Mouse2)select" "") yuuji@53: " ?)help")) yuuji@52: (defvar YaTeX-hierarchy-saved-wc nil "Saved window configuration.") yuuji@52: yuuji@52: ;; ----- Functions for parsing hierarchy ----- yuuji@52: yuuji@52: (defun YaTeX-all-included-files (&optional file) yuuji@52: "Return all included files from FILE as a list. yuuji@52: If FILE is nil, use current buffer." yuuji@52: (save-excursion yuuji@52: (let ((include-regex (concat YaTeX-ec-regexp yuuji@52: "\\(\\(input\\)\\|" ;match#2 yuuji@52: "\\(include\\)\\)\\b")) ;match#3 yuuji@52: list file (cb (current-buffer))) yuuji@52: (if file (set-buffer (YaTeX-switch-to-buffer file t))) yuuji@52: (goto-char (point-min)) yuuji@52: (while (YaTeX-re-search-active-forward yuuji@52: include-regex YaTeX-comment-prefix nil t) yuuji@52: (cond yuuji@52: ((match-beginning 2) ;\input, {} is optional, 1 argument yuuji@52: (skip-chars-forward " {") yuuji@52: (setq file (buffer-substring yuuji@52: (point) yuuji@52: (progn yuuji@52: (skip-chars-forward yuuji@52: (concat "^ \t\n\r" YaTeX-ec-regexp "{}")) yuuji@52: (point))))) yuuji@68: ((and (match-beginning 3) (looking-at "{")) yuuji@52: (skip-chars-forward "{") yuuji@52: (setq file (buffer-substring yuuji@52: (point) yuuji@52: (progn yuuji@52: (forward-char -1) (forward-list 1) (1- (point))))))) yuuji@52: (or (string-match YaTeX-default-TeX-extensions file) yuuji@52: (setq file (concat file ".tex"))) yuuji@52: (setq list (cons file list))) yuuji@52: (set-buffer cb) yuuji@52: (nreverse list)))) yuuji@52: yuuji@70: (defun YaTeX-document-hierarchy (&optional file basedir) yuuji@52: "Return the document hierarchy beginning from FILE as a list. yuuji@52: If FILE is nil, beginning with current buffer's file." yuuji@52: (setq file (or file buffer-file-name)) yuuji@70: (and YaTeX-search-file-from-top-directory yuuji@70: (not (file-exists-p file)) yuuji@70: (string-match "^[^/].*/" file) yuuji@70: (setq file (expand-file-name file basedir))) yuuji@52: (message "Parsing [%s]..." (file-name-nondirectory file)) yuuji@52: (prog1 yuuji@52: (save-excursion yuuji@52: (if (or (file-exists-p file) (null file)) yuuji@52: (progn yuuji@52: (if file yuuji@52: (let ((parent buffer-file-name)) yuuji@52: (YaTeX-switch-to-buffer file t) ;set buffer to file yuuji@52: (or YaTeX-parent-file yuuji@52: (YaTeX-get-builtin "!") yuuji@52: (setq YaTeX-parent-file parent)))) yuuji@52: (cons (buffer-file-name (current-buffer)) yuuji@353: (mapcar (function ;return value yuuji@353: (lambda (f) yuuji@353: (YaTeX-document-hierarchy f basedir))) yuuji@52: (YaTeX-all-included-files)))))) yuuji@52: (message "Parsing [%s]...done" (file-name-nondirectory file)))) yuuji@52: yuuji@52: ;; ----- Functions for displaying hierarchy ----- yuuji@52: yuuji@52: (defun YaTeX-hierarchy-get-file-heading (file) yuuji@52: "Get a FILE's heading." yuuji@52: (save-excursion yuuji@52: (set-buffer (find-file-noselect file)) yuuji@52: (save-excursion yuuji@53: (let (p) yuuji@53: (goto-char (point-min)) yuuji@53: (cond yuuji@53: ((re-search-forward yuuji@53: (concat YaTeX-ec-regexp YaTeX-sectioning-regexp) nil t) yuuji@53: (search-forward "{") yuuji@53: (forward-char -1) yuuji@53: (setq p (condition-case nil yuuji@53: (progn (forward-list 1) (1- (point))) yuuji@53: (error (point-end-of-line)))) yuuji@53: (goto-char (1+ (match-beginning 0))) yuuji@53: (skip-chars-forward " \t\n") yuuji@53: (buffer-substring (point) (min (point-end-of-line) p))) yuuji@53: ((catch 'found yuuji@53: (while (re-search-forward "^ *%\\([^#]\\)" nil t) yuuji@53: (or (re-search-forward yuuji@53: YaTeX-hierarchy-ignore-heading-regexp yuuji@53: (point-end-of-line) t) yuuji@53: (throw 'found t)))) yuuji@53: (beginning-of-line) yuuji@53: (search-forward "%") yuuji@53: (skip-chars-forward "% \t") yuuji@53: (buffer-substring (point) (point-end-of-line))) yuuji@53: (t "")))))) yuuji@52: yuuji@52: (defun YaTeX-display-a-hierachy (hier level) yuuji@52: "Put a HIER of document hierarchy. yuuji@52: LEVEL is including depth." yuuji@52: (message "Formatting hierarchy buffer...") yuuji@52: (let ((lastatomcol 0) list i p) yuuji@52: (cond yuuji@52: ((listp hier) yuuji@52: (setq list hier) yuuji@52: (while list yuuji@52: (YaTeX-display-a-hierachy (car list) (1+ level)) yuuji@52: (setq list (cdr list)))) yuuji@52: ((stringp hier) ;is an atom yuuji@52: (insert " ") yuuji@52: (setq i level) yuuji@52: (while (> i 2) yuuji@52: (insert "| ") yuuji@52: (setq i (1- i))) yuuji@52: (if (> level 1) (insert "+---")) yuuji@52: (setq p (point)) yuuji@52: (insert (or (buffer-name (get-file-buffer hier)) yuuji@52: (file-name-nondirectory hier))) yuuji@52: (if (and window-system YaTeX-emacs-19) yuuji@52: (put-text-property p (point) 'mouse-face 'underline)) yuuji@52: (insert " ") yuuji@52: (indent-to-column (1- (/ (window-width) 2))) yuuji@52: (insert "% " (YaTeX-hierarchy-get-file-heading hier)) yuuji@52: (insert "\n")))) yuuji@52: (message "Formatting hierarchy buffer...")) yuuji@52: yuuji@52: (defun YaTeX-display-hierarchy (file &optional use-default) yuuji@52: "Display document hierarchy that is beginning from FILE." yuuji@52: (interactive "P") yuuji@52: (setq YaTeX-hierarchy-saved-wc yuuji@52: (list (current-window-configuration) yuuji@52: (and (featurep 'windows) yuuji@52: (boundp 'win:current-config) yuuji@52: win:current-config))) yuuji@52: (let*((b-in (YaTeX-get-builtin "!")) yuuji@70: default) yuuji@52: ;;むーん↓このへんの仕様どうしたらいいか良く分からん... yuuji@52: (if default (setq default (expand-file-name default))) yuuji@52: (YaTeX-visit-main t) ;move to parent file yuuji@70: (setq default buffer-file-name) yuuji@52: (setq file yuuji@52: (or (if use-default default file) yuuji@52: (read-file-name yuuji@52: (format yuuji@52: "Main .tex file%s: " yuuji@52: (if default yuuji@52: (format "(default %s)"(file-name-nondirectory default)) yuuji@52: "")) yuuji@52: "" default 1)))) yuuji@52: (setq file (expand-file-name file)) yuuji@52: (setq YaTeX-hierarchy-current-main file) yuuji@70: (let ((dbuf "*document hierarchy*") yuuji@70: (topdir default-directory)) yuuji@52: (YaTeX-showup-buffer dbuf nil t) yuuji@52: (set-buffer (get-buffer dbuf)) yuuji@52: (setq truncate-lines t) yuuji@52: (let ((buffer-read-only nil)) yuuji@52: (erase-buffer) yuuji@70: (YaTeX-display-a-hierachy (YaTeX-document-hierarchy file topdir) 0)) yuuji@52: (goto-char (point-min)) yuuji@52: (YaTeX-hierarchy-next 0) yuuji@52: (set-buffer-modified-p nil) yuuji@52: (YaTeX-hierarchy-mode) yuuji@52: )) yuuji@52: yuuji@52: (defun YaTeX-display-hierarchy-directly () yuuji@52: "Same as YaTeX-display-hierarchy. Call from mouse." yuuji@52: (interactive) yuuji@52: (YaTeX-display-hierarchy nil t)) yuuji@52: yuuji@52: (defun YaTeX-hierarchy-mode () yuuji@52: "Major mode to browse and select document hierarchy. yuuji@52: yuuji@52: \\[YaTeX-hierarchy-next] next line yuuji@52: \\[YaTeX-hierarchy-prev] previous line yuuji@53: \\[YaTeX-hierarchy-forward] move forward in the same level yuuji@53: \\[YaTeX-hierarchy-backward] move backward in the same level yuuji@52: \\[YaTeX-hierarchy-up-document] move to parent file yuuji@52: \\[delete-other-windows] delete other windows yuuji@52: \\[other-window] other window yuuji@53: \\[shrink-window] shrink window yuuji@53: \\[enlarge-window] enlarge window yuuji@53: \\[YaTeX-hierarchy-show] show file contents in the next window yuuji@53: \\[YaTeX-hierarchy-scroll-up] scroll up file contents buffer yuuji@53: \\[YaTeX-hierarchy-scroll-down] scroll down file contents buffer yuuji@53: \\[YaTeX-hierarchy-top] show the top of file contents yuuji@53: \\[YaTeX-hierarchy-bottom] show the bottom of file contents yuuji@53: \\[YaTeX-hierarchy-lastpos] return to the previous position yuuji@52: \\[YaTeX-hierarchy-select] select file yuuji@52: \\[YaTeX-hierarchy-mouse-select] select yuuji@52: " yuuji@52: (setq major-mode 'YaTeX-hierarchy-mode yuuji@52: mode-name "YaTeX hier") yuuji@52: (use-local-map YaTeX-hierarchy-mode-map) yuuji@52: (setq buffer-read-only t) yuuji@52: (message YaTeX-hierarchy-buffer-message)) yuuji@52: yuuji@52: ;; ----- Subfunctions for interactive functions ----- yuuji@52: (defun YaTeX-hierarchy-get-current-file-buffer () yuuji@52: "Return the buffer associated with current line's file." yuuji@52: (let ((file (buffer-substring yuuji@52: (point) yuuji@52: (save-excursion yuuji@52: (skip-chars-forward "^ \t" (point-end-of-line)) (point)))) yuuji@52: (hilit-auto-highlight) buffer) yuuji@52: (set-buffer (find-file-noselect YaTeX-hierarchy-current-main)) yuuji@52: (if (get-buffer file) ;buffer is active yuuji@52: (setq buffer (get-buffer file)) ;may contain `<2>' yuuji@52: (if (string-match "<[2-9]>$" file) yuuji@52: (setq file (substring file 0 -3))) yuuji@52: (save-excursion yuuji@52: (setq buffer (YaTeX-switch-to-buffer file t)))))) ; open it! yuuji@52: yuuji@52: ;; ----- Interactive functions ----- yuuji@52: (defun YaTeX-hierarchy-next (arg &optional quiet) yuuji@52: "Move to next line's file in YaTeX document hierarchy buffer." yuuji@52: (interactive "p") yuuji@52: (forward-line arg) yuuji@52: (skip-chars-forward "- +\\|") yuuji@53: (if (and (/= arg 0) (not quiet)) yuuji@52: (YaTeX-hierarchy-select t)) yuuji@52: (message YaTeX-hierarchy-buffer-message)) yuuji@52: yuuji@52: (defun YaTeX-hierarchy-prev (arg) yuuji@52: "Move to previous line's file in YaTeX document hierarchy buffer." yuuji@52: (interactive "p") yuuji@52: (YaTeX-hierarchy-next (- arg))) yuuji@52: yuuji@52: (defun YaTeX-hierarchy-next-line (arg) yuuji@52: (interactive "p") yuuji@52: (YaTeX-hierarchy-next arg t)) yuuji@52: yuuji@52: (defun YaTeX-hierarchy-prev-line (arg) yuuji@52: (interactive "p") yuuji@52: (YaTeX-hierarchy-next (- arg) t)) yuuji@52: yuuji@52: (defun YaTeX-hierarchy-forward (arg) yuuji@52: "Move to forward file in same hierarchy level." yuuji@52: (interactive "p") yuuji@52: (YaTeX-hierarchy-next 0) yuuji@52: (let ((p (point))(column (current-column)) (i (if (> arg 0) arg (- arg)))) yuuji@52: (if (= column 0) (error "Not on file line.")) yuuji@52: (while (> i 0) yuuji@52: (if (catch 'found yuuji@52: (while (and (not (eobp)) (not (bobp))) yuuji@52: (forward-line (if (> arg 0) 1 -1)) yuuji@52: (move-to-column column) yuuji@52: (if (looking-at "[- +\\|]") nil yuuji@52: (YaTeX-hierarchy-next 0) yuuji@52: (if (= (current-column) column) (throw 'found t))) yuuji@52: (beginning-of-line))) yuuji@52: nil yuuji@52: (goto-char p) yuuji@52: (error "No same level file.")) yuuji@52: (setq i (1- i))))) yuuji@52: yuuji@52: (defun YaTeX-hierarchy-backward (arg) yuuji@52: "Move to backward file in same hierarchy level." yuuji@52: (interactive "p") yuuji@52: (YaTeX-hierarchy-forward (- arg))) yuuji@52: yuuji@52: (defun YaTeX-hierarchy-up-document () yuuji@52: "Up level, that is, move to parent file position." yuuji@52: (interactive) yuuji@52: (YaTeX-hierarchy-next 0) ;adjust column yuuji@52: (let ((p (point)) (line (count-lines (point-min) (point))) column) yuuji@52: (if (or (<= line 1) (< (current-column) 6)) yuuji@52: (message "No more parent") yuuji@52: (backward-char 1) yuuji@52: (or (= (char-after (point)) ?-) (error "Unexpected hierarchy buffer")) yuuji@52: (setq column (current-column)) yuuji@52: (while (and (> line 1) (looking-at "[- +\\|]")) yuuji@52: (forward-line -1) yuuji@52: (move-to-column column)) yuuji@52: (YaTeX-hierarchy-next 0) yuuji@52: (push-mark p t) yuuji@52: (message "Mark set to last position")))) yuuji@52: yuuji@52: (defun YaTeX-hierarchy-kill-buffer (arg) yuuji@52: "Kill buffer associated with current line's file." yuuji@52: (interactive "p") yuuji@52: (YaTeX-hierarchy-next 0) ;move to file name column yuuji@52: (if (bolp) (error "Not on file name line")) yuuji@53: (let ((file (buffer-substring yuuji@53: (point) yuuji@53: (progn (skip-chars-forward "^ \t") (point))))) yuuji@52: (YaTeX-hierarchy-next arg) yuuji@52: (cond yuuji@52: ((get-buffer file) yuuji@52: (kill-buffer (get-buffer file)) yuuji@52: (message "Buffer [%s] was killed" file)) yuuji@52: (t (message "Buffer [%s] is not active." file))))) yuuji@52: yuuji@52: (defun YaTeX-hierarchy-select (arg) yuuji@52: "Select current line's file in YaTeX document hierarchy buffer. yuuji@52: If ARG is non-nil, show the buffer in the next window." yuuji@52: (interactive "P") yuuji@52: (beginning-of-line) yuuji@52: (skip-chars-forward "- +\\|") yuuji@52: (or (eolp) yuuji@52: (let ((buffer (YaTeX-hierarchy-get-current-file-buffer))) yuuji@52: (if buffer ;if file was found yuuji@52: (if arg yuuji@52: (YaTeX-showup-buffer buffer nil) yuuji@52: (if (and YaTeX-emacs-19 window-system yuuji@52: (get-buffer-window buffer t)) yuuji@52: (goto-buffer-window buffer) ;select currently displaying yuuji@52: (YaTeX-switch-to-buffer-other-window buffer))))))) yuuji@52: yuuji@52: (defun YaTeX-hierarchy-show () yuuji@52: "Show current line's file in the next window." yuuji@52: (interactive) yuuji@52: (YaTeX-hierarchy-select t)) yuuji@52: yuuji@52: (defun YaTeX-hierarchy-mouse-select (event) yuuji@52: (interactive "e") yuuji@52: (mouse-set-point event) yuuji@52: (YaTeX-hierarchy-select nil)) yuuji@52: yuuji@52: (defun YaTeX-hierarchy-quit () yuuji@52: "Quit from YaTeX-hierarchy buffer and restore window configuration." yuuji@52: (interactive) yuuji@52: (if (or (not (featurep 'windows)) yuuji@52: (car YaTeX-hierarchy-saved-wc) yuuji@52: (and (= (car (cdr YaTeX-hierarchy-saved-wc)) win:current-config))) yuuji@52: (set-window-configuration (car YaTeX-hierarchy-saved-wc)) yuuji@52: (bury-buffer nil))) yuuji@52: yuuji@53: (defun YaTeX-hierarchy-scroll-up (arg &optional action) yuuji@53: "Scroll up file contents of YaTeX-hierarchy." yuuji@52: (interactive "P") yuuji@53: (YaTeX-hierarchy-next 0 t) yuuji@53: (let*((bufname (buffer-substring yuuji@53: (point) yuuji@53: (save-excursion (skip-chars-forward "^ \t") (point)))) yuuji@53: (buf (get-buffer bufname)) yuuji@53: (cw (selected-window))) yuuji@53: (cond yuuji@53: ((and buf (get-buffer-window buf)) yuuji@53: (select-window (get-buffer-window buf))) yuuji@53: ((and buf (YaTeX-showup-buffer buf nil t)) t) yuuji@53: (t (YaTeX-hierarchy-select nil))) yuuji@53: (unwind-protect yuuji@53: (cond yuuji@53: ((eq action 'down) (scroll-down arg)) yuuji@53: ((eq action 'top) (beginning-of-buffer)) yuuji@53: ((eq action 'bottom) (end-of-buffer)) yuuji@53: ((eq action 'last) (exchange-point-and-mark)) yuuji@53: (t (scroll-up arg))) yuuji@53: (select-window cw)))) yuuji@53: yuuji@53: (defun YaTeX-hierarchy-scroll-down (arg) yuuji@53: "Scroll down file contents of YaTeX-hierarchy." yuuji@53: (interactive "P") yuuji@53: (YaTeX-hierarchy-scroll-up arg 'down)) yuuji@53: yuuji@53: (defun YaTeX-hierarchy-top () yuuji@53: "Show the top of YaTeX-hierarchy inspection buffer's." yuuji@53: (interactive) yuuji@53: (YaTeX-hierarchy-scroll-up nil 'top) yuuji@53: ) yuuji@53: yuuji@53: (defun YaTeX-hierarchy-bottom () yuuji@53: "Show the top of YaTeX-hierarchy inspection buffer's." yuuji@53: (interactive) yuuji@53: (YaTeX-hierarchy-scroll-up nil 'bottom) yuuji@53: ) yuuji@53: yuuji@53: (defun YaTeX-hierarchy-lastpos () yuuji@53: "Go to last position in YaTeX-hierarchy buffer." yuuji@53: (interactive) yuuji@53: (YaTeX-hierarchy-scroll-up nil 'last) yuuji@53: ) yuuji@52: yuuji@52: ;; ----- Setting up keymap ----- yuuji@52: (defvar YaTeX-hierarchy-mode-map nil "Keymap used in YaTeX-hierarchy-mode.") yuuji@52: (if YaTeX-hierarchy-mode-map nil yuuji@52: (setq YaTeX-hierarchy-mode-map (make-sparse-keymap)) yuuji@52: (define-key YaTeX-hierarchy-mode-map "n" 'YaTeX-hierarchy-next) yuuji@52: (define-key YaTeX-hierarchy-mode-map "p" 'YaTeX-hierarchy-prev) yuuji@52: (define-key YaTeX-hierarchy-mode-map "j" 'YaTeX-hierarchy-next-line) yuuji@52: (define-key YaTeX-hierarchy-mode-map "k" 'YaTeX-hierarchy-prev-line) yuuji@52: (substitute-all-key-definition yuuji@52: 'next-line 'YaTeX-hierarchy-next-line YaTeX-hierarchy-mode-map) yuuji@52: (substitute-all-key-definition yuuji@52: 'previous-line 'YaTeX-hierarchy-prev-line YaTeX-hierarchy-mode-map) yuuji@52: (define-key YaTeX-hierarchy-mode-map "N" 'YaTeX-hierarchy-forward) yuuji@52: (define-key YaTeX-hierarchy-mode-map "P" 'YaTeX-hierarchy-backward) yuuji@52: (define-key YaTeX-hierarchy-mode-map "u" 'YaTeX-hierarchy-up-document) yuuji@52: (define-key YaTeX-hierarchy-mode-map "K" 'YaTeX-hierarchy-kill-buffer) yuuji@52: (define-key YaTeX-hierarchy-mode-map "1" 'delete-other-windows) yuuji@52: (define-key YaTeX-hierarchy-mode-map "o" 'other-window) yuuji@53: (define-key YaTeX-hierarchy-mode-map "-" 'shrink-window) yuuji@53: (define-key YaTeX-hierarchy-mode-map "+" 'enlarge-window) yuuji@52: (define-key YaTeX-hierarchy-mode-map "." 'YaTeX-hierarchy-show) yuuji@53: (define-key YaTeX-hierarchy-mode-map " " 'YaTeX-hierarchy-scroll-up) yuuji@53: (define-key YaTeX-hierarchy-mode-map "b" 'YaTeX-hierarchy-scroll-down) yuuji@53: (define-key YaTeX-hierarchy-mode-map "\C-?" 'YaTeX-hierarchy-scroll-down) yuuji@52: (define-key YaTeX-hierarchy-mode-map "\C-m" 'YaTeX-hierarchy-select) yuuji@53: (define-key YaTeX-hierarchy-mode-map "<" 'YaTeX-hierarchy-top) yuuji@53: (define-key YaTeX-hierarchy-mode-map ">" 'YaTeX-hierarchy-bottom) yuuji@53: (define-key YaTeX-hierarchy-mode-map "'" 'YaTeX-hierarchy-lastpos) yuuji@53: (define-key YaTeX-hierarchy-mode-map "g" 'YaTeX-hierarchy-select) yuuji@52: (define-key YaTeX-hierarchy-mode-map "q" 'YaTeX-hierarchy-quit) yuuji@52: (define-key YaTeX-hierarchy-mode-map "?" 'describe-mode) yuuji@52: (if (and YaTeX-emacs-19 window-system) yuuji@52: (define-key YaTeX-hierarchy-mode-map yuuji@52: [mouse-2] 'YaTeX-hierarchy-mouse-select)) yuuji@52: ) yuuji@52: yuuji@52: (provide 'yatexhie) yuuji@52: ;;end of yatexhie.el