(require (quote TeX-mode)) (defconst tex-index-buff "--- TeX Indexing Help ---") (defconst tex-index-char 33) (defconst tex-index-limit 30 "\ Max REGEXP string length in minibuffer display.") (defconst tex-index-entries "\\\\index\\|\\\\cite\\|\\\\nocite") (defconst tex-index-pattern (concat tex-index-level "\\|" tex-index-entries)) (defvar tex-index-keyfile nil) (defun tex-index-chmod nil "\ Change mode permanently. A mode is a 3-bit code prefix-actual-encap-keyptrn." (interactive) (byte-code "Ɉ!OOOO & !\" 4 !\" B !\" P !\"tY\"-" [mode m1 m2 m3 m4 tex-index-level-on tex-index-actual-on tex-index-encap-on tex-index-keyptrn-on nil read-string "Change mode (level-actual-encap-keyptrn, 4-bit binary): " 0 1 2 3 4 /= string-to-char 48 message "Index mode (prefix-actual-encap-keyptrn) is now %s"] 12)) (defun tex-index-level-toggle nil "\ Toggle the flag tex-index-level-on." (interactive) (byte-code "!‰!" [tex-index-level-on nil t message "Index level specification disabled." "Index level specification enabled."] 3)) (defun tex-index-actual-toggle nil "\ Toggle the flag tex-index-actual-on." (interactive) (byte-code "!‰!" [tex-index-actual-on nil t message "Index actual field disabled." "Index actual field enabled."] 3)) (defun tex-index-encap-toggle nil "\ Toggle the flag tex-index-encap-on." (interactive) (byte-code "!‰!" [tex-index-encap-on nil t message "Page number encapsulator disabled." "Page number encapsulator enabled."] 3)) (defun tex-index-keyptrn-toggle nil "\ Toggle the flag tex-index-keyptrn-on." (interactive) (byte-code "!‰!" [tex-index-keyptrn-on nil t message "Saving [key, ptrn] pair disabled." "Saving [key, ptrn] pair enabled."] 3)) (defun tex-index-get-level nil "\ Get the index level. If the prefix is not terminated by tex-index-level, one is attached." (byte-code "* Q! G U S O \"# & P*+ɇ" [tex-index-level-on pre tex-index-level l read-string "Index prefix (max 2 levels, " " as delimiter, RET if none): " 0 string-equal ""] 5)) (defun tex-index-get-actual nil "\ Get index actual field." (byte-code "! \"Ƃ P)Ƈ" [tex-index-actual-on str tex-index-actual read-string "Index actual field: " string-equal ""] 4)) (defun tex-index-get-encap nil "\ Get the index page number encapsulator." (byte-code "Ǎ+ȇ" [tex-index-encap-on msg var ans "Page encapsulator: RET=none, b=Bf, i=It, s=Sl, u=Ul, c=see, o=other." nil done (byte-code " !r Uʂ U\" P U. P U: P UF P UR P Un! \"gʂj P)lj \"!lj \"" [t msg var ans tex-index-encap str cont nil message 13 "" 98 "Bf" 105 "It" 115 "Sl" 117 "Ul" 99 "see" 111 read-string "Encapsulator string: " string-equal ding "%s...WHAT?" sit-for 1 throw done] 10) ""] 3)) (defun tex-index-save (key &optional regexp) "\ Save a [KEY, PATTERN] pair in a specified file." (interactive "sSave index key: ") (byte-code "ˆtx ‚ \" \"#! ,\" ! !q U)k!!^h ! n  $+" [tex-index-keyptrn-on regexp nil key kf tex-index-keyfile default-directory buf kfnd read-string "Save regexp: " string-equal "" error "Can't take empty string as index search pattern. Abort." "Index key file: " find-file-noselect file-name-nondirectory buffer-size 0 kill-buffer get-buffer tex-index-sort] 15)) (defun tex-index-sort (key regexp buf fn) "\ Sort and insert the [KEY, REGEXP] pair in file FN bound to buffer BUF." (byte-code "qb G W  OP%  #Ս  #-)" [buf l regexp pair key tex-index-limit pos key0 regexp0 fn 1 concat "[" ", " 0 "..." "]" nil message "Saving %s in \"%s\"..." sorted (byte-code "` ! ! \"/ b \"\" \" \"Bǂ WN U  OP %!v `\" \"\" b \"\"  # \"\"" [t pos key0 buf regexp0 key regexp nil l tex-index-limit fn tex-index-read string-lessp tex-index-save-pair throw sorted string-equal 0 "..." y-or-n-p concat "Overwrite [" ", " "]? " delete-region error "Key %s doesn't have a matching regexp in \"%s\"...abort"] 20) "Saving %s in \"%s\"...done"] 7)) (defun tex-index-save-pair (key regexp) (byte-code " %`! ˍ)" [key regexp pt insert " \"" "\" \"" "\" " previous-line 1 beginning-of-line ok (byte-code " #!c\"" [t pt search-forward "\\" looking-at "[0-9|()`'bBwWsS]" 92 throw ok] 6)] 6)) (defun tex-index-insert (key &optional regexp) (byte-code "\" !  & \"" [key tex-index-command-prefix tex-index-command-suffix regexp string-equal "" error "Can't take empty string as index key. Abort." insert tex-index-get-level tex-index-get-actual tex-index-get-encap tex-index-save] 12)) (defun tex-index-goto-right nil (byte-code "! !" [nil looking-at "[ ]" skip-chars-forward "^ ^ ^ ^\\"] 3)) (defun tex-index-word (&optional n) "\ Copy the previous word in \\index{...}. With positive prefix argument N, do it for previous N words. If N is negative, it is converted to 1 implicitly. The user will be prompted to enter index prefix (cf. tex-index-level)." (interactive "P") (byte-code "È ] !`) `\" !+" [n start key nil 1 backward-word buffer-substring tex-index-insert] 4)) (defun tex-index-region (start end) "\ Copy the content of region in \\index{...}. The user will be prompted to enter index prefix (cf. tex-index-level)." (interactive "r") (byte-code "ˆ`U \"!b \"!)" [end start nil tex-index-insert buffer-substring] 6)) (defun tex-index-read (buf) "\ Read and return the next Lisp expression in BUF, skipping blank lines until end-of-buffer and assuming BUF has already been set already. Return nil if nothing to read. This avoids the unpleasant abort on \"End of file during parsing\" in regular (read buf)." (byte-code "Ím  !" [nil buf stop (byte-code " m !?\"! " [t looking-at " *$" throw stop next-line 1 beginning-of-line] 6) read] 2)) (defun tex-index-file (kf &optional lst) "\ Index each [key, pattern] pair saved in file KF. If the optional LST is non-nil, process each pair for the entire document, else process only the current buffer." (byte-code " ɂ  ! ! ς % ! q U)_ ! ! N q V\"X \\ \"c ݍ \"." [func lst buf kf kfnd msg key regexp tex-index-keyfile tex-index-dsingle tex-index-bsingle find-file-noselect file-name-nondirectory concat "Indexing " "entire document" "current buffer" " based on key file \"" "\"..." nil message buffer-size 0 kill-buffer get-buffer save-excusrion error "%sabort (file is empty)" done (byte-code "qb)8q!?\"!?+\") $" [buf t key regexp nil func lst 1 tex-index-read throw done funcall] 10) "%sdone"] 13)) (defun tex-index-document (&optional kf &optional key) "\ Process single or multiple [key, pattern] pairs for the entire document. With C-u as prefix, a file of [key, pattern] pairs is expected. Otherwise, prompt for just a single pair." (interactive (byte-code " \"C!D" [current-prefix-arg tex-index-keyfile default-directory nil read-string "Index key file: " "Index key: "] 4)) (byte-code "È  ! \"D\" !\"\"3! !#)" [current-prefix-arg tex-index-keyfile default-directory nil kf t tex-include-files key regexp tex-check-master-file tex-get-include-files tex-index-file string-equal "" error "Can't take empty string as index key. Abort." read-string "Regexp: " "Can't take empty string as index search pattern. Abort." tex-index-dsingle] 14)) (defun tex-index-dsingle (key regexp lst) "\ Enter \\index{KEY} at each instance of REGEXP for each file in LST, subject to confirmation from the user." (byte-code " Q ̍ \"." [asknot nil quiet finish msg key kf kfnd ans start "Indexing `" "' for document" (byte-code "a@!q ! \"A\" ) R!\\ ! #b!V! #[ #))" [lst kf kfnd msg asknot key regexp start find-file-noselect file-name-nondirectory append tex-get-input-files tex-confirm "Indexing `" "' for " find-file message "%s, doing %s..." 1 tex-index-search match-beginning 0 tex-index-goto-right tex-index-get-cmd "%s, doing %s...done" "%s, doing %s...failed (pattern not found)"] 17) message "%s...done"] 8)) (defun tex-index-buffer (&optional kf &optional key) "\ Process single or multiple [key, pattern] pairs for the current buffer. With C-u as prefix, a file of [key, pattern] pairs is expected. Otherwise, prompt for just a single pair." (interactive (byte-code " \"C!D" [current-prefix-arg tex-index-keyfile default-directory nil read-string "Index key file: " "Index key: "] 4)) (byte-code "È !/ \"! \"\"(! \")" [current-prefix-arg tex-index-keyfile default-directory nil kf key regexp tex-index-file string-equal "" error "Can't take empty string as index key. Abort." read-string "Regexp: " "Can't take empty string as index search pattern. Abort." tex-index-bsingle] 9)) (defun tex-index-bsingle (key regexp &optional lst) "\ Enter \\index{KEY} at each instance of REGEXP for the current buffer. LST should always be nil (it's included for the convenience of the caller." (byte-code "b !&! \"+\",)" [asknot nil quiet finish start regexp key 1 done tex-index-search match-beginning 0 tex-index-goto-right tex-index-get-cmd message "Indexing `%s' for current buffer...done" "Indexing `%s' for current buffer...failed (pattern not found)"] 8)) (defun tex-index-get-cmd nil "\ Give a menu of options and take appropriate action upon receving the answer." (byte-code " Q    ǂ ΂ Q Q Ӎ." [msg key KEY local QUIET quiet next nil t cmd nmsg pmsg "Insert \\index{" "}? [SPC=y DEL=n LFD=p ? for more options]" 121 "Can't find next instance to index `" "', done? " "Can't find previous instance to index `" done (byte-code " ? ! r % * /  U@UV  \" !S\"UaUq !n\"U|U \"UU U U! \"rȉU! \"rȉU!  \"rȉU$ Q!! ҉UJ Q!G  ҉ UX\"Ug\"Uw! U \"!+" [t next QUIET msg local KEY cmd tex-index-actual-on nil tex-index-level-on tex-index-keyptrn-on regexp key asknot quiet finish message 32 121 tex-index-insert tex-index-scroll-down throw done 127 110 10 112 tex-index-scroll-up 13 109 tex-index-chmod-temporary 77 tex-index-chmod 107 read-string "New index key (single instance): " "Insert \\index{%s}? (SPC/y, DEL/n, LFD/p, ? for more options)" 11 "New index key (remaining buffer): " 75 "New index key (remaining document): " 64 y-or-n-p "Quietly insert \\index{" "} for buffer, are you sure? " 33 "} for document, are you sure? " 27 3 18 "Entering recursive edit...(return by ESC C-c)" recursive-edit 63 ((byte-code "  !r" [next nil msg cmd tex-index-help message] 4)) ding "%s...WHAT?" sit-for 1] 27)] 3)) (defun tex-index-chmod-temporary nil "\ Confirm insertion with single instance mode change." (byte-code "!OOO !\"!  / !\"0  > !\"@\". !V\"" [mode m1 m2 m3 tex-index-actual-on tex-index-level-on tex-index-keyptrn-on local regexp QUIET t read-string "Confirm with mode (prefix-actual-keyptrn, 3-bit binary): " 0 1 2 3 /= string-to-char 48 tex-index-insert tex-index-scroll-down throw done] 12)) (defun tex-index-scroll-down (&optional quiet) "\ Search forward for the next instance of REGEXP. Prompt for exit confirmation, if not found. Wrap around if denied." (byte-code "!! ‚/  !!ł/!!b !" [regexp start nil quiet nmsg t tex-index-search match-beginning 0 tex-index-goto-right y-or-n-p message "Wrapping around..." sit-for 1 tex-index-scroll-down] 8)) (defun tex-index-scroll-up nil "\ Search backward for the previous instance of REGEXP. Prompt for exit confirmation, if not found. Wrap around if denied." (byte-code "b \")!!b Â6 !(‚6!!d " [start regexp t nil pmsg tex-index-search match-beginning 0 match-end tex-index-goto-right y-or-n-p message "Wrapping around..." sit-for 1 tex-index-scroll-up] 9)) (defun tex-index-search (regexp &optional backward) "\ Locate the next instance of REGEXP. Ignore one that is in the argument list of \\index{...}. if the optional BACKWARD is non-nil, search backward." (byte-code " ǂ `ˍ-" [func backward here case-fold-search t pos bol re-search-backward re-search-forward nil found (byte-code "Q $` b\" `)#?4\"!!` WJ b\" b" [t func regexp nil pos here bol tex-index-entries funcall throw found beginning-of-line re-search-backward forward-word 1 forward-sexp] 11)] 5)) (defun tex-index-help nil (byte-code "! Vc Z!b!" [tex-index-buff nil pop-to-buffer buffer-size 0 "SPC/y -- Confirm index entry insertion and advance to next instance, if any. DEL/n -- Ignore current instance and advance to the next, if any. LFD/p -- Ignore current instance and go back to the previous, if any. RET/m -- Confirm with mode change (actual-prefix-keyptrn as a 3-bit binary). M -- Permanent change mode (actual-prefix-keyptrn as a 3-bit binary). k -- Change single instance of index key. C-k -- Change index key for remaining instances in buffer. K -- Change index key for remaining instances in document. @ -- Quietly insert \\index{key} for remaining buffer. ! -- Quietly insert \\index{key} for remaining document. ESC -- Quit working on current buffer. Try next file in document, if any. C-c -- Quit working on current key. Try next key in key file, if any. C-r -- Enter recursive edit. Return by ESC C-c. ? -- This help message." enlarge-window 15 window-height 1 other-window] 6)) (defun tex-index-make nil "\ Make index for the TeX/AmSTeX/LaTeX document rooted at current file." (interactive) (byte-code "Ɉ ! !\"O P  \"(ւB \"3؂B \">ڂB \" \"rUX PsUe Ps \"pւs P) !Q \" \"." [buff base idx doc-type type t flag ch tex-index-processor nil tex-check-master-file sit-for 1 file-name-nondirectory buffer-file-name 0 string-match "\\." ".idx" tex-check-document-type string-equal "LaTeX" "" "TeX" "t" "AmSTeX" "a" error "Don't know how to make index for document of type %s" message "%s index formatting option: e=entire doc, s=separate index, else=nothing" 101 "-e" 115 "-s" "-" file-exists-p tex-execute " " ding "\"%s\" doesn't exist...run formatter first."] 18)) (defun tex-index-authors nil "\ Process each author's name and insert \\index{AUTHOR} in the specified bibliography file BBL. Prompt each author's name appearing in the \\bibitem entry (but ignoring any one that's in \\index{...}) for confirmation. The prompted name will be last name first, followed by a comma, and then the other parts of the name. Names like ``Michael Van De Vanter'' will be regarded as ``Vanter, Michael Van De'' which is of course wrong. However, this can be modified before the final confirmation is made (i.e. typing RET)." (interactive) (byte-code "ň   \"OP \" !'ł5 \"! ֋-" [master-file fn bn bbl asknot nil t tex-check-master-file buffer-file-name 0 string-match "\\." ".bbl" read-string "Indexing author names in bibliography file " file-exists-p ding message "File \"%s\" not found...try again" sit-for 1 tex-index-authors ((byte-code " \" !!bɍ!" [bbl nil t string-equal buffer-file-name find-file-other-window tex-mode 1 finish (byte-code "#)! !% !% " [nil t asknot re-search-forward "\\\\bibitem" next-line 1 beginning-of-line looking-at "{\\\\it\\| *{" tex-confirm "Ok to process current line" tex-index-author-name] 8) message "Indexing author names...done"] 6))] 10)) (defun tex-index-author-name nil (byte-code "`ȍ.)" [pos1 pos2 =done= nil =index= name name1 loop1 (byte-code "f bȍ Q! b '!! `\" !iV9 bc)!F!P!PZ\"!`" [t pos1 name name1 pos2 =index= =done= ok (byte-code "@ `!` \"!! `\"! \"0 \"8 b<\"" [t pos2 name name1 pos1 tex-index-author-stop backward-sexp 1 tex-index-remove-lfd buffer-substring skip-chars-backward " ,~ " string-equal " " "" throw ok] 13) tex-index-author-read ", " forward-word 1 forward-sexp delete-region tex-index-insert 72 10 looking-at "[ ,] *and" "[ ,] *editor" throw loop1 skip-chars-forward " ,.~ "] 13)] 6)) (defun tex-index-author-stop nil (byte-code "#` Zb!! b! ~ b Z \"\"6!i Z \" \"H \")V!i Z \"\"i!!! ?xgU!) \"Q!\"!" [nil t pt st5 =done= =index= pos1 re-search-forward ",\\|\\.$\\|\\band\\b\\|\\bet al\\.\\|\\bet~al\\.\\|\\\\index" 3 looking-at "^\\w.\\| \\w." delete-char 1 tex-index-author-stop string-equal buffer-substring "and" backward-word 5 "et al" "et~al" 2 6 "\\index" backward-char skip-chars-backward " ,.~ " 46 "\\\\index" ding y-or-n-p "Line " count-lines " contains invalid author field, continue? " throw loop1 error "Abort."] 23)) (defun tex-index-remove-lfd (in) (byte-code " \"?F O \"ʉ\"+ \"2Ă; P  O +" [p out c in nil "" string-equal 0 1 " " " "] 8)) (defun tex-index-author-read (author) (byte-code "Í)" [name nil loop2 (byte-code "# \" \" ! \"" [t name author read-string "Author name: " string-equal "" ding message "Can't take an empty author name...try again" throw loop2] 8)] 2))