1;;; yatexhlp.el --- YaTeX helper for LaTeX -*- coding: sjis -*-
2;;;
3;;; (c)1994,1998,2004,2014,2015,2018 by HIROSE Yuuji.[yuuji@yatex.org]
4;;; Last modified Sat Jun  2 16:45:45 2018 on firestorm
5;;; $Id: yatexhlp.el,v a58a35eac93f 2018-07-31 08:21 +0900 yuuji $
6
7;;; Code:
8(let ((help-file (concat "YATEXHLP."
9			 (cond (YaTeX-japan "jp")
10			       (t "eng"))))
11      (help-dir
12       (cond
13	((and (boundp 'site-directory) site-directory) site-directory)
14	((string-match "\\.app/" doc-directory)	;For Emacs.app(Darwin)
15	 (expand-file-name "../site-lisp/yatex" doc-directory))
16	(YaTeX-emacs-19
17	 (expand-file-name "../../site-lisp/yatex" doc-directory))
18	(t exec-directory))))
19  (defvar YaTeX-help-file
20    (expand-file-name help-file help-dir)
21    "*Help file of LaTeX/TeX commands or macros.")
22  (defvar YaTeX-help-file-private
23    (expand-file-name (concat "~/" help-file))
24    "*Private help file of LaTeX/TeX macros."))
25
26(defvar YaTeX-help-delimiter "\C-_" "Delimiter of each help entry.")
27(defvar YaTeX-help-entry-map (copy-keymap YaTeX-mode-map)
28  "Key map used in help entry.")
29(defvar YaTeX-help-file-current nil
30  "Holds help file name to which the description in current buffer should go.")
31(defvar YaTeX-help-command-current nil
32  "Holds command name on which the user currently write description.")
33(defvar YaTeX-help-saved-config nil
34  "Holds window configruation before the editing of manual.")
35(defvar YaTeX-help-synopsis
36  (cond (YaTeX-japan "�y�����z")
37	(t "[[ Synopsis ]]"))
38  "Section header of synopsis.")
39(defvar YaTeX-help-description
40  (cond (YaTeX-japan "�y�����z")
41	(t "[[ Description ]]"))
42  "Section header of description.")
43
44(defvar YaTeX-help-mode-map nil "Keymap used in YaTeX-help buffer")
45(if YaTeX-help-mode-map nil
46  (setq YaTeX-help-mode-map (make-sparse-keymap))
47  (let ((map YaTeX-help-mode-map))
48    (suppress-keymap map)
49    (define-key map "j" (function (lambda () (interactive) (scroll-up 1))))
50    (define-key map "k" (function (lambda () (interactive) (scroll-up -1))))
51    (define-key map "n" 'next-line)
52    (define-key map "p" 'previous-line)
53    (define-key map " " 'scroll-up)
54    (define-key map "\C-?" 'scroll-down)
55    (define-key map "o" 'other-window)
56    (define-key map "h" 'describe-bindings)
57    (define-key map "q" 'YaTeX-help-quit)
58    (define-key map "<" 'beginning-of-buffer)
59    (define-key map ">" 'end-of-buffer)))
60
61(defun YaTeX-help-quit ()
62  "Close help and return to privious buffer"
63  (interactive)
64  (bury-buffer (current-buffer))
65  (set-window-configuration YaTeX-help-saved-config))
66
67(defvar YaTeX-help-reference-regexp "<refer\\s +\\([^>]+\\)>"
68  "Regexp of reference format of YaTeX-help file.")
69(defvar YaTeX-help-buffer "** YaTeX HELP **" "Help buffer name for yatexhlp")
70
71(defun YaTeX-help-entries ()
72  "Return the alist which contains all the entries in YaTeX-help file."
73  (let (entries entry)
74    (save-excursion
75      (mapcar
76       (function
77	(lambda (help)
78	  (if (file-exists-p help)
79	      (progn
80		(set-buffer (find-file-noselect help))
81		(save-excursion
82		  (goto-char (point-min))
83		  (while (re-search-forward
84			  (concat "^" (regexp-quote YaTeX-help-delimiter)
85				  "\\(.+\\)$") nil t)
86		    (setq entry (buffer-substring
87				 (match-beginning 1) (match-end 1)))
88		    (or (assoc entry entries)
89			(setq entries (cons (list entry) entries)))))))))
90       (list YaTeX-help-file YaTeX-help-file-private)))
91    entries))
92
93(defvar YaTeX-help-entries nil
94  "Helo entries alist.")
95(setq YaTeX-help-entries (YaTeX-help-entries))
96
97(defun YaTeX-help-resolve-reference (buffer1 buffer2 &optional done-list)
98  "Replace reference format in buffer1 with refered contents in buffer2."
99  (let (ref ref-list beg end)
100    (save-excursion
101      (switch-to-buffer buffer1)
102      (goto-char (point-min))
103      (while (re-search-forward YaTeX-help-reference-regexp nil t)
104	(setq ref (buffer-substring (match-beginning 1) (match-end 1))
105	      ref-list (cons (list ref) ref-list))
106	(replace-match "")
107	(if (assoc ref done-list) nil	;already documented.
108	  (switch-to-buffer buffer2)
109	  (save-excursion
110	    (goto-char (point-min))
111	    (if (re-search-forward
112		 (concat (regexp-quote YaTeX-help-delimiter)
113			 (regexp-quote ref)
114			 "$") nil t)
115		(progn
116		  (setq beg (progn (forward-line 2) (point))
117			end (progn
118			      (re-search-forward
119			       (concat "^" (regexp-quote YaTeX-help-delimiter))
120			       nil 1)
121			      (goto-char (match-beginning 0))
122			      (forward-line -1)
123			      (while (and (bolp) (eolp) (not (bobp)))
124				(forward-char -1))
125			      (point)))
126		  (switch-to-buffer buffer1)
127		  (insert-buffer-substring buffer2 beg end))))
128	  (switch-to-buffer buffer1)))
129      (if beg (YaTeX-help-resolve-reference
130	       buffer1 buffer2 (append done-list ref-list))))))
131
132(defun YaTeX-refer-help (command help-file &optional append)
133  "Refer the COMMAND's help into HELP-FILE.
134\[Help-file format\]
135<DELIM><LaTeX/TeX command without escape character(\\)><NL>
136<Synopsis><NL>
137<Documentation><TERM>
138Where:	<DELIM> is the value of YaTeX-help-delimiter.
139	<NL> is newline.
140	<TERM> is newline or end of buffer."
141  (let ((hfbuf (find-file-noselect help-file))
142	(hbuf (get-buffer-create YaTeX-help-buffer))
143	(curwin (selected-window))
144	sb se db de)
145    (set-buffer hfbuf)
146    (goto-char (point-min))
147    (if (null
148	 (let ((case-fold-search nil))
149	   (re-search-forward
150	    (concat (regexp-quote YaTeX-help-delimiter)
151		    (regexp-quote command)
152		    "$") nil t)))
153	nil				;if not found, return nil
154      (forward-line 1)
155      (setq sb (point)
156	    se (progn (forward-line 1) (point))
157	    db (point)
158	    de (progn
159		 (re-search-forward
160		  (concat "^" (regexp-quote YaTeX-help-delimiter)) nil 1)
161		 (- (point) (length YaTeX-help-delimiter))))
162      (YaTeX-showup-buffer
163       hbuf 'YaTeX-showup-buffer-bottom-most t)
164      (set-buffer hbuf)
165      (setq buffer-read-only nil)
166      (if append (goto-char (point-max)) (erase-buffer))
167      (insert YaTeX-help-synopsis "\n")
168      (insert-buffer-substring hfbuf sb se)
169      (insert "\n" YaTeX-help-description "\n")
170      (insert-buffer-substring hfbuf db de)
171      (YaTeX-help-resolve-reference hbuf hfbuf (list (list command)))
172      (goto-char (point-min))
173      (setq buffer-read-only t)
174      (set-buffer-modified-p nil)
175      (YaTeX-help-mode)
176      (select-window curwin)
177      t)))
178
179(defun YaTeX-help-mode ()
180  (interactive)
181  (use-local-map YaTeX-help-mode-map)
182  (setq major-mode 'yatex-help-mode
183	mode-name "YaTeX-HELP"))
184
185(defun YaTeX-help-newline (&optional arg)
186  (interactive "P")
187  (if (and (= (current-column) 1) (= (preceding-char) ?.) (eolp))
188      (let ((cbuf (current-buffer)))
189	(beginning-of-line)
190	(delete-region (point) (progn (forward-line 1) (point)))
191	(save-excursion
192	  (YaTeX-help-add-entry
193	   YaTeX-help-command-current YaTeX-help-file-current))
194	(set-window-configuration YaTeX-help-saved-config)
195	(bury-buffer cbuf))
196    (newline arg)))
197
198(defun YaTeX-help-add-entry (command help-file)
199  (let ((hfbuf (find-file-noselect help-file))
200	(dbuf (current-buffer)) beg end)
201    (goto-char (point-min))
202    (re-search-forward (concat "^" (regexp-quote YaTeX-help-synopsis)))
203    (forward-line 1)	(setq beg (point))
204    (end-of-line)	(setq end (point))
205    (set-buffer hfbuf)
206    (goto-char (point-min))
207    (insert YaTeX-help-delimiter command "\n")
208    (insert-buffer-substring dbuf beg end)
209    (insert "\n")
210    (set-buffer dbuf)
211    (re-search-forward (concat "^" (regexp-quote YaTeX-help-description)))
212    (forward-line 1)
213    (setq beg (point))
214    (setq end (point-max))
215    (set-buffer hfbuf)
216    (insert-buffer-substring dbuf beg end)
217    (insert "\n\n")
218    (forward-line -1)
219    (delete-blank-lines)
220    (let ((make-backup-files t))
221      (basic-save-buffer))
222    (bury-buffer hfbuf)
223    (setq YaTeX-help-entries (cons (list command) YaTeX-help-entries))))
224
225(defun YaTeX-help-prepare-entry (command help-file)
226  "Read help description on COMMAND and add it to HELP-FILE."
227  (let ((buf (get-buffer-create "**Description**"))
228	(conf (current-window-configuration)))
229    (YaTeX-showup-buffer
230     buf 'YaTeX-showup-buffer-bottom-most t)
231    (make-local-variable 'YaTeX-help-file-current)
232    (make-local-variable 'YaTeX-help-command-current)
233    (make-local-variable 'YaTeX-help-saved-config)
234    (setq YaTeX-help-file-current help-file
235	  YaTeX-help-command-current command
236	  YaTeX-help-saved-config conf
237	  mode-name "Text"
238	  major-mode 'text)
239    (erase-buffer)
240    (insert YaTeX-help-synopsis "\n\n" YaTeX-help-description "\n\n")
241    (define-key YaTeX-help-entry-map "\r" 'YaTeX-help-newline)
242    (use-local-map YaTeX-help-entry-map)
243    (message
244     (cond (YaTeX-japan "���͂��I������ . �̂ݓ��͂���RET")
245	   (t "Type only `.' and RET to exit.")))))
246
247(defun YaTeX-enrich-help (command)
248  "Add the COMMAND's help to help file."
249  (if (y-or-n-p (format "No help on `%s'. Create help?" command))
250      (YaTeX-help-prepare-entry
251       command
252       (if (y-or-n-p "Add help to global documentation?")
253	   YaTeX-help-file YaTeX-help-file-private))))
254
255(defun YaTeX-help-sort (&optional help-file)
256  "Sort help file HELP-FILE.
257If HELP-FILE is nil or called interactively, sort current buffer
258as a help file."
259  (interactive)
260  (if help-file (set-buffer (find-file-noselect help-file)))
261  (sort-regexp-fields
262   nil "\\(\\sw+\\)\\([^]+\\|\\s'\\)" "\\1" (point-min) (point-max)))
263
264(defun YaTeX-apropos-file (keyword help-file &optional append)
265  (let ((hb (find-file-noselect help-file))
266	(ab (get-buffer-create YaTeX-help-buffer))
267	(sw (selected-window))
268	(head (concat "^" (regexp-quote YaTeX-help-delimiter)))
269	pt command)
270    (YaTeX-showup-buffer ab 'YaTeX-showup-buffer-bottom-most)
271    (select-window (get-buffer-window ab))
272    (set-buffer ab)			;assertion
273    (setq buffer-read-only nil)
274    (or append (erase-buffer))
275    (set-buffer hb)
276    (goto-char (point-min))
277    (while (re-search-forward keyword nil t)
278      (setq pt (point))
279      (re-search-backward head nil t)
280      (setq command (buffer-substring (match-end 0) (point-end-of-line)))
281      (switch-to-buffer ab)
282      (goto-char (point-max))
283      (insert-char ?- (1- (window-width)))
284      (insert (format "\n<<%s>>\n" command))
285      (YaTeX-refer-help command help-file t) ;append mode
286      (setq buffer-read-only nil)
287      (set-buffer hb)
288      (goto-char pt)
289      (if (re-search-forward head nil 1)
290	  (goto-char (1- (match-beginning 0)))))
291    (setq buffer-read-only t)
292    (select-window sw)
293    pt))
294
295;;;###autoload
296(defun YaTeX-apropos (key)
297  (interactive "sLaTeX apropos (regexp): ")
298  (if (string= "" key) (error "Nothing to show"))
299  (setq YaTeX-help-saved-config (current-window-configuration))
300  (or (YaTeX-apropos-file key YaTeX-help-file)
301      (YaTeX-apropos-file key YaTeX-help-file-private t)
302      (message "No matches found.")))
303
304;;;###autoload
305(defun YaTeX-help (&optional macro ref-only)
306  "Show help buffer of LaTeX/TeX commands or macros.
307Optional argument MACRO, if supplied, is directly selected to keyword.
308Non-nil for optional second argument REF-ONLY inhibits call enrich-help
309for non-interactive use."
310  (interactive)
311  (let (p beg end command)
312    (save-excursion
313      (if (looking-at YaTeX-ec-regexp)
314	  (goto-char (match-end 0)))
315      (setq p (point))			;remember current position.
316      (cond
317       (macro nil)
318       ((YaTeX-on-begin-end-p)
319	;;if on \begin or \end, extract its environment.
320	(setq command
321	      (cond ((match-beginning 1)
322		     (buffer-substring (match-beginning 1) (match-end 1)))
323		    ((match-beginning 2)
324		     (buffer-substring (match-beginning 2) (match-end 2))))))
325       ((search-backward YaTeX-ec (point-beginning-of-line) t)
326	(goto-char (setq beg (match-end 0)))
327	(re-search-forward YaTeX-TeX-token-regexp (point-end-of-line) t)
328	(setq end (point))
329	(if (and (<= beg p) (<= p end))
330	    (setq command (buffer-substring beg end)))))
331      (if (or (string= command "begin") (string= command "end"))
332	  (progn
333	    (search-forward "{" (point-end-of-line))
334	    (setq beg (point))
335	    (search-forward "}" (point-end-of-line))
336	    (setq command (buffer-substring beg (match-beginning 0)))))
337      (setq command
338	    (or macro
339		(completing-read
340		 "Describe (La)TeX command: "
341		 YaTeX-help-entries nil nil command))));end excursion
342
343    (setq YaTeX-help-saved-config (current-window-configuration))
344    (or (YaTeX-refer-help command YaTeX-help-file)
345	(YaTeX-refer-help command YaTeX-help-file-private)
346	ref-only
347	(YaTeX-enrich-help command))))
348