summaryrefslogtreecommitdiff
path: root/ocaml-binary-annot/otherlibs/labltk/browser
diff options
context:
space:
mode:
Diffstat (limited to 'ocaml-binary-annot/otherlibs/labltk/browser')
-rw-r--r--ocaml-binary-annot/otherlibs/labltk/browser/.cvsignore2
-rw-r--r--ocaml-binary-annot/otherlibs/labltk/browser/.depend66
-rw-r--r--ocaml-binary-annot/otherlibs/labltk/browser/Makefile8
-rw-r--r--ocaml-binary-annot/otherlibs/labltk/browser/Makefile.nt21
-rw-r--r--ocaml-binary-annot/otherlibs/labltk/browser/Makefile.shared64
-rw-r--r--ocaml-binary-annot/otherlibs/labltk/browser/README170
-rw-r--r--ocaml-binary-annot/otherlibs/labltk/browser/dummyUnix.mli27
-rw-r--r--ocaml-binary-annot/otherlibs/labltk/browser/dummyWin.mli15
-rw-r--r--ocaml-binary-annot/otherlibs/labltk/browser/editor.ml667
-rw-r--r--ocaml-binary-annot/otherlibs/labltk/browser/editor.mli20
-rw-r--r--ocaml-binary-annot/otherlibs/labltk/browser/fileselect.ml290
-rw-r--r--ocaml-binary-annot/otherlibs/labltk/browser/fileselect.mli39
-rw-r--r--ocaml-binary-annot/otherlibs/labltk/browser/help.ml168
-rw-r--r--ocaml-binary-annot/otherlibs/labltk/browser/help.txt166
-rw-r--r--ocaml-binary-annot/otherlibs/labltk/browser/jg_bind.ml28
-rw-r--r--ocaml-binary-annot/otherlibs/labltk/browser/jg_bind.mli21
-rw-r--r--ocaml-binary-annot/otherlibs/labltk/browser/jg_box.ml82
-rw-r--r--ocaml-binary-annot/otherlibs/labltk/browser/jg_button.ml25
-rw-r--r--ocaml-binary-annot/otherlibs/labltk/browser/jg_completion.ml53
-rw-r--r--ocaml-binary-annot/otherlibs/labltk/browser/jg_completion.mli25
-rw-r--r--ocaml-binary-annot/otherlibs/labltk/browser/jg_config.ml40
-rw-r--r--ocaml-binary-annot/otherlibs/labltk/browser/jg_config.mli17
-rw-r--r--ocaml-binary-annot/otherlibs/labltk/browser/jg_entry.ml27
-rw-r--r--ocaml-binary-annot/otherlibs/labltk/browser/jg_memo.ml33
-rw-r--r--ocaml-binary-annot/otherlibs/labltk/browser/jg_memo.mli19
-rw-r--r--ocaml-binary-annot/otherlibs/labltk/browser/jg_menu.ml44
-rw-r--r--ocaml-binary-annot/otherlibs/labltk/browser/jg_message.ml111
-rw-r--r--ocaml-binary-annot/otherlibs/labltk/browser/jg_message.mli33
-rw-r--r--ocaml-binary-annot/otherlibs/labltk/browser/jg_multibox.ml185
-rw-r--r--ocaml-binary-annot/otherlibs/labltk/browser/jg_multibox.mli35
-rw-r--r--ocaml-binary-annot/otherlibs/labltk/browser/jg_text.ml104
-rw-r--r--ocaml-binary-annot/otherlibs/labltk/browser/jg_text.mli28
-rw-r--r--ocaml-binary-annot/otherlibs/labltk/browser/jg_tk.ml24
-rw-r--r--ocaml-binary-annot/otherlibs/labltk/browser/jg_toplevel.ml25
-rw-r--r--ocaml-binary-annot/otherlibs/labltk/browser/jglib.mllib13
-rw-r--r--ocaml-binary-annot/otherlibs/labltk/browser/lexical.ml145
-rw-r--r--ocaml-binary-annot/otherlibs/labltk/browser/lexical.mli20
-rw-r--r--ocaml-binary-annot/otherlibs/labltk/browser/list2.ml23
-rw-r--r--ocaml-binary-annot/otherlibs/labltk/browser/main.ml132
-rw-r--r--ocaml-binary-annot/otherlibs/labltk/browser/mytypes.mli29
-rw-r--r--ocaml-binary-annot/otherlibs/labltk/browser/searchid.ml533
-rw-r--r--ocaml-binary-annot/otherlibs/labltk/browser/searchid.mli45
-rw-r--r--ocaml-binary-annot/otherlibs/labltk/browser/searchpos.ml890
-rw-r--r--ocaml-binary-annot/otherlibs/labltk/browser/searchpos.mli77
-rw-r--r--ocaml-binary-annot/otherlibs/labltk/browser/setpath.ml162
-rw-r--r--ocaml-binary-annot/otherlibs/labltk/browser/setpath.mli25
-rw-r--r--ocaml-binary-annot/otherlibs/labltk/browser/shell.ml365
-rw-r--r--ocaml-binary-annot/otherlibs/labltk/browser/shell.mli46
-rw-r--r--ocaml-binary-annot/otherlibs/labltk/browser/typecheck.ml188
-rw-r--r--ocaml-binary-annot/otherlibs/labltk/browser/typecheck.mli23
-rw-r--r--ocaml-binary-annot/otherlibs/labltk/browser/useunix.ml69
-rw-r--r--ocaml-binary-annot/otherlibs/labltk/browser/useunix.mli23
-rw-r--r--ocaml-binary-annot/otherlibs/labltk/browser/viewer.ml631
-rw-r--r--ocaml-binary-annot/otherlibs/labltk/browser/viewer.mli31
-rw-r--r--ocaml-binary-annot/otherlibs/labltk/browser/winmain.c26
55 files changed, 6178 insertions, 0 deletions
diff --git a/ocaml-binary-annot/otherlibs/labltk/browser/.cvsignore b/ocaml-binary-annot/otherlibs/labltk/browser/.cvsignore
new file mode 100644
index 0000000000..8ced21de22
--- /dev/null
+++ b/ocaml-binary-annot/otherlibs/labltk/browser/.cvsignore
@@ -0,0 +1,2 @@
+ocamlbrowser
+dummy.mli
diff --git a/ocaml-binary-annot/otherlibs/labltk/browser/.depend b/ocaml-binary-annot/otherlibs/labltk/browser/.depend
new file mode 100644
index 0000000000..4438a1dd83
--- /dev/null
+++ b/ocaml-binary-annot/otherlibs/labltk/browser/.depend
@@ -0,0 +1,66 @@
+editor.cmo: viewer.cmi typecheck.cmi shell.cmi setpath.cmi searchpos.cmi \
+ searchid.cmi mytypes.cmi lexical.cmi jg_toplevel.cmo jg_tk.cmo \
+ jg_text.cmi jg_message.cmi jg_menu.cmo jg_button.cmo jg_bind.cmi \
+ fileselect.cmi editor.cmi
+editor.cmx: viewer.cmx typecheck.cmx shell.cmx setpath.cmx searchpos.cmx \
+ searchid.cmx mytypes.cmi lexical.cmx jg_toplevel.cmx jg_tk.cmx \
+ jg_text.cmx jg_message.cmx jg_menu.cmx jg_button.cmx jg_bind.cmx \
+ fileselect.cmx editor.cmi
+fileselect.cmo: useunix.cmi setpath.cmi list2.cmo jg_toplevel.cmo jg_memo.cmi \
+ jg_entry.cmo jg_box.cmo fileselect.cmi
+fileselect.cmx: useunix.cmx setpath.cmx list2.cmx jg_toplevel.cmx jg_memo.cmx \
+ jg_entry.cmx jg_box.cmx fileselect.cmi
+jg_bind.cmo: jg_bind.cmi
+jg_bind.cmx: jg_bind.cmi
+jg_box.cmo: jg_completion.cmi jg_bind.cmi
+jg_box.cmx: jg_completion.cmx jg_bind.cmx
+jg_completion.cmo: jg_completion.cmi
+jg_completion.cmx: jg_completion.cmi
+jg_config.cmo: jg_tk.cmo jg_config.cmi
+jg_config.cmx: jg_tk.cmx jg_config.cmi
+jg_entry.cmo: jg_bind.cmi
+jg_entry.cmx: jg_bind.cmx
+jg_memo.cmo: jg_memo.cmi
+jg_memo.cmx: jg_memo.cmi
+jg_message.cmo: jg_toplevel.cmo jg_tk.cmo jg_text.cmi jg_bind.cmi \
+ jg_message.cmi
+jg_message.cmx: jg_toplevel.cmx jg_tk.cmx jg_text.cmx jg_bind.cmx \
+ jg_message.cmi
+jg_multibox.cmo: jg_completion.cmi jg_bind.cmi jg_multibox.cmi
+jg_multibox.cmx: jg_completion.cmx jg_bind.cmx jg_multibox.cmi
+jg_text.cmo: jg_toplevel.cmo jg_tk.cmo jg_button.cmo jg_bind.cmi jg_text.cmi
+jg_text.cmx: jg_toplevel.cmx jg_tk.cmx jg_button.cmx jg_bind.cmx jg_text.cmi
+lexical.cmo: jg_tk.cmo lexical.cmi
+lexical.cmx: jg_tk.cmx lexical.cmi
+main.cmo: viewer.cmi shell.cmi searchpos.cmi searchid.cmi jg_config.cmi \
+ editor.cmi
+main.cmx: viewer.cmx shell.cmx searchpos.cmx searchid.cmx jg_config.cmx \
+ editor.cmx
+searchid.cmo: list2.cmo searchid.cmi
+searchid.cmx: list2.cmx searchid.cmi
+searchpos.cmo: searchid.cmi lexical.cmi jg_tk.cmo jg_text.cmi jg_message.cmi \
+ jg_memo.cmi jg_bind.cmi searchpos.cmi
+searchpos.cmx: searchid.cmx lexical.cmx jg_tk.cmx jg_text.cmx jg_message.cmx \
+ jg_memo.cmx jg_bind.cmx searchpos.cmi
+setpath.cmo: useunix.cmi list2.cmo jg_toplevel.cmo jg_button.cmo jg_box.cmo \
+ jg_bind.cmi setpath.cmi
+setpath.cmx: useunix.cmx list2.cmx jg_toplevel.cmx jg_button.cmx jg_box.cmx \
+ jg_bind.cmx setpath.cmi
+shell.cmo: list2.cmo lexical.cmi jg_toplevel.cmo jg_tk.cmo jg_text.cmi \
+ jg_message.cmi jg_menu.cmo jg_memo.cmi fileselect.cmi dummy.cmi shell.cmi
+shell.cmx: list2.cmx lexical.cmx jg_toplevel.cmx jg_tk.cmx jg_text.cmx \
+ jg_message.cmx jg_menu.cmx jg_memo.cmx fileselect.cmx dummy.cmi shell.cmi
+typecheck.cmo: mytypes.cmi jg_tk.cmo jg_text.cmi jg_message.cmi typecheck.cmi
+typecheck.cmx: mytypes.cmi jg_tk.cmx jg_text.cmx jg_message.cmx typecheck.cmi
+useunix.cmo: useunix.cmi
+useunix.cmx: useunix.cmi
+viewer.cmo: useunix.cmi shell.cmi setpath.cmi searchpos.cmi searchid.cmi \
+ mytypes.cmi jg_toplevel.cmo jg_tk.cmo jg_text.cmi jg_multibox.cmi \
+ jg_message.cmi jg_menu.cmo jg_entry.cmo jg_completion.cmi jg_button.cmo \
+ jg_box.cmo jg_bind.cmi help.cmo viewer.cmi
+viewer.cmx: useunix.cmx shell.cmx setpath.cmx searchpos.cmx searchid.cmx \
+ mytypes.cmi jg_toplevel.cmx jg_tk.cmx jg_text.cmx jg_multibox.cmx \
+ jg_message.cmx jg_menu.cmx jg_entry.cmx jg_completion.cmx jg_button.cmx \
+ jg_box.cmx jg_bind.cmx help.cmx viewer.cmi
+mytypes.cmi: shell.cmi
+typecheck.cmi: mytypes.cmi
diff --git a/ocaml-binary-annot/otherlibs/labltk/browser/Makefile b/ocaml-binary-annot/otherlibs/labltk/browser/Makefile
new file mode 100644
index 0000000000..5caed2bf60
--- /dev/null
+++ b/ocaml-binary-annot/otherlibs/labltk/browser/Makefile
@@ -0,0 +1,8 @@
+# $Id$
+
+OTHERSLIB=-I $(OTHERS)/unix -I $(OTHERS)/str
+
+include Makefile.shared
+
+dummy.mli:
+ cp dummyUnix.mli dummy.mli
diff --git a/ocaml-binary-annot/otherlibs/labltk/browser/Makefile.nt b/ocaml-binary-annot/otherlibs/labltk/browser/Makefile.nt
new file mode 100644
index 0000000000..405f47e746
--- /dev/null
+++ b/ocaml-binary-annot/otherlibs/labltk/browser/Makefile.nt
@@ -0,0 +1,21 @@
+# $Id$
+
+OTHERSLIB=-I $(OTHERS)/win32unix -I $(OTHERS)/str -I $(OTHERS)/systhreads
+
+CCFLAGS=-I../../../byterun $(TK_DEFS)
+
+include ../support/Makefile.common
+
+ifeq ($(CCOMPTYPE),cc)
+WINDOWS_APP=-ccopt "-link -Wl,--subsystem,windows"
+else
+WINDOWS_APP=-ccopt "-link /subsystem:windows"
+endif
+
+XTRAOBJ=winmain.$(O)
+XTRALIBS=threads.cma -custom $(WINDOWS_APP)
+
+include Makefile.shared
+
+dummy.mli:
+ cp dummyWin.mli dummy.mli
diff --git a/ocaml-binary-annot/otherlibs/labltk/browser/Makefile.shared b/ocaml-binary-annot/otherlibs/labltk/browser/Makefile.shared
new file mode 100644
index 0000000000..b80967086f
--- /dev/null
+++ b/ocaml-binary-annot/otherlibs/labltk/browser/Makefile.shared
@@ -0,0 +1,64 @@
+include ../support/Makefile.common
+
+LABLTKLIB=-I ../labltk -I ../lib -I ../support
+OCAMLTOPLIB=-I $(TOPDIR)/parsing -I $(TOPDIR)/utils -I $(TOPDIR)/typing
+INCLUDES=$(OTHERSLIB) $(LABLTKLIB) $(OCAMLTOPLIB)
+
+OBJ = list2.cmo useunix.cmo setpath.cmo lexical.cmo \
+ fileselect.cmo searchid.cmo searchpos.cmo shell.cmo \
+ help.cmo \
+ viewer.cmo typecheck.cmo editor.cmo main.cmo
+
+JG = jg_tk.cmo jg_config.cmo jg_bind.cmo jg_completion.cmo \
+ jg_box.cmo \
+ jg_button.cmo jg_toplevel.cmo jg_text.cmo jg_message.cmo \
+ jg_menu.cmo jg_entry.cmo jg_multibox.cmo jg_memo.cmo
+
+# Default rules
+
+.SUFFIXES: .ml .mli .cmo .cmi .cmx .c .$(O)
+
+.ml.cmo:
+ $(CAMLCOMP) $(INCLUDES) $<
+
+.mli.cmi:
+ $(CAMLCOMP) $(INCLUDES) $<
+
+.c.$(O):
+ $(BYTECC) $(BYTECCCOMPOPTS) $(CCFLAGS) -c $<
+
+all: ocamlbrowser$(EXE)
+
+ocamlbrowser$(EXE): $(TOPDIR)/toplevel/toplevellib.cma jglib.cma $(OBJ) \
+ ../support/lib$(LIBNAME).$(A) $(XTRAOBJ)
+ $(CAMLC) -o ocamlbrowser$(EXE) $(INCLUDES) \
+ $(TOPDIR)/toplevel/toplevellib.cma \
+ unix.cma str.cma $(XTRALIBS) $(LIBNAME).cma jglib.cma \
+ $(OBJ) $(XTRAOBJ)
+
+ocamlbrowser.cma: jglib.cma $(OBJ)
+ $(CAMLC) -a -o $@ -linkall jglib.cma $(OBJ)
+
+jglib.cma: $(JG)
+ $(CAMLC) -a -o $@ $(JG)
+
+help.ml:
+ echo 'let text = "\\' > $@
+ sed -e 's/^ /\\032/' -e 's/$$/\\n\\/' help.txt >> $@
+ echo '";;' >> $@
+
+install:
+ if test -f ocamlbrowser$(EXE); then : ; \
+ cp ocamlbrowser$(EXE) $(BINDIR); fi
+
+clean:
+ rm -f *.cm? ocamlbrowser$(EXE) dummy.mli *~ *.orig *.$(O)
+
+depend:
+ $(CAMLDEP) *.ml *.mli > .depend
+
+shell.cmo: dummy.cmi
+setpath.cmo fileselect.cmo lexical.cmi searchid.cmi typecheck.cmi: $(TOPDIR)/toplevel/toplevellib.cma
+mytypes.cmi searchpos.cmi searchpos.cmo typecheck.cmo: $(TOPDIR)/typing/stypes.cmi
+
+include .depend
diff --git a/ocaml-binary-annot/otherlibs/labltk/browser/README b/ocaml-binary-annot/otherlibs/labltk/browser/README
new file mode 100644
index 0000000000..e8953541bf
--- /dev/null
+++ b/ocaml-binary-annot/otherlibs/labltk/browser/README
@@ -0,0 +1,170 @@
+
+ Installing and Using OCamlBrowser
+
+
+INSTALLATION
+ If you installed it with LablTk, nothing to do.
+ Otherwise, the source is in labltk/browser.
+ After installing LablTk, simply do "make" and "make install".
+ The name of the command is `ocamlbrowser'.
+
+USE
+ OCamlBrowser is composed of three tools, the Viewer, to walk around
+ compiled modules, the Editor, which allows one to
+ edit/typecheck/analyse .mli and .ml files, and the Shell, to run an
+ OCaml subshell. You may only have one instance of Editor and
+ Viewer, but you may use several subshells.
+
+ As with the compiler, you may specify a different path for the
+ standard library by setting CAMLLIB. You may also extend the
+ initial load path (only standard library by default) by using the
+ -I command line option, or set various other options (see -help).
+
+ If you prefered the old GUI, it is still available with the option
+ -oldui, otherwise you get a new Smalltalkish user interface.
+
+1) Viewer
+
+ Menus
+
+ File - Open and File - Editor give access to the editor.
+
+ File - Shell opens an OCaml shell.
+
+ View - Show all defs displays all the interface of the currently
+ selected module
+ View - Search entry shows/hides the search entry at the top of the
+ window
+
+ Modules - Path editor changes the load path.
+ Pressing [Add to path] or Insert key adds selected directories
+ to the load path.
+ Pressing [Remove from path] or Delete key removes selected
+ paths from the load path.
+ Modules - Reset cache rescans the load path and resets the module
+ cache. Do it if you recompile some interface, or change the load
+ path in a conflictual way.
+
+ Modules - Search symbol allows to search a symbol either by its
+ name, like the bottom line of the viewer, or, more
+ interestingly, by its type. Exact type searches for a type
+ with exactly the same information as the pattern (variables
+ match only variables), included type allows to give only
+ partial information: the actual type may take more arguments
+ and return more results, and variables in the pattern match
+ anything. In both cases, argument and tuple order is
+ irrelevant (*), and unlabeled arguments in the pattern match
+ any label.
+
+ (*) To avoid combinatorial explosion of the search space, optional
+ arguments in the actual type are ignored if (1) there are to many
+ of them, and (2) they do not appear explicitly in the pattern.
+
+ Search entry
+
+ The entry line at the top allows one to search for an identifier
+ in all modules, either by its name (? and * patterns allowed) or by
+ its type. When search by type is used, it is done in inclusion mode
+ (cf. Modules - search symbol)
+
+ The Close all button at the bottom is there to dismiss the windows
+ created by the Detach button. By double-clicking on it you will
+ quit the browser.
+
+ Module browsing
+
+ You select a module in the leftmost box by either cliking on it or
+ pressing return when it is selected. Fast access is available in
+ all boxes pressing the first few letter of the desired
+ name. Double-clicking / double-return displays the whole signature
+ for the module.
+
+ Defined identifiers inside the module are displayed in a box to the
+ right of the previous one. If you click on one, this will either
+ display its contents in another box (if this is a sub-module) or
+ display the signature for this identifier below.
+
+ Signatures are clickable. Double clicking with the left mouse
+ button on an identifier in a signature brings you to its signature.
+ A single click on the right button pops up a menu displaying the
+ type declaration for the selected identifier. Its title, when
+ selectable, also brings you to its signature.
+
+ At the bottom, a series of buttons, depending on the context.
+ * Detach copies the currently displayed signature in a new window,
+ to keep it. You can discard these windows with Close all.
+ * Impl and Intf bring you to the implementation or interface of
+ the currently displayed signature, if it is available.
+
+ C-s opens a text search dialog for the displayed signature.
+
+2) Editor
+ You can edit files with it, but there is no auto-save nor undo at
+ the moment. Otherwise you can use it as a browser, making
+ occasional corrections.
+
+ The Edit menu contains commands for jump (C-g), search (C-s), and
+ sending the current selection to a sub-shell (M-x). For this last
+ option, you may choose the shell via a dialog.
+
+ Essential function are in the Compiler menu.
+
+ Preferences opens a dialog to set internals of the editor and
+ type checker.
+
+ Lex (M-l) adds colors according to lexical categories.
+
+ Typecheck (M-t) verifies typing, and memorizes it to let one see an
+ expression's type by double-clicking on it. This is also valid for
+ interfaces. If an error occurs, the part of the interface preceding
+ the error is computed.
+
+ After typechecking, pressing the right button pops up a menu giving
+ the type of the pointed expression, and eventually allowing to
+ follow some links.
+
+ Clear errors dismisses type checker error messages and warnings.
+
+ Signature shows the signature of the current file.
+
+3) Shell
+ When you create a shell, a dialog is presented to you, letting you
+ choose which command you want to run, and the title of the shell
+ (to choose it in the Editor).
+
+ You may change the default command by setting the OLABL environment
+ variable.
+
+ The executed subshell is given the current load path.
+ File: use a source file or load a bytecode file.
+ You may also import the browser's path into the subprocess.
+ History: M-p and M-n browse up and down.
+ Signal: C-c interrupts and you can kill the subprocess.
+
+BUGS
+
+* This not really a bug, but OCamlBrowser is a huge memory consumer.
+ Go and buy some.
+
+* When you quit the editor and some file was modified, a dialogue is
+ displayed asking wether you want to really quit or not. But 1) if
+ you quit directly from the viewer, there is no dialogue at all, and
+ 2) if you close from the window manager, the dialogue is displayed,
+ but you cannot cancel the destruction... Beware.
+
+* When you run it through xon, the shell hangs at the first error. But
+ its ok if you start ocamlbrowser from a remote shell...
+
+TODO
+
+* Complete cross-references.
+
+* Power up editor.
+
+* Add support for the debugger.
+
+* Make this a real programming environment, both for beginners an
+ experimented users.
+
+
+Bug reports and comments to <garrigue@kurims.kyoto-u.ac.jp>
diff --git a/ocaml-binary-annot/otherlibs/labltk/browser/dummyUnix.mli b/ocaml-binary-annot/otherlibs/labltk/browser/dummyUnix.mli
new file mode 100644
index 0000000000..2272419236
--- /dev/null
+++ b/ocaml-binary-annot/otherlibs/labltk/browser/dummyUnix.mli
@@ -0,0 +1,27 @@
+(*************************************************************************)
+(* *)
+(* Objective Caml LablTk library *)
+(* *)
+(* Jacques Garrigue, Kyoto University RIMS *)
+(* *)
+(* Copyright 2000 Institut National de Recherche en Informatique et *)
+(* en Automatique and Kyoto University. All rights reserved. *)
+(* This file is distributed under the terms of the GNU Library *)
+(* General Public License, with the special exception on linking *)
+(* described in file ../../../LICENSE. *)
+(* *)
+(*************************************************************************)
+
+(* $Id$ *)
+
+module Mutex : sig
+ type t
+ external create : unit -> t = "%ignore"
+ external lock : t -> unit = "%ignore"
+ external unlock : t -> unit = "%ignore"
+end
+
+module Thread : sig
+ type t
+ external create : ('a -> 'b) -> 'a -> t = "caml_ml_input"
+end
diff --git a/ocaml-binary-annot/otherlibs/labltk/browser/dummyWin.mli b/ocaml-binary-annot/otherlibs/labltk/browser/dummyWin.mli
new file mode 100644
index 0000000000..a4b75ee37b
--- /dev/null
+++ b/ocaml-binary-annot/otherlibs/labltk/browser/dummyWin.mli
@@ -0,0 +1,15 @@
+(*************************************************************************)
+(* *)
+(* Objective Caml LablTk library *)
+(* *)
+(* Jacques Garrigue, Kyoto University RIMS *)
+(* *)
+(* Copyright 2000 Institut National de Recherche en Informatique et *)
+(* en Automatique and Kyoto University. All rights reserved. *)
+(* This file is distributed under the terms of the GNU Library *)
+(* General Public License, with the special exception on linking *)
+(* described in file ../../../LICENSE. *)
+(* *)
+(*************************************************************************)
+
+(* $Id$ *)
diff --git a/ocaml-binary-annot/otherlibs/labltk/browser/editor.ml b/ocaml-binary-annot/otherlibs/labltk/browser/editor.ml
new file mode 100644
index 0000000000..617cdfa855
--- /dev/null
+++ b/ocaml-binary-annot/otherlibs/labltk/browser/editor.ml
@@ -0,0 +1,667 @@
+(*************************************************************************)
+(* *)
+(* Objective Caml LablTk library *)
+(* *)
+(* Jacques Garrigue, Kyoto University RIMS *)
+(* *)
+(* Copyright 1999 Institut National de Recherche en Informatique et *)
+(* en Automatique and Kyoto University. All rights reserved. *)
+(* This file is distributed under the terms of the GNU Library *)
+(* General Public License, with the special exception on linking *)
+(* described in file ../../../LICENSE. *)
+(* *)
+(*************************************************************************)
+
+(* $Id$ *)
+
+open StdLabels
+open Tk
+open Parsetree
+open Location
+open Jg_tk
+open Mytypes
+
+let lex_on_load = ref true
+and type_on_load = ref false
+
+let compiler_preferences master =
+ let tl = Jg_toplevel.titled "Compiler" in
+ Wm.transient_set tl ~master;
+ let mk_chkbutton ~text ~ref ~invert =
+ let variable = Textvariable.create ~on:tl () in
+ if (if invert then not !ref else !ref) then
+ Textvariable.set variable "1";
+ Checkbutton.create tl ~text ~variable,
+ (fun () ->
+ ref := Textvariable.get variable = (if invert then "0" else "1"))
+ in
+ let use_pp = ref (!Clflags.preprocessor <> None) in
+ let chkbuttons, setflags = List.split
+ (List.map
+ ~f:(fun (text, ref, invert) -> mk_chkbutton ~text ~ref ~invert)
+ [ "No pervasives", Clflags.nopervasives, false;
+ "No warnings", Typecheck.nowarnings, false;
+ "No labels", Clflags.classic, false;
+ "Recursive types", Clflags.recursive_types, false;
+ "Lex on load", lex_on_load, false;
+ "Type on load", type_on_load, false;
+ "Preprocessor", use_pp, false ])
+ in
+ let pp_command = Entry.create tl (* ~state:(if !use_pp then `Normal else`Disabled) *) in
+ begin match !Clflags.preprocessor with None -> ()
+ | Some pp -> Entry.insert pp_command ~index:(`Num 0) ~text:pp
+ end;
+ let buttons = Frame.create tl in
+ let ok = Button.create buttons ~text:"Ok" ~padx:20 ~command:
+ begin fun () ->
+ List.iter ~f:(fun f -> f ()) setflags;
+ Clflags.preprocessor :=
+ if !use_pp then Some (Entry.get pp_command) else None;
+ destroy tl
+ end
+ and cancel = Jg_button.create_destroyer tl ~parent:buttons ~text:"Cancel"
+ in
+ pack chkbuttons ~side:`Top ~anchor:`W;
+ pack [pp_command] ~side:`Top ~anchor:`E;
+ pack [ok;cancel] ~side:`Left ~fill:`X ~expand:true;
+ pack [buttons] ~side:`Bottom ~fill:`X
+
+let rec exclude txt = function
+ [] -> []
+ | x :: l -> if txt.number = x.number then l else x :: exclude txt l
+
+let goto_line tw =
+ let tl = Jg_toplevel.titled "Go to" in
+ Wm.transient_set tl ~master:(Winfo.toplevel tw);
+ Jg_bind.escape_destroy tl;
+ let ef = Frame.create tl in
+ let fl = Frame.create ef
+ and fi = Frame.create ef in
+ let ll = Label.create fl ~text:"Line ~number:"
+ and il = Entry.create fi ~width:10
+ and lc = Label.create fl ~text:"Col ~number:"
+ and ic = Entry.create fi ~width:10
+ and get_int ew =
+ try int_of_string (Entry.get ew)
+ with Failure "int_of_string" -> 0
+ in
+ let buttons = Frame.create tl in
+ let ok = Button.create buttons ~text:"Ok" ~command:
+ begin fun () ->
+ let l = get_int il
+ and c = get_int ic in
+ Text.mark_set tw ~mark:"insert" ~index:(`Linechar (l,0), [`Char c]);
+ Text.see tw ~index:(`Mark "insert", []);
+ destroy tl
+ end
+ and cancel = Jg_button.create_destroyer tl ~parent:buttons ~text:"Cancel" in
+
+ Focus.set il;
+ List.iter [il; ic] ~f:
+ begin fun w ->
+ Jg_bind.enter_focus w;
+ Jg_bind.return_invoke w ~button:ok
+ end;
+ pack [ll; lc] ~side:`Top ~anchor:`W;
+ pack [il; ic] ~side:`Top ~fill:`X ~expand:true;
+ pack [fl; fi] ~side:`Left ~fill:`X ~expand:true;
+ pack [ok; cancel] ~side:`Left ~fill:`X ~expand:true;
+ pack [ef; buttons] ~side:`Top ~fill:`X ~expand:true
+
+let select_shell txt =
+ let shells = Shell.get_all () in
+ let shells = List.sort shells ~cmp:compare in
+ let tl = Jg_toplevel.titled "Select Shell" in
+ Jg_bind.escape_destroy tl;
+ Wm.transient_set tl ~master:(Winfo.toplevel txt.tw);
+ let label = Label.create tl ~text:"Send to:"
+ and box = Listbox.create tl
+ and frame = Frame.create tl in
+ Jg_bind.enter_focus box;
+ let cancel = Jg_button.create_destroyer tl ~parent:frame ~text:"Cancel"
+ and ok = Button.create frame ~text:"Ok" ~command:
+ begin fun () ->
+ try
+ let name = Listbox.get box ~index:`Active in
+ txt.shell <- Some (name, List.assoc name shells);
+ destroy tl
+ with Not_found -> txt.shell <- None; destroy tl
+ end
+ in
+ Listbox.insert box ~index:`End ~texts:(List.map ~f:fst shells);
+ Listbox.configure box ~height:(List.length shells);
+ bind box ~events:[`KeyPressDetail"Return"] ~breakable:true
+ ~action:(fun _ -> Button.invoke ok; break ());
+ bind box ~events:[`Modified([`Double],`ButtonPressDetail 1)] ~breakable:true
+ ~fields:[`MouseX;`MouseY]
+ ~action:(fun ev ->
+ Listbox.activate box ~index:(`Atxy (ev.ev_MouseX, ev.ev_MouseY));
+ Button.invoke ok; break ());
+ pack [label] ~side:`Top ~anchor:`W;
+ pack [box] ~side:`Top ~fill:`Both;
+ pack [frame] ~side:`Bottom ~fill:`X ~expand:true;
+ pack [ok;cancel] ~side:`Left ~fill:`X ~expand:true
+
+open Parser
+
+let send_phrase txt =
+ if txt.shell = None then begin
+ match Shell.get_all () with [] -> ()
+ | [sh] -> txt.shell <- Some sh
+ | l -> select_shell txt
+ end;
+ match txt.shell with None -> ()
+ | Some (_,sh) ->
+ try
+ let i1,i2 = Text.tag_nextrange txt.tw ~tag:"sel" ~start:tstart in
+ let phrase = Text.get txt.tw ~start:(i1,[]) ~stop:(i2,[]) in
+ sh#send phrase;
+ if Str.string_match (Str.regexp ";;") phrase 0
+ then sh#send "\n" else sh#send ";;\n"
+ with Not_found | Protocol.TkError _ ->
+ let text = Text.get txt.tw ~start:tstart ~stop:tend in
+ let buffer = Lexing.from_string text in
+ let start = ref 0
+ and block_start = ref []
+ and pend = ref (-1)
+ and after = ref false in
+ while !pend = -1 do
+ let token = Lexer.token buffer in
+ let pos =
+ if token = SEMISEMI then Lexing.lexeme_end buffer
+ else Lexing.lexeme_start buffer
+ in
+ let bol = (pos = 0) || text.[pos-1] = '\n' in
+ if not !after &&
+ Text.compare txt.tw ~index:(tpos pos) ~op:(if bol then `Gt else `Ge)
+ ~index:(`Mark"insert",[])
+ then begin
+ after := true;
+ let anon, real =
+ List.partition !block_start ~f:(fun x -> x = -1) in
+ block_start := anon;
+ if real <> [] then start := List.hd real;
+ end;
+ match token with
+ CLASS | EXTERNAL | EXCEPTION | FUNCTOR
+ | LET | MODULE | OPEN | TYPE | VAL | SHARP when bol ->
+ if !block_start = [] then
+ if !after then pend := pos else start := pos
+ else block_start := pos :: List.tl !block_start
+ | SEMISEMI ->
+ if !block_start = [] then
+ if !after then pend := Lexing.lexeme_start buffer
+ else start := pos
+ else block_start := pos :: List.tl !block_start
+ | BEGIN | OBJECT ->
+ block_start := -1 :: !block_start
+ | STRUCT | SIG ->
+ block_start := Lexing.lexeme_end buffer :: !block_start
+ | END ->
+ if !block_start = [] then
+ if !after then pend := pos else ()
+ else block_start := List.tl !block_start
+ | EOF ->
+ pend := pos
+ | _ ->
+ ()
+ done;
+ let phrase = String.sub text ~pos:!start ~len:(!pend - !start) in
+ sh#send phrase;
+ sh#send ";;\n"
+
+let search_pos_window txt ~x ~y =
+ if txt.type_info = [] && txt.psignature = [] then () else
+ let `Linechar (l, c) = Text.index txt.tw ~index:(`Atxy(x,y), []) in
+ let text = Jg_text.get_all txt.tw in
+ let pos = Searchpos.lines_to_chars l ~text + c in
+ try if txt.type_info <> [] then begin match
+ Searchpos.search_pos_info txt.type_info ~pos
+ with [] -> ()
+ | (kind, env, loc) :: _ -> Searchpos.view_type kind ~env
+ end else begin match
+ Searchpos.search_pos_signature txt.psignature ~pos ~env:!Searchid.start_env
+ with [] -> ()
+ | ((kind, lid), env, loc) :: _ ->
+ Searchpos.view_decl lid ~kind ~env
+ end
+ with Not_found -> ()
+
+let search_pos_menu txt ~x ~y =
+ if txt.type_info = [] && txt.psignature = [] then () else
+ let `Linechar (l, c) = Text.index txt.tw ~index:(`Atxy(x,y), []) in
+ let text = Jg_text.get_all txt.tw in
+ let pos = Searchpos.lines_to_chars l ~text + c in
+ try if txt.type_info <> [] then begin match
+ Searchpos.search_pos_info txt.type_info ~pos
+ with [] -> ()
+ | (kind, env, loc) :: _ ->
+ let menu = Searchpos.view_type_menu kind ~env ~parent:txt.tw in
+ let x = x + Winfo.rootx txt.tw and y = y + Winfo.rooty txt.tw - 10 in
+ Menu.popup menu ~x ~y
+ end else begin match
+ Searchpos.search_pos_signature txt.psignature ~pos ~env:!Searchid.start_env
+ with [] -> ()
+ | ((kind, lid), env, loc) :: _ ->
+ let menu = Searchpos.view_decl_menu lid ~kind ~env ~parent:txt.tw in
+ let x = x + Winfo.rootx txt.tw and y = y + Winfo.rooty txt.tw - 10 in
+ Menu.popup menu ~x ~y
+ end
+ with Not_found -> ()
+
+let string_width s =
+ let width = ref 0 in
+ for i = 0 to String.length s - 1 do
+ if s.[i] = '\t' then width := (!width / 8 + 1) * 8
+ else incr width
+ done;
+ !width
+
+let indent_line =
+ let ins = `Mark"insert" and reg = Str.regexp "[ \t]*" in
+ fun tw ->
+ let `Linechar(l,c) = Text.index tw ~index:(ins,[])
+ and line = Text.get tw ~start:(ins,[`Linestart]) ~stop:(ins,[`Lineend]) in
+ ignore (Str.string_match reg line 0);
+ let len = Str.match_end () in
+ if len < c then Text.insert tw ~index:(ins,[]) ~text:"\t" else
+ let width = string_width (Str.matched_string line) in
+ Text.mark_set tw ~mark:"insert" ~index:(ins,[`Linestart;`Char len]);
+ let indent =
+ if l <= 1 then 2 else
+ let previous =
+ Text.get tw ~start:(ins,[`Line(-1);`Linestart])
+ ~stop:(ins,[`Line(-1);`Lineend]) in
+ ignore (Str.string_match reg previous 0);
+ let previous = Str.matched_string previous in
+ let width_previous = string_width previous in
+ if width_previous <= width then 2 else width_previous - width
+ in
+ Text.insert tw ~index:(ins,[]) ~text:(String.make indent ' ')
+
+(* The editor class *)
+
+class editor ~top ~menus = object (self)
+ val file_menu = new Jg_menu.c "File" ~parent:menus
+ val edit_menu = new Jg_menu.c "Edit" ~parent:menus
+ val compiler_menu = new Jg_menu.c "Compiler" ~parent:menus
+ val module_menu = new Jg_menu.c "Modules" ~parent:menus
+ val window_menu = new Jg_menu.c "Windows" ~parent:menus
+ initializer
+ Menu.add_checkbutton menus ~state:`Disabled
+ ~onvalue:"modified" ~offvalue:"unchanged"
+ val mutable current_dir = Unix.getcwd ()
+ val mutable error_messages = []
+ val mutable windows = []
+ val mutable current_tw = Text.create top
+ val vwindow = Textvariable.create ~on:top ()
+ val mutable window_counter = 0
+
+ method has_window name =
+ List.exists windows ~f:(fun x -> x.name = name)
+
+ method reset_window_menu =
+ Menu.delete window_menu#menu ~first:(`Num 0) ~last:`End;
+ List.iter
+ (List.sort windows ~cmp:
+ (fun w1 w2 ->
+ compare (Filename.basename w1.name) (Filename.basename w2.name)))
+ ~f:
+ begin fun txt ->
+ Menu.add_radiobutton window_menu#menu
+ ~label:(Filename.basename txt.name)
+ ~variable:vwindow ~value:txt.number
+ ~command:(fun () -> self#set_edit txt)
+ end
+
+ method set_file_name txt =
+ Menu.configure_checkbutton menus `Last
+ ~label:(Filename.basename txt.name)
+ ~variable:txt.modified
+
+ method set_edit txt =
+ if windows <> [] then
+ Pack.forget [(List.hd windows).frame];
+ windows <- txt :: exclude txt windows;
+ self#reset_window_menu;
+ current_tw <- txt.tw;
+ self#set_file_name txt;
+ Textvariable.set vwindow txt.number;
+ Text.yview txt.tw ~scroll:(`Page 0);
+ pack [txt.frame] ~fill:`Both ~expand:true ~side:`Bottom
+
+ method new_window name =
+ let tl, tw, sb = Jg_text.create_with_scrollbar top in
+ Text.configure tw ~background:`White;
+ Jg_bind.enter_focus tw;
+ window_counter <- window_counter + 1;
+ let txt =
+ { name = name; tw = tw; frame = tl;
+ number = string_of_int window_counter;
+ modified = Textvariable.create ~on:tw ();
+ shell = None;
+ structure = []; type_info = []; signature = []; psignature = [] }
+ in
+ let control c = Char.chr (Char.code c - 96) in
+ bind tw ~events:[`Modified([`Alt], `KeyPress)] ~action:ignore;
+ bind tw ~events:[`KeyPress] ~fields:[`Char]
+ ~action:(fun ev ->
+ if ev.ev_Char <> "" &&
+ (ev.ev_Char.[0] >= ' ' ||
+ List.mem ev.ev_Char.[0]
+ (List.map ~f:control ['d'; 'h'; 'i'; 'k'; 'o'; 't'; 'w'; 'y']))
+ then Textvariable.set txt.modified "modified");
+ bind tw ~events:[`KeyPressDetail"Tab"] ~breakable:true
+ ~action:(fun _ ->
+ indent_line tw;
+ Textvariable.set txt.modified "modified";
+ break ());
+ bind tw ~events:[`Modified([`Control],`KeyPressDetail"k")]
+ ~action:(fun _ ->
+ let text =
+ Text.get tw ~start:(`Mark"insert",[]) ~stop:(`Mark"insert",[`Lineend])
+ in ignore (Str.string_match (Str.regexp "[ \t]*") text 0);
+ if Str.match_end () <> String.length text then begin
+ Clipboard.clear ();
+ Clipboard.append ~data:text ()
+ end);
+ bind tw ~events:[`KeyRelease] ~fields:[`Char]
+ ~action:(fun ev ->
+ if ev.ev_Char <> "" then
+ Lexical.tag tw ~start:(`Mark"insert", [`Linestart])
+ ~stop:(`Mark"insert", [`Lineend]));
+ bind tw ~events:[`Motion] ~action:(fun _ -> Focus.set tw);
+ bind tw ~events:[`ButtonPressDetail 2]
+ ~action:(fun _ ->
+ Textvariable.set txt.modified "modified";
+ Lexical.tag txt.tw ~start:(`Mark"insert", [`Linestart])
+ ~stop:(`Mark"insert", [`Lineend]));
+ bind tw ~events:[`Modified([`Double], `ButtonPressDetail 1)]
+ ~fields:[`MouseX;`MouseY]
+ ~action:(fun ev -> search_pos_window txt ~x:ev.ev_MouseX ~y:ev.ev_MouseY);
+ bind tw ~events:[`ButtonPressDetail 3] ~fields:[`MouseX;`MouseY]
+ ~action:(fun ev -> search_pos_menu txt ~x:ev.ev_MouseX ~y:ev.ev_MouseY);
+
+ pack [sb] ~fill:`Y ~side:`Right;
+ pack [tw] ~fill:`Both ~expand:true ~side:`Left;
+ self#set_edit txt;
+ Textvariable.set txt.modified "unchanged";
+ Lexical.init_tags txt.tw
+
+ method clear_errors () =
+ Text.tag_remove current_tw ~tag:"error" ~start:tstart ~stop:tend;
+ List.iter error_messages
+ ~f:(fun tl -> try destroy tl with Protocol.TkError _ -> ());
+ error_messages <- []
+
+ method typecheck () =
+ self#clear_errors ();
+ error_messages <- Typecheck.f (List.hd windows)
+
+ method lex () =
+ List.iter [ Widget.default_toplevel; top ]
+ ~f:(Toplevel.configure ~cursor:(`Xcursor "watch"));
+ Text.configure current_tw ~cursor:(`Xcursor "watch");
+ ignore (Timer.add ~ms:1 ~callback:
+ begin fun () ->
+ Text.tag_remove current_tw ~tag:"error" ~start:tstart ~stop:tend;
+ Lexical.tag current_tw;
+ Text.configure current_tw ~cursor:(`Xcursor "xterm");
+ List.iter [ Widget.default_toplevel; top ]
+ ~f:(Toplevel.configure ~cursor:(`Xcursor ""))
+ end)
+
+ method save_text ?name:l txt =
+ let l = match l with None -> [txt.name] | Some l -> l in
+ if l = [] then () else
+ let name = List.hd l in
+ if txt.name <> name then current_dir <- Filename.dirname name;
+ try
+ if Sys.file_exists name then
+ if txt.name = name then begin
+ let backup = name ^ "~" in
+ if Sys.file_exists backup then Sys.remove backup;
+ try Sys.rename name backup with Sys_error _ -> ()
+ end else begin
+ match Jg_message.ask ~master:top ~title:"Save"
+ ("File `" ^ name ^ "' exists. Overwrite it?")
+ with `Yes -> Sys.remove name
+ | `No -> raise (Sys_error "")
+ | `Cancel -> raise Exit
+ end;
+ let file = open_out name in
+ let text = Text.get txt.tw ~start:tstart ~stop:(tposend 1) in
+ output_string file text;
+ close_out file;
+ txt.name <- name;
+ self#set_file_name txt
+ with
+ Sys_error _ ->
+ Jg_message.info ~master:top ~title:"Error"
+ ("Could not save `" ^ name ^ "'.")
+ | Exit -> ()
+
+ method load_text l =
+ if l = [] then () else
+ let name = List.hd l in
+ try
+ let index =
+ try
+ self#set_edit (List.find windows ~f:(fun x -> x.name = name));
+ let txt = List.hd windows in
+ if Textvariable.get txt.modified = "modified" then
+ begin match Jg_message.ask ~master:top ~title:"Open"
+ ("`" ^ Filename.basename txt.name ^ "' modified. Save it?")
+ with `Yes -> self#save_text txt
+ | `No -> ()
+ | `Cancel -> raise Exit
+ end;
+ Textvariable.set txt.modified "unchanged";
+ (Text.index current_tw ~index:(`Mark"insert", []), [])
+ with Not_found -> self#new_window name; tstart
+ in
+ current_dir <- Filename.dirname name;
+ let file = open_in name
+ and tw = current_tw
+ and len = ref 0
+ and buf = String.create 4096 in
+ Text.delete tw ~start:tstart ~stop:tend;
+ while
+ len := input file buf 0 4096;
+ !len > 0
+ do
+ Jg_text.output tw ~buf ~pos:0 ~len:!len
+ done;
+ close_in file;
+ Text.mark_set tw ~mark:"insert" ~index;
+ Text.see tw ~index;
+ if Filename.check_suffix name ".ml" ||
+ Filename.check_suffix name ".mli"
+ then begin
+ if !lex_on_load then self#lex ();
+ if !type_on_load then self#typecheck ()
+ end
+ with
+ Sys_error _ | Exit -> ()
+
+ method close_window txt =
+ try
+ if Textvariable.get txt.modified = "modified" then
+ begin match Jg_message.ask ~master:top ~title:"Close"
+ ("`" ^ Filename.basename txt.name ^ "' modified. Save it?")
+ with `Yes -> self#save_text txt
+ | `No -> ()
+ | `Cancel -> raise Exit
+ end;
+ windows <- exclude txt windows;
+ if windows = [] then
+ self#new_window (current_dir ^ "/untitled")
+ else self#set_edit (List.hd windows);
+ destroy txt.frame
+ with Exit -> ()
+
+ method open_file () =
+ Fileselect.f ~title:"Open File" ~action:self#load_text
+ ~dir:current_dir ~filter:("*.{ml,mli}") ~sync:true ()
+
+ method save_file () = self#save_text (List.hd windows)
+
+ method close_file () = self#close_window (List.hd windows)
+
+ method quit ?(cancel=true) () =
+ try
+ List.iter windows ~f:
+ begin fun txt ->
+ if Textvariable.get txt.modified = "modified" then
+ match Jg_message.ask ~master:top ~title:"Quit" ~cancel
+ ("`" ^ Filename.basename txt.name ^ "' modified. Save it?")
+ with `Yes -> self#save_text txt
+ | `No -> ()
+ | `Cancel -> raise Exit
+ end;
+ bind top ~events:[`Destroy];
+ destroy top
+ with Exit -> ()
+
+ method reopen ~file ~pos =
+ if not (Winfo.ismapped top) then Wm.deiconify top;
+ match file with None -> ()
+ | Some file ->
+ self#load_text [file];
+ Text.mark_set current_tw ~mark:"insert" ~index:(tpos pos);
+ try
+ let index =
+ Text.search current_tw ~switches:[`Backwards] ~pattern:"*)"
+ ~start:(tpos pos) ~stop:(tpos pos ~modi:[`Line(-1)]) in
+ let index =
+ Text.search current_tw ~switches:[`Backwards] ~pattern:"(*"
+ ~start:(index,[]) ~stop:(tpos pos ~modi:[`Line(-20)]) in
+ let s = Text.get current_tw ~start:(index,[`Line(-1);`Linestart])
+ ~stop:(index,[`Line(-1);`Lineend]) in
+ for i = 0 to String.length s - 1 do
+ match s.[i] with '\t'|' ' -> () | _ -> raise Not_found
+ done;
+ Text.yview_index current_tw ~index:(index,[`Line(-1)])
+ with _ ->
+ Text.yview_index current_tw ~index:(tpos pos ~modi:[`Line(-2)])
+
+ initializer
+ (* Create a first window *)
+ self#new_window (current_dir ^ "/untitled");
+
+ (* Bindings for the main window *)
+ List.iter
+ [ [`Control], "s", (fun () -> Jg_text.search_string current_tw);
+ [`Control], "g", (fun () -> goto_line current_tw);
+ [`Alt], "s", self#save_file;
+ [`Alt], "x", (fun () -> send_phrase (List.hd windows));
+ [`Alt], "l", self#lex;
+ [`Alt], "t", self#typecheck ]
+ ~f:begin fun (modi,key,act) ->
+ bind top ~events:[`Modified(modi, `KeyPressDetail key)] ~breakable:true
+ ~action:(fun _ -> act (); break ())
+ end;
+
+ bind top ~events:[`Destroy] ~fields:[`Widget] ~action:
+ begin fun ev ->
+ if Widget.name ev.ev_Widget = Widget.name top
+ then self#quit ~cancel:false ()
+ end;
+
+ (* File menu *)
+ file_menu#add_command "Open File..." ~command:self#open_file;
+ file_menu#add_command "Reopen"
+ ~command:(fun () -> self#load_text [(List.hd windows).name]);
+ file_menu#add_command "Save File" ~command:self#save_file ~accelerator:"M-s";
+ file_menu#add_command "Save As..." ~underline:5 ~command:
+ begin fun () ->
+ let txt = List.hd windows in
+ Fileselect.f ~title:"Save as File"
+ ~action:(fun name -> self#save_text txt ~name)
+ ~dir:(Filename.dirname txt.name)
+ ~filter:"*.{ml,mli}"
+ ~file:(Filename.basename txt.name)
+ ~sync:true ~usepath:false ()
+ end;
+ file_menu#add_command "Close File" ~command:self#close_file;
+ file_menu#add_command "Close Window" ~command:self#quit ~underline:6;
+
+ (* Edit menu *)
+ edit_menu#add_command "Paste selection" ~command:
+ begin fun () ->
+ Text.insert current_tw ~index:(`Mark"insert",[])
+ ~text:(Selection.get ~displayof:top ())
+ end;
+ edit_menu#add_command "Goto..." ~accelerator:"C-g"
+ ~command:(fun () -> goto_line current_tw);
+ edit_menu#add_command "Search..." ~accelerator:"C-s"
+ ~command:(fun () -> Jg_text.search_string current_tw);
+ edit_menu#add_command "To shell" ~accelerator:"M-x"
+ ~command:(fun () -> send_phrase (List.hd windows));
+ edit_menu#add_command "Select shell..."
+ ~command:(fun () -> select_shell (List.hd windows));
+
+ (* Compiler menu *)
+ compiler_menu#add_command "Preferences..."
+ ~command:(fun () -> compiler_preferences top);
+ compiler_menu#add_command "Lex" ~accelerator:"M-l"
+ ~command:self#lex;
+ compiler_menu#add_command "Typecheck" ~accelerator:"M-t"
+ ~command:self#typecheck;
+ compiler_menu#add_command "Clear errors"
+ ~command:self#clear_errors;
+ compiler_menu#add_command "Signature..." ~command:
+ begin fun () ->
+ let txt = List.hd windows in if txt.signature <> [] then
+ let basename = Filename.basename txt.name in
+ let modname = String.capitalize
+ (try Filename.chop_extension basename with _ -> basename) in
+ let env =
+ Env.add_module (Ident.create modname)
+ (Types.Tmty_signature txt.signature)
+ Env.initial
+ in Viewer.view_defined (Longident.Lident modname) ~env ~show_all:true
+ end;
+
+ (* Modules *)
+ module_menu#add_command "Path editor..."
+ ~command:(fun () -> Setpath.set ~dir:current_dir);
+ module_menu#add_command "Reset cache"
+ ~command:(fun () -> Setpath.exec_update_hooks (); Env.reset_cache ());
+ module_menu#add_command "Search symbol..."
+ ~command:Viewer.search_symbol;
+ module_menu#add_command "Close all"
+ ~command:Viewer.close_all_views;
+end
+
+(* The main function starts here ! *)
+
+let already_open : editor list ref = ref []
+
+let editor ?file ?(pos=0) ?(reuse=false) () =
+
+ if !already_open <> [] &&
+ let ed = List.hd !already_open
+ (* try
+ let name = match file with Some f -> f | None -> raise Not_found in
+ List.find !already_open ~f:(fun ed -> ed#has_window name)
+ with Not_found -> List.hd !already_open *)
+ in try
+ ed#reopen ~file ~pos;
+ true
+ with Protocol.TkError _ ->
+ already_open := [] (* List.filter !already_open ~f:((<>) ed) *);
+ false
+ then () else
+ let top = Jg_toplevel.titled "OCamlBrowser Editor" in
+ let menus = Jg_menu.menubar top in
+ let ed = new editor ~top ~menus in
+ already_open := !already_open @ [ed];
+ if file <> None then ed#reopen ~file ~pos
+
+let f ?file ?pos ?(opendialog=false) () =
+ if opendialog then
+ Fileselect.f ~title:"Open File"
+ ~action:(function [file] -> editor ~file () | _ -> ())
+ ~filter:("*.{ml,mli}") ~sync:true ()
+ else editor ?file ?pos ~reuse:(file <> None) ()
diff --git a/ocaml-binary-annot/otherlibs/labltk/browser/editor.mli b/ocaml-binary-annot/otherlibs/labltk/browser/editor.mli
new file mode 100644
index 0000000000..665ee813f3
--- /dev/null
+++ b/ocaml-binary-annot/otherlibs/labltk/browser/editor.mli
@@ -0,0 +1,20 @@
+(*************************************************************************)
+(* *)
+(* Objective Caml LablTk library *)
+(* *)
+(* Jacques Garrigue, Kyoto University RIMS *)
+(* *)
+(* Copyright 1999 Institut National de Recherche en Informatique et *)
+(* en Automatique and Kyoto University. All rights reserved. *)
+(* This file is distributed under the terms of the GNU Library *)
+(* General Public License, with the special exception on linking *)
+(* described in file ../../../LICENSE. *)
+(* *)
+(*************************************************************************)
+
+(* $Id$ *)
+
+open Widget
+
+val f : ?file:string -> ?pos:int -> ?opendialog:bool -> unit -> unit
+ (* open the file editor *)
diff --git a/ocaml-binary-annot/otherlibs/labltk/browser/fileselect.ml b/ocaml-binary-annot/otherlibs/labltk/browser/fileselect.ml
new file mode 100644
index 0000000000..22052b4237
--- /dev/null
+++ b/ocaml-binary-annot/otherlibs/labltk/browser/fileselect.ml
@@ -0,0 +1,290 @@
+(*************************************************************************)
+(* *)
+(* Objective Caml LablTk library *)
+(* *)
+(* Jacques Garrigue, Kyoto University RIMS *)
+(* *)
+(* Copyright 1999 Institut National de Recherche en Informatique et *)
+(* en Automatique and Kyoto University. All rights reserved. *)
+(* This file is distributed under the terms of the GNU Library *)
+(* General Public License, with the special exception on linking *)
+(* described in file ../../../LICENSE. *)
+(* *)
+(*************************************************************************)
+
+(* $Id$ *)
+
+(* file selection box *)
+
+open StdLabels
+open Str
+open Filename
+open Tk
+
+open Useunix
+
+(**** Memoized rexgexp *)
+
+let (~!) = Jg_memo.fast ~f:Str.regexp
+
+(************************************************************ Path name *)
+
+(* Convert Windows-style directory separator '\' to caml-style '/' *)
+let caml_dir path =
+ if Sys.os_type = "Win32" then
+ global_replace ~!"\\\\" "/" path
+ else path
+
+let parse_filter s =
+ let s = caml_dir s in
+ (* replace // by / *)
+ let s = global_replace ~!"/+" "/" s in
+ (* replace /./ by / *)
+ let s = global_replace ~!"/\\./" "/" s in
+ (* replace hoge/../ by "" *)
+ let s = global_replace
+ ~!"\\([^/]\\|[^\\./][^/]\\|[^/][^\\./]\\|[^/][^/]+\\)/\\.\\./" "" s in
+ (* replace hoge/..$ by *)
+ let s = global_replace
+ ~!"\\([^/]\\|[^\\./][^/]\\|[^/][^\\./]\\|[^/][^/]+\\)/\\.\\.$" "" s in
+ (* replace ^/hoge/../ by / *)
+ let s = global_replace ~!"^\\(/\\.\\.\\)+/" "/" s in
+ if string_match ~!"^\\([^\\*?[]*[/:]\\)\\(.*\\)" s 0 then
+ let dirs = matched_group 1 s
+ and ptrn = matched_group 2 s
+ in
+ dirs, ptrn
+ else "", s
+
+let rec fixpoint ~f v =
+ let v' = f v in
+ if v = v' then v else fixpoint ~f v'
+
+let unix_regexp s =
+ let s = Str.global_replace ~!"[$^.+]" "\\\\\\0" s in
+ let s = Str.global_replace ~!"\\*" ".*" s in
+ let s = Str.global_replace ~!"\\?" ".?" s in
+ let s =
+ fixpoint s
+ ~f:(Str.replace_first ~!"\\({.*\\),\\(.*}\\)" "\\1\\|\\2") in
+ let s =
+ Str.global_replace ~!"{\\(.*\\)}" "\\(\\1\\)" s in
+ Str.regexp s
+
+let exact_match ~pat s =
+ Str.string_match pat s 0 && Str.match_end () = String.length s
+
+let ls ~dir ~pattern =
+ let files = get_files_in_directory dir in
+ let regexp = unix_regexp pattern in
+ List.filter files ~f:(exact_match ~pat:regexp)
+
+(********************************************* Creation *)
+let load_in_path = ref false
+
+let search_in_path ~name = Misc.find_in_path !Config.load_path name
+
+let f ~title ~action:proc ?(dir = Unix.getcwd ())
+ ?filter:(deffilter ="*") ?file:(deffile ="")
+ ?(multi=false) ?(sync=false) ?(usepath=true) () =
+
+ let current_pattern = ref ""
+ and current_dir = ref (caml_dir dir) in
+
+ let may_prefix name =
+ if Filename.is_relative name then concat !current_dir name else name in
+
+ let tl = Jg_toplevel.titled title in
+ Focus.set tl;
+
+ let new_var () = Textvariable.create ~on:tl () in
+ let filter_var = new_var ()
+ and selection_var = new_var ()
+ and sync_var = new_var () in
+ Textvariable.set filter_var deffilter;
+
+ let frm = Frame.create tl ~borderwidth:1 ~relief:`Raised in
+ let df = Frame.create frm in
+ let dfl = Frame.create df in
+ let dfll = Label.create dfl ~text:"Directories" in
+ let dflf, directory_listbox, directory_scrollbar =
+ Jg_box.create_with_scrollbar dfl in
+ let dfr = Frame.create df in
+ let dfrl = Label.create dfr ~text:"Files" in
+ let dfrf, filter_listbox, filter_scrollbar =
+ Jg_box.create_with_scrollbar dfr in
+ let cfrm = Frame.create tl ~borderwidth:1 ~relief:`Raised in
+
+ let configure ~filter =
+ let filter = may_prefix filter in
+ let dir, pattern = parse_filter filter in
+ let dir = if !load_in_path && usepath then "" else
+ (current_dir := Filename.dirname dir; dir)
+ and pattern = if pattern = "" then "*" else pattern in
+ current_pattern := pattern;
+ let filter =
+ if !load_in_path && usepath then pattern else dir ^ pattern in
+ let directories = get_directories_in_files ~path:dir
+ (get_files_in_directory dir) in
+ let matched_files = (* get matched file by subshell call. *)
+ if !load_in_path && usepath then
+ List.fold_left !Config.load_path ~init:[] ~f:
+ begin fun acc dir ->
+ let files = ls ~dir ~pattern in
+ Sort.merge (<) files
+ (List.fold_left files ~init:acc
+ ~f:(fun acc name -> List2.exclude name acc))
+ end
+ else
+ List.fold_left directories ~init:(ls ~dir ~pattern)
+ ~f:(fun acc dir -> List2.exclude dir acc)
+ in
+ Textvariable.set filter_var filter;
+ Textvariable.set selection_var (dir ^ deffile);
+ Listbox.delete filter_listbox ~first:(`Num 0) ~last:`End;
+ Listbox.insert filter_listbox ~index:`End ~texts:matched_files;
+ Jg_box.recenter filter_listbox ~index:(`Num 0);
+ if !load_in_path && usepath then
+ Listbox.configure directory_listbox ~takefocus:false
+ else
+ begin
+ Listbox.configure directory_listbox ~takefocus:true;
+ Listbox.delete directory_listbox ~first:(`Num 0) ~last:`End;
+ Listbox.insert directory_listbox ~index:`End ~texts:directories;
+ Jg_box.recenter directory_listbox ~index:(`Num 0)
+ end
+ in
+
+ let selected_files = ref [] in (* used for synchronous mode *)
+ let activate l =
+ Grab.release tl;
+ destroy tl;
+ let l =
+ if !load_in_path && usepath then
+ List.fold_right l ~init:[] ~f:
+ begin fun name acc ->
+ if not (Filename.is_implicit name) then
+ may_prefix name :: acc
+ else try search_in_path ~name :: acc with Not_found -> acc
+ end
+ else
+ List.map l ~f:may_prefix
+ in
+ if sync then
+ begin
+ selected_files := l;
+ Textvariable.set sync_var "1"
+ end
+ else proc l
+ in
+
+ (* entries *)
+ let fl = Label.create frm ~text:"Filter" in
+ let sl = Label.create frm ~text:"Selection" in
+ let filter_entry = Jg_entry.create frm ~textvariable:filter_var
+ ~command:(fun filter -> configure ~filter) in
+ let selection_entry = Jg_entry.create frm ~textvariable:selection_var
+ ~command:(fun file -> activate [file]) in
+
+ (* and buttons *)
+ let set_path = Button.create dfl ~text:"Path editor" ~command:
+ begin fun () ->
+ Setpath.add_update_hook (fun () -> configure ~filter:!current_pattern);
+ let w = Setpath.f ~dir:!current_dir in
+ Grab.set w;
+ bind w ~events:[`Destroy] ~extend:true ~action:(fun _ -> Grab.set tl)
+ end in
+ let toggle_in_path = Checkbutton.create dfl ~text:"Use load path"
+ ~command:
+ begin fun () ->
+ load_in_path := not !load_in_path;
+ if !load_in_path then
+ pack [set_path] ~side:`Bottom ~fill:`X ~expand:true
+ else
+ Pack.forget [set_path];
+ configure ~filter:(Textvariable.get filter_var)
+ end
+ and okb = Button.create cfrm ~text:"Ok" ~command:
+ begin fun () ->
+ let files =
+ List.map (Listbox.curselection filter_listbox) ~f:
+ begin fun x ->
+ !current_dir ^ Listbox.get filter_listbox ~index:x
+ end
+ in
+ let files = if files = [] then [Textvariable.get selection_var]
+ else files in
+ activate files
+ end
+ and flb = Button.create cfrm ~text:"Filter"
+ ~command:(fun () -> configure ~filter:(Textvariable.get filter_var))
+ and ccb = Button.create cfrm ~text:"Cancel"
+ ~command:(fun () -> activate []) in
+
+ (* binding *)
+ bind tl ~events:[`KeyPressDetail "Escape"] ~action:(fun _ -> activate []);
+ Jg_box.add_completion filter_listbox
+ ~action:(fun index -> activate [Listbox.get filter_listbox ~index]);
+ if multi then Listbox.configure filter_listbox ~selectmode:`Multiple else
+ bind filter_listbox ~events:[`ButtonPressDetail 1] ~fields:[`MouseY]
+ ~action:(fun ev ->
+ let name = Listbox.get filter_listbox
+ ~index:(Listbox.nearest filter_listbox ~y:ev.ev_MouseY) in
+ if !load_in_path && usepath then
+ try Textvariable.set selection_var (search_in_path ~name)
+ with Not_found -> ()
+ else Textvariable.set selection_var (may_prefix name));
+
+ Jg_box.add_completion directory_listbox ~action:
+ begin fun index ->
+ let filter =
+ may_prefix (Listbox.get directory_listbox ~index) ^
+ "/" ^ !current_pattern
+ in configure ~filter
+ end;
+
+ pack [frm] ~fill:`Both ~expand:true;
+ (* filter *)
+ pack [fl] ~side:`Top ~anchor:`W;
+ pack [filter_entry] ~side:`Top ~fill:`X;
+
+ (* directory + files *)
+ pack [df] ~side:`Top ~fill:`Both ~expand:true;
+ (* directory *)
+ pack [dfl] ~side:`Left ~fill:`Both ~expand:true;
+ pack [dfll] ~side:`Top ~anchor:`W;
+ if usepath then pack [toggle_in_path] ~side:`Bottom ~anchor:`W;
+ pack [dflf] ~side:`Top ~fill:`Both ~expand:true;
+ pack [directory_scrollbar] ~side:`Right ~fill:`Y;
+ pack [directory_listbox] ~side:`Left ~fill:`Both ~expand:true;
+ (* files *)
+ pack [dfr] ~side:`Right ~fill:`Both ~expand:true;
+ pack [dfrl] ~side:`Top ~anchor:`W;
+ pack [dfrf] ~side:`Top ~fill:`Both ~expand:true;
+ pack [filter_scrollbar] ~side:`Right ~fill:`Y;
+ pack [filter_listbox] ~side:`Left ~fill:`Both ~expand:true;
+
+ (* selection *)
+ pack [sl] ~before:df ~side:`Bottom ~anchor:`W;
+ pack [selection_entry] ~before:sl ~side:`Bottom ~fill:`X;
+
+ (* create OK, Filter and Cancel buttons *)
+ pack [okb; flb; ccb] ~side:`Left ~fill:`X ~expand:true;
+ pack [cfrm] ~before:frm ~side:`Bottom ~fill:`X;
+
+ if !load_in_path && usepath then begin
+ load_in_path := false;
+ Checkbutton.invoke toggle_in_path;
+ Checkbutton.select toggle_in_path
+ end
+ else configure ~filter:deffilter;
+
+ Tkwait.visibility tl;
+ Grab.set tl;
+
+ if sync then
+ begin
+ Tkwait.variable sync_var;
+ proc !selected_files
+ end;
+ ()
diff --git a/ocaml-binary-annot/otherlibs/labltk/browser/fileselect.mli b/ocaml-binary-annot/otherlibs/labltk/browser/fileselect.mli
new file mode 100644
index 0000000000..b723c626d5
--- /dev/null
+++ b/ocaml-binary-annot/otherlibs/labltk/browser/fileselect.mli
@@ -0,0 +1,39 @@
+(*************************************************************************)
+(* *)
+(* Objective Caml LablTk library *)
+(* *)
+(* Jacques Garrigue, Kyoto University RIMS *)
+(* *)
+(* Copyright 1999 Institut National de Recherche en Informatique et *)
+(* en Automatique and Kyoto University. All rights reserved. *)
+(* This file is distributed under the terms of the GNU Library *)
+(* General Public License, with the special exception on linking *)
+(* described in file ../../../LICENSE. *)
+(* *)
+(*************************************************************************)
+
+(* $Id$ *)
+
+val f :
+ title:string ->
+ action:(string list -> unit) ->
+ ?dir:string ->
+ ?filter:string ->
+ ?file:string ->
+ ?multi:bool -> ?sync:bool -> ?usepath:bool -> unit -> unit
+
+(* action
+ [] means canceled
+ if multi select is false, then the list is null or a singleton *)
+
+(* multi
+ If true then more than one file are selectable *)
+
+(* sync
+ If true then synchronous mode *)
+
+(* usepath
+ Enables/disables load path search. Defaults to true *)
+
+val caml_dir : string -> string
+(* Convert Windows-style directory separator '\' to caml-style '/' *)
diff --git a/ocaml-binary-annot/otherlibs/labltk/browser/help.ml b/ocaml-binary-annot/otherlibs/labltk/browser/help.ml
new file mode 100644
index 0000000000..632e762fdb
--- /dev/null
+++ b/ocaml-binary-annot/otherlibs/labltk/browser/help.ml
@@ -0,0 +1,168 @@
+let text = "\
+\032 OCamlBrowser Help\n\
+\n\
+USE\n\
+\n\
+\032 OCamlBrowser is composed of three tools, the Editor, which allows\n\
+\032 one to edit/typecheck/analyse .mli and .ml files, the Viewer, to\n\
+\032 walk around compiled modules, and the Shell, to run an OCaml\n\
+\032 subshell. You may only have one instance of Editor and Viewer, but\n\
+\032 you may use several subshells.\n\
+\n\
+\032 As with the compiler, you may specify a different path for the\n\
+\032 standard library by setting OCAMLLIB. You may also extend the\n\
+\032 initial load path (only standard library by default) by using the\n\
+\032 -I command line option. The -nolabels, -rectypes and -w options are\n\
+\032 also accepted, and inherited by subshells.\n\
+\032 The -oldui options selects the old multi-window interface. The\n\
+\032 default is now more like Smalltalk's class browser.\n\
+\n\
+1) Viewer\n\
+\n\
+\032 This is the first window you get when you start OCamlBrowser. It\n\
+\032 displays a search window, and the list of modules in the load path.\n\
+\032 At the top a row of menus.\n\
+\n\
+\032 File - Open and File - Editor give access to the editor.\n\
+\n\
+\032 File - Shell opens an OCaml shell.\n\
+\n\
+\032 View - Show all defs displays the signature of the currently\n\
+\032 selected module.\n\
+\n\
+\032 View - Search entry shows/hides the search entry just\n\
+\032 below the menu bar.\n\
+\n\
+\032 Modules - Path editor changes the load path.\n\
+\032 Pressing [Add to path] or Insert key adds selected directories\n\
+\032 to the load path.\n\
+\032 Pressing [Remove from path] or Delete key removes selected\n\
+\032 paths from the load path.\n\
+\n\
+\032 Modules - Reset cache rescans the load path and resets the module\n\
+\032 cache. Do it if you recompile some interface, or change the load\n\
+\032 path in a conflictual way.\n\
+\n\
+\032 Modules - Search symbol allows to search a symbol either by its\n\
+\032 name, like the bottom line of the viewer, or, more interestingly,\n\
+\032 by its type. Exact type searches for a type with exactly the same\n\
+\032 information as the pattern (variables match only variables),\n\
+\032 included type allows to give only partial information: the actual\n\
+\032 type may take more arguments and return more results, and variables\n\
+\032 in the pattern match anything. In both cases, argument and tuple\n\
+\032 order is irrelevant (*), and unlabeled arguments in the pattern\n\
+\032 match any label.\n\
+\n\
+\032 (*) To avoid combinatorial explosion of the search space, optional\n\
+\032 arguments in the actual type are ignored if (1) there are to many\n\
+\032 of them, and (2) they do not appear explicitly in the pattern.\n\
+\n\
+\032 The Search entry just below the menu bar allows one to search for\n\
+\032 an identifier in all modules, either by its name (? and * patterns\n\
+\032 allowed) or by its type (if there is an arrow in the input). When\n\
+\032 search by type is used, it is done in inclusion mode (cf. Modules -\n\
+\032 search symbol)\n\
+\n\
+\032 The Close all button is there to dismiss the windows created\n\
+\032 by the Detach button. By double-clicking on it you will quit the\n\
+\032 browser.\n\
+\n\
+\n\
+2) Module browsing\n\
+\n\
+\032 You select a module in the leftmost box by either cliking on it or\n\
+\032 pressing return when it is selected. Fast access is available in\n\
+\032 all boxes pressing the first few letter of the desired name.\n\
+\032 Double-clicking / double-return displays the whole signature for\n\
+\032 the module.\n\
+\n\
+\032 Defined identifiers inside the module are displayed in a box to the\n\
+\032 right of the previous one. If you click on one, this will either\n\
+\032 display its contents in another box (if this is a sub-module) or\n\
+\032 display the signature for this identifier below.\n\
+\n\
+\032 Signatures are clickable. Double clicking with the left mouse\n\
+\032 button on an identifier in a signature brings you to its signature,\n\
+\032 inside its module box.\n\
+\032 A single click on the right button pops up a menu displaying the\n\
+\032 type declaration for the selected identifier. Its title, when\n\
+\032 selectable, also brings you to its signature.\n\
+\n\
+\032 At the bottom, a series of buttons, depending on the context.\n\
+\032 * Detach copies the currently displayed signature in a new window,\n\
+\032 to keep it.\n\
+\032 * Impl and Intf bring you to the implementation or interface of\n\
+\032 the currently displayed signature, if it is available.\n\
+\n\
+\032 C-s opens a text search dialog for the displayed signature.\n\
+\n\
+3) File editor\n\
+\n\
+\032 You can edit files with it, but there is no auto-save nor undo at\n\
+\032 the moment. Otherwise you can use it as a browser, making\n\
+\032 occasional corrections.\n\
+\n\
+\032 The Edit menu contains commands for jump (C-g), search (C-s), and\n\
+\032 sending the current selection to a sub-shell (M-x). For this last\n\
+\032 option, you may choose the shell via a dialog.\n\
+\n\
+\032 Essential function are in the Compiler menu.\n\
+\n\
+\032 Preferences opens a dialog to set internals of the editor and\n\
+\032 type checker.\n\
+\n\
+\032 Lex (M-l) adds colors according to lexical categories.\n\
+\n\
+\032 Typecheck (M-t) verifies typing, and memorizes it to let one see an\n\
+\032 expression's type by double-clicking on it. This is also valid for\n\
+\032 interfaces. If an error occurs, the part of the interface preceding\n\
+\032 the error is computed.\n\
+\n\
+\032 After typechecking, pressing the right button pops up a menu giving\n\
+\032 the type of the pointed expression, and eventually allowing to\n\
+\032 follow some links.\n\
+\n\
+\032 Clear errors dismisses type checker error messages and warnings.\n\
+\n\
+\032 Signature shows the signature of the current file.\n\
+\n\
+4) Shell\n\
+\n\
+\032 When you create a shell, a dialog is presented to you, letting you\n\
+\032 choose which command you want to run, and the title of the shell\n\
+\032 (to choose it in the Editor).\n\
+\n\
+\032 You may change the default command by setting the OLABL environment\n\
+\032 variable.\n\
+\n\
+\032 The executed subshell is given the current load path.\n\
+\032 File: use a source file or load a bytecode file.\n\
+\032 You may also import the browser's path into the subprocess.\n\
+\032 History: M-p and M-n browse up and down.\n\
+\032 Signal: C-c interrupts and you can kill the subprocess.\n\
+\n\
+BUGS\n\
+\n\
+* When you quit the editor and some file was modified, a dialogue is\n\
+\032 displayed asking wether you want to really quit or not. But 1) if\n\
+\032 you quit directly from the viewer, there is no dialogue at all, and\n\
+\032 2) if you close from the window manager, the dialogue is displayed,\n\
+\032 but you cannot cancel the destruction... Beware.\n\
+\n\
+* When you run it through xon, the shell hangs at the first error. But\n\
+\032 its ok if you start ocamlbrowser from a remote shell...\n\
+\n\
+TODO\n\
+\n\
+* Complete cross-references.\n\
+\n\
+* Power up editor.\n\
+\n\
+* Add support for the debugger.\n\
+\n\
+* Make this a real programming environment, both for beginners an\n\
+\032 experimented users.\n\
+\n\
+\n\
+Bug reports and comments to <garrigue@kurims.kyoto-u.ac.jp>\n\
+";;
diff --git a/ocaml-binary-annot/otherlibs/labltk/browser/help.txt b/ocaml-binary-annot/otherlibs/labltk/browser/help.txt
new file mode 100644
index 0000000000..62bfc59211
--- /dev/null
+++ b/ocaml-binary-annot/otherlibs/labltk/browser/help.txt
@@ -0,0 +1,166 @@
+ OCamlBrowser Help
+
+USE
+
+ OCamlBrowser is composed of three tools, the Editor, which allows
+ one to edit/typecheck/analyse .mli and .ml files, the Viewer, to
+ walk around compiled modules, and the Shell, to run an OCaml
+ subshell. You may only have one instance of Editor and Viewer, but
+ you may use several subshells.
+
+ As with the compiler, you may specify a different path for the
+ standard library by setting OCAMLLIB. You may also extend the
+ initial load path (only standard library by default) by using the
+ -I command line option. The -nolabels, -rectypes and -w options are
+ also accepted, and inherited by subshells.
+ The -oldui options selects the old multi-window interface. The
+ default is now more like Smalltalk's class browser.
+
+1) Viewer
+
+ This is the first window you get when you start OCamlBrowser. It
+ displays a search window, and the list of modules in the load path.
+ At the top a row of menus.
+
+ File - Open and File - Editor give access to the editor.
+
+ File - Shell opens an OCaml shell.
+
+ View - Show all defs displays the signature of the currently
+ selected module.
+
+ View - Search entry shows/hides the search entry just
+ below the menu bar.
+
+ Modules - Path editor changes the load path.
+ Pressing [Add to path] or Insert key adds selected directories
+ to the load path.
+ Pressing [Remove from path] or Delete key removes selected
+ paths from the load path.
+
+ Modules - Reset cache rescans the load path and resets the module
+ cache. Do it if you recompile some interface, or change the load
+ path in a conflictual way.
+
+ Modules - Search symbol allows to search a symbol either by its
+ name, like the bottom line of the viewer, or, more interestingly,
+ by its type. Exact type searches for a type with exactly the same
+ information as the pattern (variables match only variables),
+ included type allows to give only partial information: the actual
+ type may take more arguments and return more results, and variables
+ in the pattern match anything. In both cases, argument and tuple
+ order is irrelevant (*), and unlabeled arguments in the pattern
+ match any label.
+
+ (*) To avoid combinatorial explosion of the search space, optional
+ arguments in the actual type are ignored if (1) there are to many
+ of them, and (2) they do not appear explicitly in the pattern.
+
+ The Search entry just below the menu bar allows one to search for
+ an identifier in all modules, either by its name (? and * patterns
+ allowed) or by its type (if there is an arrow in the input). When
+ search by type is used, it is done in inclusion mode (cf. Modules -
+ search symbol)
+
+ The Close all button is there to dismiss the windows created
+ by the Detach button. By double-clicking on it you will quit the
+ browser.
+
+
+2) Module browsing
+
+ You select a module in the leftmost box by either cliking on it or
+ pressing return when it is selected. Fast access is available in
+ all boxes pressing the first few letter of the desired name.
+ Double-clicking / double-return displays the whole signature for
+ the module.
+
+ Defined identifiers inside the module are displayed in a box to the
+ right of the previous one. If you click on one, this will either
+ display its contents in another box (if this is a sub-module) or
+ display the signature for this identifier below.
+
+ Signatures are clickable. Double clicking with the left mouse
+ button on an identifier in a signature brings you to its signature,
+ inside its module box.
+ A single click on the right button pops up a menu displaying the
+ type declaration for the selected identifier. Its title, when
+ selectable, also brings you to its signature.
+
+ At the bottom, a series of buttons, depending on the context.
+ * Detach copies the currently displayed signature in a new window,
+ to keep it.
+ * Impl and Intf bring you to the implementation or interface of
+ the currently displayed signature, if it is available.
+
+ C-s opens a text search dialog for the displayed signature.
+
+3) File editor
+
+ You can edit files with it, but there is no auto-save nor undo at
+ the moment. Otherwise you can use it as a browser, making
+ occasional corrections.
+
+ The Edit menu contains commands for jump (C-g), search (C-s), and
+ sending the current selection to a sub-shell (M-x). For this last
+ option, you may choose the shell via a dialog.
+
+ Essential function are in the Compiler menu.
+
+ Preferences opens a dialog to set internals of the editor and
+ type checker.
+
+ Lex (M-l) adds colors according to lexical categories.
+
+ Typecheck (M-t) verifies typing, and memorizes it to let one see an
+ expression's type by double-clicking on it. This is also valid for
+ interfaces. If an error occurs, the part of the interface preceding
+ the error is computed.
+
+ After typechecking, pressing the right button pops up a menu giving
+ the type of the pointed expression, and eventually allowing to
+ follow some links.
+
+ Clear errors dismisses type checker error messages and warnings.
+
+ Signature shows the signature of the current file.
+
+4) Shell
+
+ When you create a shell, a dialog is presented to you, letting you
+ choose which command you want to run, and the title of the shell
+ (to choose it in the Editor).
+
+ You may change the default command by setting the OLABL environment
+ variable.
+
+ The executed subshell is given the current load path.
+ File: use a source file or load a bytecode file.
+ You may also import the browser's path into the subprocess.
+ History: M-p and M-n browse up and down.
+ Signal: C-c interrupts and you can kill the subprocess.
+
+BUGS
+
+* When you quit the editor and some file was modified, a dialogue is
+ displayed asking wether you want to really quit or not. But 1) if
+ you quit directly from the viewer, there is no dialogue at all, and
+ 2) if you close from the window manager, the dialogue is displayed,
+ but you cannot cancel the destruction... Beware.
+
+* When you run it through xon, the shell hangs at the first error. But
+ its ok if you start ocamlbrowser from a remote shell...
+
+TODO
+
+* Complete cross-references.
+
+* Power up editor.
+
+* Add support for the debugger.
+
+* Make this a real programming environment, both for beginners an
+ experimented users.
+
+
+Bug reports and comments to <garrigue@kurims.kyoto-u.ac.jp>
diff --git a/ocaml-binary-annot/otherlibs/labltk/browser/jg_bind.ml b/ocaml-binary-annot/otherlibs/labltk/browser/jg_bind.ml
new file mode 100644
index 0000000000..2e3ec9870b
--- /dev/null
+++ b/ocaml-binary-annot/otherlibs/labltk/browser/jg_bind.ml
@@ -0,0 +1,28 @@
+(*************************************************************************)
+(* *)
+(* Objective Caml LablTk library *)
+(* *)
+(* Jacques Garrigue, Kyoto University RIMS *)
+(* *)
+(* Copyright 1999 Institut National de Recherche en Informatique et *)
+(* en Automatique and Kyoto University. All rights reserved. *)
+(* This file is distributed under the terms of the GNU Library *)
+(* General Public License, with the special exception on linking *)
+(* described in file ../../../LICENSE. *)
+(* *)
+(*************************************************************************)
+
+(* $Id$ *)
+
+open Tk
+
+let enter_focus w =
+ bind w ~events:[`Enter] ~action:(fun _ -> Focus.set w)
+
+let escape_destroy ?destroy:tl w =
+ let tl = match tl with Some w -> w | None -> w in
+ bind w ~events:[`KeyPressDetail "Escape"] ~action:(fun _ -> destroy tl)
+
+let return_invoke w ~button =
+ bind w ~events:[`KeyPressDetail "Return"]
+ ~action:(fun _ -> Button.invoke button)
diff --git a/ocaml-binary-annot/otherlibs/labltk/browser/jg_bind.mli b/ocaml-binary-annot/otherlibs/labltk/browser/jg_bind.mli
new file mode 100644
index 0000000000..e09c2ba460
--- /dev/null
+++ b/ocaml-binary-annot/otherlibs/labltk/browser/jg_bind.mli
@@ -0,0 +1,21 @@
+(*************************************************************************)
+(* *)
+(* Objective Caml LablTk library *)
+(* *)
+(* Jacques Garrigue, Kyoto University RIMS *)
+(* *)
+(* Copyright 1999 Institut National de Recherche en Informatique et *)
+(* en Automatique and Kyoto University. All rights reserved. *)
+(* This file is distributed under the terms of the GNU Library *)
+(* General Public License, with the special exception on linking *)
+(* described in file ../../../LICENSE. *)
+(* *)
+(*************************************************************************)
+
+(* $Id$ *)
+
+open Widget
+
+val enter_focus : 'a widget -> unit
+val escape_destroy : ?destroy:'a widget -> 'a widget ->unit
+val return_invoke : 'a widget -> button:button widget -> unit
diff --git a/ocaml-binary-annot/otherlibs/labltk/browser/jg_box.ml b/ocaml-binary-annot/otherlibs/labltk/browser/jg_box.ml
new file mode 100644
index 0000000000..3675f4bfa8
--- /dev/null
+++ b/ocaml-binary-annot/otherlibs/labltk/browser/jg_box.ml
@@ -0,0 +1,82 @@
+(*************************************************************************)
+(* *)
+(* Objective Caml LablTk library *)
+(* *)
+(* Jacques Garrigue, Kyoto University RIMS *)
+(* *)
+(* Copyright 1999 Institut National de Recherche en Informatique et *)
+(* en Automatique and Kyoto University. All rights reserved. *)
+(* This file is distributed under the terms of the GNU Library *)
+(* General Public License, with the special exception on linking *)
+(* described in file ../../../LICENSE. *)
+(* *)
+(*************************************************************************)
+
+(* $Id$ *)
+
+open Tk
+
+let add_scrollbar lb =
+ let sb =
+ Scrollbar.create (Winfo.parent lb) ~command:(Listbox.yview lb) in
+ Listbox.configure lb ~yscrollcommand:(Scrollbar.set sb); sb
+
+let create_with_scrollbar ?selectmode parent =
+ let frame = Frame.create parent in
+ let lb = Listbox.create frame ?selectmode in
+ frame, lb, add_scrollbar lb
+
+(* from frx_listbox,adapted *)
+
+let recenter lb ~index =
+ Listbox.selection_clear lb ~first:(`Num 0) ~last:`End;
+ (* Activate it, to keep consistent with Up/Down.
+ You have to be in Extended or Browse mode *)
+ Listbox.activate lb ~index;
+ Listbox.selection_anchor lb ~index;
+ Listbox.yview_index lb ~index
+
+class timed ?wait ?nocase get_texts = object
+ val get_texts = get_texts
+ inherit Jg_completion.timed [] ?wait ?nocase as super
+ method! reset =
+ texts <- get_texts ();
+ super#reset
+end
+
+let add_completion ?action ?wait ?nocase ?(double=true) lb =
+ let comp =
+ new timed ?wait ?nocase
+ (fun () -> Listbox.get_range lb ~first:(`Num 0) ~last:`End) in
+
+ Jg_bind.enter_focus lb;
+
+ bind lb ~events:[`KeyPress] ~fields:[`Char] ~action:
+ begin fun ev ->
+ (* consider only keys producing characters. The callback is called
+ even if you press Shift. *)
+ if ev.ev_Char <> "" then
+ recenter lb ~index:(`Num (comp#add ev.ev_Char))
+ end;
+
+ begin match action with
+ Some action ->
+ bind lb ~events:[`KeyPressDetail "Return"]
+ ~action:(fun _ -> action `Active);
+ let bmod = if double then [`Double] else [] in
+ bind lb ~events:[`Modified(bmod, `ButtonPressDetail 1)]
+ ~breakable:true ~fields:[`MouseY]
+ ~action:
+ begin fun ev ->
+ let index = Listbox.nearest lb ~y:ev.ev_MouseY in
+ if not double then begin
+ Listbox.selection_clear lb ~first:(`Num 0) ~last:`End;
+ Listbox.selection_set lb ~first:index ~last:index;
+ end;
+ action index;
+ break ()
+ end
+ | None -> ()
+ end;
+
+ recenter lb ~index:(`Num 0) (* so that first item is active *)
diff --git a/ocaml-binary-annot/otherlibs/labltk/browser/jg_button.ml b/ocaml-binary-annot/otherlibs/labltk/browser/jg_button.ml
new file mode 100644
index 0000000000..11abd68aba
--- /dev/null
+++ b/ocaml-binary-annot/otherlibs/labltk/browser/jg_button.ml
@@ -0,0 +1,25 @@
+(*************************************************************************)
+(* *)
+(* Objective Caml LablTk library *)
+(* *)
+(* Jacques Garrigue, Kyoto University RIMS *)
+(* *)
+(* Copyright 1999 Institut National de Recherche en Informatique et *)
+(* en Automatique and Kyoto University. All rights reserved. *)
+(* This file is distributed under the terms of the GNU Library *)
+(* General Public License, with the special exception on linking *)
+(* described in file ../../../LICENSE. *)
+(* *)
+(*************************************************************************)
+
+(* $Id$ *)
+
+open Tk
+
+let create_destroyer ~parent ?(text="Ok") tl =
+ Button.create parent ~text ~command:(fun () -> destroy tl)
+
+let add_destroyer ?text tl =
+ let b = create_destroyer tl ~parent:tl ?text in
+ pack [b] ~side:`Bottom ~fill:`X;
+ b
diff --git a/ocaml-binary-annot/otherlibs/labltk/browser/jg_completion.ml b/ocaml-binary-annot/otherlibs/labltk/browser/jg_completion.ml
new file mode 100644
index 0000000000..c93b099b3a
--- /dev/null
+++ b/ocaml-binary-annot/otherlibs/labltk/browser/jg_completion.ml
@@ -0,0 +1,53 @@
+(*************************************************************************)
+(* *)
+(* Objective Caml LablTk library *)
+(* *)
+(* Jacques Garrigue, Kyoto University RIMS *)
+(* *)
+(* Copyright 1999 Institut National de Recherche en Informatique et *)
+(* en Automatique and Kyoto University. All rights reserved. *)
+(* This file is distributed under the terms of the GNU Library *)
+(* General Public License, with the special exception on linking *)
+(* described in file ../../../LICENSE. *)
+(* *)
+(*************************************************************************)
+
+(* $Id$ *)
+
+let lt_string ?(nocase=false) s1 s2 =
+ if nocase then String.lowercase s1 < String.lowercase s2 else s1 < s2
+
+class completion ?nocase texts = object
+ val mutable texts = texts
+ val nocase = nocase
+ val mutable prefix = ""
+ val mutable current = 0
+ method add c =
+ prefix <- prefix ^ c;
+ while current < List.length texts - 1 &&
+ lt_string (List.nth texts current) prefix ?nocase
+ do
+ current <- current + 1
+ done;
+ current
+ method current = current
+ method get_current = List.nth texts current
+ method reset =
+ prefix <- "";
+ current <- 0
+end
+
+class timed ?nocase ?wait texts = object (self)
+ inherit completion texts ?nocase as super
+ val wait = match wait with None -> 500 | Some n -> n
+ val mutable timer = None
+ method! add c =
+ begin match timer with
+ None -> self#reset
+ | Some t -> Timer.remove t
+ end;
+ timer <- Some (Timer.add ~ms:wait ~callback:(fun () -> self#reset));
+ super#add c
+ method! reset =
+ timer <- None; super#reset
+end
diff --git a/ocaml-binary-annot/otherlibs/labltk/browser/jg_completion.mli b/ocaml-binary-annot/otherlibs/labltk/browser/jg_completion.mli
new file mode 100644
index 0000000000..69c7a134c2
--- /dev/null
+++ b/ocaml-binary-annot/otherlibs/labltk/browser/jg_completion.mli
@@ -0,0 +1,25 @@
+(*************************************************************************)
+(* *)
+(* Objective Caml LablTk library *)
+(* *)
+(* Jacques Garrigue, Kyoto University RIMS *)
+(* *)
+(* Copyright 1999 Institut National de Recherche en Informatique et *)
+(* en Automatique and Kyoto University. All rights reserved. *)
+(* This file is distributed under the terms of the GNU Library *)
+(* General Public License, with the special exception on linking *)
+(* described in file ../../../LICENSE. *)
+(* *)
+(*************************************************************************)
+
+(* $Id$ *)
+
+val lt_string : ?nocase:bool -> string -> string -> bool
+
+class timed : ?nocase:bool -> ?wait:int -> string list -> object
+ val mutable texts : string list
+ method add : string -> int
+ method current : int
+ method get_current : string
+ method reset : unit
+end
diff --git a/ocaml-binary-annot/otherlibs/labltk/browser/jg_config.ml b/ocaml-binary-annot/otherlibs/labltk/browser/jg_config.ml
new file mode 100644
index 0000000000..bce0e50e76
--- /dev/null
+++ b/ocaml-binary-annot/otherlibs/labltk/browser/jg_config.ml
@@ -0,0 +1,40 @@
+(*************************************************************************)
+(* *)
+(* Objective Caml LablTk library *)
+(* *)
+(* Jacques Garrigue, Kyoto University RIMS *)
+(* *)
+(* Copyright 1999 Institut National de Recherche en Informatique et *)
+(* en Automatique and Kyoto University. All rights reserved. *)
+(* This file is distributed under the terms of the GNU Library *)
+(* General Public License, with the special exception on linking *)
+(* described in file ../../../LICENSE. *)
+(* *)
+(*************************************************************************)
+
+(* $Id$ *)
+
+open StdLabels
+open Jg_tk
+
+let fixed = if wingui then "{Courier New} 8" else "fixed"
+let variable = if wingui then "Arial 9" else "variable"
+
+let init () =
+ if wingui then Option.add ~path:"*font" fixed;
+ let font =
+ let font =
+ Option.get Widget.default_toplevel ~name:"variableFont" ~clas:"Font" in
+ if font = "" then variable else font
+ in
+ List.iter ["Button"; "Label"; "Menu"; "Menubutton"; "Radiobutton"]
+ ~f:(fun cl -> Option.add ~path:("*" ^ cl ^ ".font") font);
+ Option.add ~path:"*Menu.tearOff" "0" ~priority:`StartupFile;
+ Option.add ~path:"*Button.padY" "0" ~priority:`StartupFile;
+ Option.add ~path:"*Text.highlightThickness" "0" ~priority:`StartupFile;
+ Option.add ~path:"*interface.background" "gray85" ~priority:`StartupFile;
+ let foreground =
+ Option.get Widget.default_toplevel
+ ~name:"disabledForeground" ~clas:"Foreground" in
+ if foreground = "" then
+ Option.add ~path:"*disabledForeground" "black"
diff --git a/ocaml-binary-annot/otherlibs/labltk/browser/jg_config.mli b/ocaml-binary-annot/otherlibs/labltk/browser/jg_config.mli
new file mode 100644
index 0000000000..511e2b3a67
--- /dev/null
+++ b/ocaml-binary-annot/otherlibs/labltk/browser/jg_config.mli
@@ -0,0 +1,17 @@
+(*************************************************************************)
+(* *)
+(* Objective Caml LablTk library *)
+(* *)
+(* Jacques Garrigue, Kyoto University RIMS *)
+(* *)
+(* Copyright 1999 Institut National de Recherche en Informatique et *)
+(* en Automatique and Kyoto University. All rights reserved. *)
+(* This file is distributed under the terms of the GNU Library *)
+(* General Public License, with the special exception on linking *)
+(* described in file ../../../LICENSE. *)
+(* *)
+(*************************************************************************)
+
+(* $Id$ *)
+
+val init: unit -> unit
diff --git a/ocaml-binary-annot/otherlibs/labltk/browser/jg_entry.ml b/ocaml-binary-annot/otherlibs/labltk/browser/jg_entry.ml
new file mode 100644
index 0000000000..c09a273e82
--- /dev/null
+++ b/ocaml-binary-annot/otherlibs/labltk/browser/jg_entry.ml
@@ -0,0 +1,27 @@
+(*************************************************************************)
+(* *)
+(* Objective Caml LablTk library *)
+(* *)
+(* Jacques Garrigue, Kyoto University RIMS *)
+(* *)
+(* Copyright 1999 Institut National de Recherche en Informatique et *)
+(* en Automatique and Kyoto University. All rights reserved. *)
+(* This file is distributed under the terms of the GNU Library *)
+(* General Public License, with the special exception on linking *)
+(* described in file ../../../LICENSE. *)
+(* *)
+(*************************************************************************)
+
+(* $Id$ *)
+
+open Tk
+
+let create ?command ?width ?textvariable parent =
+ let ew = Entry.create parent ?width ?textvariable in
+ Jg_bind.enter_focus ew;
+ begin match command with Some command ->
+ bind ew ~events:[`KeyPressDetail "Return"]
+ ~action:(fun _ -> command (Entry.get ew))
+ | None -> ()
+ end;
+ ew
diff --git a/ocaml-binary-annot/otherlibs/labltk/browser/jg_memo.ml b/ocaml-binary-annot/otherlibs/labltk/browser/jg_memo.ml
new file mode 100644
index 0000000000..e238929a08
--- /dev/null
+++ b/ocaml-binary-annot/otherlibs/labltk/browser/jg_memo.ml
@@ -0,0 +1,33 @@
+(*************************************************************************)
+(* *)
+(* Objective Caml LablTk library *)
+(* *)
+(* Jacques Garrigue, Kyoto University RIMS *)
+(* *)
+(* Copyright 1999 Institut National de Recherche en Informatique et *)
+(* en Automatique and Kyoto University. All rights reserved. *)
+(* This file is distributed under the terms of the GNU Library *)
+(* General Public License, with the special exception on linking *)
+(* described in file ../../../LICENSE. *)
+(* *)
+(*************************************************************************)
+
+(* $Id$ *)
+
+type ('a, 'b) assoc_list =
+ Nil
+ | Cons of 'a * 'b * ('a, 'b) assoc_list
+
+let rec assq key = function
+ Nil -> raise Not_found
+ | Cons (a, b, l) ->
+ if key == a then b else assq key l
+
+let fast ~f =
+ let memo = ref Nil in
+ fun key ->
+ try assq key !memo
+ with Not_found ->
+ let data = f key in
+ memo := Cons(key, data, !memo);
+ data
diff --git a/ocaml-binary-annot/otherlibs/labltk/browser/jg_memo.mli b/ocaml-binary-annot/otherlibs/labltk/browser/jg_memo.mli
new file mode 100644
index 0000000000..5491dee32f
--- /dev/null
+++ b/ocaml-binary-annot/otherlibs/labltk/browser/jg_memo.mli
@@ -0,0 +1,19 @@
+(*************************************************************************)
+(* *)
+(* Objective Caml LablTk library *)
+(* *)
+(* Jacques Garrigue, Kyoto University RIMS *)
+(* *)
+(* Copyright 1999 Institut National de Recherche en Informatique et *)
+(* en Automatique and Kyoto University. All rights reserved. *)
+(* This file is distributed under the terms of the GNU Library *)
+(* General Public License, with the special exception on linking *)
+(* described in file ../../../LICENSE. *)
+(* *)
+(*************************************************************************)
+
+(* $Id$ *)
+
+val fast : f:('a -> 'b) -> 'a -> 'b
+(* "fast" memoizer: uses a List.assq like function *)
+(* Good for a smallish number of keys, phisically equal *)
diff --git a/ocaml-binary-annot/otherlibs/labltk/browser/jg_menu.ml b/ocaml-binary-annot/otherlibs/labltk/browser/jg_menu.ml
new file mode 100644
index 0000000000..b399d10d87
--- /dev/null
+++ b/ocaml-binary-annot/otherlibs/labltk/browser/jg_menu.ml
@@ -0,0 +1,44 @@
+(*************************************************************************)
+(* *)
+(* Objective Caml LablTk library *)
+(* *)
+(* Jacques Garrigue, Kyoto University RIMS *)
+(* *)
+(* Copyright 1999 Institut National de Recherche en Informatique et *)
+(* en Automatique and Kyoto University. All rights reserved. *)
+(* This file is distributed under the terms of the GNU Library *)
+(* General Public License, with the special exception on linking *)
+(* described in file ../../../LICENSE. *)
+(* *)
+(*************************************************************************)
+
+(* $Id$ *)
+
+open Tk
+
+class c ~parent ?(underline=0) label = object (self)
+ val menu =
+ let menu = Menu.create parent in
+ Menu.add_cascade parent ~menu ~label ~underline;
+ menu
+ method menu = menu
+ method virtual add_command :
+ ?underline:int ->
+ ?accelerator:string -> ?activebackground:color ->
+ ?activeforeground:color -> ?background:color ->
+ ?bitmap:bitmap -> ?command:(unit -> unit) ->
+ ?font:string -> ?foreground:color ->
+ ?image:image -> ?state:state ->
+ string -> unit
+ method add_command ?(underline=0) ?accelerator ?activebackground
+ ?activeforeground ?background ?bitmap ?command ?font ?foreground
+ ?image ?state label =
+ Menu.add_command menu ~label ~underline ?accelerator
+ ?activebackground ?activeforeground ?background ?bitmap
+ ?command ?font ?foreground ?image ?state
+end
+
+let menubar tl =
+ let menu = Menu.create tl ~name:"menubar" ~typ:`Menubar in
+ Toplevel.configure tl ~menu;
+ menu
diff --git a/ocaml-binary-annot/otherlibs/labltk/browser/jg_message.ml b/ocaml-binary-annot/otherlibs/labltk/browser/jg_message.ml
new file mode 100644
index 0000000000..3c18f193c4
--- /dev/null
+++ b/ocaml-binary-annot/otherlibs/labltk/browser/jg_message.ml
@@ -0,0 +1,111 @@
+(*************************************************************************)
+(* *)
+(* Objective Caml LablTk library *)
+(* *)
+(* Jacques Garrigue, Kyoto University RIMS *)
+(* *)
+(* Copyright 1999 Institut National de Recherche en Informatique et *)
+(* en Automatique and Kyoto University. All rights reserved. *)
+(* This file is distributed under the terms of the GNU Library *)
+(* General Public License, with the special exception on linking *)
+(* described in file ../../../LICENSE. *)
+(* *)
+(*************************************************************************)
+
+(* $Id$ *)
+
+open StdLabels
+open Tk
+open Jg_tk
+
+(*
+class formatted ~parent ~width ~maxheight ~minheight =
+ val parent = (parent : Widget.any Widget.widget)
+ val width = width
+ val maxheight = maxheight
+ val minheight = minheight
+ val tw = Text.create ~parent ~width ~wrap:`Word
+ val fof = Format.get_formatter_output_functions ()
+ method parent = parent
+ method init =
+ pack [tw] ~side:`Left ~fill:`Both ~expand:true;
+ Format.print_flush ();
+ Format.set_margin (width - 2);
+ Format.set_formatter_output_functions ~out:(Jg_text.output tw)
+ ~flush:(fun () -> ())
+ method finish =
+ Format.print_flush ();
+ Format.set_formatter_output_functions ~out:(fst fof) ~flush:(snd fof);
+ let `Linechar (l, _) = Text.index tw ~index:(tposend 1) in
+ Text.configure tw ~height:(max minheight (min l maxheight));
+ if l > 5 then
+ pack [Jg_text.add_scrollbar tw] ~before:tw ~side:`Right ~fill:`Y
+end
+*)
+
+let formatted ~title ?on ?(ppf = Format.std_formatter)
+ ?(width=60) ?(maxheight=10) ?(minheight=0) () =
+ let tl, frame =
+ match on with
+ Some frame ->
+(* let label = Label.create frame ~anchor:`W ~padx:10 ~text:title in
+ pack [label] ~side:`Top ~fill:`X;
+ let frame2 = Frame.create frame in
+ pack [frame2] ~side:`Bottom ~fill:`Both ~expand:true; *)
+ coe frame, frame
+ | None ->
+ let tl = Jg_toplevel.titled title in
+ Jg_bind.escape_destroy tl;
+ let frame = Frame.create tl in
+ pack [frame] ~side:`Top ~fill:`Both ~expand:true;
+ coe tl, frame
+ in
+ let tw = Text.create frame ~width ~wrap:`Word in
+ pack [tw] ~side:`Left ~fill:`Both ~expand:true;
+ Format.pp_print_flush ppf ();
+ Format.pp_set_margin ppf (width - 2);
+ let fof,fff = Format.pp_get_formatter_output_functions ppf () in
+ Format.pp_set_formatter_output_functions ppf
+ (fun buf pos len -> Jg_text.output tw ~buf ~pos ~len)
+ ignore;
+ tl, tw,
+ begin fun () ->
+ Format.pp_print_flush ppf ();
+ Format.pp_set_formatter_output_functions ppf fof fff;
+ let `Linechar (l, _) = Text.index tw ~index:(tposend 1) in
+ Text.configure tw ~height:(max minheight (min l maxheight));
+ if l > 5 then
+ pack [Jg_text.add_scrollbar tw] ~before:tw ~side:`Right ~fill:`Y
+ end
+
+let ask ~title ?master ?(no=true) ?(cancel=true) text =
+ let tl = Jg_toplevel.titled title in
+ begin match master with None -> ()
+ | Some master -> Wm.transient_set tl ~master
+ end;
+ let mw = Message.create tl ~text ~padx:20 ~pady:10
+ ~width:250 ~justify:`Left ~aspect:400 ~anchor:`W
+ and fw = Frame.create tl
+ and sync = Textvariable.create ~on:tl ()
+ and r = ref (`Cancel : [`Yes|`No|`Cancel]) in
+ let accept = Button.create fw
+ ~text:(if no || cancel then "Yes" else "Dismiss")
+ ~command:(fun () -> r := `Yes; destroy tl)
+ and refuse = Button.create fw ~text:"No"
+ ~command:(fun () -> r := `No; destroy tl)
+ and cancelB = Button.create fw ~text:"Cancel"
+ ~command:(fun () -> r := `Cancel; destroy tl)
+ in
+ bind tl ~events:[`Destroy] ~extend:true
+ ~action:(fun _ -> Textvariable.set sync "1");
+ pack [accept] ~side:`Left ~fill:`X ~expand:true;
+ if no then pack [refuse] ~side:`Left ~fill:`X ~expand:true;
+ if cancel then pack [cancelB] ~side:`Left ~fill:`X ~expand:true;
+ pack [mw] ~side:`Top ~fill:`Both;
+ pack [fw] ~side:`Bottom ~fill:`X ~expand:true;
+ Grab.set tl;
+ Tkwait.variable sync;
+ !r
+
+let info ~title ?master text =
+ ignore (ask ~title ?master ~no:false ~cancel:false text)
diff --git a/ocaml-binary-annot/otherlibs/labltk/browser/jg_message.mli b/ocaml-binary-annot/otherlibs/labltk/browser/jg_message.mli
new file mode 100644
index 0000000000..0a83a594ff
--- /dev/null
+++ b/ocaml-binary-annot/otherlibs/labltk/browser/jg_message.mli
@@ -0,0 +1,33 @@
+(*************************************************************************)
+(* *)
+(* Objective Caml LablTk library *)
+(* *)
+(* Jacques Garrigue, Kyoto University RIMS *)
+(* *)
+(* Copyright 1999 Institut National de Recherche en Informatique et *)
+(* en Automatique and Kyoto University. All rights reserved. *)
+(* This file is distributed under the terms of the GNU Library *)
+(* General Public License, with the special exception on linking *)
+(* described in file ../../../LICENSE. *)
+(* *)
+(*************************************************************************)
+
+(* $Id$ *)
+
+open Widget
+
+val formatted :
+ title:string ->
+ ?on:frame widget ->
+ ?ppf:Format.formatter ->
+ ?width:int ->
+ ?maxheight:int ->
+ ?minheight:int ->
+ unit -> any widget * text widget * (unit -> unit)
+
+val ask :
+ title:string -> ?master:toplevel widget ->
+ ?no:bool -> ?cancel:bool -> string -> [`Cancel|`No|`Yes]
+
+val info :
+ title:string -> ?master:toplevel widget -> string -> unit
diff --git a/ocaml-binary-annot/otherlibs/labltk/browser/jg_multibox.ml b/ocaml-binary-annot/otherlibs/labltk/browser/jg_multibox.ml
new file mode 100644
index 0000000000..febec8e5de
--- /dev/null
+++ b/ocaml-binary-annot/otherlibs/labltk/browser/jg_multibox.ml
@@ -0,0 +1,185 @@
+(*************************************************************************)
+(* *)
+(* Objective Caml LablTk library *)
+(* *)
+(* Jacques Garrigue, Kyoto University RIMS *)
+(* *)
+(* Copyright 1999 Institut National de Recherche en Informatique et *)
+(* en Automatique and Kyoto University. All rights reserved. *)
+(* This file is distributed under the terms of the GNU Library *)
+(* General Public License, with the special exception on linking *)
+(* described in file ../../../LICENSE. *)
+(* *)
+(*************************************************************************)
+
+(* $Id$ *)
+
+open StdLabels
+
+let rec gen_list ~f:f ~len =
+ if len = 0 then [] else f () :: gen_list ~f:f ~len:(len - 1)
+
+let rec make_list ~len ~fill =
+ if len = 0 then [] else fill :: make_list ~len:(len - 1) ~fill
+
+(* By column version
+let rec firsts ~len l =
+ if len = 0 then ([],l) else
+ match l with
+ a::l ->
+ let (f,l) = firsts l len:(len - 1) in
+ (a::f,l)
+ | [] ->
+ (l,[])
+
+let rec split ~len = function
+ [] -> []
+ | l ->
+ let (f,r) = firsts l ~len in
+ let ret = split ~len r in
+ f :: ret
+
+let extend l ~len ~fill =
+ if List.length l >= len then l
+ else l @ make_list ~fill len:(len - List.length l)
+*)
+
+(* By row version *)
+
+let rec first l ~len =
+ if len = 0 then [], l else
+ match l with
+ [] -> make_list ~len ~fill:"", []
+ | a::l ->
+ let (l',r) = first ~len:(len - 1) l in a::l',r
+
+let rec split l ~len =
+ if l = [] then make_list ~len ~fill:[] else
+ let (cars,r) = first l ~len in
+ let cdrs = split r ~len in
+ List.map2 cars cdrs ~f:(fun a l -> a::l)
+
+
+open Tk
+
+class c ~cols ~texts ?maxheight ?width parent = object (self)
+ val parent' = coe parent
+ val length = List.length texts
+ val boxes =
+ let height = (List.length texts - 1) / cols + 1 in
+ let height =
+ match maxheight with None -> height
+ | Some max -> min max height
+ in
+ gen_list ~len:cols ~f:
+ begin fun () ->
+ Listbox.create parent ~height ?width
+ ~highlightthickness:0
+ ~borderwidth:1
+ end
+ val mutable current = 0
+ method cols = cols
+ method texts = texts
+ method parent = parent'
+ method boxes = boxes
+ method current = current
+ method recenter ?(aligntop=false) n =
+ current <-
+ if n < 0 then 0 else
+ if n < length then n else length - 1;
+ (* Activate it, to keep consistent with Up/Down.
+ You have to be in Extended or Browse mode *)
+ let box = List.nth boxes (current mod cols)
+ and index = `Num (current / cols) in
+ List.iter boxes ~f:
+ begin fun box ->
+ Listbox.selection_clear box ~first:(`Num 0) ~last:`End;
+ Listbox.selection_anchor box ~index;
+ Listbox.activate box ~index
+ end;
+ Focus.set box;
+ if aligntop then Listbox.yview_index box ~index
+ else Listbox.see box ~index;
+ let (first,last) = Listbox.yview_get box in
+ List.iter boxes ~f:(Listbox.yview ~scroll:(`Moveto first))
+ method init =
+ let textl = split ~len:cols texts in
+ List.iter2 boxes textl ~f:
+ begin fun box texts ->
+ Jg_bind.enter_focus box;
+ Listbox.insert box ~texts ~index:`End
+ end;
+ pack boxes ~side:`Left ~expand:true ~fill:`Both;
+ self#bind_mouse ~events:[`ButtonPressDetail 1]
+ ~action:(fun _ ~index:n -> self#recenter n; break ());
+ let current_height () =
+ let (top,bottom) = Listbox.yview_get (List.hd boxes) in
+ truncate ((bottom -. top) *. float (Listbox.size (List.hd boxes))
+ +. 0.99)
+ in
+ List.iter
+ [ "Right", (fun n -> n+1);
+ "Left", (fun n -> n-1);
+ "Up", (fun n -> n-cols);
+ "Down", (fun n -> n+cols);
+ "Prior", (fun n -> n - current_height () * cols);
+ "Next", (fun n -> n + current_height () * cols);
+ "Home", (fun _ -> 0);
+ "End", (fun _ -> List.length texts) ]
+ ~f:begin fun (key,f) ->
+ self#bind_kbd ~events:[`KeyPressDetail key]
+ ~action:(fun _ ~index:n -> self#recenter (f n); break ())
+ end;
+ self#recenter 0
+ method bind_mouse ~events ~action =
+ let i = ref 0 in
+ List.iter boxes ~f:
+ begin fun box ->
+ let b = !i in
+ bind box ~events ~breakable:true ~fields:[`MouseX;`MouseY]
+ ~action:(fun ev ->
+ let `Num n = Listbox.nearest box ~y:ev.ev_MouseY
+ in action ev ~index:(n * cols + b));
+ incr i
+ end
+ method bind_kbd ~events ~action =
+ let i = ref 0 in
+ List.iter boxes ~f:
+ begin fun box ->
+ let b = !i in
+ bind box ~events ~breakable:true ~fields:[`Char]
+ ~action:(fun ev ->
+ let `Num n = Listbox.index box ~index:`Active in
+ action ev ~index:(n * cols + b));
+ incr i
+ end
+end
+
+let add_scrollbar (box : c) =
+ let boxes = box#boxes in
+ let sb =
+ Scrollbar.create (box#parent)
+ ~command:(fun ~scroll -> List.iter boxes ~f:(Listbox.yview ~scroll)) in
+ List.iter boxes
+ ~f:(fun lb -> Listbox.configure lb ~yscrollcommand:(Scrollbar.set sb));
+ pack [sb] ~before:(List.hd boxes) ~side:`Right ~fill:`Y;
+ sb
+
+let add_completion ?action ?wait (box : c) =
+ let comp = new Jg_completion.timed (box#texts) ?wait in
+ box#bind_kbd ~events:[`KeyPress]
+ ~action:(fun ev ~index ->
+ (* consider only keys producing characters. The callback is called
+ * even if you press Shift. *)
+ if ev.ev_Char <> "" then
+ box#recenter (comp#add ev.ev_Char) ~aligntop:true);
+ match action with
+ Some action ->
+ box#bind_kbd ~events:[`KeyPressDetail "space"]
+ ~action:(fun ev ~index -> action (box#current));
+ box#bind_kbd ~events:[`KeyPressDetail "Return"]
+ ~action:(fun ev ~index -> action (box#current));
+ box#bind_mouse ~events:[`ButtonPressDetail 1]
+ ~action:(fun ev ~index ->
+ box#recenter index; action (box#current); break ())
+ | None -> ()
diff --git a/ocaml-binary-annot/otherlibs/labltk/browser/jg_multibox.mli b/ocaml-binary-annot/otherlibs/labltk/browser/jg_multibox.mli
new file mode 100644
index 0000000000..6dfe7d8fb3
--- /dev/null
+++ b/ocaml-binary-annot/otherlibs/labltk/browser/jg_multibox.mli
@@ -0,0 +1,35 @@
+(*************************************************************************)
+(* *)
+(* Objective Caml LablTk library *)
+(* *)
+(* Jacques Garrigue, Kyoto University RIMS *)
+(* *)
+(* Copyright 1999 Institut National de Recherche en Informatique et *)
+(* en Automatique and Kyoto University. All rights reserved. *)
+(* This file is distributed under the terms of the GNU Library *)
+(* General Public License, with the special exception on linking *)
+(* described in file ../../../LICENSE. *)
+(* *)
+(*************************************************************************)
+
+(* $Id$ *)
+
+class c :
+ cols:int -> texts:string list ->
+ ?maxheight:int -> ?width:int -> 'a Widget.widget ->
+object
+ method cols : int
+ method texts : string list
+ method parent : Widget.any Widget.widget
+ method boxes : Widget.listbox Widget.widget list
+ method current : int
+ method init : unit
+ method recenter : ?aligntop:bool -> int -> unit
+ method bind_mouse :
+ events:Tk.event list -> action:(Tk.eventInfo -> index:int -> unit) -> unit
+ method bind_kbd :
+ events:Tk.event list -> action:(Tk.eventInfo -> index:int -> unit) -> unit
+end
+
+val add_scrollbar : c -> Widget.scrollbar Widget.widget
+val add_completion : ?action:(int -> unit) -> ?wait:int -> c -> unit
diff --git a/ocaml-binary-annot/otherlibs/labltk/browser/jg_text.ml b/ocaml-binary-annot/otherlibs/labltk/browser/jg_text.ml
new file mode 100644
index 0000000000..067b9dac55
--- /dev/null
+++ b/ocaml-binary-annot/otherlibs/labltk/browser/jg_text.ml
@@ -0,0 +1,104 @@
+(*************************************************************************)
+(* *)
+(* Objective Caml LablTk library *)
+(* *)
+(* Jacques Garrigue, Kyoto University RIMS *)
+(* *)
+(* Copyright 1999 Institut National de Recherche en Informatique et *)
+(* en Automatique and Kyoto University. All rights reserved. *)
+(* This file is distributed under the terms of the GNU Library *)
+(* General Public License, with the special exception on linking *)
+(* described in file ../../../LICENSE. *)
+(* *)
+(*************************************************************************)
+
+(* $Id$ *)
+
+open StdLabels
+open Tk
+open Jg_tk
+
+let get_all tw = Text.get tw ~start:tstart ~stop:(tposend 1)
+
+let tag_and_see tw ~tag ~start ~stop =
+ Text.tag_remove tw ~start:(tpos 0) ~stop:tend ~tag;
+ Text.tag_add tw ~start ~stop ~tag;
+ try
+ Text.see tw ~index:(`Tagfirst tag, []);
+ Text.mark_set tw ~mark:"insert" ~index:(`Tagfirst tag, [])
+ with Protocol.TkError _ -> ()
+
+let output tw ~buf ~pos ~len =
+ Text.insert tw ~index:tend ~text:(String.sub buf ~pos ~len)
+
+let add_scrollbar tw =
+ let sb = Scrollbar.create (Winfo.parent tw) ~command:(Text.yview tw)
+ in Text.configure tw ~yscrollcommand:(Scrollbar.set sb); sb
+
+let create_with_scrollbar parent =
+ let frame = Frame.create parent in
+ let tw = Text.create frame in
+ frame, tw, add_scrollbar tw
+
+let goto_tag tw ~tag =
+ let index = (`Tagfirst tag, []) in
+ try Text.see tw ~index;
+ Text.mark_set tw ~index ~mark:"insert"
+ with Protocol.TkError _ -> ()
+
+let search_string tw =
+ let tl = Jg_toplevel.titled "Search" in
+ Wm.transient_set tl ~master:(Winfo.toplevel tw);
+ let fi = Frame.create tl
+ and fd = Frame.create tl
+ and fm = Frame.create tl
+ and buttons = Frame.create tl
+ and direction = Textvariable.create ~on:tl ()
+ and mode = Textvariable.create ~on:tl ()
+ and count = Textvariable.create ~on:tl ()
+ in
+ let label = Label.create fi ~text:"Pattern:"
+ and text = Entry.create fi ~width:20
+ and back = Radiobutton.create fd ~variable:direction
+ ~text:"Backwards" ~value:"backward"
+ and forw = Radiobutton.create fd ~variable:direction
+ ~text:"Forwards" ~value:"forward"
+ and exact = Radiobutton.create fm ~variable:mode
+ ~text:"Exact" ~value:"exact"
+ and nocase = Radiobutton.create fm ~variable:mode
+ ~text:"No case" ~value:"nocase"
+ and regexp = Radiobutton.create fm ~variable:mode
+ ~text:"Regexp" ~value:"regexp"
+ in
+ let search = Button.create buttons ~text:"Search" ~command:
+ begin fun () ->
+ try
+ let pattern = Entry.get text in
+ let dir, ofs = match Textvariable.get direction with
+ "forward" -> `Forwards, 1
+ | "backward" -> `Backwards, -1
+ | _ -> assert false
+ and mode = match Textvariable.get mode with "exact" -> [`Exact]
+ | "nocase" -> [`Nocase] | "regexp" -> [`Regexp] | _ -> []
+ in
+ let ndx =
+ Text.search tw ~pattern ~switches:([dir;`Count count] @ mode)
+ ~start:(`Mark "insert", [`Char ofs])
+ in
+ tag_and_see tw ~tag:"sel" ~start:(ndx,[])
+ ~stop:(ndx,[`Char(int_of_string (Textvariable.get count))])
+ with Invalid_argument _ -> ()
+ end
+ and ok = Jg_button.create_destroyer tl ~parent:buttons ~text:"Cancel" in
+
+ Focus.set text;
+ Jg_bind.return_invoke text ~button:search;
+ Jg_bind.escape_destroy tl;
+ Textvariable.set direction "forward";
+ Textvariable.set mode "nocase";
+ pack [label] ~side:`Left;
+ pack [text] ~side:`Right ~fill:`X ~expand:true;
+ pack [back; forw] ~side:`Left;
+ pack [exact; nocase; regexp] ~side:`Left;
+ pack [search; ok] ~side:`Left ~fill:`X ~expand:true;
+ pack [fi; fd; fm; buttons] ~side:`Top ~fill:`X
diff --git a/ocaml-binary-annot/otherlibs/labltk/browser/jg_text.mli b/ocaml-binary-annot/otherlibs/labltk/browser/jg_text.mli
new file mode 100644
index 0000000000..e8646dd9d1
--- /dev/null
+++ b/ocaml-binary-annot/otherlibs/labltk/browser/jg_text.mli
@@ -0,0 +1,28 @@
+(*************************************************************************)
+(* *)
+(* Objective Caml LablTk library *)
+(* *)
+(* Jacques Garrigue, Kyoto University RIMS *)
+(* *)
+(* Copyright 1999 Institut National de Recherche en Informatique et *)
+(* en Automatique and Kyoto University. All rights reserved. *)
+(* This file is distributed under the terms of the GNU Library *)
+(* General Public License, with the special exception on linking *)
+(* described in file ../../../LICENSE. *)
+(* *)
+(*************************************************************************)
+
+(* $Id$ *)
+
+open Widget
+
+val get_all : text widget -> string
+val tag_and_see :
+ text widget ->
+ tag:Tk.textTag -> start:Tk.textIndex -> stop:Tk.textIndex -> unit
+val output : text widget -> buf:string -> pos:int -> len:int -> unit
+val add_scrollbar : text widget -> scrollbar widget
+val create_with_scrollbar :
+ 'a widget -> frame widget * text widget * scrollbar widget
+val goto_tag : text widget -> tag:string -> unit
+val search_string : text widget -> unit
diff --git a/ocaml-binary-annot/otherlibs/labltk/browser/jg_tk.ml b/ocaml-binary-annot/otherlibs/labltk/browser/jg_tk.ml
new file mode 100644
index 0000000000..7fc77f096a
--- /dev/null
+++ b/ocaml-binary-annot/otherlibs/labltk/browser/jg_tk.ml
@@ -0,0 +1,24 @@
+(*************************************************************************)
+(* *)
+(* Objective Caml LablTk library *)
+(* *)
+(* Jacques Garrigue, Kyoto University RIMS *)
+(* *)
+(* Copyright 1999 Institut National de Recherche en Informatique et *)
+(* en Automatique and Kyoto University. All rights reserved. *)
+(* This file is distributed under the terms of the GNU Library *)
+(* General Public License, with the special exception on linking *)
+(* described in file ../../../LICENSE. *)
+(* *)
+(*************************************************************************)
+
+(* $Id$ *)
+
+open Tk
+
+let tpos ?(modi=[]) x : textIndex = `Linechar (1,0), `Char x :: modi
+and tposend ?(modi=[]) x : textIndex = `End, `Char (-x) :: modi
+let tstart : textIndex = `Linechar (1,0), []
+and tend : textIndex = `End, []
+
+let wingui = Sys.os_type = "Win32" || Sys.os_type = "Cygwin"
diff --git a/ocaml-binary-annot/otherlibs/labltk/browser/jg_toplevel.ml b/ocaml-binary-annot/otherlibs/labltk/browser/jg_toplevel.ml
new file mode 100644
index 0000000000..64b6f54d76
--- /dev/null
+++ b/ocaml-binary-annot/otherlibs/labltk/browser/jg_toplevel.ml
@@ -0,0 +1,25 @@
+(*************************************************************************)
+(* *)
+(* Objective Caml LablTk library *)
+(* *)
+(* Jacques Garrigue, Kyoto University RIMS *)
+(* *)
+(* Copyright 1999 Institut National de Recherche en Informatique et *)
+(* en Automatique and Kyoto University. All rights reserved. *)
+(* This file is distributed under the terms of the GNU Library *)
+(* General Public License, with the special exception on linking *)
+(* described in file ../../../LICENSE. *)
+(* *)
+(*************************************************************************)
+
+(* $Id$ *)
+
+open Tk
+
+let titled ?iconname title =
+ let iconname = match iconname with None -> title | Some s -> s in
+ let tl = Toplevel.create Widget.default_toplevel in
+ Wm.title_set tl title;
+ Wm.iconname_set tl iconname;
+ Wm.group_set tl ~leader: Widget.default_toplevel;
+ tl
diff --git a/ocaml-binary-annot/otherlibs/labltk/browser/jglib.mllib b/ocaml-binary-annot/otherlibs/labltk/browser/jglib.mllib
new file mode 100644
index 0000000000..5c254ff552
--- /dev/null
+++ b/ocaml-binary-annot/otherlibs/labltk/browser/jglib.mllib
@@ -0,0 +1,13 @@
+Jg_tk
+Jg_config
+Jg_bind
+Jg_completion
+Jg_box
+Jg_button
+Jg_toplevel
+Jg_text
+Jg_message
+Jg_menu
+Jg_entry
+Jg_multibox
+Jg_memo
diff --git a/ocaml-binary-annot/otherlibs/labltk/browser/lexical.ml b/ocaml-binary-annot/otherlibs/labltk/browser/lexical.ml
new file mode 100644
index 0000000000..72f1957ec0
--- /dev/null
+++ b/ocaml-binary-annot/otherlibs/labltk/browser/lexical.ml
@@ -0,0 +1,145 @@
+(*************************************************************************)
+(* *)
+(* Objective Caml LablTk library *)
+(* *)
+(* Jacques Garrigue, Kyoto University RIMS *)
+(* *)
+(* Copyright 1999 Institut National de Recherche en Informatique et *)
+(* en Automatique and Kyoto University. All rights reserved. *)
+(* This file is distributed under the terms of the GNU Library *)
+(* General Public License, with the special exception on linking *)
+(* described in file ../../../LICENSE. *)
+(* *)
+(*************************************************************************)
+
+(* $Id$ *)
+
+open StdLabels
+open Tk
+open Jg_tk
+open Parser
+
+let tags =
+ ["control"; "define"; "structure"; "char";
+ "infix"; "label"; "uident"]
+and colors =
+ ["blue"; "forestgreen"; "purple"; "gray40";
+ "indianred4"; "saddlebrown"; "midnightblue"]
+
+let init_tags tw =
+ List.iter2 tags colors ~f:
+ begin fun tag col ->
+ Text.tag_configure tw ~tag ~foreground:(`Color col)
+ end;
+ Text.tag_configure tw ~tag:"error" ~foreground:`Red;
+ Text.tag_configure tw ~tag:"error" ~relief:`Raised;
+ Text.tag_raise tw ~tag:"error"
+
+let tag ?(start=tstart) ?(stop=tend) tw =
+ let tpos c = (Text.index tw ~index:start, [`Char c]) in
+ let text = Text.get tw ~start ~stop in
+ let buffer = Lexing.from_string text in
+ Location.init buffer "";
+ Location.input_name := "";
+ List.iter tags
+ ~f:(fun tag -> Text.tag_remove tw ~start ~stop ~tag);
+ let last = ref (EOF, 0, 0) in
+ try
+ while true do
+ let token = Lexer.token buffer
+ and start = Lexing.lexeme_start buffer
+ and stop = Lexing.lexeme_end buffer in
+ let tag =
+ match token with
+ AMPERAMPER
+ | AMPERSAND
+ | BARBAR
+ | DO | DONE
+ | DOWNTO
+ | ELSE
+ | FOR
+ | IF
+ | LAZY
+ | MATCH
+ | OR
+ | THEN
+ | TO
+ | TRY
+ | WHEN
+ | WHILE
+ | WITH
+ -> "control"
+ | AND
+ | AS
+ | BAR
+ | CLASS
+ | CONSTRAINT
+ | EXCEPTION
+ | EXTERNAL
+ | FUN
+ | FUNCTION
+ | FUNCTOR
+ | IN
+ | INHERIT
+ | INITIALIZER
+ | LET
+ | METHOD
+ | MODULE
+ | MUTABLE
+ | NEW
+ | OF
+ | PRIVATE
+ | REC
+ | TYPE
+ | VAL
+ | VIRTUAL
+ -> "define"
+ | BEGIN
+ | END
+ | INCLUDE
+ | OBJECT
+ | OPEN
+ | SIG
+ | STRUCT
+ -> "structure"
+ | CHAR _
+ | STRING _
+ -> "char"
+ | BACKQUOTE
+ | INFIXOP1 _
+ | INFIXOP2 _
+ | INFIXOP3 _
+ | INFIXOP4 _
+ | PREFIXOP _
+ | SHARP
+ -> "infix"
+ | LABEL _
+ | OPTLABEL _
+ | QUESTION
+ | TILDE
+ -> "label"
+ | UIDENT _ -> "uident"
+ | LIDENT _ ->
+ begin match !last with
+ (QUESTION | TILDE), _, _ -> "label"
+ | _ -> ""
+ end
+ | COLON ->
+ begin match !last with
+ LIDENT _, lstart, lstop ->
+ if lstop = start then
+ Text.tag_add tw ~tag:"label"
+ ~start:(tpos lstart) ~stop:(tpos stop);
+ ""
+ | _ -> ""
+ end
+ | EOF -> raise End_of_file
+ | _ -> ""
+ in
+ if tag <> "" then
+ Text.tag_add tw ~tag ~start:(tpos start) ~stop:(tpos stop);
+ last := (token, start, stop)
+ done
+ with
+ End_of_file -> ()
+ | Lexer.Error (err, loc) -> ()
diff --git a/ocaml-binary-annot/otherlibs/labltk/browser/lexical.mli b/ocaml-binary-annot/otherlibs/labltk/browser/lexical.mli
new file mode 100644
index 0000000000..3be04d3246
--- /dev/null
+++ b/ocaml-binary-annot/otherlibs/labltk/browser/lexical.mli
@@ -0,0 +1,20 @@
+(*************************************************************************)
+(* *)
+(* Objective Caml LablTk library *)
+(* *)
+(* Jacques Garrigue, Kyoto University RIMS *)
+(* *)
+(* Copyright 1999 Institut National de Recherche en Informatique et *)
+(* en Automatique and Kyoto University. All rights reserved. *)
+(* This file is distributed under the terms of the GNU Library *)
+(* General Public License, with the special exception on linking *)
+(* described in file ../../../LICENSE. *)
+(* *)
+(*************************************************************************)
+
+(* $Id$ *)
+
+open Widget
+
+val init_tags : text widget -> unit
+val tag : ?start:Tk.textIndex -> ?stop:Tk.textIndex -> text widget -> unit
diff --git a/ocaml-binary-annot/otherlibs/labltk/browser/list2.ml b/ocaml-binary-annot/otherlibs/labltk/browser/list2.ml
new file mode 100644
index 0000000000..87b88f496a
--- /dev/null
+++ b/ocaml-binary-annot/otherlibs/labltk/browser/list2.ml
@@ -0,0 +1,23 @@
+(*************************************************************************)
+(* *)
+(* Objective Caml LablTk library *)
+(* *)
+(* Jacques Garrigue, Kyoto University RIMS *)
+(* *)
+(* Copyright 1999 Institut National de Recherche en Informatique et *)
+(* en Automatique and Kyoto University. All rights reserved. *)
+(* This file is distributed under the terms of the GNU Library *)
+(* General Public License, with the special exception on linking *)
+(* described in file ../../../LICENSE. *)
+(* *)
+(*************************************************************************)
+
+(* $Id$ *)
+
+open StdLabels
+
+let exclude x l = List.filter l ~f:((<>) x)
+
+let rec flat_map ~f = function
+ [] -> []
+ | x :: l -> f x @ flat_map ~f l
diff --git a/ocaml-binary-annot/otherlibs/labltk/browser/main.ml b/ocaml-binary-annot/otherlibs/labltk/browser/main.ml
new file mode 100644
index 0000000000..181506960a
--- /dev/null
+++ b/ocaml-binary-annot/otherlibs/labltk/browser/main.ml
@@ -0,0 +1,132 @@
+(*************************************************************************)
+(* *)
+(* Objective Caml LablTk library *)
+(* *)
+(* Jacques Garrigue, Kyoto University RIMS *)
+(* *)
+(* Copyright 1999 Institut National de Recherche en Informatique et *)
+(* en Automatique and Kyoto University. All rights reserved. *)
+(* This file is distributed under the terms of the GNU Library *)
+(* General Public License, with the special exception on linking *)
+(* described in file ../../../LICENSE. *)
+(* *)
+(*************************************************************************)
+
+(* $Id$ *)
+
+open StdLabels
+module Unix = UnixLabels
+open Tk
+
+let fatal_error text =
+ let top = openTk ~clas:"OCamlBrowser" () in
+ let mw = Message.create top ~text ~padx:20 ~pady:10
+ ~width:400 ~justify:`Left ~aspect:400 ~anchor:`W
+ and b = Button.create top ~text:"OK" ~command:(fun () -> destroy top) in
+ pack [mw] ~side:`Top ~fill:`Both;
+ pack [b] ~side:`Bottom;
+ mainLoop ();
+ exit 0
+
+let rec get_incr key = function
+ [] -> raise Not_found
+ | (k, c, d) :: rem ->
+ if k = key then
+ match c with Arg.Set _ | Arg.Clear _ | Arg.Unit _ -> false | _ -> true
+ else get_incr key rem
+
+let check ~spec argv =
+ let i = ref 1 in
+ while !i < Array.length argv do
+ try
+ let a = get_incr argv.(!i) spec in
+ incr i; if a then incr i
+ with Not_found ->
+ i := Array.length argv + 1
+ done;
+ !i = Array.length argv
+
+open Printf
+
+let print_version () =
+ printf "The Objective Caml browser, version %s\n" Sys.ocaml_version;
+ exit 0;
+;;
+
+let print_version_num () =
+ printf "%s\n" Sys.ocaml_version;
+ exit 0;
+;;
+
+let usage ~spec errmsg =
+ let b = Buffer.create 1024 in
+ bprintf b "%s\n" errmsg;
+ List.iter (function (key, _, doc) -> bprintf b " %s %s\n" key doc) spec;
+ Buffer.contents b
+
+let _ =
+ let is_win32 = Sys.os_type = "Win32" in
+ if is_win32 then
+ Format.pp_set_formatter_output_functions Format.err_formatter
+ (fun _ _ _ -> ()) (fun _ -> ());
+
+ let path = ref [] in
+ let st = ref true in
+ let spec =
+ [ "-I", Arg.String (fun s -> path := s :: !path),
+ "<dir> Add <dir> to the list of include directories";
+ "-labels", Arg.Clear Clflags.classic, " <obsolete>";
+ "-nolabels", Arg.Set Clflags.classic,
+ " Ignore non-optional labels in types";
+ "-oldui", Arg.Clear st, " Revert back to old UI";
+ "-pp", Arg.String (fun s -> Clflags.preprocessor := Some s),
+ "<command> Pipe sources through preprocessor <command>";
+ "-rectypes", Arg.Set Clflags.recursive_types,
+ " Allow arbitrary recursive types";
+ "-version", Arg.Unit print_version,
+ " Print version and exit";
+ "-vnum", Arg.Unit print_version_num, " Print version number and exit";
+ "-w", Arg.String (fun s -> Shell.warnings := s),
+ "<flags> Enable or disable warnings according to <flags>"; ]
+ and errmsg = "Command line: ocamlbrowser <options>" in
+ if not (check ~spec Sys.argv) then fatal_error (usage ~spec errmsg);
+ Arg.parse spec
+ (fun name -> raise(Arg.Bad("don't know what to do with " ^ name)))
+ errmsg;
+ Config.load_path :=
+ Sys.getcwd ()
+ :: List.rev_map ~f:(Misc.expand_directory Config.standard_library) !path
+ @ [Config.standard_library];
+ Warnings.parse_options false !Shell.warnings;
+ Unix.putenv "TERM" "noterminal";
+ begin
+ try Searchid.start_env := Env.open_pers_signature "Pervasives" Env.initial
+ with _ ->
+ fatal_error
+ (Printf.sprintf "%s\nPlease check that %s %s\nCurrent value is `%s'"
+ "Couldn't initialize environment."
+ (if is_win32 then "%OCAMLLIB%" else "$OCAMLLIB")
+ "points to the Objective Caml library."
+ Config.standard_library)
+ end;
+
+ Searchpos.view_defined_ref := (fun s ~env -> Viewer.view_defined s ~env);
+ Searchpos.editor_ref := Editor.f;
+
+ let top = openTk ~clas:"OCamlBrowser" () in
+ Jg_config.init ();
+
+ (* bind top ~events:[`Destroy] ~action:(fun _ -> exit 0); *)
+ at_exit Shell.kill_all;
+
+
+ if !st then Viewer.st_viewer ~on:top ()
+ else Viewer.f ~on:top ();
+
+ while true do
+ try
+ if is_win32 then mainLoop ()
+ else Printexc.print mainLoop ()
+ with Protocol.TkError _ ->
+ if not is_win32 then flush stderr
+ done
diff --git a/ocaml-binary-annot/otherlibs/labltk/browser/mytypes.mli b/ocaml-binary-annot/otherlibs/labltk/browser/mytypes.mli
new file mode 100644
index 0000000000..6db120adcc
--- /dev/null
+++ b/ocaml-binary-annot/otherlibs/labltk/browser/mytypes.mli
@@ -0,0 +1,29 @@
+(*************************************************************************)
+(* *)
+(* Objective Caml LablTk library *)
+(* *)
+(* Jacques Garrigue, Kyoto University RIMS *)
+(* *)
+(* Copyright 1999 Institut National de Recherche en Informatique et *)
+(* en Automatique and Kyoto University. All rights reserved. *)
+(* This file is distributed under the terms of the GNU Library *)
+(* General Public License, with the special exception on linking *)
+(* described in file ../../../LICENSE. *)
+(* *)
+(*************************************************************************)
+
+(* $Id$ *)
+
+open Widget
+
+type edit_window =
+ { mutable name: string;
+ tw: text widget;
+ frame: frame widget;
+ modified: Textvariable.textVariable;
+ mutable shell: (string * Shell.shell) option;
+ mutable structure: Typedtree.structure;
+ mutable type_info: Stypes.annotation list;
+ mutable signature: Types.signature;
+ mutable psignature: Parsetree.signature;
+ number: string }
diff --git a/ocaml-binary-annot/otherlibs/labltk/browser/searchid.ml b/ocaml-binary-annot/otherlibs/labltk/browser/searchid.ml
new file mode 100644
index 0000000000..6742039c11
--- /dev/null
+++ b/ocaml-binary-annot/otherlibs/labltk/browser/searchid.ml
@@ -0,0 +1,533 @@
+(*************************************************************************)
+(* *)
+(* Objective Caml LablTk library *)
+(* *)
+(* Jacques Garrigue, Kyoto University RIMS *)
+(* *)
+(* Copyright 1999 Institut National de Recherche en Informatique et *)
+(* en Automatique and Kyoto University. All rights reserved. *)
+(* This file is distributed under the terms of the GNU Library *)
+(* General Public License, with the special exception on linking *)
+(* described in file ../../../LICENSE. *)
+(* *)
+(*************************************************************************)
+
+(* $Id$ *)
+
+open StdLabels
+open Location
+open Longident
+open Path
+open Types
+open Typedtree
+open Env
+open Btype
+open Ctype
+
+(* only initial here, but replaced by Pervasives later *)
+let start_env = ref initial
+let module_list = ref []
+
+type pkind =
+ Pvalue
+ | Ptype
+ | Plabel
+ | Pconstructor
+ | Pmodule
+ | Pmodtype
+ | Pclass
+ | Pcltype
+
+let string_of_kind = function
+ Pvalue -> "v"
+ | Ptype -> "t"
+ | Plabel -> "l"
+ | Pconstructor -> "cn"
+ | Pmodule -> "m"
+ | Pmodtype -> "s"
+ | Pclass -> "c"
+ | Pcltype -> "ct"
+
+let rec longident_of_path = function
+ Pident id -> Lident (Ident.name id)
+ | Pdot (path, s, _) -> Ldot (longident_of_path path, s)
+ | Papply (p1, p2) -> Lapply (longident_of_path p1, longident_of_path p2)
+
+let rec remove_prefix lid ~prefix =
+ let rec remove_hd lid ~name =
+ match lid with
+ Ldot (Lident s1, s2) when s1 = name -> Lident s2
+ | Ldot (l, s) -> Ldot (remove_hd ~name l, s)
+ | _ -> raise Not_found
+ in
+ match prefix with
+ [] -> lid
+ | name :: prefix ->
+ try remove_prefix ~prefix (remove_hd ~name lid)
+ with Not_found -> lid
+
+let rec permutations l = match l with
+ [] | [_] -> [l]
+ | [a;b] -> [l; [b;a]]
+ | _ ->
+ let _, perms =
+ List.fold_left l ~init:(l,[]) ~f:
+ begin fun (l, perms) a ->
+ let l = List.tl l in
+ l @ [a],
+ List.map (permutations l) ~f:(fun l -> a :: l) @ perms
+ end
+ in perms
+
+let rec choose n ~card:l =
+ let len = List.length l in
+ if n = len then [l] else
+ if n = 1 then List.map l ~f:(fun x -> [x]) else
+ if n = 0 then [[]] else
+ if n > len then [] else
+ match l with [] -> []
+ | a :: l ->
+ List.map (choose (n-1) ~card:l) ~f:(fun l -> a :: l)
+ @ choose n ~card:l
+
+let rec arr p ~card:n =
+ if p = 0 then 1 else n * arr (p-1) ~card:(n-1)
+
+let rec all_args ty =
+ let ty = repr ty in
+ match ty.desc with
+ Tarrow(l, ty1, ty2, _) -> let (tl,ty) = all_args ty2 in ((l,ty1)::tl, ty)
+ | _ -> ([], ty)
+
+let rec equal ~prefix t1 t2 =
+ match (repr t1).desc, (repr t2).desc with
+ Tvar, Tvar -> true
+ | Tvariant row1, Tvariant row2 ->
+ let row1 = row_repr row1 and row2 = row_repr row2 in
+ let fields1 = filter_row_fields false row1.row_fields
+ and fields2 = filter_row_fields false row1.row_fields
+ in
+ let r1, r2, pairs = merge_row_fields fields1 fields2 in
+ row1.row_closed = row2.row_closed && r1 = [] && r2 = [] &&
+ List.for_all pairs ~f:
+ begin fun (_,f1,f2) ->
+ match row_field_repr f1, row_field_repr f2 with
+ Rpresent None, Rpresent None -> true
+ | Rpresent(Some t1), Rpresent (Some t2) -> equal t1 t2 ~prefix
+ | Reither(c1, tl1, _, _), Reither(c2, tl2, _, _) ->
+ c1 = c2 && List.length tl1 = List.length tl2 &&
+ List.for_all2 tl1 tl2 ~f:(equal ~prefix)
+ | _ -> false
+ end
+ | Tarrow _, Tarrow _ ->
+ let l1, t1 = all_args t1 and l2, t2 = all_args t2 in
+ equal t1 t2 ~prefix &&
+ List.length l1 = List.length l2 &&
+ List.exists (permutations l1) ~f:
+ begin fun l1 ->
+ List.for_all2 l1 l2 ~f:
+ begin fun (p1,t1) (p2,t2) ->
+ (p1 = "" || p1 = p2) && equal t1 t2 ~prefix
+ end
+ end
+ | Ttuple l1, Ttuple l2 ->
+ List.length l1 = List.length l2 &&
+ List.for_all2 l1 l2 ~f:(equal ~prefix)
+ | Tconstr (p1, l1, _), Tconstr (p2, l2, _) ->
+ remove_prefix ~prefix (longident_of_path p1) = (longident_of_path p2)
+ && List.length l1 = List.length l2
+ && List.for_all2 l1 l2 ~f:(equal ~prefix)
+ | _ -> false
+
+let is_opt s = s <> "" && s.[0] = '?'
+let get_options = List.filter ~f:is_opt
+
+let rec included ~prefix t1 t2 =
+ match (repr t1).desc, (repr t2).desc with
+ Tvar, _ -> true
+ | Tvariant row1, Tvariant row2 ->
+ let row1 = row_repr row1 and row2 = row_repr row2 in
+ let fields1 = filter_row_fields false row1.row_fields
+ and fields2 = filter_row_fields false row2.row_fields
+ in
+ let r1, r2, pairs = merge_row_fields fields1 fields2 in
+ r1 = [] &&
+ List.for_all pairs ~f:
+ begin fun (_,f1,f2) ->
+ match row_field_repr f1, row_field_repr f2 with
+ Rpresent None, Rpresent None -> true
+ | Rpresent(Some t1), Rpresent (Some t2) -> included t1 t2 ~prefix
+ | Reither(c1, tl1, _, _), Reither(c2, tl2, _, _) ->
+ c1 = c2 && List.length tl1 = List.length tl2 &&
+ List.for_all2 tl1 tl2 ~f:(included ~prefix)
+ | _ -> false
+ end
+ | Tarrow _, Tarrow _ ->
+ let l1, t1 = all_args t1 and l2, t2 = all_args t2 in
+ included t1 t2 ~prefix &&
+ let len1 = List.length l1 and len2 = List.length l2 in
+ let l2 = if arr len1 ~card:len2 < 100 then l2 else
+ let ll1 = get_options (fst (List.split l1)) in
+ List.filter l2
+ ~f:(fun (l,_) -> not (is_opt l) || List.mem l ll1)
+ in
+ len1 <= len2 &&
+ List.exists (List2.flat_map ~f:permutations (choose len1 ~card:l2)) ~f:
+ begin fun l2 ->
+ List.for_all2 l1 l2 ~f:
+ begin fun (p1,t1) (p2,t2) ->
+ (p1 = "" || p1 = p2) && included t1 t2 ~prefix
+ end
+ end
+ | Ttuple l1, Ttuple l2 ->
+ let len1 = List.length l1 in
+ len1 <= List.length l2 &&
+ List.exists (List2.flat_map ~f:permutations (choose len1 ~card:l2)) ~f:
+ begin fun l2 ->
+ List.for_all2 l1 l2 ~f:(included ~prefix)
+ end
+ | _, Ttuple _ -> included (newty (Ttuple [t1])) t2 ~prefix
+ | Tconstr (p1, l1, _), Tconstr (p2, l2, _) ->
+ remove_prefix ~prefix (longident_of_path p1) = (longident_of_path p2)
+ && List.length l1 = List.length l2
+ && List.for_all2 l1 l2 ~f:(included ~prefix)
+ | _ -> false
+
+let mklid = function
+ [] -> raise (Invalid_argument "Searchid.mklid")
+ | x :: l ->
+ List.fold_left l ~init:(Lident x) ~f:(fun acc x -> Ldot (acc, x))
+
+let mkpath = function
+ [] -> raise (Invalid_argument "Searchid.mklid")
+ | x :: l ->
+ List.fold_left l ~init:(Pident (Ident.create x))
+ ~f:(fun acc x -> Pdot (acc, x, 0))
+
+let get_fields ~prefix ~sign self =
+ let env = open_signature (mkpath prefix) sign initial in
+ match (expand_head env self).desc with
+ Tobject (ty_obj, _) ->
+ let l,_ = flatten_fields ty_obj in l
+ | _ -> []
+
+let rec search_type_in_signature t ~sign ~prefix ~mode =
+ let matches = match mode with
+ `Included -> included t ~prefix
+ | `Exact -> equal t ~prefix
+ and lid_of_id id = mklid (prefix @ [Ident.name id]) in
+ List2.flat_map sign ~f:
+ begin fun item -> match item with
+ Tsig_value (id, vd) ->
+ if matches vd.val_type then [lid_of_id id, Pvalue] else []
+ | Tsig_type (id, td, _) ->
+ if
+ begin match td.type_manifest with
+ None -> false
+ | Some t -> matches t
+ end ||
+ begin match td.type_kind with
+ Type_abstract -> false
+ | Type_variant l ->
+ List.exists l ~f:(fun (_, l) -> List.exists l ~f:matches)
+ | Type_record(l, rep) ->
+ List.exists l ~f:(fun (_, _, t) -> matches t)
+ end
+ then [lid_of_id id, Ptype] else []
+ | Tsig_exception (id, l) ->
+ if List.exists l ~f:matches
+ then [lid_of_id id, Pconstructor]
+ else []
+ | Tsig_module (id, Tmty_signature sign, _) ->
+ search_type_in_signature t ~sign ~mode
+ ~prefix:(prefix @ [Ident.name id])
+ | Tsig_module _ -> []
+ | Tsig_modtype _ -> []
+ | Tsig_class (id, cl, _) ->
+ let self = self_type cl.cty_type in
+ if matches self
+ || (match cl.cty_new with None -> false | Some ty -> matches ty)
+ (* || List.exists (get_fields ~prefix ~sign self)
+ ~f:(fun (_,_,ty_field) -> matches ty_field) *)
+ then [lid_of_id id, Pclass] else []
+ | Tsig_cltype (id, cl, _) ->
+ let self = self_type cl.clty_type in
+ if matches self
+ (* || List.exists (get_fields ~prefix ~sign self)
+ ~f:(fun (_,_,ty_field) -> matches ty_field) *)
+ then [lid_of_id id, Pclass] else []
+ end
+
+let search_all_types t ~mode =
+ let tl = match mode, t.desc with
+ `Exact, _ -> [t]
+ | `Included, Tarrow _ -> [t]
+ | `Included, _ ->
+ [t; newty(Tarrow("",t,newvar(),Cok)); newty(Tarrow("",newvar(),t,Cok))]
+ in List2.flat_map !module_list ~f:
+ begin fun modname ->
+ let mlid = Lident modname in
+ try match lookup_module mlid initial with
+ _, Tmty_signature sign ->
+ List2.flat_map tl
+ ~f:(search_type_in_signature ~sign ~prefix:[modname] ~mode)
+ | _ -> []
+ with Not_found | Env.Error _ -> []
+ end
+
+exception Error of int * int
+
+let search_string_type text ~mode =
+ try
+ let sexp = Parse.interface (Lexing.from_string ("val z : " ^ text)) in
+ let sign =
+ try Typemod.transl_signature !start_env sexp with _ ->
+ let env = List.fold_left !module_list ~init:initial ~f:
+ begin fun acc m ->
+ try open_pers_signature m acc with Env.Error _ -> acc
+ end in
+ try Typemod.transl_signature env sexp
+ with Env.Error err -> []
+ | Typemod.Error (l,_) ->
+ let start_c = l.loc_start.Lexing.pos_cnum in
+ let end_c = l.loc_end.Lexing.pos_cnum in
+ raise (Error (start_c - 8, end_c - 8))
+ | Typetexp.Error (l,_) ->
+ let start_c = l.loc_start.Lexing.pos_cnum in
+ let end_c = l.loc_end.Lexing.pos_cnum in
+ raise (Error (start_c - 8, end_c - 8))
+ in match sign with
+ [Tsig_value (_, vd)] ->
+ search_all_types vd.val_type ~mode
+ | _ -> []
+ with
+ Syntaxerr.Error(Syntaxerr.Unclosed(l,_,_,_)) ->
+ let start_c = l.loc_start.Lexing.pos_cnum in
+ let end_c = l.loc_end.Lexing.pos_cnum in
+ raise (Error (start_c - 8, end_c - 8))
+ | Syntaxerr.Error(Syntaxerr.Other l) ->
+ let start_c = l.loc_start.Lexing.pos_cnum in
+ let end_c = l.loc_end.Lexing.pos_cnum in
+ raise (Error (start_c - 8, end_c - 8))
+ | Lexer.Error (_, l) ->
+ let start_c = l.loc_start.Lexing.pos_cnum in
+ let end_c = l.loc_end.Lexing.pos_cnum in
+ raise (Error (start_c - 8, end_c - 8))
+
+let longident_of_string text =
+ let exploded = ref [] and l = ref 0 in
+ for i = 0 to String.length text - 2 do
+ if text.[i] ='.' then
+ (exploded := String.sub text ~pos:!l ~len:(i - !l) :: !exploded; l := i+1)
+ done;
+ let sym = String.sub text ~pos:!l ~len:(String.length text - !l) in
+ let rec mklid = function
+ [s] -> Lident s
+ | s :: l -> Ldot (mklid l, s)
+ | [] -> assert false in
+ sym, fun l -> mklid (sym :: !exploded @ l)
+
+
+let explode s =
+ let l = ref [] in
+ for i = String.length s - 1 downto 0 do
+ l := s.[i] :: !l
+ done; !l
+
+let rec check_match ~pattern s =
+ match pattern, s with
+ [], [] -> true
+ | '*'::l, l' -> check_match ~pattern:l l'
+ || check_match ~pattern:('?'::'*'::l) l'
+ | '?'::l, _::l' -> check_match ~pattern:l l'
+ | x::l, y::l' when x == y -> check_match ~pattern:l l'
+ | _ -> false
+
+let search_pattern_symbol text =
+ if text = "" then [] else
+ let pattern = explode text in
+ let check i = check_match ~pattern (explode (Ident.name i)) in
+ let l = List.map !module_list ~f:
+ begin fun modname -> Lident modname,
+ try match lookup_module (Lident modname) initial with
+ _, Tmty_signature sign ->
+ List2.flat_map sign ~f:
+ begin function
+ Tsig_value (i, _) when check i -> [i, Pvalue]
+ | Tsig_type (i, _, _) when check i -> [i, Ptype]
+ | Tsig_exception (i, _) when check i -> [i, Pconstructor]
+ | Tsig_module (i, _, _) when check i -> [i, Pmodule]
+ | Tsig_modtype (i, _) when check i -> [i, Pmodtype]
+ | Tsig_class (i, cl, _) when check i
+ || List.exists
+ (get_fields ~prefix:[modname] ~sign (self_type cl.cty_type))
+ ~f:(fun (name,_,_) -> check_match ~pattern (explode name))
+ -> [i, Pclass]
+ | Tsig_cltype (i, cl, _) when check i
+ || List.exists
+ (get_fields ~prefix:[modname] ~sign (self_type cl.clty_type))
+ ~f:(fun (name,_,_) -> check_match ~pattern (explode name))
+ -> [i, Pcltype]
+ | _ -> []
+ end
+ | _ -> []
+ with Env.Error _ -> []
+ end
+ in
+ List2.flat_map l ~f:
+ begin fun (m, l) ->
+ List.map l ~f:(fun (i, p) -> Ldot (m, Ident.name i), p)
+ end
+
+(*
+let is_pattern s =
+ try for i = 0 to String.length s -1 do
+ if s.[i] = '?' || s.[i] = '*' then raise Exit
+ done; false
+ with Exit -> true
+*)
+
+let search_string_symbol text =
+ if text = "" then [] else
+ let lid = snd (longident_of_string text) [] in
+ let try_lookup f k =
+ try let _ = f lid Env.initial in [lid, k]
+ with Not_found | Env.Error _ -> []
+ in
+ try_lookup lookup_constructor Pconstructor @
+ try_lookup lookup_module Pmodule @
+ try_lookup lookup_modtype Pmodtype @
+ try_lookup lookup_value Pvalue @
+ try_lookup lookup_type Ptype @
+ try_lookup lookup_label Plabel @
+ try_lookup lookup_class Pclass
+
+open Parsetree
+
+let rec bound_variables pat =
+ match pat.ppat_desc with
+ Ppat_any | Ppat_constant _ | Ppat_type _ | Ppat_unpack _ -> []
+ | Ppat_var s -> [s]
+ | Ppat_alias (pat,s) -> s :: bound_variables pat
+ | Ppat_tuple l -> List2.flat_map l ~f:bound_variables
+ | Ppat_construct (_,None,_) -> []
+ | Ppat_construct (_,Some pat,_) -> bound_variables pat
+ | Ppat_variant (_,None) -> []
+ | Ppat_variant (_,Some pat) -> bound_variables pat
+ | Ppat_record (l, _) ->
+ List2.flat_map l ~f:(fun (_,pat) -> bound_variables pat)
+ | Ppat_array l ->
+ List2.flat_map l ~f:bound_variables
+ | Ppat_or (pat1,pat2) ->
+ bound_variables pat1 @ bound_variables pat2
+ | Ppat_constraint (pat,_) -> bound_variables pat
+ | Ppat_lazy pat -> bound_variables pat
+
+let search_structure str ~name ~kind ~prefix =
+ let loc = ref 0 in
+ let rec search_module str ~prefix =
+ match prefix with [] -> str
+ | modu::prefix ->
+ let str =
+ List.fold_left ~init:[] str ~f:
+ begin fun acc item ->
+ match item.pstr_desc with
+ Pstr_module (s, mexp) when s = modu ->
+ loc := mexp.pmod_loc.loc_start.Lexing.pos_cnum;
+ begin match mexp.pmod_desc with
+ Pmod_structure str -> str
+ | _ -> []
+ end
+ | _ -> acc
+ end
+ in search_module str ~prefix
+ in
+ List.iter (search_module str ~prefix) ~f:
+ begin fun item ->
+ if match item.pstr_desc with
+ Pstr_value (_, l) when kind = Pvalue ->
+ List.iter l ~f:
+ begin fun (pat,_) ->
+ if List.mem name (bound_variables pat)
+ then loc := pat.ppat_loc.loc_start.Lexing.pos_cnum
+ end;
+ false
+ | Pstr_primitive (s, _) when kind = Pvalue -> name = s
+ | Pstr_type l when kind = Ptype ->
+ List.iter l ~f:
+ begin fun (s, td) ->
+ if s = name then loc := td.ptype_loc.loc_start.Lexing.pos_cnum
+ end;
+ false
+ | Pstr_exception (s, _) when kind = Pconstructor -> name = s
+ | Pstr_module (s, _) when kind = Pmodule -> name = s
+ | Pstr_modtype (s, _) when kind = Pmodtype -> name = s
+ | Pstr_class l when kind = Pclass || kind = Ptype || kind = Pcltype ->
+ List.iter l ~f:
+ begin fun c ->
+ if c.pci_name = name
+ then loc := c.pci_loc.loc_start.Lexing.pos_cnum
+ end;
+ false
+ | Pstr_class_type l when kind = Pcltype || kind = Ptype ->
+ List.iter l ~f:
+ begin fun c ->
+ if c.pci_name = name
+ then loc := c.pci_loc.loc_start.Lexing.pos_cnum
+ end;
+ false
+ | _ -> false
+ then loc := item.pstr_loc.loc_start.Lexing.pos_cnum
+ end;
+ !loc
+
+let search_signature sign ~name ~kind ~prefix =
+ let loc = ref 0 in
+ let rec search_module_type sign ~prefix =
+ match prefix with [] -> sign
+ | modu::prefix ->
+ let sign =
+ List.fold_left ~init:[] sign ~f:
+ begin fun acc item ->
+ match item.psig_desc with
+ Psig_module (s, mtyp) when s = modu ->
+ loc := mtyp.pmty_loc.loc_start.Lexing.pos_cnum;
+ begin match mtyp.pmty_desc with
+ Pmty_signature sign -> sign
+ | _ -> []
+ end
+ | _ -> acc
+ end
+ in search_module_type sign ~prefix
+ in
+ List.iter (search_module_type sign ~prefix) ~f:
+ begin fun item ->
+ if match item.psig_desc with
+ Psig_value (s, _) when kind = Pvalue -> name = s
+ | Psig_type l when kind = Ptype ->
+ List.iter l ~f:
+ begin fun (s, td) ->
+ if s = name then loc := td.ptype_loc.loc_start.Lexing.pos_cnum
+ end;
+ false
+ | Psig_exception (s, _) when kind = Pconstructor -> name = s
+ | Psig_module (s, _) when kind = Pmodule -> name = s
+ | Psig_modtype (s, _) when kind = Pmodtype -> name = s
+ | Psig_class l when kind = Pclass || kind = Ptype || kind = Pcltype ->
+ List.iter l ~f:
+ begin fun c ->
+ if c.pci_name = name
+ then loc := c.pci_loc.loc_start.Lexing.pos_cnum
+ end;
+ false
+ | Psig_class_type l when kind = Ptype || kind = Pcltype ->
+ List.iter l ~f:
+ begin fun c ->
+ if c.pci_name = name
+ then loc := c.pci_loc.loc_start.Lexing.pos_cnum
+ end;
+ false
+ | _ -> false
+ then loc := item.psig_loc.loc_start.Lexing.pos_cnum
+ end;
+ !loc
diff --git a/ocaml-binary-annot/otherlibs/labltk/browser/searchid.mli b/ocaml-binary-annot/otherlibs/labltk/browser/searchid.mli
new file mode 100644
index 0000000000..980c141d08
--- /dev/null
+++ b/ocaml-binary-annot/otherlibs/labltk/browser/searchid.mli
@@ -0,0 +1,45 @@
+(*************************************************************************)
+(* *)
+(* Objective Caml LablTk library *)
+(* *)
+(* Jacques Garrigue, Kyoto University RIMS *)
+(* *)
+(* Copyright 1999 Institut National de Recherche en Informatique et *)
+(* en Automatique and Kyoto University. All rights reserved. *)
+(* This file is distributed under the terms of the GNU Library *)
+(* General Public License, with the special exception on linking *)
+(* described in file ../../../LICENSE. *)
+(* *)
+(*************************************************************************)
+
+(* $Id$ *)
+
+val start_env : Env.t ref
+val module_list : string list ref
+val longident_of_path : Path.t ->Longident.t
+
+type pkind =
+ Pvalue
+ | Ptype
+ | Plabel
+ | Pconstructor
+ | Pmodule
+ | Pmodtype
+ | Pclass
+ | Pcltype
+
+val string_of_kind : pkind -> string
+
+exception Error of int * int
+
+val search_string_type :
+ string -> mode:[`Exact|`Included] -> (Longident.t * pkind) list
+val search_pattern_symbol : string -> (Longident.t * pkind) list
+val search_string_symbol : string -> (Longident.t * pkind) list
+
+val search_structure :
+ Parsetree.structure ->
+ name:string -> kind:pkind -> prefix:string list -> int
+val search_signature :
+ Parsetree.signature ->
+ name:string -> kind:pkind -> prefix:string list -> int
diff --git a/ocaml-binary-annot/otherlibs/labltk/browser/searchpos.ml b/ocaml-binary-annot/otherlibs/labltk/browser/searchpos.ml
new file mode 100644
index 0000000000..8cae995930
--- /dev/null
+++ b/ocaml-binary-annot/otherlibs/labltk/browser/searchpos.ml
@@ -0,0 +1,890 @@
+(*************************************************************************)
+(* *)
+(* Objective Caml LablTk library *)
+(* *)
+(* Jacques Garrigue, Kyoto University RIMS *)
+(* *)
+(* Copyright 1999 Institut National de Recherche en Informatique et *)
+(* en Automatique and Kyoto University. All rights reserved. *)
+(* This file is distributed under the terms of the GNU Library *)
+(* General Public License, with the special exception on linking *)
+(* described in file ../../../LICENSE. *)
+(* *)
+(*************************************************************************)
+
+(* $Id$ *)
+
+open StdLabels
+open Support
+open Tk
+open Jg_tk
+open Parsetree
+open Types
+open Typedtree
+open Location
+open Longident
+open Path
+open Env
+open Searchid
+
+(* auxiliary functions *)
+
+let (~!) = Jg_memo.fast ~f:Str.regexp
+
+let lines_to_chars n ~text:s =
+ let l = String.length s in
+ let rec ltc n ~pos =
+ if n = 1 || pos >= l then pos else
+ if s.[pos] = '\n' then ltc (n-1) ~pos:(pos+1) else ltc n ~pos:(pos+1)
+ in ltc n ~pos:0
+
+let in_loc loc ~pos =
+ loc.loc_ghost || pos >= loc.loc_start.Lexing.pos_cnum
+ && pos < loc.loc_end.Lexing.pos_cnum
+
+let le_loc loc1 loc2 =
+ loc1.loc_start.Lexing.pos_cnum <= loc2.loc_start.Lexing.pos_cnum
+ && loc1.loc_end.Lexing.pos_cnum >= loc2.loc_end.Lexing.pos_cnum
+
+let add_found ~found sol ~env ~loc =
+ if loc.loc_ghost then () else
+ if List.exists !found ~f:(fun (_,_,loc') -> le_loc loc loc') then ()
+ else found := (sol, env, loc) ::
+ List.filter !found ~f:(fun (_,_,loc') -> not (le_loc loc' loc))
+
+let observe ~ref ?init f x =
+ let old = !ref in
+ begin match init with None -> () | Some x -> ref := x end;
+ try (f x : unit); let v = !ref in ref := old; v
+ with exn -> ref := old; raise exn
+
+let rec string_of_longident = function
+ Lident s -> s
+ | Ldot (id,s) -> string_of_longident id ^ "." ^ s
+ | Lapply (id1, id2) ->
+ string_of_longident id1 ^ "(" ^ string_of_longident id2 ^ ")"
+
+let string_of_path p = string_of_longident (Searchid.longident_of_path p)
+
+let parent_path = function
+ Pdot (path, _, _) -> Some path
+ | Pident _ | Papply _ -> None
+
+let ident_of_path ~default = function
+ Pident i -> i
+ | Pdot (_, s, _) -> Ident.create s
+ | Papply _ -> Ident.create default
+
+let rec head_id = function
+ Pident id -> id
+ | Pdot (path,_,_) -> head_id path
+ | Papply (path,_) -> head_id path (* wrong, but ... *)
+
+let rec list_of_path = function
+ Pident id -> [Ident.name id]
+ | Pdot (path, s, _) -> list_of_path path @ [s]
+ | Papply (path, _) -> list_of_path path (* wrong, but ... *)
+
+(* a simple wrapper *)
+
+class buffer ~size = object
+ val buffer = Buffer.create size
+ method out buf = Buffer.add_substring buffer buf
+ method get = Buffer.contents buffer
+end
+
+(* Search in a signature *)
+
+type skind = [`Type|`Class|`Module|`Modtype]
+
+let found_sig = ref ([] : ((skind * Longident.t) * Env.t * Location.t) list)
+let add_found_sig = add_found ~found:found_sig
+
+let rec search_pos_type t ~pos ~env =
+ if in_loc ~pos t.ptyp_loc then
+ begin match t.ptyp_desc with
+ Ptyp_any
+ | Ptyp_var _ -> ()
+ | Ptyp_variant(tl, _, _) ->
+ List.iter tl ~f:
+ begin function
+ Rtag (_,_,tl) -> List.iter tl ~f:(search_pos_type ~pos ~env)
+ | Rinherit st -> search_pos_type ~pos ~env st
+ end
+ | Ptyp_arrow (_, t1, t2) ->
+ search_pos_type t1 ~pos ~env;
+ search_pos_type t2 ~pos ~env
+ | Ptyp_tuple tl ->
+ List.iter tl ~f:(search_pos_type ~pos ~env)
+ | Ptyp_constr (lid, tl) ->
+ List.iter tl ~f:(search_pos_type ~pos ~env);
+ add_found_sig (`Type, lid) ~env ~loc:t.ptyp_loc
+ | Ptyp_object fl ->
+ List.iter fl ~f:
+ begin function
+ | {pfield_desc = Pfield (_, ty)} -> search_pos_type ty ~pos ~env
+ | _ -> ()
+ end
+ | Ptyp_class (lid, tl, _) ->
+ List.iter tl ~f:(search_pos_type ~pos ~env);
+ add_found_sig (`Type, lid) ~env ~loc:t.ptyp_loc
+ | Ptyp_alias (t, _)
+ | Ptyp_poly (_, t) -> search_pos_type ~pos ~env t
+ | Ptyp_package (_, stl) ->
+ List.iter stl ~f:(fun (_, ty) -> search_pos_type ty ~pos ~env)
+ end
+
+let rec search_pos_class_type cl ~pos ~env =
+ if in_loc cl.pcty_loc ~pos then
+ begin match cl.pcty_desc with
+ Pcty_constr (lid, _) ->
+ add_found_sig (`Class, lid) ~env ~loc:cl.pcty_loc
+ | Pcty_signature (_, cfl) ->
+ List.iter cfl ~f:
+ begin function
+ Pctf_inher cty -> search_pos_class_type cty ~pos ~env
+ | Pctf_val (_, _, _, ty, loc) ->
+ if in_loc loc ~pos then search_pos_type ty ~pos ~env
+ | Pctf_virt (_, _, ty, loc) ->
+ if in_loc loc ~pos then search_pos_type ty ~pos ~env
+ | Pctf_meth (_, _, ty, loc) ->
+ if in_loc loc ~pos then search_pos_type ty ~pos ~env
+ | Pctf_cstr (ty1, ty2, loc) ->
+ if in_loc loc ~pos then begin
+ search_pos_type ty1 ~pos ~env;
+ search_pos_type ty2 ~pos ~env
+ end
+ end
+ | Pcty_fun (_, ty, cty) ->
+ search_pos_type ty ~pos ~env;
+ search_pos_class_type cty ~pos ~env
+ end
+
+let search_pos_type_decl td ~pos ~env =
+ if in_loc ~pos td.ptype_loc then begin
+ begin match td.ptype_manifest with
+ Some t -> search_pos_type t ~pos ~env
+ | None -> ()
+ end;
+ let rec search_tkind = function
+ Ptype_abstract -> ()
+ | Ptype_variant dl ->
+ List.iter dl
+ ~f:(fun (_, tl, _) -> List.iter tl ~f:(search_pos_type ~pos ~env))
+ | Ptype_record dl ->
+ List.iter dl ~f:(fun (_, _, t, _) -> search_pos_type t ~pos ~env) in
+ search_tkind td.ptype_kind;
+ List.iter td.ptype_cstrs ~f:
+ begin fun (t1, t2, _) ->
+ search_pos_type t1 ~pos ~env;
+ search_pos_type t2 ~pos ~env
+ end
+ end
+
+let rec search_pos_signature l ~pos ~env =
+ ignore (
+ List.fold_left l ~init:env ~f:
+ begin fun env pt ->
+ let env = match pt.psig_desc with
+ Psig_open id ->
+ let path, mt = lookup_module id env in
+ begin match mt with
+ Tmty_signature sign -> open_signature path sign env
+ | _ -> env
+ end
+ | sign_item ->
+ try add_signature (Typemod.transl_signature env [pt]) env
+ with Typemod.Error _ | Typeclass.Error _
+ | Typetexp.Error _ | Typedecl.Error _ -> env
+ in
+ if in_loc ~pos pt.psig_loc then
+ begin match pt.psig_desc with
+ Psig_value (_, desc) -> search_pos_type desc.pval_type ~pos ~env
+ | Psig_type l ->
+ List.iter l ~f:(fun (_,desc) -> search_pos_type_decl ~pos desc ~env)
+ | Psig_exception (_, l) ->
+ List.iter l ~f:(search_pos_type ~pos ~env);
+ add_found_sig (`Type, Lident "exn") ~env ~loc:pt.psig_loc
+ | Psig_module (_, t) ->
+ search_pos_module t ~pos ~env
+ | Psig_recmodule decls ->
+ List.iter decls ~f:(fun (_, t) -> search_pos_module t ~pos ~env)
+ | Psig_modtype (_, Pmodtype_manifest t) ->
+ search_pos_module t ~pos ~env
+ | Psig_modtype _ -> ()
+ | Psig_class l ->
+ List.iter l
+ ~f:(fun ci -> search_pos_class_type ci.pci_expr ~pos ~env)
+ | Psig_class_type l ->
+ List.iter l
+ ~f:(fun ci -> search_pos_class_type ci.pci_expr ~pos ~env)
+ (* The last cases should not happen in generated interfaces *)
+ | Psig_open lid -> add_found_sig (`Module, lid) ~env ~loc:pt.psig_loc
+ | Psig_include t -> search_pos_module t ~pos ~env
+ end;
+ env
+ end)
+
+and search_pos_module m ~pos ~env =
+ if in_loc m.pmty_loc ~pos then begin
+ begin match m.pmty_desc with
+ Pmty_ident lid -> add_found_sig (`Modtype, lid) ~env ~loc:m.pmty_loc
+ | Pmty_signature sg -> search_pos_signature sg ~pos ~env
+ | Pmty_functor (_ , m1, m2) ->
+ search_pos_module m1 ~pos ~env;
+ search_pos_module m2 ~pos ~env
+ | Pmty_with (m, l) ->
+ search_pos_module m ~pos ~env;
+ List.iter l ~f:
+ begin function
+ _, Pwith_type t -> search_pos_type_decl t ~pos ~env
+ | _ -> ()
+ end
+ | Pmty_typeof md ->
+ () (* TODO? *)
+ end
+ end
+
+let search_pos_signature l ~pos ~env =
+ observe ~ref:found_sig (search_pos_signature ~pos ~env) l
+
+(* the module display machinery *)
+
+type module_widgets =
+ { mw_frame: Widget.frame Widget.widget;
+ mw_title: Widget.label Widget.widget option;
+ mw_detach: Widget.button Widget.widget;
+ mw_edit: Widget.button Widget.widget;
+ mw_intf: Widget.button Widget.widget }
+
+let shown_modules = Hashtbl.create 17
+let default_frame = ref None
+let set_path = ref (fun _ ~sign -> assert false)
+let filter_modules () =
+ Hashtbl.iter
+ (fun key data ->
+ if not (Winfo.exists data.mw_frame) then
+ Hashtbl.remove shown_modules key)
+ shown_modules
+let add_shown_module path ~widgets =
+ Hashtbl.add shown_modules path widgets
+let find_shown_module path =
+ try
+ filter_modules ();
+ Hashtbl.find shown_modules path
+ with Not_found ->
+ match !default_frame with
+ None -> raise Not_found
+ | Some mw -> mw
+
+let is_shown_module path =
+ !default_frame <> None ||
+ (filter_modules (); Hashtbl.mem shown_modules path)
+
+(* Viewing a signature *)
+
+(* Forward definitions of Viewer.view_defined and Editor.editor *)
+let view_defined_ref = ref (fun lid ~env -> ())
+let editor_ref = ref (fun ?file ?pos ?opendialog () -> ())
+
+let edit_source ~file ~path ~sign =
+ match sign with
+ [item] ->
+ let id, kind =
+ match item with
+ Tsig_value (id, _) -> id, Pvalue
+ | Tsig_type (id, _, _) -> id, Ptype
+ | Tsig_exception (id, _) -> id, Pconstructor
+ | Tsig_module (id, _, _) -> id, Pmodule
+ | Tsig_modtype (id, _) -> id, Pmodtype
+ | Tsig_class (id, _, _) -> id, Pclass
+ | Tsig_cltype (id, _, _) -> id, Pcltype
+ in
+ let prefix = List.tl (list_of_path path) and name = Ident.name id in
+ let pos =
+ try
+ let chan = open_in file in
+ if Filename.check_suffix file ".ml" then
+ let parsed = Parse.implementation (Lexing.from_channel chan) in
+ close_in chan;
+ Searchid.search_structure parsed ~name ~kind ~prefix
+ else
+ let parsed = Parse.interface (Lexing.from_channel chan) in
+ close_in chan;
+ Searchid.search_signature parsed ~name ~kind ~prefix
+ with _ -> 0
+ in !editor_ref ~file ~pos ()
+ | _ -> !editor_ref ~file ()
+
+(* List of windows to destroy by Close All *)
+let top_widgets = ref []
+
+let dummy_item = Tsig_modtype (Ident.create "dummy", Tmodtype_abstract)
+
+let rec view_signature ?title ?path ?(env = !start_env) ?(detach=false) sign =
+ let env =
+ match path with None -> env
+ | Some path -> Env.open_signature path sign env in
+ let title =
+ match title, path with Some title, _ -> title
+ | None, Some path -> string_of_path path
+ | None, None -> "Signature"
+ in
+ let tl, tw, finish =
+ try match path, !default_frame with
+ None, Some ({mw_title=Some label} as mw) when not detach ->
+ Button.configure mw.mw_detach
+ ~command:(fun () -> view_signature sign ~title ~env ~detach:true);
+ pack [mw.mw_detach] ~side:`Left;
+ Pack.forget [mw.mw_edit; mw.mw_intf];
+ List.iter ~f:destroy (Winfo.children mw.mw_frame);
+ Label.configure label ~text:title;
+ pack [label] ~fill:`X ~side:`Bottom;
+ Jg_message.formatted ~title ~on:mw.mw_frame ~maxheight:15 ()
+ | None, _ -> raise Not_found
+ | Some path, _ ->
+ let mw =
+ try find_shown_module path
+ with Not_found ->
+ view_module path ~env;
+ find_shown_module path
+ in
+ (try !set_path path ~sign with _ -> ());
+ begin match mw.mw_title with None -> ()
+ | Some label ->
+ Label.configure label ~text:title;
+ pack [label] ~fill:`X ~side:`Bottom
+ end;
+ Button.configure mw.mw_detach
+ ~command:(fun () -> view_signature sign ~title ~env ~detach:true);
+ pack [mw.mw_detach] ~side:`Left;
+ let repack = ref false in
+ List.iter2 [mw.mw_edit; mw.mw_intf] [".ml"; ".mli"] ~f:
+ begin fun button ext ->
+ try
+ let id = head_id path in
+ let file =
+ Misc.find_in_path_uncap !Config.load_path
+ ((Ident.name id) ^ ext) in
+ Button.configure button
+ ~command:(fun () -> edit_source ~file ~path ~sign);
+ if !repack then Pack.forget [button] else
+ if not (Winfo.viewable button) then repack := true;
+ pack [button] ~side:`Left
+ with Not_found ->
+ Pack.forget [button]
+ end;
+ let top = Winfo.toplevel mw.mw_frame in
+ if not (Winfo.ismapped top) then Wm.deiconify top;
+ List.iter ~f:destroy (Winfo.children mw.mw_frame);
+ Jg_message.formatted ~title ~on:mw.mw_frame ~maxheight:15 ()
+ with Not_found ->
+ let tl, tw, finish = Jg_message.formatted ~title ~maxheight:15 () in
+ top_widgets := tl :: !top_widgets;
+ tl, tw, finish
+ in
+ Format.set_max_boxes 100;
+ Printtyp.signature Format.std_formatter sign;
+ finish ();
+ Lexical.init_tags tw;
+ Lexical.tag tw;
+ Text.configure tw ~state:`Disabled;
+ let text = Jg_text.get_all tw in
+ let pt =
+ try Parse.interface (Lexing.from_string text)
+ with Syntaxerr.Error e ->
+ let l =
+ match e with
+ Syntaxerr.Unclosed(l,_,_,_) -> l
+ | Syntaxerr.Applicative_path l -> l
+ | Syntaxerr.Other l -> l
+ in
+ Jg_text.tag_and_see tw ~start:(tpos l.loc_start.Lexing.pos_cnum)
+ ~stop:(tpos l.loc_end.Lexing.pos_cnum) ~tag:"error"; []
+ | Lexer.Error (_, l) ->
+ let s = l.loc_start.Lexing.pos_cnum in
+ let e = l.loc_end.Lexing.pos_cnum in
+ Jg_text.tag_and_see tw ~start:(tpos s) ~stop:(tpos e) ~tag:"error"; []
+ in
+ Jg_bind.enter_focus tw;
+ bind tw ~events:[`Modified([`Control], `KeyPressDetail"s")]
+ ~action:(fun _ -> Jg_text.search_string tw);
+ bind tw ~events:[`Modified([`Double], `ButtonPressDetail 1)]
+ ~fields:[`MouseX;`MouseY] ~breakable:true
+ ~action:(fun ev ->
+ let `Linechar (l, c) =
+ Text.index tw ~index:(`Atxy(ev.ev_MouseX,ev.ev_MouseY), []) in
+ try
+ match search_pos_signature pt ~pos:(lines_to_chars l ~text + c) ~env
+ with [] -> break ()
+ | ((kind, lid), env, loc) :: _ -> view_decl lid ~kind ~env
+ with Not_found | Env.Error _ -> ());
+ bind tw ~events:[`ButtonPressDetail 3] ~breakable:true
+ ~fields:[`MouseX;`MouseY]
+ ~action:(fun ev ->
+ let x = ev.ev_MouseX and y = ev.ev_MouseY in
+ let `Linechar (l, c) =
+ Text.index tw ~index:(`Atxy(x,y), []) in
+ try
+ match search_pos_signature pt ~pos:(lines_to_chars l ~text + c) ~env
+ with [] -> break ()
+ | ((kind, lid), env, loc) :: _ ->
+ let menu = view_decl_menu lid ~kind ~env ~parent:tw in
+ let x = x + Winfo.rootx tw and y = y + Winfo.rooty tw - 10 in
+ Menu.popup menu ~x ~y
+ with Not_found -> ())
+
+and view_signature_item sign ~path ~env =
+ view_signature sign ~title:(string_of_path path)
+ ?path:(parent_path path) ~env
+
+and view_module path ~env =
+ match find_module path env with
+ Tmty_signature sign ->
+ !view_defined_ref (Searchid.longident_of_path path) ~env
+ | modtype ->
+ let id = ident_of_path path ~default:"M" in
+ view_signature_item [Tsig_module (id, modtype, Trec_not)] ~path ~env
+
+and view_module_id id ~env =
+ let path, _ = lookup_module id env in
+ view_module path ~env
+
+and view_type_decl path ~env =
+ let td = find_type path env in
+ try match td.type_manifest with None -> raise Not_found
+ | Some ty -> match Ctype.repr ty with
+ {desc = Tobject _} ->
+ let clt = find_cltype path env in
+ view_signature_item ~path ~env
+ [Tsig_cltype(ident_of_path path ~default:"ct", clt, Trec_first);
+ dummy_item; dummy_item]
+ | _ -> raise Not_found
+ with Not_found ->
+ view_signature_item ~path ~env
+ [Tsig_type(ident_of_path path ~default:"t", td, Trec_first)]
+
+and view_type_id li ~env =
+ let path, decl = lookup_type li env in
+ view_type_decl path ~env
+
+and view_class_id li ~env =
+ let path, cl = lookup_class li env in
+ view_signature_item ~path ~env
+ [Tsig_class(ident_of_path path ~default:"c", cl, Trec_first);
+ dummy_item; dummy_item; dummy_item]
+
+and view_cltype_id li ~env =
+ let path, clt = lookup_cltype li env in
+ view_signature_item ~path ~env
+ [Tsig_cltype(ident_of_path path ~default:"ct", clt, Trec_first);
+ dummy_item; dummy_item]
+
+and view_modtype_id li ~env =
+ let path, td = lookup_modtype li env in
+ view_signature_item ~path ~env
+ [Tsig_modtype(ident_of_path path ~default:"S", td)]
+
+and view_expr_type ?title ?path ?env ?(name="noname") t =
+ let title =
+ match title, path with Some title, _ -> title
+ | None, Some path -> string_of_path path
+ | None, None -> "Expression type"
+ and path, id =
+ match path with None -> None, Ident.create name
+ | Some path -> parent_path path, ident_of_path path ~default:name
+ in
+ view_signature ~title ?path ?env
+ [Tsig_value (id, {val_type = t; val_kind = Val_reg})]
+
+and view_decl lid ~kind ~env =
+ match kind with
+ `Type -> view_type_id lid ~env
+ | `Class -> view_class_id lid ~env
+ | `Module -> view_module_id lid ~env
+ | `Modtype -> view_modtype_id lid ~env
+
+and view_decl_menu lid ~kind ~env ~parent =
+ let path, kname =
+ try match kind with
+ `Type -> fst (lookup_type lid env), "Type"
+ | `Class -> fst (lookup_class lid env), "Class"
+ | `Module -> fst (lookup_module lid env), "Module"
+ | `Modtype -> fst (lookup_modtype lid env), "Module type"
+ with Env.Error _ -> raise Not_found
+ in
+ let menu = Menu.create parent ~tearoff:false in
+ let label = kname ^ " " ^ string_of_path path in
+ begin match path with
+ Pident _ ->
+ Menu.add_command menu ~label ~state:`Disabled
+ | _ ->
+ Menu.add_command menu ~label
+ ~command:(fun () -> view_decl lid ~kind ~env);
+ end;
+ if kind = `Type || kind = `Modtype then begin
+ let buf = new buffer ~size:60 in
+ let (fo,ff) = Format.get_formatter_output_functions ()
+ and margin = Format.get_margin () in
+ Format.set_formatter_output_functions buf#out (fun () -> ());
+ Format.set_margin 60;
+ Format.open_hbox ();
+ if kind = `Type then
+ Printtyp.type_declaration
+ (ident_of_path path ~default:"t")
+ Format.std_formatter
+ (find_type path env)
+ else
+ Printtyp.modtype_declaration
+ (ident_of_path path ~default:"S")
+ Format.std_formatter
+ (find_modtype path env);
+ Format.close_box (); Format.print_flush ();
+ Format.set_formatter_output_functions fo ff;
+ Format.set_margin margin;
+ let l = Str.split ~!"\n" buf#get in
+ let font =
+ let font =
+ Option.get Widget.default_toplevel ~name:"font" ~clas:"Font" in
+ if font = "" then "7x14" else font
+ in
+ (* Menu.add_separator menu; *)
+ List.iter l
+ ~f:(fun label -> Menu.add_command menu ~label ~font ~state:`Disabled)
+ end;
+ menu
+
+(* search and view in a structure *)
+
+type fkind = [
+ `Exp of
+ [`Expr|`Pat|`Const|`Val of Path.t|`Var of Path.t|`New of Path.t]
+ * Types.type_expr
+ | `Class of Path.t * Types.class_type
+ | `Module of Path.t * Types.module_type
+]
+
+let view_type kind ~env =
+ match kind with
+ `Exp (k, ty) ->
+ begin match k with
+ `Expr -> view_expr_type ty ~title:"Expression type" ~env
+ | `Pat -> view_expr_type ty ~title:"Pattern type" ~env
+ | `Const -> view_expr_type ty ~title:"Constant type" ~env
+ | `Val path ->
+ begin try
+ let vd = find_value path env in
+ view_signature_item ~path ~env
+ [Tsig_value(ident_of_path path ~default:"v", vd)]
+ with Not_found ->
+ view_expr_type ty ~path ~env
+ end
+ | `Var path ->
+ let vd = find_value path env in
+ view_expr_type vd.val_type ~env ~path ~title:"Variable type"
+ | `New path ->
+ let cl = find_class path env in
+ view_signature_item ~path ~env
+ [Tsig_class(ident_of_path path ~default:"c", cl, Trec_first)]
+ end
+ | `Class (path, cty) ->
+ let cld = { cty_params = []; cty_variance = []; cty_type = cty;
+ cty_path = path; cty_new = None } in
+ view_signature_item ~path ~env
+ [Tsig_class(ident_of_path path ~default:"c", cld, Trec_first)]
+ | `Module (path, mty) ->
+ match mty with
+ Tmty_signature sign -> view_signature sign ~path ~env
+ | modtype ->
+ view_signature_item ~path ~env
+ [Tsig_module(ident_of_path path ~default:"M", mty, Trec_not)]
+
+let view_type_menu kind ~env ~parent =
+ let title =
+ match kind with
+ `Exp (`Expr,_) -> "Expression :"
+ | `Exp (`Pat, _) -> "Pattern :"
+ | `Exp (`Const, _) -> "Constant :"
+ | `Exp (`Val path, _) -> "Value " ^ string_of_path path ^ " :"
+ | `Exp (`Var path, _) ->
+ "Variable " ^ Ident.name (ident_of_path path ~default:"noname") ^ " :"
+ | `Exp (`New path, _) -> "Class " ^ string_of_path path ^ " :"
+ | `Class (path, _) -> "Class " ^ string_of_path path ^ " :"
+ | `Module (path,_) -> "Module " ^ string_of_path path in
+ let menu = Menu.create parent ~tearoff:false in
+ begin match kind with
+ `Exp((`Expr | `Pat | `Const | `Val (Pident _)),_) ->
+ Menu.add_command menu ~label:title ~state:`Disabled
+ | `Exp _ | `Class _ | `Module _ ->
+ Menu.add_command menu ~label:title
+ ~command:(fun () -> view_type kind ~env)
+ end;
+ begin match kind with `Module _ | `Class _ -> ()
+ | `Exp(_, ty) ->
+ let buf = new buffer ~size:60 in
+ let (fo,ff) = Format.get_formatter_output_functions ()
+ and margin = Format.get_margin () in
+ Format.set_formatter_output_functions buf#out ignore;
+ Format.set_margin 60;
+ Format.open_hbox ();
+ Printtyp.reset ();
+ Printtyp.mark_loops ty;
+ Printtyp.type_expr Format.std_formatter ty;
+ Format.close_box (); Format.print_flush ();
+ Format.set_formatter_output_functions fo ff;
+ Format.set_margin margin;
+ let l = Str.split ~!"\n" buf#get in
+ let font =
+ let font =
+ Option.get Widget.default_toplevel ~name:"font" ~clas:"Font" in
+ if font = "" then "7x14" else font
+ in
+ (* Menu.add_separator menu; *)
+ List.iter l ~f:
+ begin fun label -> match (Ctype.repr ty).desc with
+ Tconstr (path,_,_) ->
+ Menu.add_command menu ~label ~font
+ ~command:(fun () -> view_type_decl path ~env)
+ | Tvariant {row_name = Some (path, _)} ->
+ Menu.add_command menu ~label ~font
+ ~command:(fun () -> view_type_decl path ~env)
+ | _ ->
+ Menu.add_command menu ~label ~font ~state:`Disabled
+ end
+ end;
+ menu
+
+let found_str = ref ([] : (fkind * Env.t * Location.t) list)
+let add_found_str = add_found ~found:found_str
+
+let rec search_pos_structure ~pos str =
+ List.iter str ~f:
+ begin function
+ Tstr_eval exp -> search_pos_expr exp ~pos
+ | Tstr_value (rec_flag, l) ->
+ List.iter l ~f:
+ begin fun (pat, exp) ->
+ let env =
+ if rec_flag = Asttypes.Recursive then exp.exp_env else Env.empty in
+ search_pos_pat pat ~pos ~env;
+ search_pos_expr exp ~pos
+ end
+ | Tstr_primitive (_, vd) ->()
+ | Tstr_type _ -> ()
+ | Tstr_exception _ -> ()
+ | Tstr_exn_rebind(_, _) -> ()
+ | Tstr_module (_, m) -> search_pos_module_expr m ~pos
+ | Tstr_recmodule bindings ->
+ List.iter bindings ~f:(fun (_, m) -> search_pos_module_expr m ~pos)
+ | Tstr_modtype _ -> ()
+ | Tstr_open _ -> ()
+ | Tstr_class l ->
+ List.iter l ~f:(fun (id, _, _, cl, _) -> search_pos_class_expr cl ~pos)
+ | Tstr_cltype _ -> ()
+ | Tstr_include (m, _) -> search_pos_module_expr m ~pos
+ end
+
+and search_pos_class_structure ~pos cls =
+ List.iter cls.cl_field ~f:
+ begin function
+ Cf_inher (cl, _, _) ->
+ search_pos_class_expr cl ~pos
+ | Cf_val (_, _, Some exp, _) -> search_pos_expr exp ~pos
+ | Cf_val _ -> ()
+ | Cf_meth (_, exp) -> search_pos_expr exp ~pos
+ | Cf_let (_, pel, iel) ->
+ List.iter pel ~f:
+ begin fun (pat, exp) ->
+ search_pos_pat pat ~pos ~env:exp.exp_env;
+ search_pos_expr exp ~pos
+ end;
+ List.iter iel ~f:(fun (_,exp) -> search_pos_expr exp ~pos)
+ | Cf_init exp -> search_pos_expr exp ~pos
+ end
+
+and search_pos_class_expr ~pos cl =
+ if in_loc cl.cl_loc ~pos then begin
+ begin match cl.cl_desc with
+ Tclass_ident path ->
+ add_found_str (`Class (path, cl.cl_type))
+ ~env:!start_env ~loc:cl.cl_loc
+ | Tclass_structure cls ->
+ search_pos_class_structure ~pos cls
+ | Tclass_fun (pat, iel, cl, _) ->
+ search_pos_pat pat ~pos ~env:pat.pat_env;
+ List.iter iel ~f:(fun (_,exp) -> search_pos_expr exp ~pos);
+ search_pos_class_expr cl ~pos
+ | Tclass_apply (cl, el) ->
+ search_pos_class_expr cl ~pos;
+ List.iter el ~f:(fun (x,_) -> Misc.may (search_pos_expr ~pos) x)
+ | Tclass_let (_, pel, iel, cl) ->
+ List.iter pel ~f:
+ begin fun (pat, exp) ->
+ search_pos_pat pat ~pos ~env:exp.exp_env;
+ search_pos_expr exp ~pos
+ end;
+ List.iter iel ~f:(fun (_,exp) -> search_pos_expr exp ~pos);
+ search_pos_class_expr cl ~pos
+ | Tclass_constraint (cl, _, _, _) ->
+ search_pos_class_expr cl ~pos
+ end;
+ add_found_str (`Class (Pident (Ident.create "c"), cl.cl_type))
+ ~env:!start_env ~loc:cl.cl_loc
+ end
+
+and search_pos_expr ~pos exp =
+ if in_loc exp.exp_loc ~pos then begin
+ begin match exp.exp_desc with
+ Texp_ident (path, _) ->
+ add_found_str (`Exp(`Val path, exp.exp_type))
+ ~env:exp.exp_env ~loc:exp.exp_loc
+ | Texp_constant v ->
+ add_found_str (`Exp(`Const, exp.exp_type))
+ ~env:exp.exp_env ~loc:exp.exp_loc
+ | Texp_let (_, expl, exp) ->
+ List.iter expl ~f:
+ begin fun (pat, exp') ->
+ search_pos_pat pat ~pos ~env:exp.exp_env;
+ search_pos_expr exp' ~pos
+ end;
+ search_pos_expr exp ~pos
+ | Texp_function (l, _) ->
+ List.iter l ~f:
+ begin fun (pat, exp) ->
+ search_pos_pat pat ~pos ~env:exp.exp_env;
+ search_pos_expr exp ~pos
+ end
+ | Texp_apply (exp, l) ->
+ List.iter l ~f:(fun (x,_) -> Misc.may (search_pos_expr ~pos) x);
+ search_pos_expr exp ~pos
+ | Texp_match (exp, l, _) ->
+ search_pos_expr exp ~pos;
+ List.iter l ~f:
+ begin fun (pat, exp) ->
+ search_pos_pat pat ~pos ~env:exp.exp_env;
+ search_pos_expr exp ~pos
+ end
+ | Texp_try (exp, l) ->
+ search_pos_expr exp ~pos;
+ List.iter l ~f:
+ begin fun (pat, exp) ->
+ search_pos_pat pat ~pos ~env:exp.exp_env;
+ search_pos_expr exp ~pos
+ end
+ | Texp_tuple l -> List.iter l ~f:(search_pos_expr ~pos)
+ | Texp_construct (_, l) -> List.iter l ~f:(search_pos_expr ~pos)
+ | Texp_variant (_, None) -> ()
+ | Texp_variant (_, Some exp) -> search_pos_expr exp ~pos
+ | Texp_record (l, opt) ->
+ List.iter l ~f:(fun (_, exp) -> search_pos_expr exp ~pos);
+ (match opt with None -> () | Some exp -> search_pos_expr exp ~pos)
+ | Texp_field (exp, _) -> search_pos_expr exp ~pos
+ | Texp_setfield (a, _, b) ->
+ search_pos_expr a ~pos; search_pos_expr b ~pos
+ | Texp_array l -> List.iter l ~f:(search_pos_expr ~pos)
+ | Texp_ifthenelse (a, b, c) ->
+ search_pos_expr a ~pos; search_pos_expr b ~pos;
+ begin match c with None -> ()
+ | Some exp -> search_pos_expr exp ~pos
+ end
+ | Texp_sequence (a,b) ->
+ search_pos_expr a ~pos; search_pos_expr b ~pos
+ | Texp_while (a,b) ->
+ search_pos_expr a ~pos; search_pos_expr b ~pos
+ | Texp_for (_, a, b, _, c) ->
+ List.iter [a;b;c] ~f:(search_pos_expr ~pos)
+ | Texp_when (a, b) ->
+ search_pos_expr a ~pos; search_pos_expr b ~pos
+ | Texp_send (exp, _) -> search_pos_expr exp ~pos
+ | Texp_new (path, _) ->
+ add_found_str (`Exp(`New path, exp.exp_type))
+ ~env:exp.exp_env ~loc:exp.exp_loc
+ | Texp_instvar (_,path) ->
+ add_found_str (`Exp(`Var path, exp.exp_type))
+ ~env:exp.exp_env ~loc:exp.exp_loc
+ | Texp_setinstvar (_, path, exp) ->
+ search_pos_expr exp ~pos;
+ add_found_str (`Exp(`Var path, exp.exp_type))
+ ~env:exp.exp_env ~loc:exp.exp_loc
+ | Texp_override (_, l) ->
+ List.iter l ~f:(fun (_, exp) -> search_pos_expr exp ~pos)
+ | Texp_letmodule (id, modexp, exp) ->
+ search_pos_module_expr modexp ~pos;
+ search_pos_expr exp ~pos
+ | Texp_assertfalse -> ()
+ | Texp_assert exp ->
+ search_pos_expr exp ~pos
+ | Texp_lazy exp ->
+ search_pos_expr exp ~pos
+ | Texp_object (cls, _, _) ->
+ search_pos_class_structure ~pos cls
+ | Texp_pack modexp ->
+ search_pos_module_expr modexp ~pos
+ end;
+ add_found_str (`Exp(`Expr, exp.exp_type)) ~env:exp.exp_env ~loc:exp.exp_loc
+ end
+
+and search_pos_pat ~pos ~env pat =
+ if in_loc pat.pat_loc ~pos then begin
+ begin match pat.pat_desc with
+ Tpat_any -> ()
+ | Tpat_var id ->
+ add_found_str (`Exp(`Val (Pident id), pat.pat_type))
+ ~env ~loc:pat.pat_loc
+ | Tpat_alias (pat, _) -> search_pos_pat pat ~pos ~env
+ | Tpat_lazy pat -> search_pos_pat pat ~pos ~env
+ | Tpat_constant _ ->
+ add_found_str (`Exp(`Const, pat.pat_type)) ~env ~loc:pat.pat_loc
+ | Tpat_tuple l ->
+ List.iter l ~f:(search_pos_pat ~pos ~env)
+ | Tpat_construct (_, l) ->
+ List.iter l ~f:(search_pos_pat ~pos ~env)
+ | Tpat_variant (_, None, _) -> ()
+ | Tpat_variant (_, Some pat, _) -> search_pos_pat pat ~pos ~env
+ | Tpat_record l ->
+ List.iter l ~f:(fun (_, pat) -> search_pos_pat pat ~pos ~env)
+ | Tpat_array l ->
+ List.iter l ~f:(search_pos_pat ~pos ~env)
+ | Tpat_or (a, b, None) ->
+ search_pos_pat a ~pos ~env; search_pos_pat b ~pos ~env
+ | Tpat_or (_, _, Some _) ->
+ ()
+ end;
+ add_found_str (`Exp(`Pat, pat.pat_type)) ~env ~loc:pat.pat_loc
+ end
+
+and search_pos_module_expr ~pos m =
+ if in_loc m.mod_loc ~pos then begin
+ begin match m.mod_desc with
+ Tmod_ident path ->
+ add_found_str (`Module (path, m.mod_type))
+ ~env:m.mod_env ~loc:m.mod_loc
+ | Tmod_structure str -> search_pos_structure str ~pos
+ | Tmod_functor (_, _, m) -> search_pos_module_expr m ~pos
+ | Tmod_apply (a, b, _) ->
+ search_pos_module_expr a ~pos; search_pos_module_expr b ~pos
+ | Tmod_constraint (m, _, _) -> search_pos_module_expr m ~pos
+ | Tmod_unpack (e, _) -> search_pos_expr e ~pos
+ end;
+ add_found_str (`Module (Pident (Ident.create "M"), m.mod_type))
+ ~env:m.mod_env ~loc:m.mod_loc
+ end
+
+let search_pos_structure ~pos str =
+ observe ~ref:found_str (search_pos_structure ~pos) str
+
+open Stypes
+
+let search_pos_ti ~pos = function
+ Ti_pat p -> search_pos_pat ~pos ~env:p.pat_env p
+ | Ti_expr e -> search_pos_expr ~pos e
+ | Ti_class c -> search_pos_class_expr ~pos c
+ | Ti_mod m -> search_pos_module_expr ~pos m
+ | _ -> ()
+
+let rec search_pos_info ~pos = function
+ [] -> []
+ | ti :: l ->
+ if in_loc ~pos (get_location ti)
+ then observe ~ref:found_str (search_pos_ti ~pos) ti
+ else search_pos_info ~pos l
diff --git a/ocaml-binary-annot/otherlibs/labltk/browser/searchpos.mli b/ocaml-binary-annot/otherlibs/labltk/browser/searchpos.mli
new file mode 100644
index 0000000000..b2f89cd81c
--- /dev/null
+++ b/ocaml-binary-annot/otherlibs/labltk/browser/searchpos.mli
@@ -0,0 +1,77 @@
+(*************************************************************************)
+(* *)
+(* Objective Caml LablTk library *)
+(* *)
+(* Jacques Garrigue, Kyoto University RIMS *)
+(* *)
+(* Copyright 1999 Institut National de Recherche en Informatique et *)
+(* en Automatique and Kyoto University. All rights reserved. *)
+(* This file is distributed under the terms of the GNU Library *)
+(* General Public License, with the special exception on linking *)
+(* described in file ../../../LICENSE. *)
+(* *)
+(*************************************************************************)
+
+(* $Id$ *)
+
+open Widget
+
+val top_widgets : any widget list ref
+
+type module_widgets =
+ { mw_frame: frame widget;
+ mw_title: label widget option;
+ mw_detach: button widget;
+ mw_edit: button widget;
+ mw_intf: button widget }
+
+val add_shown_module : Path.t -> widgets:module_widgets -> unit
+val find_shown_module : Path.t -> module_widgets
+val is_shown_module : Path.t -> bool
+val default_frame : module_widgets option ref
+val set_path : (Path.t -> sign:Types.signature -> unit) ref
+
+val view_defined_ref : (Longident.t -> env:Env.t -> unit) ref
+val editor_ref :
+ (?file:string -> ?pos:int -> ?opendialog:bool -> unit -> unit) ref
+
+val view_signature :
+ ?title:string ->
+ ?path:Path.t -> ?env:Env.t -> ?detach:bool -> Types.signature -> unit
+val view_signature_item :
+ Types.signature -> path:Path.t -> env:Env.t -> unit
+val view_module_id : Longident.t -> env:Env.t -> unit
+val view_type_id : Longident.t -> env:Env.t -> unit
+val view_class_id : Longident.t -> env:Env.t -> unit
+val view_cltype_id : Longident.t -> env:Env.t -> unit
+val view_modtype_id : Longident.t -> env:Env.t -> unit
+val view_type_decl : Path.t -> env:Env.t -> unit
+
+type skind = [`Type|`Class|`Module|`Modtype]
+val search_pos_signature :
+ Parsetree.signature -> pos:int -> env:Env.t ->
+ ((skind * Longident.t) * Env.t * Location.t) list
+val view_decl : Longident.t -> kind:skind -> env:Env.t -> unit
+val view_decl_menu :
+ Longident.t ->
+ kind:skind -> env:Env.t -> parent:text widget -> menu widget
+
+type fkind = [
+ `Exp of
+ [`Expr|`Pat|`Const|`Val of Path.t|`Var of Path.t|`New of Path.t]
+ * Types.type_expr
+ | `Class of Path.t * Types.class_type
+ | `Module of Path.t * Types.module_type
+]
+val search_pos_structure :
+ pos:int -> Typedtree.structure_item list ->
+ (fkind * Env.t * Location.t) list
+val search_pos_info :
+ pos:int -> Stypes.annotation list -> (fkind * Env.t * Location.t) list
+val view_type : fkind -> env:Env.t -> unit
+val view_type_menu : fkind -> env:Env.t -> parent:'a widget -> menu widget
+
+val parent_path : Path.t -> Path.t option
+val string_of_path : Path.t -> string
+val string_of_longident : Longident.t -> string
+val lines_to_chars : int -> text:string -> int
diff --git a/ocaml-binary-annot/otherlibs/labltk/browser/setpath.ml b/ocaml-binary-annot/otherlibs/labltk/browser/setpath.ml
new file mode 100644
index 0000000000..1a41b573b5
--- /dev/null
+++ b/ocaml-binary-annot/otherlibs/labltk/browser/setpath.ml
@@ -0,0 +1,162 @@
+(*************************************************************************)
+(* *)
+(* Objective Caml LablTk library *)
+(* *)
+(* Jacques Garrigue, Kyoto University RIMS *)
+(* *)
+(* Copyright 1999 Institut National de Recherche en Informatique et *)
+(* en Automatique and Kyoto University. All rights reserved. *)
+(* This file is distributed under the terms of the GNU Library *)
+(* General Public License, with the special exception on linking *)
+(* described in file ../../../LICENSE. *)
+(* *)
+(*************************************************************************)
+
+(* $Id$ *)
+
+open StdLabels
+open Tk
+
+(* Listboxes *)
+
+let update_hooks = ref []
+
+let add_update_hook f = update_hooks := f :: !update_hooks
+
+let exec_update_hooks () =
+ update_hooks := List.filter !update_hooks ~f:
+ begin fun f ->
+ try f (); true
+ with Protocol.TkError _ -> false
+ end
+
+let set_load_path l =
+ Config.load_path := l;
+ exec_update_hooks ()
+
+let get_load_path () = !Config.load_path
+
+let renew_dirs box ~var ~dir =
+ Textvariable.set var dir;
+ Listbox.delete box ~first:(`Num 0) ~last:`End;
+ Listbox.insert box ~index:`End
+ ~texts:(Useunix.get_directories_in_files ~path:dir
+ (Useunix.get_files_in_directory dir));
+ Jg_box.recenter box ~index:(`Num 0)
+
+let renew_path box =
+ Listbox.delete box ~first:(`Num 0) ~last:`End;
+ Listbox.insert box ~index:`End ~texts:!Config.load_path;
+ Jg_box.recenter box ~index:(`Num 0)
+
+let add_to_path ~dirs ?(base="") box =
+ let dirs =
+ if base = "" then dirs else
+ if dirs = [] then [base] else
+ List.map dirs ~f:
+ begin function
+ "." -> base
+ | ".." -> Filename.dirname base
+ | x -> Filename.concat base x
+ end
+ in
+ set_load_path
+ (dirs @ List.fold_left dirs ~init:(get_load_path ())
+ ~f:(fun acc x -> List2.exclude x acc))
+
+let remove_path box ~dirs =
+ set_load_path
+ (List.fold_left dirs ~init:(get_load_path ())
+ ~f:(fun acc x -> List2.exclude x acc))
+
+(* main function *)
+
+let f ~dir =
+ let current_dir = ref dir in
+ let tl = Jg_toplevel.titled "Edit Load Path" in
+ Jg_bind.escape_destroy tl;
+ let var_dir = Textvariable.create ~on:tl () in
+ let caplab = Label.create tl ~text:"Path"
+ and dir_name = Entry.create tl ~textvariable:var_dir
+ and browse = Frame.create tl in
+ let dirs = Frame.create browse
+ and path = Frame.create browse in
+ let dirframe, dirbox, dirsb = Jg_box.create_with_scrollbar dirs
+ and pathframe, pathbox, pathsb = Jg_box.create_with_scrollbar path
+ in
+ add_update_hook (fun () -> renew_path pathbox);
+ Listbox.configure pathbox ~width:40 ~selectmode:`Multiple;
+ Listbox.configure dirbox ~selectmode:`Multiple;
+ Jg_box.add_completion dirbox ~action:
+ begin fun index ->
+ begin match Listbox.get dirbox ~index with
+ "." -> ()
+ | ".." -> current_dir := Filename.dirname !current_dir
+ | x -> current_dir := !current_dir ^ "/" ^ x
+ end;
+ renew_dirs dirbox ~var:var_dir ~dir:!current_dir;
+ Listbox.selection_clear dirbox ~first:(`Num 0) ~last:`End
+ end;
+ Jg_box.add_completion pathbox ~action:
+ begin fun index ->
+ current_dir := Listbox.get pathbox ~index;
+ renew_dirs dirbox ~var:var_dir ~dir:!current_dir
+ end;
+
+ bind dir_name ~events:[`KeyPressDetail"Return"]
+ ~action:(fun _ ->
+ let dir = Textvariable.get var_dir in
+ if Useunix.is_directory dir then begin
+ current_dir := dir;
+ renew_dirs dirbox ~var:var_dir ~dir
+ end);
+
+ (* Avoid space being used by the completion mechanism *)
+ let bind_space_toggle lb =
+ bind lb ~events:[`KeyPressDetail "space"] ~extend:true ~action:ignore in
+ bind_space_toggle dirbox;
+ bind_space_toggle pathbox;
+
+ let add_paths _ =
+ add_to_path pathbox ~base:!current_dir
+ ~dirs:(List.map (Listbox.curselection dirbox)
+ ~f:(fun x -> Listbox.get dirbox ~index:x));
+ Listbox.selection_clear dirbox ~first:(`Num 0) ~last:`End
+ and remove_paths _ =
+ remove_path pathbox
+ ~dirs:(List.map (Listbox.curselection pathbox)
+ ~f:(fun x -> Listbox.get pathbox ~index:x))
+ in
+ bind dirbox ~events:[`KeyPressDetail "Insert"] ~action:add_paths;
+ bind pathbox ~events:[`KeyPressDetail "Delete"] ~action:remove_paths;
+
+ let dirlab = Label.create dirs ~text:"Directories"
+ and pathlab = Label.create path ~text:"Load path"
+ and addbutton = Button.create dirs ~text:"Add to path" ~command:add_paths
+ and pathbuttons = Frame.create path in
+ let removebutton =
+ Button.create pathbuttons ~text:"Remove from path" ~command:remove_paths
+ and ok =
+ Jg_button.create_destroyer tl ~parent:pathbuttons
+ in
+ renew_dirs dirbox ~var:var_dir ~dir:!current_dir;
+ renew_path pathbox;
+ pack [dirsb] ~side:`Right ~fill:`Y;
+ pack [dirbox] ~side:`Left ~fill:`Y ~expand:true;
+ pack [pathsb] ~side:`Right ~fill:`Y;
+ pack [pathbox] ~side:`Left ~fill:`Both ~expand:true;
+ pack [dirlab] ~side:`Top ~anchor:`W ~padx:10;
+ pack [addbutton] ~side:`Bottom ~fill:`X;
+ pack [dirframe] ~fill:`Y ~expand:true;
+ pack [pathlab] ~side:`Top ~anchor:`W ~padx:10;
+ pack [removebutton; ok] ~side:`Left ~fill:`X ~expand:true;
+ pack [pathbuttons] ~fill:`X ~side:`Bottom;
+ pack [pathframe] ~fill:`Both ~expand:true;
+ pack [dirs] ~side:`Left ~fill:`Y;
+ pack [path] ~side:`Right ~fill:`Both ~expand:true;
+ pack [caplab] ~side:`Top ~anchor:`W ~padx:10;
+ pack [dir_name] ~side:`Top ~anchor:`W ~fill:`X;
+ pack [browse] ~side:`Bottom ~expand:true ~fill:`Both;
+ tl
+
+let set ~dir = ignore (f ~dir);;
diff --git a/ocaml-binary-annot/otherlibs/labltk/browser/setpath.mli b/ocaml-binary-annot/otherlibs/labltk/browser/setpath.mli
new file mode 100644
index 0000000000..22bf5dc583
--- /dev/null
+++ b/ocaml-binary-annot/otherlibs/labltk/browser/setpath.mli
@@ -0,0 +1,25 @@
+(*************************************************************************)
+(* *)
+(* Objective Caml LablTk library *)
+(* *)
+(* Jacques Garrigue, Kyoto University RIMS *)
+(* *)
+(* Copyright 1999 Institut National de Recherche en Informatique et *)
+(* en Automatique and Kyoto University. All rights reserved. *)
+(* This file is distributed under the terms of the GNU Library *)
+(* General Public License, with the special exception on linking *)
+(* described in file ../../../LICENSE. *)
+(* *)
+(*************************************************************************)
+
+(* $Id$ *)
+
+open Widget
+
+val add_update_hook : (unit -> unit) -> unit
+val exec_update_hooks : unit -> unit
+ (* things to do when Config.load_path changes *)
+
+val set : dir:string -> unit
+val f : dir:string -> toplevel widget
+ (* edit the load path *)
diff --git a/ocaml-binary-annot/otherlibs/labltk/browser/shell.ml b/ocaml-binary-annot/otherlibs/labltk/browser/shell.ml
new file mode 100644
index 0000000000..be93ef5fda
--- /dev/null
+++ b/ocaml-binary-annot/otherlibs/labltk/browser/shell.ml
@@ -0,0 +1,365 @@
+(*************************************************************************)
+(* *)
+(* Objective Caml LablTk library *)
+(* *)
+(* Jacques Garrigue, Kyoto University RIMS *)
+(* *)
+(* Copyright 1999 Institut National de Recherche en Informatique et *)
+(* en Automatique and Kyoto University. All rights reserved. *)
+(* This file is distributed under the terms of the GNU Library *)
+(* General Public License, with the special exception on linking *)
+(* described in file ../../../LICENSE. *)
+(* *)
+(*************************************************************************)
+
+(* $Id$ *)
+
+open StdLabels
+module Unix = UnixLabels
+open Tk
+open Jg_tk
+open Dummy
+
+(* Here again, memoize regexps *)
+
+let (~!) = Jg_memo.fast ~f:Str.regexp
+
+(* Nice history class. May reuse *)
+
+class ['a] history () = object
+ val mutable history = ([] : 'a list)
+ val mutable count = 0
+ method empty = history = []
+ method add s = count <- 0; history <- s :: history
+ method previous =
+ let s = List.nth history count in
+ count <- (count + 1) mod List.length history;
+ s
+ method next =
+ let l = List.length history in
+ count <- (l + count - 1) mod l;
+ List.nth history ((l + count - 1) mod l)
+end
+
+let dump_handle (h : Unix.file_descr) =
+ let obj = Obj.repr h in
+ if Obj.is_int obj || Obj.tag obj <> Obj.custom_tag then
+ invalid_arg "Shell.dump_handle";
+ Nativeint.format "%x" (Obj.obj obj)
+
+(* The shell class. Now encapsulated *)
+
+let protect f x = try f x with _ -> ()
+
+let is_win32 = Sys.os_type = "Win32"
+let use_threads = is_win32
+let use_sigpipe = is_win32
+
+class shell ~textw ~prog ~args ~env ~history =
+ let (in2,out1) = Unix.pipe ()
+ and (in1,out2) = Unix.pipe ()
+ and (err1,err2) = Unix.pipe ()
+ and (sig2,sig1) = Unix.pipe () in
+object (self)
+ val pid =
+ let env =
+ if use_sigpipe then
+ let sigdef = "CAMLSIGPIPE=" ^ dump_handle sig2 in
+ Array.append env [|sigdef|]
+ else env
+ in
+ Unix.create_process_env ~prog ~args ~env
+ ~stdin:in2 ~stdout:out2 ~stderr:err2
+ val out = Unix.out_channel_of_descr out1
+ val h : _ history = history
+ val mutable alive = true
+ val mutable reading = false
+ val ibuffer = Buffer.create 1024
+ val imutex = Mutex.create ()
+ val mutable ithreads = []
+ method alive = alive
+ method kill =
+ if Winfo.exists textw then Text.configure textw ~state:`Disabled;
+ if alive then begin
+ alive <- false;
+ protect close_out out;
+ try
+ if use_sigpipe then ignore (Unix.write sig1 ~buf:"T" ~pos:0 ~len:1);
+ List.iter ~f:(protect Unix.close) [in1; err1; sig1; sig2];
+ if not use_threads then begin
+ Fileevent.remove_fileinput ~fd:in1;
+ Fileevent.remove_fileinput ~fd:err1;
+ end;
+ if not use_sigpipe then begin
+ Unix.kill ~pid ~signal:Sys.sigkill;
+ ignore (Unix.waitpid ~mode:[] pid)
+ end
+ with _ -> ()
+ end
+ method interrupt =
+ if alive then try
+ reading <- false;
+ if use_sigpipe then begin
+ ignore (Unix.write sig1 ~buf:"C" ~pos:0 ~len:1);
+ self#send " "
+ end else
+ Unix.kill ~pid ~signal:Sys.sigint
+ with Unix.Unix_error _ -> ()
+ method send s =
+ if alive then try
+ output_string out s;
+ flush out
+ with Sys_error _ -> ()
+ method private read ~fd ~len =
+ begin try
+ let buf = String.create len in
+ let len = Unix.read fd ~buf ~pos:0 ~len in
+ if len > 0 then begin
+ self#insert (String.sub buf ~pos:0 ~len);
+ Text.mark_set textw ~mark:"input" ~index:(`Mark"insert",[`Char(-1)])
+ end;
+ len
+ with Unix.Unix_error _ -> 0
+ end;
+ method history (dir : [`Next|`Previous]) =
+ if not h#empty then begin
+ if reading then begin
+ Text.delete textw ~start:(`Mark"input",[`Char 1])
+ ~stop:(`Mark"insert",[])
+ end else begin
+ reading <- true;
+ Text.mark_set textw ~mark:"input"
+ ~index:(`Mark"insert",[`Char(-1)])
+ end;
+ self#insert (if dir = `Previous then h#previous else h#next)
+ end
+ method private lex ?(start = `Mark"insert",[`Linestart])
+ ?(stop = `Mark"insert",[`Lineend]) () =
+ Lexical.tag textw ~start ~stop
+ method insert text =
+ let idx = Text.index textw
+ ~index:(`Mark"insert",[`Char(-1);`Linestart]) in
+ Text.insert textw ~text ~index:(`Mark"insert",[]);
+ self#lex ~start:(idx,[`Linestart]) ();
+ Text.see textw ~index:(`Mark"insert",[])
+ method private keypress c =
+ if not reading && c > " " then begin
+ reading <- true;
+ Text.mark_set textw ~mark:"input" ~index:(`Mark"insert",[`Char(-1)])
+ end
+ method private keyrelease c = if c <> "" then self#lex ()
+ method private return =
+ if reading then reading <- false
+ else Text.mark_set textw ~mark:"input"
+ ~index:(`Mark"insert",[`Linestart;`Char 1]);
+ Text.mark_set textw ~mark:"insert" ~index:(`Mark"insert",[`Lineend]);
+ self#lex ~start:(`Mark"input",[`Linestart]) ();
+ let s =
+ (* input is one character before real input *)
+ Text.get textw ~start:(`Mark"input",[`Char 1])
+ ~stop:(`Mark"insert",[]) in
+ h#add s;
+ Text.insert textw ~index:(`Mark"insert",[]) ~text:"\n";
+ Text.yview_index textw ~index:(`Mark"insert",[]);
+ self#send s;
+ self#send "\n"
+ method private paste ev =
+ if not reading then begin
+ reading <- true;
+ Text.mark_set textw ~mark:"input"
+ ~index:(`Atxy(ev.ev_MouseX, ev.ev_MouseY),[`Char(-1)])
+ end
+ initializer
+ Lexical.init_tags textw;
+ let rec bindings =
+ [ ([], `KeyPress, [`Char], fun ev -> self#keypress ev.ev_Char);
+ ([], `KeyRelease, [`Char], fun ev -> self#keyrelease ev.ev_Char);
+ (* [], `KeyPressDetail"Return", [], fun _ -> self#return; *)
+ ([], `ButtonPressDetail 2, [`MouseX; `MouseY], self#paste);
+ ([`Alt], `KeyPressDetail"p", [], fun _ -> self#history `Previous);
+ ([`Alt], `KeyPressDetail"n", [], fun _ -> self#history `Next);
+ ([`Meta], `KeyPressDetail"p", [], fun _ -> self#history `Previous);
+ ([`Meta], `KeyPressDetail"n", [], fun _ -> self#history `Next);
+ ([`Control], `KeyPressDetail"c", [], fun _ -> self#interrupt);
+ ([], `Destroy, [], fun _ -> self#kill) ]
+ in
+ List.iter bindings ~f:
+ begin fun (modif,event,fields,action) ->
+ bind textw ~events:[`Modified(modif,event)] ~fields ~action
+ end;
+ bind textw ~events:[`KeyPressDetail"Return"] ~breakable:true
+ ~action:(fun _ -> self#return; break());
+ List.iter ~f:Unix.close [in2;out2;err2];
+ if use_threads then begin
+ let fileinput_thread fd =
+ let buf = String.create 1024 in
+ let len = ref 0 in
+ try while len := Unix.read fd ~buf ~pos:0 ~len:1024; !len > 0 do
+ Mutex.lock imutex;
+ Buffer.add_substring ibuffer buf 0 !len;
+ Mutex.unlock imutex
+ done with Unix.Unix_error _ -> ()
+ in
+ ithreads <- List.map [in1; err1] ~f:(Thread.create fileinput_thread);
+ let rec read_buffer () =
+ Mutex.lock imutex;
+ if Buffer.length ibuffer > 0 then begin
+ self#insert (Str.global_replace ~!"\r\n" "\n"
+ (Buffer.contents ibuffer));
+ Buffer.reset ibuffer;
+ Text.mark_set textw ~mark:"input" ~index:(`Mark"insert",[`Char(-1)])
+ end;
+ Mutex.unlock imutex;
+ Timer.set ~ms:100 ~callback:read_buffer
+ in
+ read_buffer ()
+ end else begin
+ try
+ List.iter [in1;err1] ~f:
+ begin fun fd ->
+ Fileevent.add_fileinput ~fd
+ ~callback:(fun () -> ignore (self#read ~fd ~len:1024))
+ end
+ with _ -> ()
+ end
+end
+
+(* Specific use of shell, for OCamlBrowser *)
+
+let shells : (string * shell) list ref = ref []
+
+(* Called before exiting *)
+let kill_all () =
+ List.iter !shells ~f:(fun (_,sh) -> if sh#alive then sh#kill);
+ shells := []
+
+let get_all () =
+ let all = List.filter !shells ~f:(fun (_,sh) -> sh#alive) in
+ shells := all;
+ all
+
+let may_exec_unix prog =
+ try Unix.access prog ~perm:[Unix.X_OK]; prog
+ with Unix.Unix_error _ -> ""
+
+let may_exec_win prog =
+ let has_ext =
+ List.exists ~f:(Filename.check_suffix prog) ["exe"; "com"; "bat"] in
+ if has_ext then may_exec_unix prog else
+ List.fold_left [prog^".bat"; prog^".exe"; prog^".com"] ~init:""
+ ~f:(fun res prog -> if res = "" then may_exec_unix prog else res)
+
+let may_exec =
+ if is_win32 then may_exec_win else may_exec_unix
+
+let path_sep = if is_win32 then ";" else ":"
+
+let warnings = ref "Al"
+
+let program_not_found prog =
+ Jg_message.info ~title:"Error"
+ ("Program \"" ^ prog ^ "\"\nwas not found in path")
+
+let protect_arg s =
+ if String.contains s ' ' then "\"" ^ s ^ "\"" else s
+
+let f ~prog ~title =
+ let progargs =
+ List.filter ~f:((<>) "") (Str.split ~!" " prog) in
+ if progargs = [] then () else
+ let prog = List.hd progargs in
+ let path =
+ try Sys.getenv "PATH" with Not_found -> "/bin" ^ path_sep ^ "/usr/bin" in
+ let exec_path = Str.split ~!path_sep path in
+ let exec_path = if is_win32 then "."::exec_path else exec_path in
+ let progpath =
+ if not (Filename.is_implicit prog) then may_exec prog else
+ List.fold_left exec_path ~init:"" ~f:
+ (fun res dir ->
+ if res = "" then may_exec (Filename.concat dir prog) else res) in
+ if progpath = "" then program_not_found prog else
+ let tl = Jg_toplevel.titled title in
+ let menus = Menu.create tl ~name:"menubar" ~typ:`Menubar in
+ Toplevel.configure tl ~menu:menus;
+ let file_menu = new Jg_menu.c "File" ~parent:menus
+ and history_menu = new Jg_menu.c "History" ~parent:menus
+ and signal_menu = new Jg_menu.c "Signal" ~parent:menus in
+ let frame, tw, sb = Jg_text.create_with_scrollbar tl in
+ Text.configure tw ~background:`White;
+ pack [sb] ~fill:`Y ~side:`Right;
+ pack [tw] ~fill:`Both ~expand:true ~side:`Left;
+ pack [frame] ~fill:`Both ~expand:true;
+ let env = Array.map (Unix.environment ()) ~f:
+ begin fun s ->
+ if Str.string_match ~!"TERM=" s 0 then "TERM=dumb" else s
+ end in
+ let load_path =
+ List2.flat_map !Config.load_path ~f:(fun dir -> ["-I"; dir]) in
+ let load_path =
+ if is_win32 then List.map ~f:protect_arg load_path else load_path in
+ let labels = if !Clflags.classic then ["-nolabels"] else [] in
+ let rectypes = if !Clflags.recursive_types then ["-rectypes"] else [] in
+ let warnings =
+ if List.mem "-w" progargs || !warnings = "Al" then []
+ else ["-w"; !warnings]
+ in
+ let args =
+ Array.of_list (progargs @ labels @ warnings @ rectypes @ load_path) in
+ let history = new history () in
+ let start_shell () =
+ let sh = new shell ~textw:tw ~prog:progpath ~env ~args ~history in
+ shells := (title, sh) :: !shells;
+ sh
+ in
+ let sh = ref (start_shell ()) in
+ let current_dir = ref (Unix.getcwd ()) in
+ file_menu#add_command "Restart" ~command:
+ begin fun () ->
+ (!sh)#kill;
+ Text.configure tw ~state:`Normal;
+ Text.insert tw ~index:(`End,[]) ~text:"\n";
+ Text.see tw ~index:(`End,[]);
+ Text.mark_set tw ~mark:"insert" ~index:(`End,[]);
+ sh := start_shell ();
+ end;
+ file_menu#add_command "Use..." ~command:
+ begin fun () ->
+ Fileselect.f ~title:"Use File" ~filter:"*.ml"
+ ~sync:true ~dir:!current_dir ()
+ ~action:(fun l ->
+ if l = [] then () else
+ let name = Fileselect.caml_dir (List.hd l) in
+ current_dir := Filename.dirname name;
+ if Filename.check_suffix name ".ml"
+ then
+ let cmd = "#use \"" ^ String.escaped name ^ "\";;\n" in
+ (!sh)#insert cmd; (!sh)#send cmd)
+ end;
+ file_menu#add_command "Load..." ~command:
+ begin fun () ->
+ Fileselect.f ~title:"Load File" ~filter:"*.cm[oa]" ~sync:true ()
+ ~dir:!current_dir
+ ~action:(fun l ->
+ if l = [] then () else
+ let name = Fileselect.caml_dir (List.hd l) in
+ current_dir := Filename.dirname name;
+ if Filename.check_suffix name ".cmo" ||
+ Filename.check_suffix name ".cma"
+ then
+ let cmd = "#load \"" ^ String.escaped name ^ "\";;\n" in
+ (!sh)#insert cmd; (!sh)#send cmd)
+ end;
+ file_menu#add_command "Import path" ~command:
+ begin fun () ->
+ List.iter (List.rev !Config.load_path) ~f:
+ (fun dir ->
+ (!sh)#send ("#directory \"" ^ String.escaped dir ^ "\";;\n"))
+ end;
+ file_menu#add_command "Close" ~command:(fun () -> destroy tl);
+ history_menu#add_command "Previous " ~accelerator:"M-p"
+ ~command:(fun () -> (!sh)#history `Previous);
+ history_menu#add_command "Next" ~accelerator:"M-n"
+ ~command:(fun () -> (!sh)#history `Next);
+ signal_menu#add_command "Interrupt " ~accelerator:"C-c"
+ ~command:(fun () -> (!sh)#interrupt);
+ signal_menu#add_command "Kill" ~command:(fun () -> (!sh)#kill)
diff --git a/ocaml-binary-annot/otherlibs/labltk/browser/shell.mli b/ocaml-binary-annot/otherlibs/labltk/browser/shell.mli
new file mode 100644
index 0000000000..ac94f43d7c
--- /dev/null
+++ b/ocaml-binary-annot/otherlibs/labltk/browser/shell.mli
@@ -0,0 +1,46 @@
+(*************************************************************************)
+(* *)
+(* Objective Caml LablTk library *)
+(* *)
+(* Jacques Garrigue, Kyoto University RIMS *)
+(* *)
+(* Copyright 1999 Institut National de Recherche en Informatique et *)
+(* en Automatique and Kyoto University. All rights reserved. *)
+(* This file is distributed under the terms of the GNU Library *)
+(* General Public License, with the special exception on linking *)
+(* described in file ../../../LICENSE. *)
+(* *)
+(*************************************************************************)
+
+(* $Id$ *)
+
+class ['a] history :
+ unit ->
+ object
+ val mutable count : int
+ val mutable history : 'a list
+ method add : 'a -> unit
+ method empty : bool
+ method next : 'a
+ method previous : 'a
+ end
+
+(* toplevel shell *)
+
+class shell :
+ textw:Widget.text Widget.widget -> prog:string ->
+ args:string array -> env:string array -> history:string history ->
+ object
+ method alive : bool
+ method kill : unit
+ method interrupt : unit
+ method insert : string -> unit
+ method send : string -> unit
+ method history : [`Next|`Previous] -> unit
+ end
+
+val kill_all : unit -> unit
+val get_all : unit -> (string * shell) list
+val warnings : string ref
+
+val f : prog:string -> title:string -> unit
diff --git a/ocaml-binary-annot/otherlibs/labltk/browser/typecheck.ml b/ocaml-binary-annot/otherlibs/labltk/browser/typecheck.ml
new file mode 100644
index 0000000000..d5347ef53b
--- /dev/null
+++ b/ocaml-binary-annot/otherlibs/labltk/browser/typecheck.ml
@@ -0,0 +1,188 @@
+(*************************************************************************)
+(* *)
+(* Objective Caml LablTk library *)
+(* *)
+(* Jacques Garrigue, Kyoto University RIMS *)
+(* *)
+(* Copyright 1999 Institut National de Recherche en Informatique et *)
+(* en Automatique and Kyoto University. All rights reserved. *)
+(* This file is distributed under the terms of the GNU Library *)
+(* General Public License, with the special exception on linking *)
+(* described in file ../../../LICENSE. *)
+(* *)
+(*************************************************************************)
+
+(* $Id$ *)
+
+open StdLabels
+open Tk
+open Parsetree
+open Location
+open Jg_tk
+open Mytypes
+
+(* Optionally preprocess a source file *)
+
+let preprocess ~pp ~ext text =
+ let sourcefile = Filename.temp_file "caml" ext in
+ begin try
+ let oc = open_out_bin sourcefile in
+ output_string oc text;
+ flush oc;
+ close_out oc
+ with _ ->
+ failwith "Preprocessing error"
+ end;
+ let tmpfile = Filename.temp_file "camlpp" ext in
+ let comm = Printf.sprintf "%s %s > %s" pp sourcefile tmpfile in
+ if Ccomp.command comm <> 0 then begin
+ Sys.remove sourcefile;
+ Sys.remove tmpfile;
+ failwith "Preprocessing error"
+ end;
+ Sys.remove sourcefile;
+ tmpfile
+
+exception Outdated_version
+
+let parse_pp ~parse ~wrap ~ext text =
+ Location.input_name := "";
+ match !Clflags.preprocessor with
+ None ->
+ let buffer = Lexing.from_string text in
+ Location.init buffer "";
+ parse buffer
+ | Some pp ->
+ let tmpfile = preprocess ~pp ~ext text in
+ let ast_magic =
+ if ext = ".ml" then Config.ast_impl_magic_number
+ else Config.ast_intf_magic_number in
+ let ic = open_in_bin tmpfile in
+ let ast =
+ try
+ let buffer = String.create (String.length ast_magic) in
+ really_input ic buffer 0 (String.length ast_magic);
+ if buffer = ast_magic then begin
+ ignore (input_value ic);
+ wrap (input_value ic)
+ end else if String.sub buffer 0 9 = String.sub ast_magic 0 9 then
+ raise Outdated_version
+ else
+ raise Exit
+ with
+ Outdated_version ->
+ close_in ic;
+ Sys.remove tmpfile;
+ failwith "Ocaml and preprocessor have incompatible versions"
+ | _ ->
+ seek_in ic 0;
+ let buffer = Lexing.from_channel ic in
+ Location.init buffer "";
+ parse buffer
+ in
+ close_in ic;
+ Sys.remove tmpfile;
+ ast
+
+let nowarnings = ref false
+
+let f txt =
+ let error_messages = ref [] in
+ let text = Jg_text.get_all txt.tw
+ and env = ref (Env.open_pers_signature "Pervasives" Env.initial) in
+ let tl, ew, end_message =
+ Jg_message.formatted ~title:"Warnings" ~ppf:Format.err_formatter () in
+ Text.tag_remove txt.tw ~tag:"error" ~start:tstart ~stop:tend;
+ txt.structure <- [];
+ txt.type_info <- [];
+ txt.signature <- [];
+ txt.psignature <- [];
+ ignore (Stypes.get_info ());
+ Clflags.annotations := true;
+
+ begin try
+
+ if Filename.check_suffix txt.name ".mli" then
+ let psign = parse_pp text ~ext:".mli"
+ ~parse:Parse.interface ~wrap:(fun x -> x) in
+ txt.psignature <- psign;
+ txt.signature <- Typemod.transl_signature !env psign
+
+ else (* others are interpreted as .ml *)
+
+ let psl = parse_pp text ~ext:".ml"
+ ~parse:Parse.use_file ~wrap:(fun x -> [Parsetree.Ptop_def x]) in
+ List.iter psl ~f:
+ begin function
+ Ptop_def pstr ->
+ let str, sign, env' = Typemod.type_structure !env pstr Location.none in
+ txt.structure <- txt.structure @ str;
+ txt.signature <- txt.signature @ sign;
+ env := env'
+ | Ptop_dir _ -> ()
+ end;
+ txt.type_info <- Stypes.get_info ();
+
+ with
+ Lexer.Error _ | Syntaxerr.Error _
+ | Typecore.Error _ | Typemod.Error _
+ | Typeclass.Error _ | Typedecl.Error _
+ | Typetexp.Error _ | Includemod.Error _
+ | Env.Error _ | Ctype.Tags _ | Failure _ as exn ->
+ txt.type_info <- Stypes.get_info ();
+ let et, ew, end_message = Jg_message.formatted ~title:"Error !" () in
+ error_messages := et :: !error_messages;
+ let range = match exn with
+ Lexer.Error (err, l) ->
+ Lexer.report_error Format.std_formatter err; l
+ | Syntaxerr.Error err ->
+ Syntaxerr.report_error Format.std_formatter err;
+ begin match err with
+ Syntaxerr.Unclosed(l,_,_,_) -> l
+ | Syntaxerr.Applicative_path l -> l
+ | Syntaxerr.Other l -> l
+ end
+ | Typecore.Error (l,err) ->
+ Typecore.report_error Format.std_formatter err; l
+ | Typeclass.Error (l,err) ->
+ Typeclass.report_error Format.std_formatter err; l
+ | Typedecl.Error (l, err) ->
+ Typedecl.report_error Format.std_formatter err; l
+ | Typemod.Error (l,err) ->
+ Typemod.report_error Format.std_formatter err; l
+ | Typetexp.Error (l,err) ->
+ Typetexp.report_error Format.std_formatter err; l
+ | Includemod.Error errl ->
+ Includemod.report_error Format.std_formatter errl; Location.none
+ | Env.Error err ->
+ Env.report_error Format.std_formatter err; Location.none
+ | Ctype.Tags(l, l') ->
+ Format.printf "In this program,@ variant constructors@ `%s and `%s@ have same hash value.@." l l';
+ Location.none
+ | Failure s ->
+ Format.printf "%s.@." s; Location.none
+ | _ -> assert false
+ in
+ end_message ();
+ let s = range.loc_start.Lexing.pos_cnum in
+ let e = range.loc_end.Lexing.pos_cnum in
+ if s < e then
+ Jg_text.tag_and_see txt.tw ~start:(tpos s) ~stop:(tpos e) ~tag:"error"
+ end;
+ end_message ();
+ if !nowarnings || Text.index ew ~index:tend = `Linechar (2,0)
+ then destroy tl
+ else begin
+ error_messages := tl :: !error_messages;
+ Text.configure ew ~state:`Disabled;
+ bind ew ~events:[`Modified([`Double], `ButtonReleaseDetail 1)]
+ ~action:(fun _ ->
+ try
+ let start, ende = Text.tag_nextrange ew ~tag:"sel" ~start:(tpos 0) in
+ let s = Text.get ew ~start:(start,[]) ~stop:(ende,[]) in
+ let n = int_of_string s in
+ Text.mark_set txt.tw ~index:(tpos n) ~mark:"insert";
+ Text.see txt.tw ~index:(`Mark "insert", [])
+ with _ -> ())
+ end;
+ !error_messages
diff --git a/ocaml-binary-annot/otherlibs/labltk/browser/typecheck.mli b/ocaml-binary-annot/otherlibs/labltk/browser/typecheck.mli
new file mode 100644
index 0000000000..d61fce62e3
--- /dev/null
+++ b/ocaml-binary-annot/otherlibs/labltk/browser/typecheck.mli
@@ -0,0 +1,23 @@
+(*************************************************************************)
+(* *)
+(* Objective Caml LablTk library *)
+(* *)
+(* Jacques Garrigue, Kyoto University RIMS *)
+(* *)
+(* Copyright 1999 Institut National de Recherche en Informatique et *)
+(* en Automatique and Kyoto University. All rights reserved. *)
+(* This file is distributed under the terms of the GNU Library *)
+(* General Public License, with the special exception on linking *)
+(* described in file ../../../LICENSE. *)
+(* *)
+(*************************************************************************)
+
+(* $Id$ *)
+
+open Widget
+open Mytypes
+
+val nowarnings : bool ref
+
+val f : edit_window -> any widget list
+ (* Typechecks the window as much as possible *)
diff --git a/ocaml-binary-annot/otherlibs/labltk/browser/useunix.ml b/ocaml-binary-annot/otherlibs/labltk/browser/useunix.ml
new file mode 100644
index 0000000000..666f866f02
--- /dev/null
+++ b/ocaml-binary-annot/otherlibs/labltk/browser/useunix.ml
@@ -0,0 +1,69 @@
+(*************************************************************************)
+(* *)
+(* Objective Caml LablTk library *)
+(* *)
+(* Jacques Garrigue, Kyoto University RIMS *)
+(* *)
+(* Copyright 1999 Institut National de Recherche en Informatique et *)
+(* en Automatique and Kyoto University. All rights reserved. *)
+(* This file is distributed under the terms of the GNU Library *)
+(* General Public License, with the special exception on linking *)
+(* described in file ../../../LICENSE. *)
+(* *)
+(*************************************************************************)
+
+(* $Id$ *)
+
+open StdLabels
+open UnixLabels
+
+let get_files_in_directory dir =
+ let len = String.length dir in
+ let dir =
+ if len > 0 && Sys.os_type = "Win32" &&
+ (dir.[len-1] = '/' || dir.[len-1] = '\\')
+ then String.sub dir ~pos:0 ~len:(len-1)
+ else dir
+ in match
+ try Some(opendir dir) with Unix_error _ -> None
+ with
+ None -> []
+ | Some dirh ->
+ let rec get_them l =
+ match
+ try Some(readdir dirh) with _ -> None
+ with
+ | Some x ->
+ get_them (x::l)
+ | None ->
+ closedir dirh; l
+ in
+ List.sort ~cmp:compare (get_them [])
+
+let is_directory name =
+ try
+ (stat name).st_kind = S_DIR
+ with _ -> false
+
+let concat dir name =
+ let len = String.length dir in
+ if len = 0 then name else
+ if dir.[len-1] = '/' then dir ^ name
+ else dir ^ "/" ^ name
+
+let get_directories_in_files ~path =
+ List.filter ~f:(fun x -> is_directory (concat path x))
+
+(************************************************** Subshell call *)
+let subshell ~cmd =
+ let rc = open_process_in cmd in
+ let rec it l =
+ match
+ try Some(input_line rc) with _ -> None
+ with
+ Some x -> it (x::l)
+ | None -> List.rev l
+ in
+ let answer = it [] in
+ ignore (close_process_in rc);
+ answer
diff --git a/ocaml-binary-annot/otherlibs/labltk/browser/useunix.mli b/ocaml-binary-annot/otherlibs/labltk/browser/useunix.mli
new file mode 100644
index 0000000000..2850c0d2da
--- /dev/null
+++ b/ocaml-binary-annot/otherlibs/labltk/browser/useunix.mli
@@ -0,0 +1,23 @@
+(*************************************************************************)
+(* *)
+(* Objective Caml LablTk library *)
+(* *)
+(* Jacques Garrigue, Kyoto University RIMS *)
+(* *)
+(* Copyright 1999 Institut National de Recherche en Informatique et *)
+(* en Automatique and Kyoto University. All rights reserved. *)
+(* This file is distributed under the terms of the GNU Library *)
+(* General Public License, with the special exception on linking *)
+(* described in file ../../../LICENSE. *)
+(* *)
+(*************************************************************************)
+
+(* $Id$ *)
+
+(* Unix utilities *)
+
+val get_files_in_directory : string -> string list
+val is_directory : string -> bool
+val concat : string -> string -> string
+val get_directories_in_files : path:string -> string list -> string list
+val subshell : cmd:string -> string list
diff --git a/ocaml-binary-annot/otherlibs/labltk/browser/viewer.ml b/ocaml-binary-annot/otherlibs/labltk/browser/viewer.ml
new file mode 100644
index 0000000000..fef3cbe104
--- /dev/null
+++ b/ocaml-binary-annot/otherlibs/labltk/browser/viewer.ml
@@ -0,0 +1,631 @@
+(*************************************************************************)
+(* *)
+(* Objective Caml LablTk library *)
+(* *)
+(* Jacques Garrigue, Kyoto University RIMS *)
+(* *)
+(* Copyright 1999 Institut National de Recherche en Informatique et *)
+(* en Automatique and Kyoto University. All rights reserved. *)
+(* This file is distributed under the terms of the GNU Library *)
+(* General Public License, with the special exception on linking *)
+(* described in file ../../../LICENSE. *)
+(* *)
+(*************************************************************************)
+
+(* $Id$ *)
+
+open StdLabels
+open Tk
+open Jg_tk
+open Mytypes
+open Longident
+open Types
+open Typedtree
+open Env
+open Searchpos
+open Searchid
+
+(* Managing the module list *)
+
+let list_modules ~path =
+ List.fold_left path ~init:[] ~f:
+ begin fun modules dir ->
+ let l =
+ List.filter (Useunix.get_files_in_directory dir)
+ ~f:(fun x -> Filename.check_suffix x ".cmi") in
+ let l = List.map l ~f:
+ begin fun x ->
+ String.capitalize (Filename.chop_suffix x ".cmi")
+ end in
+ List.fold_left l ~init:modules
+ ~f:(fun modules item ->
+ if List.mem item modules then modules else item :: modules)
+ end
+
+let reset_modules box =
+ Listbox.delete box ~first:(`Num 0) ~last:`End;
+ module_list := Sort.list (Jg_completion.lt_string ~nocase:true)
+ (list_modules ~path:!Config.load_path);
+ Listbox.insert box ~index:`End ~texts:!module_list;
+ Jg_box.recenter box ~index:(`Num 0)
+
+
+(* How to display a symbol *)
+
+let view_symbol ~kind ~env ?path id =
+ let name = match id with
+ Lident x -> x
+ | Ldot (_, x) -> x
+ | _ -> match kind with Pvalue | Ptype | Plabel -> "z" | _ -> "Z"
+ in
+ match kind with
+ Pvalue ->
+ let path, vd = lookup_value id env in
+ view_signature_item ~path ~env [Tsig_value (Ident.create name, vd)]
+ | Ptype -> view_type_id id ~env
+ | Plabel -> let ld = lookup_label id env in
+ begin match ld.lbl_res.desc with
+ Tconstr (path, _, _) -> view_type_decl path ~env
+ | _ -> ()
+ end
+ | Pconstructor ->
+ let cd = lookup_constructor id env in
+ begin match cd.cstr_res.desc with
+ Tconstr (cpath, _, _) ->
+ if Path.same cpath Predef.path_exn then
+ view_signature ~title:(string_of_longident id) ~env ?path
+ [Tsig_exception (Ident.create name, cd.cstr_args)]
+ else
+ view_type_decl cpath ~env
+ | _ -> ()
+ end
+ | Pmodule -> view_module_id id ~env
+ | Pmodtype -> view_modtype_id id ~env
+ | Pclass -> view_class_id id ~env
+ | Pcltype -> view_cltype_id id ~env
+
+
+(* Create a list of symbols you can choose from *)
+
+let choose_symbol ~title ~env ?signature ?path l =
+ if match path with
+ None -> false
+ | Some path -> is_shown_module path
+ then () else
+ let tl = Jg_toplevel.titled title in
+ Jg_bind.escape_destroy tl;
+ top_widgets := coe tl :: !top_widgets;
+ let buttons = Frame.create tl in
+ let all = Button.create buttons ~text:"Show all" ~padx:20
+ and ok = Jg_button.create_destroyer tl ~parent:buttons
+ and detach = Button.create buttons ~text:"Detach"
+ and edit = Button.create buttons ~text:"Impl"
+ and intf = Button.create buttons ~text:"Intf" in
+ let l = List.sort l ~cmp:(fun (li1, _) (li2,_) -> compare li1 li2) in
+ let nl = List.map l ~f:
+ begin fun (li, k) ->
+ string_of_longident li ^ " (" ^ string_of_kind k ^ ")"
+ end in
+ let fb = Frame.create tl in
+ let box =
+ new Jg_multibox.c fb ~cols:3 ~texts:nl ~maxheight:3 ~width:21 in
+ box#init;
+ box#bind_kbd ~events:[`KeyPressDetail"Escape"]
+ ~action:(fun _ ~index -> destroy tl; break ());
+ if List.length nl > 9 then ignore (Jg_multibox.add_scrollbar box);
+ Jg_multibox.add_completion box ~action:
+ begin fun pos ->
+ let li, k = List.nth l pos in
+ let path =
+ match path, li with
+ None, Ldot (lip, _) ->
+ begin try
+ Some (fst (lookup_module lip env))
+ with Not_found -> None
+ end
+ | _ -> path
+ in view_symbol li ~kind:k ~env ?path
+ end;
+ pack [buttons] ~side:`Bottom ~fill:`X;
+ pack [fb] ~side:`Top ~fill:`Both ~expand:true;
+ begin match signature with
+ None -> pack [ok] ~fill:`X ~expand:true
+ | Some signature ->
+ Button.configure all ~command:
+ begin fun () ->
+ view_signature signature ~title ~env ?path
+ end;
+ pack [ok; all] ~side:`Right ~fill:`X ~expand:true
+ end;
+ begin match path with None -> ()
+ | Some path ->
+ let frame = Frame.create tl in
+ pack [frame] ~side:`Bottom ~fill:`X;
+ add_shown_module path
+ ~widgets:{ mw_frame = frame; mw_title = None; mw_detach = detach;
+ mw_edit = edit; mw_intf = intf }
+ end
+
+let choose_symbol_ref = ref choose_symbol
+
+
+(* Search, both by type and name *)
+
+let guess_search_mode s : [`Type | `Long | `Pattern] =
+ let is_type = ref false and is_long = ref false in
+ for i = 0 to String.length s - 2 do
+ if s.[i] = '-' && s.[i+1] = '>' then is_type := true;
+ if s.[i] = '.' then is_long := true
+ done;
+ if !is_type then `Type else if !is_long then `Long else `Pattern
+
+
+let search_string ?(mode="symbol") ew =
+ let text = Entry.get ew in
+ try
+ if text = "" then () else
+ let l = match mode with
+ "Name" ->
+ begin match guess_search_mode text with
+ `Long -> search_string_symbol text
+ | `Pattern -> search_pattern_symbol text
+ | `Type -> search_string_type text ~mode:`Included
+ end
+ | "Type" -> search_string_type text ~mode:`Included
+ | "Exact" -> search_string_type text ~mode:`Exact
+ | _ -> assert false
+ in
+ match l with [] -> ()
+ | [lid,kind] -> view_symbol lid ~kind ~env:!start_env
+ | l -> choose_symbol ~title:"Choose symbol" ~env:!start_env l
+ with Searchid.Error (s,e) ->
+ Entry.icursor ew ~index:(`Num s)
+
+let search_which = ref "Name"
+
+let search_symbol () =
+ if !module_list = [] then
+ module_list := List.sort ~cmp:compare (list_modules ~path:!Config.load_path);
+ let tl = Jg_toplevel.titled "Search symbol" in
+ Jg_bind.escape_destroy tl;
+ let ew = Entry.create tl ~width:30 in
+ let choice = Frame.create tl
+ and which = Textvariable.create ~on:tl () in
+ let itself = Radiobutton.create choice ~text:"Itself"
+ ~variable:which ~value:"Name"
+ and extype = Radiobutton.create choice ~text:"Exact type"
+ ~variable:which ~value:"Exact"
+ and iotype = Radiobutton.create choice ~text:"Included type"
+ ~variable:which ~value:"Type"
+ and buttons = Frame.create tl in
+ let search = Button.create buttons ~text:"Search" ~command:
+ begin fun () ->
+ search_which := Textvariable.get which;
+ search_string ew ~mode:!search_which
+ end
+ and ok = Jg_button.create_destroyer tl ~parent:buttons ~text:"Cancel" in
+
+ Focus.set ew;
+ Jg_bind.return_invoke ew ~button:search;
+ Textvariable.set which !search_which;
+ pack [itself; extype; iotype] ~side:`Left ~anchor:`W;
+ pack [search; ok] ~side:`Left ~fill:`X ~expand:true;
+ pack [coe ew; coe choice; coe buttons]
+ ~side:`Top ~fill:`X ~expand:true
+
+
+(* Display the contents of a module *)
+
+let ident_of_decl ~modlid = function
+ Tsig_value (id, _) -> Lident (Ident.name id), Pvalue
+ | Tsig_type (id, _, _) -> Lident (Ident.name id), Ptype
+ | Tsig_exception (id, _) -> Ldot (modlid, Ident.name id), Pconstructor
+ | Tsig_module (id, _, _) -> Lident (Ident.name id), Pmodule
+ | Tsig_modtype (id, _) -> Lident (Ident.name id), Pmodtype
+ | Tsig_class (id, _, _) -> Lident (Ident.name id), Pclass
+ | Tsig_cltype (id, _, _) -> Lident (Ident.name id), Pcltype
+
+let view_defined ~env ?(show_all=false) modlid =
+ try match lookup_module modlid env with path, Tmty_signature sign ->
+ let rec iter_sign sign idents =
+ match sign with
+ [] -> List.rev idents
+ | decl :: rem ->
+ let rem = match decl, rem with
+ Tsig_class _, cty :: ty1 :: ty2 :: rem -> rem
+ | Tsig_cltype _, ty1 :: ty2 :: rem -> rem
+ | _, rem -> rem
+ in iter_sign rem (ident_of_decl ~modlid decl :: idents)
+ in
+ let l = iter_sign sign [] in
+ let title = string_of_path path in
+ let env = open_signature path sign env in
+ !choose_symbol_ref l ~title ~signature:sign ~env ~path;
+ if show_all then view_signature sign ~title ~env ~path
+ | _ -> ()
+ with Not_found -> ()
+ | Env.Error err ->
+ let tl, tw, finish = Jg_message.formatted ~title:"Error!" () in
+ Env.report_error Format.std_formatter err;
+ finish ()
+
+
+(* Manage toplevel windows *)
+
+let close_all_views () =
+ List.iter !top_widgets
+ ~f:(fun tl -> try destroy tl with Protocol.TkError _ -> ());
+ top_widgets := []
+
+
+(* Launch a shell *)
+
+let shell_counter = ref 1
+let default_shell = ref "ocaml"
+
+let start_shell master =
+ let tl = Jg_toplevel.titled "Start New Shell" in
+ Wm.transient_set tl ~master;
+ let input = Frame.create tl
+ and buttons = Frame.create tl in
+ let ok = Button.create buttons ~text:"Ok"
+ and cancel = Jg_button.create_destroyer tl ~parent:buttons ~text:"Cancel"
+ and labels = Frame.create input
+ and entries = Frame.create input in
+ let l1 = Label.create labels ~text:"Command:"
+ and l2 = Label.create labels ~text:"Title:"
+ and e1 =
+ Jg_entry.create entries ~command:(fun _ -> Button.invoke ok)
+ and e2 =
+ Jg_entry.create entries ~command:(fun _ -> Button.invoke ok)
+ and names = List.map ~f:fst (Shell.get_all ()) in
+ Entry.insert e1 ~index:`End ~text:!default_shell;
+ let shell_name () = "Shell #" ^ string_of_int !shell_counter in
+ while List.mem (shell_name ()) names do
+ incr shell_counter
+ done;
+ Entry.insert e2 ~index:`End ~text:(shell_name ());
+ Button.configure ok ~command:(fun () ->
+ if not (List.mem (Entry.get e2) names) then begin
+ default_shell := Entry.get e1;
+ Shell.f ~prog:!default_shell ~title:(Entry.get e2);
+ destroy tl
+ end);
+ pack [l1;l2] ~side:`Top ~anchor:`W;
+ pack [e1;e2] ~side:`Top ~fill:`X ~expand:true;
+ pack [labels;entries] ~side:`Left ~fill:`X ~expand:true;
+ pack [ok;cancel] ~side:`Left ~fill:`X ~expand:true;
+ pack [input;buttons] ~side:`Top ~fill:`X ~expand:true
+
+
+(* Help window *)
+
+let show_help () =
+ let tl = Jg_toplevel.titled "OCamlBrowser Help" in
+ Jg_bind.escape_destroy tl;
+ let fw, tw, sb = Jg_text.create_with_scrollbar tl in
+ let ok = Jg_button.create_destroyer ~parent:tl ~text:"Ok" tl in
+ Text.insert tw ~index:tend ~text:Help.text;
+ Text.configure tw ~state:`Disabled;
+ Jg_bind.enter_focus tw;
+ pack [tw] ~side:`Left ~fill:`Both ~expand:true;
+ pack [sb] ~side:`Right ~fill:`Y;
+ pack [fw] ~side:`Top ~expand:true ~fill:`Both;
+ pack [ok] ~side:`Bottom ~fill:`X
+
+(* Launch the classical viewer *)
+
+let f ?(dir=Unix.getcwd()) ?on () =
+ let (top, tl) = match on with
+ None ->
+ let tl = Jg_toplevel.titled "Module viewer" in
+ ignore (Jg_bind.escape_destroy tl); (tl, coe tl)
+ | Some top ->
+ Wm.title_set top "OCamlBrowser";
+ Wm.iconname_set top "OCamlBrowser";
+ let tl = Frame.create top in
+ bind tl ~events:[`Destroy] ~action:(fun _ -> exit 0);
+ pack [tl] ~expand:true ~fill:`Both;
+ (top, coe tl)
+ in
+ let menus = Jg_menu.menubar top in
+ let filemenu = new Jg_menu.c "File" ~parent:menus
+ and modmenu = new Jg_menu.c "Modules" ~parent:menus in
+ let fmbox, mbox, msb = Jg_box.create_with_scrollbar tl in
+
+ Jg_box.add_completion mbox ~nocase:true ~action:
+ begin fun index ->
+ view_defined (Lident (Listbox.get mbox ~index)) ~env:!start_env
+ end;
+ Setpath.add_update_hook (fun () -> reset_modules mbox);
+
+ let ew = Entry.create tl in
+ let buttons = Frame.create tl in
+ let search = Button.create buttons ~text:"Search" ~pady:1
+ ~command:(fun () -> search_string ew)
+ and close =
+ Button.create buttons ~text:"Close all" ~pady:1 ~command:close_all_views
+ in
+ (* bindings *)
+ Jg_bind.enter_focus ew;
+ Jg_bind.return_invoke ew ~button:search;
+ bind close ~events:[`Modified([`Double], `ButtonPressDetail 1)]
+ ~action:(fun _ -> destroy tl);
+
+ (* File menu *)
+ filemenu#add_command "Open..."
+ ~command:(fun () -> !editor_ref ~opendialog:true ());
+ filemenu#add_command "Editor..." ~command:(fun () -> !editor_ref ());
+ filemenu#add_command "Shell..." ~command:(fun () -> start_shell tl);
+ filemenu#add_command "Quit" ~command:(fun () -> destroy tl);
+
+ (* modules menu *)
+ modmenu#add_command "Path editor..."
+ ~command:(fun () -> Setpath.set ~dir);
+ modmenu#add_command "Reset cache"
+ ~command:(fun () -> reset_modules mbox; Env.reset_cache ());
+ modmenu#add_command "Search symbol..." ~command:search_symbol;
+
+ pack [close; search] ~fill:`X ~side:`Right ~expand:true;
+ pack [coe buttons; coe ew] ~fill:`X ~side:`Bottom;
+ pack [msb] ~side:`Right ~fill:`Y;
+ pack [mbox] ~side:`Left ~fill:`Both ~expand:true;
+ pack [fmbox] ~fill:`Both ~expand:true ~side:`Top;
+ reset_modules mbox
+
+(* Smalltalk-like version *)
+
+class st_viewer ?(dir=Unix.getcwd()) ?on () =
+ let (top, tl) = match on with
+ None ->
+ let tl = Jg_toplevel.titled "Module viewer" in
+ ignore (Jg_bind.escape_destroy tl); (tl, coe tl)
+ | Some top ->
+ Wm.title_set top "OCamlBrowser";
+ Wm.iconname_set top "OCamlBrowser";
+ let tl = Frame.create top in
+ bind tl ~events:[`Destroy] ~action:(fun _ -> exit 0);
+ pack [tl] ~side:`Bottom ~expand:true ~fill:`Both;
+ (top, coe tl)
+ in
+ let menus = Menu.create top ~name:"menubar" ~typ:`Menubar in
+ let () = Toplevel.configure top ~menu:menus in
+ let filemenu = new Jg_menu.c "File" ~parent:menus
+ and modmenu = new Jg_menu.c "Modules" ~parent:menus
+ and viewmenu = new Jg_menu.c "View" ~parent:menus
+ and helpmenu = new Jg_menu.c "Help" ~parent:menus in
+ let search_frame = Frame.create tl in
+ let boxes_frame = Frame.create tl ~name:"boxes" in
+ let label = Label.create tl ~anchor:`W ~padx:5 in
+ let view = Frame.create tl in
+ let buttons = Frame.create tl in
+ let _all = Button.create buttons ~text:"Show all" ~padx:20
+ and close = Button.create buttons ~text:"Close all" ~command:close_all_views
+ and detach = Button.create buttons ~text:"Detach"
+ and edit = Button.create buttons ~text:"Impl"
+ and intf = Button.create buttons ~text:"Intf" in
+object (self)
+ val mutable boxes = []
+ val mutable show_all = fun () -> ()
+
+ method create_box =
+ let fmbox, mbox, sb = Jg_box.create_with_scrollbar boxes_frame in
+ bind mbox ~events:[`Modified([`Double], `ButtonPressDetail 1)]
+ ~action:(fun _ -> show_all ());
+ bind mbox ~events:[`Modified([`Double], `KeyPressDetail "Return")]
+ ~action:(fun _ -> show_all ());
+ boxes <- boxes @ [fmbox, mbox];
+ pack [sb] ~side:`Right ~fill:`Y;
+ pack [mbox] ~side:`Left ~fill:`Both ~expand:true;
+ pack [fmbox] ~side:`Left ~fill:`Both ~expand:true;
+ fmbox, mbox
+
+ initializer
+ (* Search *)
+ let ew = Entry.create search_frame
+ and searchtype = Textvariable.create ~on:tl () in
+ bind ew ~events:[`KeyPressDetail "Return"] ~action:
+ (fun _ -> search_string ew ~mode:(Textvariable.get searchtype));
+ Jg_bind.enter_focus ew;
+ let search_button ?value text =
+ Radiobutton.create search_frame
+ ~text ~variable:searchtype ~value:text in
+ let symbol = search_button "Name"
+ and atype = search_button "Type" in
+ Radiobutton.select symbol;
+ pack [Label.create search_frame ~text:"Search"] ~side:`Left ~ipadx:5;
+ pack [ew] ~fill:`X ~expand:true ~side:`Left;
+ pack [Label.create search_frame ~text:"by"] ~side:`Left ~ipadx:5;
+ pack [symbol; atype] ~side:`Left;
+ pack [Label.create search_frame] ~side:`Right
+
+ initializer
+ (* Boxes *)
+ let fmbox, mbox = self#create_box in
+ Jg_box.add_completion mbox ~nocase:true ~double:false ~action:
+ begin fun index ->
+ view_defined (Lident (Listbox.get mbox ~index)) ~env:!start_env
+ end;
+ Setpath.add_update_hook (fun () -> reset_modules mbox; self#hide_after 1);
+ List.iter [1;2] ~f:(fun _ -> ignore self#create_box);
+ Searchpos.default_frame := Some
+ { mw_frame = view; mw_title = Some label;
+ mw_detach = detach; mw_edit = edit; mw_intf = intf };
+ Searchpos.set_path := self#set_path;
+
+ (* Buttons *)
+ pack [close] ~side:`Right ~fill:`X ~expand:true;
+ bind close ~events:[`Modified([`Double], `ButtonPressDetail 1)]
+ ~action:(fun _ -> destroy tl);
+
+ (* File menu *)
+ filemenu#add_command "Open..."
+ ~command:(fun () -> !editor_ref ~opendialog:true ());
+ filemenu#add_command "Editor..." ~command:(fun () -> !editor_ref ());
+ filemenu#add_command "Shell..." ~command:(fun () -> start_shell tl);
+ filemenu#add_command "Quit" ~command:(fun () -> destroy tl);
+
+ (* View menu *)
+ viewmenu#add_command "Show all defs" ~command:(fun () -> show_all ());
+ let show_search = Textvariable.create ~on:tl () in
+ Textvariable.set show_search "1";
+ Menu.add_checkbutton viewmenu#menu ~label:"Search Entry"
+ ~variable:show_search ~indicatoron:true ~state:`Active
+ ~command:
+ begin fun () ->
+ let v = Textvariable.get show_search in
+ if v = "1" then begin
+ pack [search_frame] ~after:menus ~fill:`X
+ end else Pack.forget [search_frame]
+ end;
+
+ (* modules menu *)
+ modmenu#add_command "Path editor..."
+ ~command:(fun () -> Setpath.set ~dir);
+ modmenu#add_command "Reset cache"
+ ~command:(fun () -> reset_modules mbox; Env.reset_cache ());
+ modmenu#add_command "Search symbol..." ~command:search_symbol;
+
+ (* Help menu *)
+ helpmenu#add_command "Manual..." ~command:show_help;
+
+ pack [search_frame] ~fill:`X;
+ pack [boxes_frame] ~fill:`Both ~expand:true;
+ pack [buttons] ~fill:`X ~side:`Bottom;
+ pack [view] ~fill:`Both ~side:`Bottom ~expand:true;
+ reset_modules mbox
+
+ val mutable shown_paths = []
+
+ method hide_after n =
+ for i = n to List.length boxes - 1 do
+ let fm, box = List.nth boxes i in
+ if i < 3 then Listbox.delete box ~first:(`Num 0) ~last:`End
+ else destroy fm
+ done;
+ let rec firsts n = function [] -> []
+ | a :: l -> if n > 0 then a :: firsts (pred n) l else [] in
+ shown_paths <- firsts (n-1) shown_paths;
+ boxes <- firsts (max 3 n) boxes
+
+ method get_box ~path =
+ let rec path_index p = function
+ [] -> raise Not_found
+ | a :: l -> if Path.same p a then 1 else path_index p l + 1 in
+ try
+ let n = path_index path shown_paths in
+ self#hide_after (n+1);
+ n
+ with Not_found ->
+ match path with
+ Path.Pdot (path', _, _) ->
+ let n = self#get_box ~path:path' in
+ shown_paths <- shown_paths @ [path];
+ if n + 1 >= List.length boxes then ignore self#create_box;
+ n+1
+ | _ ->
+ self#hide_after 2;
+ shown_paths <- [path];
+ 1
+
+ method set_path path ~sign =
+ let rec path_elems l path =
+ match path with
+ Path.Pdot (path, _, _) -> path_elems (path::l) path
+ | _ -> []
+ in
+ let path_elems path =
+ match path with
+ | Path.Pident _ -> [path]
+ | _ -> path_elems [] path
+ in
+ let see_path ~box:n ?(sign=[]) path =
+ let (_, box) = List.nth boxes n in
+ let texts = Listbox.get_range box ~first:(`Num 0) ~last:`End in
+ let rec index s = function
+ [] -> raise Not_found
+ | a :: l -> if a = s then 0 else 1 + index s l
+ in
+ try
+ let modlid, s =
+ match path with
+ Path.Pdot (p, s, _) -> longident_of_path p, s
+ | Path.Pident i -> Longident.Lident "M", Ident.name i
+ | _ -> assert false
+ in
+ let li, k =
+ if sign = [] then Longident.Lident s, Pmodule else
+ ident_of_decl ~modlid (List.hd sign) in
+ let s =
+ if n = 0 then string_of_longident li else
+ string_of_longident li ^ " (" ^ string_of_kind k ^ ")" in
+ let n = index s texts in
+ Listbox.see box (`Num n);
+ Listbox.activate box (`Num n)
+ with Not_found -> ()
+ in
+ let l = path_elems path in
+ if l <> [] then begin
+ List.iter l ~f:
+ begin fun path ->
+ if not (List.mem path shown_paths) then
+ view_symbol (longident_of_path path) ~kind:Pmodule
+ ~env:Env.initial ~path;
+ let n = self#get_box path - 1 in
+ see_path path ~box:n
+ end;
+ see_path path ~box:(self#get_box path) ~sign
+ end
+
+ method choose_symbol ~title ~env ?signature ?path l =
+ let n =
+ match path with None -> 1
+ | Some path -> self#get_box ~path
+ in
+ let l = List.sort l ~cmp:(fun (li1, _) (li2,_) -> compare li1 li2) in
+ let nl = List.map l ~f:
+ begin fun (li, k) ->
+ string_of_longident li ^ " (" ^ string_of_kind k ^ ")"
+ end in
+ let _, box = List.nth boxes n in
+ Listbox.delete box ~first:(`Num 0) ~last:`End;
+ Listbox.insert box ~index:`End ~texts:nl;
+
+ let current = ref None in
+ let display index =
+ let `Num pos = Listbox.index box ~index in
+ try
+ let li, k = List.nth l pos in
+ self#hide_after (n+1);
+ if !current = Some (li,k) then () else
+ let path =
+ match path, li with
+ None, Ldot (lip, _) ->
+ begin try
+ Some (fst (lookup_module lip env))
+ with Not_found -> None
+ end
+ | _ -> path
+ in
+ current := Some (li,k);
+ view_symbol li ~kind:k ~env ?path
+ with Failure "nth" -> ()
+ in
+ Jg_box.add_completion box ~double:false ~action:display;
+ bind box ~events:[`KeyRelease] ~fields:[`Char]
+ ~action:(fun ev -> display `Active);
+
+ begin match signature with
+ None -> ()
+ | Some signature ->
+ show_all <-
+ begin fun () ->
+ current := None;
+ view_signature signature ~title ~env ?path
+ end
+ end
+end
+
+let st_viewer ?dir ?on () =
+ let viewer = new st_viewer ?dir ?on () in
+ choose_symbol_ref := viewer#choose_symbol
diff --git a/ocaml-binary-annot/otherlibs/labltk/browser/viewer.mli b/ocaml-binary-annot/otherlibs/labltk/browser/viewer.mli
new file mode 100644
index 0000000000..d8bec671df
--- /dev/null
+++ b/ocaml-binary-annot/otherlibs/labltk/browser/viewer.mli
@@ -0,0 +1,31 @@
+(*************************************************************************)
+(* *)
+(* Objective Caml LablTk library *)
+(* *)
+(* Jacques Garrigue, Kyoto University RIMS *)
+(* *)
+(* Copyright 1999 Institut National de Recherche en Informatique et *)
+(* en Automatique and Kyoto University. All rights reserved. *)
+(* This file is distributed under the terms of the GNU Library *)
+(* General Public License, with the special exception on linking *)
+(* described in file ../../../LICENSE. *)
+(* *)
+(*************************************************************************)
+
+(* $Id$ *)
+
+(* Module viewer *)
+open Widget
+
+val search_symbol : unit -> unit
+ (* search a symbol in all modules in the path *)
+
+val f : ?dir:string -> ?on:toplevel widget -> unit -> unit
+ (* open then module viewer *)
+val st_viewer : ?dir:string -> ?on:toplevel widget -> unit -> unit
+ (* one-box viewer *)
+
+val view_defined : env:Env.t -> ?show_all:bool -> Longident.t -> unit
+ (* displays a signature, found in environment *)
+
+val close_all_views : unit -> unit
diff --git a/ocaml-binary-annot/otherlibs/labltk/browser/winmain.c b/ocaml-binary-annot/otherlibs/labltk/browser/winmain.c
new file mode 100644
index 0000000000..dd9146fcce
--- /dev/null
+++ b/ocaml-binary-annot/otherlibs/labltk/browser/winmain.c
@@ -0,0 +1,26 @@
+/* $Id$ */
+
+#include <windows.h>
+#include <mlvalues.h>
+#include <callback.h>
+#include <sys.h>
+
+/*CAMLextern int __argc; */
+/* CAMLextern char **__argv; */
+/* CAMLextern void caml_expand_command_line(int * argcp, char *** argvp); */
+/* extern void caml_main (char **); */
+
+int WINAPI WinMain(HINSTANCE h, HINSTANCE HPrevInstance,
+ LPSTR lpCmdLine, int nCmdShow)
+{
+ char exe_name[1024];
+ char * argv[2];
+
+ GetModuleFileName(NULL, exe_name, sizeof(exe_name) - 1);
+ exe_name[sizeof(exe_name) - 1] = '0';
+ argv[0] = exe_name;
+ argv[1] = NULL;
+ caml_main(argv);
+ sys_exit(Val_int(0));
+ return 0;
+}