1 ;(***********************************************************************)
5 ;(* Didier Remy, projet Cristal, INRIA Rocquencourt *)
7 ;(* Copyright 2001 Institut National de Recherche en Informatique et *)
8 ;(* en Automatique. All rights reserved. This file is distributed *)
9 ;(* under the terms of the GNU General Public License. *)
11 ;(***********************************************************************)
15 ;; caml-info.el --- contextual completion and help to caml-mode
17 ;; Didier Remy, November 2001.
19 ;; This provides two functions completion and help
20 ;; look for caml-complete and caml-help
22 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
24 ;; This is a preliminary version.
26 ;; Possible improvements?
27 ;; - dump some databaes: Info, Lib, ...
28 ;; - accept a search path for local libraries instead of current dir
29 ;; (then distinguish between different modules lying in different
31 ;; - improve the construction for info files.
34 ;; - the viewing method and the database, so that the documentation for
35 ;; and identifier could be search in
36 ;; * info / html / man / mli's sources
37 ;; * viewed in emacs or using an external previewer.
39 ;; Take all identifiers (labels, Constructors, exceptions, etc.)
41 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
45 (if (and (boundp 'running-xemacs
) running-xemacs
)
46 (require 'caml-xemacs
)
47 (require 'caml-emacs
)))
49 ;; Loading or building databases.
52 ;; variables to be customized
54 (defvar ocaml-lib-path
'lazy
55 "Path list for ocaml lib sources (mli files)
57 'lazy means ask ocaml to find it for your at first use.")
58 (defun ocaml-lib-path ()
59 "Computes if necessary and returns the path for ocaml libs"
60 (if (listp ocaml-lib-path
) nil
63 (shell-command-to-string
65 (and (boundp 'inferior-caml-program
)
66 (string-match "\\([^ ]*/ocaml\\)\\( \\|$\\)"
67 inferior-caml-program
)
69 (concat (match-string 1 inferior-caml-program
)
71 (and (file-executable-p file
)
72 (concat file
" -where"))))
78 ;; General purpose auxiliary functions
80 (defun ocaml-capitalize (s)
81 (concat (capitalize (substring s
0 1)) (substring s
1)))
83 (defun ocaml-uncapitalize (s)
85 (concat (downcase (substring s
0 1)) (substring s
1))
88 (defun iter (f l
) (while (consp l
) (apply f
(list (car l
))) (setq l
(cdr l
))))
90 (defun ocaml-find-files (path filter
&optional depth split
)
93 (if (file-directory-p path
) path nil
)
94 (mapconcat '(lambda (d) (if (file-directory-p d
) d
))
98 (concat "find " path-string
99 " '(' " filter
" ')' "
100 (if depth
(concat " -maxdepth " (int-to-string depth
)))
101 (if split nil
" -printf '%\p '")
104 (and command
(shell-command-to-string command
))))
105 (if (and split
(stringp files
)) (split-string files
"\n") files
)
108 ;; Specialized auxiliary functions
111 ;; Global table of modules contents of modules loaded lazily.
113 (defvar ocaml-module-alist
'lazy
114 "A-list of modules with how and where to find help information.
115 'delay means non computed yet")
117 (defun ocaml-add-mli-modules (modules tag
&optional path
)
119 (ocaml-find-files (or path
(ocaml-lib-path))
120 "-type f -name '*.mli'" 1 t
)))
122 (if (string-match "\\([^/]*\\).mli" (car files
))
123 (let* ((module (ocaml-capitalize (match-string 1 (car files
))))
124 (dir (file-name-directory (car files
)))
125 (dirp (member dir
(ocaml-lib-path))))
126 (if (and (consp dirp
) (string-equal dir
(car dirp
)))
127 (setq dir
(car dirp
)))
128 (if (assoc module modules
) nil
130 (cons (cons module
(cons (cons tag dir
) 'lazy
)) modules
))
132 (setq files
(cdr files
)))
135 (defun ocaml-add-path (dir &optional path
)
136 "Extend ocaml-module-alist with modules of DIR relative to PATH"
138 (let* ((old (ocaml-lib-path))
140 (if (file-name-absolute-p dir
) dir
142 (or (find-if '(lambda (p) (file-directory-p (concat p
"/" dir
)))
143 (cons default-directory old
))
144 (error "Directory not found"))
146 (setq ocaml-lib-path
(cons (car old
) (cons new
(cdr old
))))
147 (setq ocaml-module-alist
148 (ocaml-add-mli-modules (ocaml-module-alist) 'lib new
))))
150 (defun ocaml-module-alist ()
151 "Call by need value of variable ocaml-module-alist"
152 (if (listp ocaml-module-alist
)
154 ;; build list of mli files
155 (setq ocaml-module-alist
(ocaml-add-mli-modules nil
'lib
))
156 ;; dumping information ? TODO
160 (defun ocaml-get-or-make-module (module &optional tag
)
161 (let ((info (assoc module
(ocaml-module-alist))))
163 (setq info
(cons module
(cons (cons 'local default-directory
) 'lazy
)))
164 (setq ocaml-module-alist
(cons info ocaml-module-alist
))
168 ;; Symbols of module are lazily computed
170 (defun ocaml-module-filename (module)
171 (let ((module (ocaml-uncapitalize module
)) (name))
172 (if (file-exists-p (setq name
(concat module
".mli"))) nil
173 (let ((tmp (ocaml-lib-path)))
175 (setq name
(concat (car tmp
) "/" module
".mli"))
176 (if (file-exists-p name
) (setq tmp nil
)
180 (defun ocaml-module-symbols (module-info)
181 (let* ((module (car module-info
))
182 (tail (and module-info
(cdr module-info
)))
187 (if (listp (cdr tail
))
189 (if (equal tag
'info
)
190 (setq dir
(car ocaml-lib-path
)) ; XXX to be fixed
192 (setq file
(concat dir
"/" (ocaml-uncapitalize module
) ".mli"))
194 (save-window-excursion
195 (set-buffer (get-buffer-create "*caml-help*"))
196 (if (and file
(file-exists-p file
))
198 (message "Scanning module %s" file
)
199 (insert-file-contents file
))
200 (message "Module %s not found" module
))
201 (while (re-search-forward
202 "\\([ \t]*val\\|let\\|external\\| [|]\\) \\([a-zA-Z_0-9'][a-zA-Z_0-9']*\\)\\|^ *[{]* \\([a-z_][A-Za-z_0-9]*\\) : [^;\n][^;\n]*;"
204 (pop-to-buffer (current-buffer))
205 (setq alist
(cons (or (match-string 2) (match-string 3)) alist
)))
212 ;; Local list of visible modules.
214 (defvar ocaml-visible-modules
'lazy
215 "A-list of open modules, local to every file.")
216 (make-variable-buffer-local 'ocaml-visible-modules
)
217 (defun ocaml-visible-modules ()
218 (if (listp ocaml-visible-modules
) nil
220 (setq ocaml-visible-modules
221 (list (ocaml-get-or-make-module "Pervasives")))
223 (goto-char (point-min))
224 (while (re-search-forward "^ *open *\\([A-Z][a-zA-Z'_0-9]*\\)"
226 (let ((module (match-string 1)))
227 (if (assoc module ocaml-visible-modules
) nil
228 (setq ocaml-visible-modules
229 (cons (ocaml-get-or-make-module module
)
230 ocaml-visible-modules
)))))
232 ocaml-visible-modules
)
234 (defun ocaml-open-module (arg)
235 "*Make module of name ARG visible whe ARG is a string.
236 When call interactively, make completion over known modules."
238 (if (not (stringp arg
))
239 (let ((modules (ocaml-module-alist)))
241 (completing-read "Open module: " modules
))))
242 (if (and (stringp arg
) (not (equal arg
"")))
244 (if (assoc arg
(ocaml-visible-modules))
245 (ocaml-close-module arg
))
246 (setq ocaml-visible-modules
247 (cons (ocaml-get-or-make-module arg
) (ocaml-visible-modules)))
249 (message "%S" (mapcar 'car
(ocaml-visible-modules))))
251 (defun ocaml-close-module (arg)
252 "*Close module of name ARG when ARG is a string.
253 When call interactively, make completion over visible modules.
254 Otherwise if ARG is true, close all modules and reset to default. "
256 (if (= (prefix-numeric-value arg
) 4)
257 (setq ocaml-visible-modules
'lazy
)
258 (let* ((modules (ocaml-visible-modules)))
259 (if (null modules
) (error "No visible module to close"))
260 (unless (stringp arg
)
263 (concat "Close module [" (caar modules
) "] : ")
265 (if (equal arg
"") (setq arg
(caar modules
))))
266 (setq ocaml-visible-modules
267 (remove-if '(lambda (m) (equal (car m
) arg
))
268 ocaml-visible-modules
))
270 (message "%S" (mapcar 'car
(ocaml-visible-modules))))
273 ;; Look for identifiers around point
275 (defun ocaml-qualified-identifier (&optional show
)
276 "Search for a qualified identifier (Path. entry) around point.
279 Currently, the path may only be nil or a single Module.
280 For paths is of the form Module.Path', it returns Module
281 and always nil for entry.
283 If defined Module and Entry are represented by a region in the buffer,
284 and are nil otherwise.
286 For debugging purposes, it returns the string Module.entry if called
287 with an optional non-nil argument.
290 (let ((module) (entry))
291 (if (looking-at "[ \n]") (skip-chars-backward " "))
292 (if (re-search-backward
293 "\\([^A-Za-z0-9_.']\\|\\`\\)\\([A-Za-z0-9_']*[.]\\)*[A-Za-z0-9_']*\\="
296 (or (looking-at "\\`[A-Za-z)-9_.]") (forward-char 1))
297 (if (looking-at "\\<\\([A-Za-z_][A-Za-z0-9_']*\\)[.]")
299 (setq module
(cons (match-beginning 1) (match-end 1)))
300 (goto-char (match-end 0))))
301 (if (looking-at "\\<\\([A-Za-z_][A-Za-z0-9_']*\\)\\>")
302 (setq entry
(cons (match-beginning 1) (match-end 1))))))
305 (and module
(buffer-substring (car module
) (cdr module
)))
307 (and entry
(buffer-substring (car entry
) (cdr entry
))))
311 ;; completion around point
313 (defun ocaml-completion (pattern module
)
318 (or (assoc module
(ocaml-module-alist))
319 (error "Unknown module %s" module
))))
320 (ocaml-visible-modules))))
321 (message "Completion from %s" (mapconcat 'car list
" "))
323 (apply 'append
(mapcar 'ocaml-module-symbols list
))
324 (let ((pat (concat "^" (regexp-quote pattern
))) (res))
328 (if (string-match pat
(car l
))
329 (if (member x res
) nil
(setq res
(cons x res
)))))
330 (ocaml-module-symbols l
)))
335 (defun caml-complete (arg)
336 "Does completion for OCaml identifiers qualified.
338 It attemps to recognize an qualified identifier Module . entry
339 around point using function \\[ocaml-qualified-identifier].
341 If Module is defined, it does completion for identifier in Module.
343 If Module is undefined, it does completion in visible modules.
344 Then, if completion fails, it does completion among all modules
345 where identifier is defined."
347 (let* ((module-entry (ocaml-qualified-identifier)) (entry)
349 (beg) (end) (pattern))
350 (if (car module-entry
)
353 (buffer-substring (caar module-entry
) (cdar module-entry
)))
354 (or (assoc module
(ocaml-module-alist))
356 (completing-read "Module: " (ocaml-module-alist)
359 (goto-char (caar module-entry
))
360 (delete-region (caar module-entry
) (cdar module-entry
))
362 (setq module-entry
(ocaml-qualified-identifier))
364 (progn (setq entry
(cdr module-entry
)) t
))
365 (error "Unknown module %s" module
))))
366 (if (consp (cdr module-entry
))
368 (setq beg
(cadr module-entry
))
369 (setq end
(cddr module-entry
)))
372 (goto-char (cdar module-entry
))
373 (looking-at " *[.]")))
375 (setq beg
(match-end 0))
377 (if (not (and beg end
))
378 (error "Did not find anything to complete around point")
380 (setq pattern
(buffer-substring beg end
))
381 (let* ((all-completions (ocaml-completion pattern module
))
383 (try-completion pattern
(mapcar 'list all-completions
))))
384 (cond ((eq completion t
))
388 ((modules (ocaml-find-module pattern
))
389 (visible (intersection modules
(ocaml-visible-modules)))
395 ((equal (length modules
) 1)
397 ((equal (length visible
) 1)
400 (setq hist
(mapcar 'car modules
))
401 (completing-read "Module: " modules nil t
405 (error "Can't find completion for \"%s\"" pattern
)
406 (message "Completion found in module %s" module
)
407 (if (and (consp module-entry
) (consp (cdr module-entry
)))
408 (delete-region (caar module-entry
) end
)
409 (delete-region beg end
))
410 (insert module
"." pattern
))))
412 ((not (string-equal pattern completion
))
413 (delete-region beg end
)
418 (with-output-to-temp-buffer "*Completions*"
419 (display-completion-list all-completions
))
424 ;; Info files (only in ocamldoc style)
427 (defvar ocaml-info-prefix
"ocaml-lib"
428 "Prefix of ocaml info files describing library modules.
429 Suffix .info will be added to info files.
430 Additional suffix .gz may be added if info files are compressed.
434 (defun ocaml-hevea-info-add-entries (entries dir name
)
437 (concat "-type f -regex '.*/" name
438 "\\(.info\\|\\)\\(-[0-9]*\\|\\)\\([.]gz\\|\\)'"
441 "\\* \\(Section [1-9][0-9--]*\\)::[ \t][ \t]*Module *\\([A-Z][A-Za-z_0-9]*\\)")
442 (files (ocaml-find-files dir filter
))
444 ;; scanning info files
446 (not (stringp files
))
447 (string-match files
"^ *$"))
448 (message "No info file found: %s." (mapconcat 'identity files
" "))
449 (message "Scanning info files %s." files
)
450 (save-window-excursion
451 (set-buffer (get-buffer-create "*caml-help*"))
453 (concat "zcat -f " files
454 " | grep -e '" section-regexp
"'"))
455 (message "Scanning files with: %s" command
)
456 (or (shell-command command
(current-buffer))
457 (error "Error while scanning"))
458 (goto-char (point-min))
459 (while (re-search-forward section-regexp
(point-max) t
)
460 (let* ((module (match-string 2))
461 (section (match-string 1)))
462 ;; (message "%s %s" module section)
463 (if (assoc module entries
) nil
465 (cons (cons module
(concat "(" name
")" section
))
468 (let ((buf (get-buffer "*caml-help*")))
469 (if buf
(kill-buffer buf
)))))
472 (defun ocaml-hevea-info ()
473 "The default way to create an info data base from the value
474 of \\[Info-default-directory-list] and the base name \\[ocaml-info-name]
475 of files to look for.
477 This uses info files produced by HeVeA.
479 (let ((collect) (seen))
481 (if (member d seen
) nil
483 (ocaml-hevea-info-add-entries
484 collect d ocaml-info-prefix
))
485 (setq done
(cons d seen
))))
489 (defun ocaml-ocamldoc-info-add-entries (entries dir name
)
491 ((module-regexp "^Node: \\([A-Z][A-Za-z_0-9]*\\)[^ ]")
494 "find " dir
" -type f -regex '.*/" name
495 "\\(.info\\|\\)\\([.]gz\\|\\)' -print0"
496 " | xargs -0 zcat -f | grep '" module-regexp
"'")))
497 (message "Scanning info files in %s" dir
)
498 (save-window-excursion
499 (set-buffer (get-buffer-create "*caml-help*"))
500 (or (shell-command command
(current-buffer)) (error "HERE"))
501 (goto-char (point-min))
502 (while (re-search-forward module-regexp
(point-max) t
)
503 (if (equal (char-after (match-end 1)) 127)
504 (let* ((module (match-string 1)))
505 (if (assoc module entries
) nil
507 (cons (cons module
(concat "(" name
")" module
))
510 ; (kill-buffer (current-buffer))
514 (defun ocaml-ocamldoc-info ()
515 "The default way to create an info data base from the value
516 of \\[Info-default-directory-list] and the base name \\[ocaml-info-name]
517 of files to look for.
519 This uses info files produced by ocamldoc."
521 (let ((collect) (seen))
523 (if (member d seen
) nil
525 (ocaml-ocamldoc-info-add-entries collect d
527 (setq done
(cons d seen
))))
533 (defvar ocaml-info-alist
'ocaml-ocamldoc-info
534 "A-list binding module names to info entries:
536 nil means do not use info.
538 A function to build the list lazily (at the first call). The result of
539 the function call will be assign permanently to this variable for future
540 uses. We provide two default functions \\[ocaml-info-default-function]
541 (info produced by HeVeA is the default) and \\[ocaml-info-default-function]
542 (info produced by ocamldoc).
544 Otherwise, this value should be an alist binding module names to info
545 entries of the form to \"(entry)section\" be taken by the \\[info]
546 command. An entry may be an info module or a complete file name."
549 (defun ocaml-info-alist ()
550 "Call by need value of variable ocaml-info-alist"
552 ((listp ocaml-info-alist
))
553 ((functionp ocaml-info-alist
)
554 (setq ocaml-info-alist
(apply ocaml-info-alist nil
)))
556 (error "wrong type for ocaml-info-alist")))
561 (defun ocaml-find-module (symbol &optional module-list
)
562 (let ((list (or module-list
(ocaml-module-alist)))
565 (if (member symbol
(ocaml-module-symbols (car list
)))
566 (setq collect
(cons (car list
) collect
)))
567 (setq list
(cdr list
)))
571 (defun ocaml-buffer-substring (region)
572 (and region
(buffer-substring-no-properties (car region
) (cdr region
))))
577 (defun ocaml-goto-help (&optional module entry same-window
)
578 "Searches info manual for MODULE and ENTRY in MODULE.
579 If unspecified, MODULE and ENTRY are inferred from the position in the
580 current buffer using \\[ocaml-qualified-identifier]."
582 (let ((window (selected-window))
583 (info-section (assoc module
(ocaml-info-alist))))
585 (caml-info-other-window (cdr info-section
))
586 (ocaml-visible-modules)
588 (or (assoc module
(ocaml-module-alist))
590 (concat (ocaml-uncapitalize module
) ".mli"))
591 (ocaml-get-or-make-module module
))))
592 (location (cdr (cadr module-info
))))
595 (let ((file (concat location
(ocaml-uncapitalize module
) ".mli")))
596 (if (window-live-p same-window
)
597 (progn (select-window same-window
)
598 (view-mode-exit view-return-to-alist view-exit-action
))
599 ;; (view-buffer (find-file-noselect file) 'view))
601 (view-file-other-window file
)
602 (bury-buffer (current-buffer))))
603 (info-section (error "Aborted"))
604 (t (error "No help for module %s" module
))))
608 (case-fold-search nil
))
609 (goto-char (point-min))
610 (if (or (re-search-forward
611 (concat "\\(val\\|exception\\|type\\|external\\|[|{;]\\) +"
612 (regexp-quote entry
))
615 (concat "type [^{]*{[^}]*" (regexp-quote entry
) " :")
618 (if (window-live-p window
) (select-window window
))
619 (error "Entry %s not found in module %s"
621 ;; (search-forward entry (point-max) t)
625 (message "Help for entry %s not found in module %s"
628 (ocaml-link-activate (cdr info-section
))
629 (if (window-live-p window
) (select-window window
))
632 (defun caml-help (arg)
633 "Find documentation for OCaml qualified identifiers.
635 It attemps to recognize an qualified identifier of the form
636 ``Module . entry'' around point using function `ocaml-qualified-identifier'.
638 If Module is undetermined it is temptatively guessed from the identifier name
639 and according to visible modules. If this is still unsucessful, the user is
640 then prompted for a Module name.
642 The documentation for Module is first seach in the info manual if available,
643 then in the ``module.mli'' source file. The entry is then searched in the documentation.
645 Visible modules are computed only once, at the first call.
646 Modules can be made visible explicitly with `ocaml-open-module' and
647 hidden with `ocaml-close-module'.
649 Prefix arg 0 forces recompilation of visible modules (and their content)
650 from the file content.
652 Prefix arg 4 prompts for Module and identifier instead of guessing values
653 from the possition of point in the current buffer.
656 (let ((module) (entry) (module-entry))
661 (completing-read "Module: " (ocaml-module-alist)
662 nil t
"" (cons 'hist
0)))
663 (not (string-equal module
"")))
667 (ocaml-module-symbols
668 (assoc module
(ocaml-module-alist))))))
669 (setq entry
(completing-read "Value: " symbols nil t
)))
670 (if (string-equal entry
"") (setq entry nil
))
673 (if (= arg
0) (setq ocaml-visible-modules
'lazy
))
674 (setq module-entry
(ocaml-qualified-identifier))
675 (setq entry
(ocaml-buffer-substring (cdr module-entry
)))
677 (or (ocaml-buffer-substring (car module-entry
))
679 (or (ocaml-find-module entry
(ocaml-visible-modules))
680 (ocaml-find-module entry
)))
684 (error "No module found for entry %s" entry
))
685 ((equal (length modules
) 1)
688 (setq hist
(mapcar 'car modules
))
689 (setq default
(car hist
))
693 (and default
(concat "[" default
"] ")))
694 modules nil t
"" (cons 'hist
0)))
695 (if (string-equal module
"") default module
))
698 (message "Help for %s%s%s" module
(if entry
"." "") (or entry
""))
699 (ocaml-goto-help module entry
)
704 (defconst ocaml-link-regexp
705 "\\(type\\|and\\) \\('[a-z] +\\|(\\('[a-z], *\\)*'[a-z])\\|\\) *\\([a-zA-Z0-9_]*\\)\\( *$\\| =\\)")
706 (defconst ocaml-longident-regexp
707 "\\([A-Z][a-zA-Z_0]*\\)[.]\\([a-zA-Z][A-Za-z0-9_]*\\)")
709 (defvar ocaml-links nil
710 "Local links in the current of last info node or interface file.
712 The car of the list is a key that indentifies the module to prevent
713 recompilation when next help command is relative to the same module.
714 The cdr is a list of elments, each of which is an string and a pair of
717 (make-variable-buffer-local 'ocaml-links
)
719 (defun ocaml-info-links (section)
721 (if (and ocaml-links section
(equal (car ocaml-links
) section
))
724 (goto-char (point-min))
725 (let ((regexp (concat (if (equal major-mode
'Info-mode
) "^ - " "^")
728 (while (re-search-forward regexp
(point-max) t
)
730 (cons (cons (match-string 4)
731 (cons (match-beginning 4)
734 (setq ocaml-links
(cons section all
))
737 (defvar ocaml-link-map
(make-sparse-keymap))
738 (define-key ocaml-link-map
[mouse-2
] 'ocaml-link-goto
)
740 (defun ocaml-link-goto (click)
742 (let* ((pos (caml-event-point-start click
))
743 (win (caml-event-window click
))
744 (buf (window-buffer win
))
745 (window (selected-window))
748 (with-current-buffer buf
750 (previous-single-property-change (+ pos
1) 'local-map
752 (next-single-property-change pos
'local-map
754 (if (string-match (concat "^" ocaml-longident-regexp
"$") link
)
755 (ocaml-goto-help (match-string 1 link
) (match-string 2 link
) win
)
756 (if (not (equal (window-buffer window
) buf
))
757 (switch-to-buffer-other-window buf
))
758 (if (setq link
(assoc link
(cdr ocaml-links
)))
760 (goto-char (cadr link
))
762 (if (window-live-p window
) (select-window window
))
766 ((and (x-display-color-p)
767 (not (memq 'ocaml-link-face
(face-list))))
768 (make-face 'ocaml-link-face
)
769 (set-face-foreground 'ocaml-link-face
"Purple")))
772 (defun ocaml-link-activate (section)
773 (let ((links (ocaml-info-links section
)))
775 (let ((regexp (concat "[^A-Za-z0-9'_]\\("
776 ocaml-longident-regexp
"\\|"
777 (mapconcat 'car links
"\\|")
778 "\\)[^A-Za-z0-9'_]"))
779 (case-fold-search nil
))
780 (goto-char (point-min))
781 (let ((buffer-read-only nil
)
782 ;; use of dynamic scoping, need not be restored!
783 (modified-p (buffer-modified-p)))
786 (goto-char (point-min))
787 (while (re-search-forward regexp
(point-max) t
)
788 (put-text-property (match-beginning 1) (match-end 1)
789 'mouse-face
'highlight
)
790 (put-text-property (match-beginning 1) (match-end 1)
791 'local-map ocaml-link-map
)
792 (if (x-display-color-p)
793 (put-text-property (match-beginning 1) (match-end 1)
794 'face
'ocaml-link-face
)))
796 ;; need to restore flag if buffer was unmodified.
797 (unless modified-p
(set-buffer-modified-p nil
))
803 ;; bindings ---now in caml.el
806 ; (boundp 'caml-mode-map)
807 ; (keymapp caml-mode-map)
809 ; (define-key caml-mode-map [?\C-c?i] 'ocaml-add-path)
810 ; (define-key caml-mode-map [?\C-c?]] 'ocaml-close-module)
811 ; (define-key caml-mode-map [?\C-c?[] 'ocaml-open-module)
812 ; (define-key caml-mode-map [?\C-c?\C-h] 'caml-help)
813 ; (define-key caml-mode-map [?\C-c?\t] 'caml-complete)
814 ; (let ((map (lookup-key caml-mode-map [menu-bar caml])))
818 ; (define-key map [separator-help] '("---"))
819 ; (define-key map [open] '("Open add path" . ocaml-add-path ))
820 ; (define-key map [close]
821 ; '("Close module for help" . ocaml-close-module))
822 ; (define-key map [open] '("Open module for help" . ocaml-open-module))
823 ; (define-key map [help] '("Help for identifier" . caml-help))
824 ; (define-key map [complete] '("Complete identifier" . caml-complete))