Commits

Peter Szilagyi committed 7b6fc09 Merge

auto merge

  • Participants
  • Parent commits 8ecba19, 9ec0614
  • Tags 2013-01-09-roll-test

Comments (0)

Files changed (387)

File .JS_ELISP_ROOT

+This file is here so we can easily find the root directory from
+test code.
 *.cmi
 *.cmx
 *.d
+*.declared-1step.deps
 *.exe
 *.libdeps
 *.o
 *.pyc
 *__pycache__
 .DS_Store
+*.log
 
 bins.inferred-1step.deps
 *.build_info.c
 
 .deps
 
+bin/ocp-build
 bin/ocp-indent
 elisp/contrib/auctex/Makefile
 elisp/contrib/auctex/auctex.el
 elisp/contrib/tex-site.el
 elisp/omake/scratch.el
 ocaml/contrib/ocaml_inotify/inotify_test
-ocaml/contrib/ocp-indent/.git
-ocaml/contrib/ocp-indent/Makefile.config
-ocaml/contrib/ocp-indent/_build
-ocaml/contrib/ocp-indent/config.log
-ocaml/contrib/ocp-indent/config.status
-ocaml/contrib/ocp-indent/main.native
-ocaml/contrib/ocp-indent/src/globals.ml
-ocaml/contrib/ocp-indent/tests/js-*.1.ml
-ocaml/contrib/ocp-indent/tests/js-*.1.mlp
-ocaml/contrib/ocp-indent/tests/js-*.diff
+ocaml/contrib/ocp-build
+ocaml/contrib/ocp-indent
 ocaml/omake/OMakefile
 ocp-indent/ocp.ml
 ocp-indent/tuareg.ml
 6c51f87ca92896526e497605ba0f112843876c87 2012-11-23-roll-test
 2fa9f61e93c790a057e32f81dd599046cc720e09 2012-12-03-roll-prod
 79467e4aacd1d0b0a4b2ff2445392d23b69dabb3 2012-12-03-roll-prod
+0a2ef19b7002712a72e7ef1670d192f30f5af00c 2012-12-31-roll-test
+d472fb799dfa87e96b95e76c6be7fc907e5c8f15 1.0
+new stuff
+=========
+
+omake-mode now has an opam package.  See README for more details.
+
+changes
+=======
+- dropped a legacy compatibility definition of "jane-home"; delete a
+  reference to it from custom-set-variables in your ~/.emacs if you
+  encounter a corresponding "undefined variable" error at startup
+- unbound "C-c C-c" in edit-server (Google Chrome Edit with Emacs) to
+  focus attention on the emacsclient-compatible "C-x #" binding
+- integrated new ocp-indent Emacs Lisp bindings and latest updates
+
+bug fixes
+=========
+- used "file-truename" strategically on "load-path" entries so already
+  running Emacsen can survive upgrades by continuing to run matching,
+  start-time versions of Elisp, OMake Server, ocp-indent, etc.
+- added end-of-line whitespace-removal to jane-tuareg-hook
+
+================================================================================
+2012-12-31 Rolled rev 0a2ef19b7002 to test
+================================================================================
+
 changes
 =======
 - defaulted tuareg-indent-comments to nil to avoid accidentally
 - omake server protocol version increment to support unset environment
   variables, whose default values are determined by the project
   OMakeroot rather than Jane Elisp
-- removed post-Santy TOT hacks.  You can switch your
+- removed post-Sandy TOT hacks.  You can switch your
   ~/.omake-server/config back from "omake_command_tot_after_sandy"
   back to omake_command.
 
 =========
 - Jane.rainbow-delimiters micro-feature and rainbow-delimiters-mode
 
-[...]
-
 --------------------------------------------------------------------------------
 
 new stuff
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
 
 Jane Street Emacs utilities
 
+Linux note: I couldn't get omake to install with FAM support
+via opam or from source.  The only way it worked was via apt.
+
 * Usage
 
 ** Normal usage at the office
 
 Everyone should add one of the following lines to their .emacs file.
 
-    (load "/j/office/app/emacs/prod/jane-elisp/elisp/jane/jane-defaults")
-      loads libraries, sets variables according to our coding
-      standards, and sets standard defaults which many users find
-      useful.
+      (load "/j/office/app/emacs/prod/jane-elisp/elisp/jane/jane-defaults")
+        loads libraries, sets variables according to our coding
+        standards, and sets standard defaults which many users find
+        useful.
 
-    (load "/j/office/app/emacs/prod/jane-elisp/elisp/jane/jane-common")
-      leaves discretionary settings to the user.
+      (load "/j/office/app/emacs/prod/jane-elisp/elisp/jane/jane-common")
+        leaves discretionary settings to the user.
 
 ** Beta testers
 
   - Choose a site-lisp directory S.
   - Clone the BitBucket repo into S/jane.
   - Add one of the following to .emacs:
+
       (load "S/jane/elisp/jane/jane-defaults")
       (load "S/jane/elisp/jane/jane-common")
 
 
 * Development
 
+** At the office
+
 To build omake_server.exe:
 
     hg clone https://bitbucket.org/seanmcl/ocaml-core-external
 you access to his repo.  See
 https://confluence.atlassian.com/display/BITBUCKET/Using+the+SSH+protocol+with+bitbucket
 about setting up keys.
+
+** Opam release
+
+Our repo for opam is  https://seanmcl@bitbucket.org/seanmcl/omake-mode.
+
+Workflow:
+- Work on omake-mode in https://seanmcl@bitbucket.org/seanmcl/js-elisp.
+- When we're ready for a major release, copy from there to https://seanmcl@bitbucket.org/seanmcl/omake-mode.
+- Create a new version in opam-repository/packages/omake-mode.N.N in our fork of opam-repository
+  https://github.com/seanmcl/opam-repository.git
+- Issue a pull request to ocamlpro
+
+#!/bin/bash
+set -e -u -o pipefail
+set -x
+
+# Create a single file with all the elisp files and compile it to make
+# sure there are no errors
+
+tmp_file=/tmp/all.el
+
+home=$(dirname $0)/..
+cd $home
+home=$(pwd -L)
+bin=$home/bin
+contrib_dir=$home/elisp/contrib
+jane_dir=$home/elisp/jane
+omake_dir=$home/elisp/omake
+
+# echo "home: $home"
+# exit 1
+
+top_files="
+jane-common"
+
+omake_files="
+omake-custom
+omake-file
+omake-errors
+omake-version
+omake-face
+omake-id
+omake-path
+omake-progress
+omake-window
+omake-error
+omake-ring
+omake-failure
+omake-result
+omake-status
+omake-buffer
+omake-spinner
+omake-inotify
+omake-model
+omake-project
+omake-env
+omake-ocaml
+omake-filter
+omake-connection
+omake-server
+omake-ping
+omake-timer
+omake-interface
+omake-setup"
+
+rm -f $tmp_file
+cat > $tmp_file <<EOF
+(eval-when-compile
+  (require 'cl)
+  (require 'bytecomp)
+  (setq byte-compile-warnings (remove 'cl-functions byte-compile-warning-types))
+  (add-to-list 'load-path "$contrib_dir"))
+EOF
+
+function e {
+    echo $1 >> $tmp_file
+}
+
+function emit {
+    e ";; -----------------------------------------------------------------------------"
+    e ";; $1"
+    e ";; -----------------------------------------------------------------------------"
+}
+
+# for file in $top_files; do
+#     emit $file
+#     cat $home/$file.el >> $tmp_file
+# done
+
+for file in $omake_files; do
+    emit $file
+    cat $omake_dir/$file.el >> $tmp_file
+done
+
+batch=/tmp/batch.txt
+
+# Try to compile the file
+emacs -q --no-site-file -batch -f batch-byte-compile $tmp_file &> $batch
+
+if grep "Error\|Warning" $batch &> /dev/null; then
+    echo "check.sh: compilation failed"
+    cat $batch
+    exit 1
+fi
+
+# CR seanmcl: Testing is broken at the moment
+
+# Run tests in the file
+# emacs -q --no-site-file -batch -L $contrib_dir -l ert -l $tmp_file -f ert-run-tests-batch-and-exit &> $batch
+
+# if grep "unexpected" $batch &> /dev/null; then
+#     echo "check.sh: tests failed"
+#     cat $batch
+#     exit 1
+# fi
+
+# # run server tests
+# if [ -e $bin/omake_server.exe ]; then
+#     $home/ocaml/omake/test/runtests.sh
+# fi

File bin/check.sh

-#!/bin/bash
-set -e -u -o pipefail
-#set -x
-
-# Create a single file with all the elisp files and compile it to make
-# sure there are no errors
-
-tmp_file=/tmp/all.el
-
-home=$(dirname $0)/..
-cd $home
-home=$(pwd -L)
-bin=$home/bin
-contrib_dir=$home/elisp/contrib
-jane_dir=$home/elisp/jane
-omake_dir=$home/elisp/omake
-
-# echo "home: $home"
-# exit 1
-
-# top_files="
-# jane-common"
-
-jane_files="
-jane-lib
-jane-micro-features"
-
-omake_files="
-omake-custom
-omake-file
-omake-errors
-omake-version
-omake-face
-omake-id
-omake-path
-omake-progress
-omake-window
-omake-error
-omake-ring
-omake-failure
-omake-result
-omake-status
-omake-buffer
-omake-spinner
-omake-inotify
-omake-model
-omake-project
-omake-env
-omake-ocaml
-omake-filter
-omake-connection
-omake-server
-omake-ping
-omake-timer
-omake-interface
-omake-test
-omake-setup"
-
-rm -f $tmp_file
-cat > $tmp_file <<EOF
-(eval-when-compile
-  (require 'cl)
-  (require 'bytecomp)
-  (setq byte-compile-warnings (remove 'cl-functions byte-compile-warning-types))
-  (add-to-list 'load-path "$contrib_dir"))
-EOF
-
-function e {
-    echo $1 >> $tmp_file
-}
-
-function emit {
-    e ";; -----------------------------------------------------------------------------"
-    e ";; $1"
-    e ";; -----------------------------------------------------------------------------"
-}
-
-# for file in $top_files; do
-#     emit $file
-#     cat $home/$file.el >> $tmp_file
-# done
-
-for file in $jane_files; do
-    emit $file
-    cat $jane_dir/$file.el >> $tmp_file
-done
-
-for file in $omake_files; do
-    emit $file
-    cat $omake_dir/$file.el >> $tmp_file
-done
-
-batch=/tmp/batch.txt
-
-emacs -batch -f batch-byte-compile $tmp_file &> $batch
-
-if grep "Error\|Warning" $batch &> /dev/null; then
-    echo "check.sh: compilation failed"
-    cat $batch
-    exit 1
-fi
-
-emacs -batch -L $contrib_dir -l ert -l $tmp_file -f ert-run-tests-batch-and-exit &> $batch
-
-if grep "unexpected" $batch &> /dev/null; then
-    echo "check.sh: tests failed"
-    cat $batch
-    exit 1
-fi
-
-# run server tests
-if [ -e $bin/omake_server.exe ]; then
-    $home/ocaml/omake/test/runtests.sh
-fi
+#!/bin/bash
+
+# The word from Kilburg and cwills re. how to install in all offices
+# with Sink: maintainer responsible to find arbitrary machines in
+# those offices and sink-install to the office filesystems via those
+# machines.  The offices are four: nyc, ldn, hkg, and tot.
+offices="hkg ldn nyc tot"
+host_hkg=hkg-qws-r02
+host_ldn=ldn-qws-r02
+host_nyc=nyc-qws-147            # nyc-qws-r04 still off after Sandy
+host_tot=tot-qws-r02
+
+modes="prod test"
+target_prod=/j/office/app/emacs/prod
+target_test=/j/office/app/emacs/dev
+
+# (The CentOS 5 bash doesn't have associative arrays yet, hence going
+# old school for host_* and target_*.)
+
+set -e -u -o pipefail
+ulimit -c unlimited # allow arbitrarily large core files
+
+PATH=$PATH:/j/office/app/sink/prod/bin # sink
+
+args=$*                         # before consuming below
+
+mode=test
+message=
+# CR pszilagyi: Implement a general-purpose sink-args hook so I can
+# check "sink history list" very easily.
+while test $# -gt 0; do
+    arg=$1
+    shift
+    case $arg in
+        -prod)
+            mode=prod
+            ;;
+        -test)
+            mode=test
+            ;;
+        -message)
+            message=$1
+            shift
+            ;;
+        -offices)
+            offices=$1
+            shift
+            ;;
+        *)
+            echo "Unknown argument: $arg" >&2
+            echo "Usage: $0 [-prod] -message M [-offices '[hkg] [ldn] [nyc] [tot]']" >&2
+            exit 2
+            ;;
+    esac
+done
+
+if [ -z "$message" ]; then
+    echo "$0: -message required" >&2
+    exit 3
+fi
+
+if [ $mode = "prod" ]; then
+    test -t 1 -a -t 0
+    echo "You are about to install a new PRODUCTION version of omake-emacs."
+    echo -n "Press ENTER to proceed, Ctrl-C to abort. "
+    read
+fi
+
+dot=$(dirname "$0")             # for script-relative filenames
+
+# Log the cwd and command and some version information.
+#
+# This has to be pretty narrow to look good in "sink history list".
+#
+# CR pszilagyi: Dump this in a file and have a short message.
+message+="
+$(pwd):
+  $0 $args
+$(cd "$dot/".. && echo "$(pwd):
+  $(hg paths default)
+    $(hg id -i)")
+$(cd "$dot/"../.. && echo "$(pwd):
+  $(hg paths default)
+    $(hg id -i)")"
+
+eval target=\$target_$mode
+
+# Delete a few of the biggest wastes of space before sink'ing.
+# Really, need "sink deploy dir -exclude" to skip these.
+# (Fortunately, "sink deploy dir" does already exclude ../.hg.)
+find "$dot/".. \( \
+    -name '.nfs*' -o \
+    -name '*.cm[xit]' -o \
+    -name 'doit.exe' \) -print0 | xargs -r0tn1 rm
+
+set -x
+
+# This should be run from a functioning, built checkout, where the
+# developer has already run the following.
+
+#(cd "$dot/".. && omake)
+test -r "$dot/"../doc/jane-emacs.info
+test -r "$dot/"../doc/omake-mode.info
+test -r "$dot/"../elisp/contrib/tex-site.el
+test .elcs= = .elcs="$(find "$dot/".. -name '*.elc')"
+test -x "$dot/"../ocaml/omake/exe/omake_server.exe
+test -x "$dot/"ocp-indent
+
+for office in $offices
+do
+    eval host=\$host_$office
+    sink deploy dir "$dot/"../ "$host:$target/jane-elisp" -message "$message"
+
+    # Make all the installed files read-only so I don't accidentally
+    # edit them in-place.  I could, alternatively, do a complete
+    # clone-build-chmod and "sink" a read-only source, but this is
+    # simple and avoids the extra copy.
+    ssh "$host" "chmod -R a-w '$target'/jane-elisp/"
+    # The trailing slash follows the sink-managed symlink.
+    #
+    # Will making the managed copy read-only confuse "sink"?
+done

File bin/install.sh

-#!/bin/bash
-
-# The word from Kilburg and cwills re. how to install in all offices
-# with Sink: maintainer responsible to find arbitrary machines in
-# those offices and sink-install to the office filesystems via those
-# machines.  The offices are four: nyc, ldn, hkg, and tot.
-offices="hkg ldn nyc tot"
-host_hkg=hkg-qws-r02
-host_ldn=ldn-qws-r01
-host_nyc=nyc-qws-147            # nyc-qws-r04 still off after Sandy
-host_tot=tot-qws-r02
-
-modes="prod test"
-target_prod=/j/office/app/emacs/prod
-target_test=/j/office/app/emacs/dev
-
-# (The CentOS 5 bash doesn't have associative arrays yet, hence going
-# old school for host_* and target_*.)
-
-set -e -u -o pipefail
-ulimit -c unlimited # allow arbitrarily large core files
-
-PATH=$PATH:/j/office/app/sink/prod/bin # sink
-
-args=$*                         # before consuming below
-
-mode=test
-message=
-# CR pszilagyi: Implement a general-purpose sink-args hook so I can
-# check "sink history list" very easily.
-while test $# -gt 0; do
-    arg=$1
-    shift
-    case $arg in
-        -prod)
-            mode=prod
-            ;;
-        -test)
-            mode=test
-            ;;
-        -message)
-            message=$1
-            shift
-            ;;
-        -offices)
-            offices=$1
-            shift
-            ;;
-        *)
-            echo "Unknown argument: $arg" >&2
-            echo "Usage: $0 [-prod] -message M [-offices '[hkg] [ldn] [nyc] [tot]']" >&2
-            exit 2
-            ;;
-    esac
-done
-
-if [ -z "$message" ]; then
-    echo "$0: -message required" >&2
-    exit 3
-fi
-
-if [ $mode = "prod" ]; then
-    test -t 1 -a -t 0
-    echo "You are about to install a new PRODUCTION version of omake-emacs."
-    echo -n "Press ENTER to proceed, Ctrl-C to abort. "
-    read
-fi
-
-dot=$(dirname "$0")             # for script-relative filenames
-
-# Log the cwd and command and some version information.
-#
-# This has to be pretty narrow to look good in "sink history list".
-#
-# CR pszilagyi: Dump this in a file and have a short message.
-message+="
-$(pwd):
-  $0 $args
-$(cd "$dot/".. && echo "$(pwd):
-  $(hg paths default)
-    $(hg id -i)")
-$(cd "$dot/"../.. && echo "$(pwd):
-  $(hg paths default)
-    $(hg id -i)")"
-
-eval target=\$target_$mode
-
-# Delete a few of the biggest wastes of space before sink'ing.
-# Really, need "sink deploy dir -exclude" to skip these.
-# (Fortunately, "sink deploy dir" does already exclude ../.hg.)
-find "$dot/".. \( \
-    -name '.nfs*' -o \
-    -name '*.cm[xit]' -o \
-    -name 'doit.exe' \) -print0 | xargs -r0tn1 rm
-
-temp=$(mktemp -d)
-trap 'rm -r "$temp"' 0
-jane_elisp=$temp/jane-elisp
-
-set -x
-
-# This should be run from a functioning, built checkout, where the
-# developer has already run the following.
-
-#(cd "$dot/".. && omake)
-test -r "$dot/"../doc/jane-emacs.info
-test -r "$dot/"../doc/omake-mode.info
-test -r "$dot/"../elisp/contrib/tex-site.el
-test .elcs= = .elcs="$(find "$dot/".. -name '*.elc')"
-test -x "$dot/"../ocaml/omake/omake_server.exe
-test -x "$dot/"ocp-indent
-
-ln -sf $(cd "$dot/".. && pwd) "$jane_elisp"
-for office in $offices
-do
-    eval host=\$host_$office
-    #ssh "$host" "mkdir -p '$target'"
-
-    # "sink deploy dir" doesn't work with weird directory names like
-    # "bin/.." (yet) and doesn't rename directories as it installs
-    # them (instead, the target is a directory into which to install,
-    # not a new name).
-    #
-    #sink deploy dir "$dot/".. "$host:$target/jane-elisp" -message "$message"
-    sink deploy dir "$jane_elisp" "$host:$target" -message "$message"
-
-    # Make all the installed files read-only so I don't accidentally
-    # edit them in-place.  I could, alternatively, do a complete
-    # clone-build-chmod and "sink" a read-only source, but this is
-    # simple and avoids the extra copy.
-    ssh "$host" "chmod -R a-w '$target'/jane-elisp/"
-    # The trailing slash follows the sink-managed symlink.
-    #
-    # Will making the managed copy read-only confuse "sink"?
-done

File bin/make-release

+#!/bin/bash
+set -e -u -o pipefail
+# set -x
+
+home=$(dirname $(dirname $(readlink -f $0)))
+
+function usage {
+  echo "Usage: $0 version path-to-opam-repo"
+  echo "  e.g. $0 1.1 /usr/local/opam-repository"
+}
+
+if (( $# != 2 )); then
+  usage
+  exit 1
+fi
+
+version=$1; shift
+opam_repo=$1; shift
+
+if [ ! -e $opam_repo/packages ]; then
+  echo "$opam_repo doesn't exist"
+  echo "Create one with"
+  echo "  mkdir -p $opam_repo"
+  echo "  opam remote add testing $opam_repo"
+  exit 1
+fi
+
+opam_dir="$opam_repo/packages/omake-mode.$version"
+
+if [ -e $opam_dir ]; then
+  echo "omake-mode.$version already exists"
+  exit 1
+fi
+
+mkdir -p $opam_dir
+
+# ------------------------------------------------------------------------------
+#  Update release repo
+# ------------------------------------------------------------------------------
+
+tmpdir=$(mktemp -d -p /tmp omake-mode-XXXXXX)
+echo "temp dir: $tmpdir"
+cd $tmpdir
+hg clone https://seanmcl@bitbucket.org/seanmcl/omake-mode
+release_dir=$tmpdir/omake-mode
+cd $release_dir
+
+# Copy ocaml.
+# NB: don't copy $home/ocaml/omake/exe/omake_server.ml
+#     that refers to Omake_lib.  Since we don't make a
+#     separate library in the public release, we need a new
+#     omake_server.ml file
+# NB: Remove inotify.ml so you can use the opam installed version
+find $home/ocaml/omake/lib | grep "\.mli\?$" | grep -v "inotify.ml" | while read f; do cp -f $f $release_dir/src; done
+
+cat > $release_dir/src/omake_server.ml <<EOF
+let _ = Core.Command.run Top.cmd
+EOF
+
+# patch files due to differences between local core and
+# opam install of core
+hg patch -f --no-commit etc/patches
+
+# Copy elisp
+find $home/elisp/omake | grep "\.el$" | while read f; do cp -f $f $release_dir/elisp; done
+cp $home/elisp/jane/jane-lib.el $release_dir/elisp
+
+# ------------------------------------------------------------------------------
+#  Update opam testing repo
+# ------------------------------------------------------------------------------
+
+release_repo="https://bitbucket.org/seanmcl/omake-mode"
+repo_gz="$release_repo/get/$version.tar.gz"
+
+# create opam file
+cat > $opam_dir/opam <<EOF
+opam-version: "1"
+maintainer: "seanmcl@gmail.com"
+build: [
+  ["ocaml" "setup.ml" "-configure" "--prefix" "%{prefix}%"]
+  ["ocaml" "setup.ml" "-build"]
+  ["ocaml" "setup.ml" "-install"]
+]
+remove: [ "rm" "-rf" "%{prefix}%/share/omake-mode" ]
+depends: ["ocamlfind"
+          "oasis" {= "0.3.0"}
+          "core" {= "108.08.00"}
+          "core_extended" {= "108.08.00"}
+          "async" {= "108.08.00"}
+          "inotify"
+          "omake"
+         ]
+EOF
+
+# create descr file
+cat > $opam_dir/descr <<EOF
+Omake Emacs integration
+EOF
+
+# create url file
+cat > $opam_dir/url <<EOF
+archive: "$repo_gz"
+EOF
+
+cd $opam_repo
+
+cat <<EOF
+Look over the changes to omake-mode and make sure they make sense
+Then commit the changes
+
+  cd $release_dir
+  hg commit -m "release $version"
+  hg tag $version
+  hg push
+
+Look over the changes to opam-repository to make sure they look sane.
+Then commit the changes
+
+  cd $opam_repo
+  # Add the checksum
+  opam-mk-repo -g omake-mode
+  git add $opam_dir/*
+  git commit -m 'omake-mode release $version'
+  git push
+
+Finally, create a pull request at https://github.com/seanmcl/opam-repository
+EOF

File doc/jane-emacs.info

File contents unchanged.

File doc/omake-mode.info

Binary file modified.

File elisp/jane/Makefile

+
+modules=                \
+  jane-lexical		\
+  jane-list		\
+  jane-string		\
+  jane-buffer		\
+  jane-bytecompile	\
+  jane-whitespace	\
+  jane-cr		\
+  jane-deprecated	\
+  jane-shell		\
+  jane-filename		\
+  jane-hashtbl		\
+  jane-hg		\
+  jane-log		\
+  jane-mail		\
+  jane-micro-features	\
+  jane-ocaml		\
+  jane-option		\
+  jane-overlay		\
+  jane-test		\
+  jane-text		\
+  jane-timer		\
+  jane-util		\
+  jane-window		\
+  jane			\
+
+elc=$(addsuffix .elc, $(modules))
+
+.SUFFIXES: .elc .el
+
+%.elc : %.el
+	emacs -q --no-site-file -batch -l byte-compile-header.el -f batch-byte-compile $<
+
+.PHONY: all
+all : $(elc)
+
+clean :
+	rm -f *.elc

File elisp/jane/README

 
 Jane Street Emacs customization files.
 
-* files
+* Files
 
 ** jane-common.el
 
 
 Common variable settings for tuareg-mode.
 
-* notes
+* Notes
 
 Note that the following libraries are *not* in this repo:
 
    - tuareg
    - ocamlspot
+
+* Examples of customizations
+
+;; For quick compilation
+(global-set-key [(control return)] 'compile)
+
+;; If you don't want to see warnings or timings from omake, you
+;; can modify the command emacs runs when you run `compile'
+(setq jane-make-command
+      (concat jane-make-command " --output-only-errors --no--print-timing"))
+
+;; If you use `Omake.compile', you'll need to edit a file,
+;; ~/.omake-server/config, instead
+;;   ((omake_command "jomake --output-only-errors --no--print-timing"))
+
+;; If the buffer in question is already displayed in a frame, raise
+;; that frame.
+(custom-set-variables '(display-buffer-reuse-frames t))
+
+;; Make emacs neither beep nor flash the screen
+(setq ring-bell-function (lambda () ()))
+(custom-set-variables '(visible-bell nil))
+
+;; Don't highlight the region
+(transient-mark-mode -1)
+
+;; Kill a frame
+(defun my-delete-frame ()
+  (interactive)
+  (if (cdr (frame-list)) (delete-frame) (kill-emacs)))
+(global-set-key "\C-x\C-c" 'my-delete-frame)
+

File elisp/jane/byte-compile-header.el

+;; Don't show warnings that cl is being used at runtime
+;; Using the cl package at runtime is considered bad style among
+;; purist emacs-lisp hackers.
+;; http://www.gnu.org/software/emacs/manual/html_node/cl/Overview.html
+;; In particular:
+;;
+;;   Please note: the CL functions are not standard parts of the Emacs Lisp name
+;;   space, so it is legitimate for users to define them with other, conflicting
+;;   meanings. To avoid conflicting with those user activities, we have a policy that
+;;   packages installed in Emacs must not load CL at run time. (It is ok for them to
+;;   load CL at compile time only, with eval-when-compile, and use the macros it
+;;   provides.) If you are writing packages that you plan to distribute and invite
+;;   widespread use for, you might want to observe the same rule.
+;;
+;; I don't think there's any reason to reimplement efficient folds just
+;; to avoid importing cl.  It seems to be another internecine war
+;; among Emacs factions.
+
+(require 'bytecomp)
+(add-to-list 'load-path ".")
+(setq byte-compile-warnings (remove 'cl-functions byte-compile-warning-types))

File elisp/jane/examples.el

-;; This file is just for examples of customizations people make
-;; to emacs.  It is a source of ideas, and should not be loaded.
-
-
-;; For quick compilation
-(global-set-key [(control return)] 'compile)
-
-
-;; If you don't want to see warnings or timings from omake, you
-;; can modify the command emacs runs when you run `compile'
-(setq jane-make-command
-      (concat jane-make-command " --output-only-errors --no--print-timing"))
-
-
-;; If the buffer in question is already displayed in a frame, raise
-;; that frame.
-(custom-set-variables '(display-buffer-reuse-frames t))
-
-
-;; Make emacs neither beep nor flash the screen
-(setq ring-bell-function (lambda () ()))
-(custom-set-variables '(visible-bell nil))
-
-
-;; Don't highlight the region
-(transient-mark-mode -1)
-
-
-;; Kill a frame
-(defun my-delete-frame ()
-  (interactive)
-  (if (cdr (frame-list)) (delete-frame) (kill-emacs)))
-(global-set-key "\C-x\C-c" 'my-delete-frame)

File elisp/jane/jane-buffer.el

+;;----------------------------------------------------------------------------;;
+;; Buffers                                                                    ;;
+;;----------------------------------------------------------------------------;;
+
+(defun Buffer.name (buffer-or-name)
+  "Allow the (string) name of a buffer to be passed to buffer-name"
+  (if (bufferp buffer-or-name) (buffer-name buffer-or-name) buffer-or-name))
+
+(defun Buffer.safe-get (buffer-or-name)
+  "Allow the (string) name of a buffer to be passed to buffer-name"
+  (if (bufferp buffer-or-name) (buffer-name buffer-or-name) buffer-or-name))
+
+(defun Buffer.get (buffer-or-name)
+  "get-buffer that returns nil on a nil argument"
+  (if (null buffer-or-name) nil (get-buffer buffer-or-name)))
+
+(defun Buffer.kill (buffer-or-name)
+  "Kill a buffer.  Don't raise an exception of there is no such buffer.
+Just return nil.  This is the spec of `kill-buffer', but the former
+raises an exception."
+  (condition-case nil
+      (kill-buffer buffer-or-name)
+    (error nil)))
+
+(defun Buffer.kill-no-query-no-hooks (&optional buffer-or-name)
+  (interactive)
+  "Kill a buffer without any questions.  If there's no such buffer, just
+return nil"
+  (let ((buffer-or-name (if buffer-or-name buffer-or-name (current-buffer)))
+        (funs kill-buffer-query-functions)
+        (hook kill-buffer-hook))
+    (unwind-protect
+        (progn
+          (setq kill-buffer-query-functions nil)
+          (setq kill-buffer-hook nil)
+          (Buffer.kill buffer-or-name))
+      (setq kill-buffer-query-functions funs)
+      (setq kill-buffer-hook hook))))
+
+(defun Buffer.num-lines (buf)
+  (save-excursion
+    (with-current-buffer buf
+      (count-lines (point-min) (point-max)))))
+
+(defun Buffer.clear (&optional buffer)
+  "Remove all contents of a given buffer"
+  (let ((buf (if buffer buffer (current-buffer))))
+    (with-current-buffer buf
+      (delete-region (point-min) (point-max)))))
+
+(defun Buffer.eval-and-return (buf)
+  "Eval a buffer and return the result of the last sexp."
+  (let ((buf (get-buffer buf))
+        (sexp nil)
+        (res nil))
+    (with-current-buffer buf
+      (goto-char (point-min))
+      (condition-case nil
+          (while (setq sexp (read buf))
+            (setq res (eval sexp)))
+        (error res)))))
+
+(defmacro Buffer.edit-read-only (buf &rest form)
+  (declare (indent defun))
+  (declare (debug (body)))
+  `(with-current-buffer ,buf
+     (let ((__read-only__ buffer-read-only))
+       (toggle-read-only -1)
+       (let ((res (progn ,@form)))
+         (when __read-only__ (toggle-read-only 1))
+         res))))
+;; (Buffer.edit-read-only "abc" (insert "4") 7)
+
+(defun Buffer.line-at-point ()
+  "Return the line at point."
+  (interactive)
+  (save-excursion
+    (end-of-line)
+    (let ((end (point)))
+      (beginning-of-line)
+      (buffer-substring-no-properties (point) end))))
+
+(defun Buffer.last-lines (buffer-or-name n)
+  "return the last N lines of a buffer"
+  (save-excursion
+    (with-current-buffer buffer-or-name
+      (goto-char (point-max))
+      (let* ((aux nil) ;; dummy for compilation warning
+             (aux (lambda (k)
+                    (if (equal k 0) nil
+                      (let* ((l (Buffer.line-at-point))
+                             (res (forward-line -1))
+                             (rest (when (equal res 0) (funcall aux (- k 1)))))
+                        (cons l rest))))))
+        (reverse (funcall aux n))))))
+
+(defun Buffer.goto-line (n)
+  (goto-char (point-min))
+  (forward-line (1- n)))
+
+(font-lock-add-keywords
+ 'emacs-lisp-mode
+ '(("\\<\\(Buffer.edit-read-only\\)" 1 font-lock-keyword-face)))
+
+(provide 'jane-buffer)

File elisp/jane/jane-bytecompile.el

+
+(defun Bytecompile.check ()
+  (interactive)
+  (let ((file (read-file-name "File: ")))
+    (byte-compile-file file)
+    (message "removing compiled file")
+    (delete-file (concat file "c"))))
+
+(provide 'jane-bytecompile)

File elisp/jane/jane-common.el

 ;; Set site lisp dir for everyone and add load paths                          ;;
 ;;----------------------------------------------------------------------------;;
 
-(defvar jane-jane-lisp                  ; this directory
-  (if load-file-name (directory-file-name (file-name-directory load-file-name))))
+(defconst jane-jane-lisp
+  (file-truename (expand-file-name "."
+                                   (file-name-directory (or load-file-name
+                                                            "."))))
+  "The absolute name of this elisp/jane directory, with symlinks resolved.
+
+Symlinks are resolved in order to fix the version of the Jane
+Elisp code for the life of this Emacs.  The Jane Elisp code is
+usually installed in a date-stamped location and symlinked from
+an official name for the latest version.
+
+For example, a user typically has this in ~/.emacs:
+
+    (load \"/j/office/app/emacs/prod/jane-elisp/elisp/jane/jane-defaults\")
+
+The \"jane-elisp\" component is typically a symlink, like this:
+
+    jane-elisp -> .sink-2012-12-03_22-11-48.277942/jane-elisp
+
+By expanding paths to use the long, ugly, versioned directory
+name, already running Emacsen will continue to work after
+jane-elisp upgrades, using their start-time version.  Even when
+an upgrade moves the OMake Server executable or increments its
+protocol version, users won't have to restart immediately.")
 
 (defvar jane-contrib-lisp (expand-file-name "../contrib" jane-jane-lisp)
   "The location of Emacs libraries")
 
 (defconst jane-home (expand-file-name "../.." jane-jane-lisp))
 
-;; CR pszilagyi: The following can be removed after we've eradicated
-;; these settings from users' ~/.emacs files, which were set by the
-;; old jane-common.el and saved by Custom:
-;;
-;;     (custom-set-variables
-;;      '(Omake\.Server\.program
-;;        (case jane-mode
-;;         ((quote prod) "/mnt/global/base/bin/omake_server.exe")
-;;         ((quote test) "/mnt/global/base/bin/omake_server_test.exe")
-;;         ((quote local) (expand-file-name "ocaml/omake/omake_server.exe" jane-home))))
-;;      )
-;;
-;; The above fragment is evaluated by Custom and references
-;; `jane-mode'.  One way to get rid of this is for the user to Erase
-;; Customizations in the Customize buffer.
-(defconst jane-mode 'local)
-
 (defconst jane-dirs
-  '("ocp-indent"
-    "elisp/jane"
+  '("elisp/jane"
     "elisp/omake"
     "elisp/contrib"                     ; incl. ert 2012
     "elisp/contrib/evil"
 (dolist (dir jane-dirs)
   (add-to-list 'load-path (expand-file-name dir jane-home)))
 
-(require 'ocp-indent)
-;; Ocp.indent-program defaults to ../../ocp-indent/ocp-indent-stdin,
-;; which runs ocp-indent from $PATH.  If the user or site doesn't have
+;; If the user or site doesn't have
 ;; their own ocp-indent, find the one included with jane-elisp.
 (let ((bin (expand-file-name "../../bin" jane-jane-lisp)))
   (add-to-list 'exec-path bin 'append)
       (find-alternate-file (concat "/sudo::" buffer-file-name))
       (error "Buffer %s does not visit a file" (current-buffer))))
 
+(defun server-restart ()
+  "Force a restart of the emacs server."
+  (interactive)
+  (progn
+    (server-force-delete)
+    (server-start)))
+
 (defun toggle-full-screen ()
   "Toggle between full screen and partial screen display on X11;
     courtesy of http://www.emacswiki.org/cgi-bin/wiki/FullScreen"

File elisp/jane/jane-defaults.el

 ;;
 ;; Reasonable defaults for new emacs users
 
-;; This is repeated in jane-common and jane-defaults.  Either can be
-;; loaded from a user's ~/.emacs.
-(when load-file-name
-  (add-to-list 'load-path (directory-file-name (file-name-directory load-file-name))))
-
-(require 'jane-common)
+;; Either jane-common or jane-defaults can be loaded from a user's
+;; ~/.emacs.
+(load (expand-file-name "jane-common"
+                        (file-name-directory (or load-file-name "."))))
 
 
 ;; Micro-features

File elisp/jane/jane-filename.el

+
+;;----------------------------------------------------------------------------;;
+;; Filenames                                                                  ;;
+;;----------------------------------------------------------------------------;;
+
+(require 'cl)
+(require 'jane-list)
+(require 'jane-shell)
+
+(defun Filename.strip-final-slash (path)
+  "/a/b/c/ ---> /a/b/c"
+  (let ((n (length path)))
+    (if (equal (elt path (- n 1)) ?/)
+        (substring path 0 (- n 1))
+      path)))
+
+(defun Filename.root-dir-p (path) (equal (Shell.readlink path) "/"))
+
+(defun Filename.up1-dir (dir)
+  "Go up 1 directory.  The input must be an existing directory."
+  (if (null dir) (error "Filename.up1-dir: %s" dir)
+    (assert (file-directory-p dir))
+    (Shell.readlink (concat dir "/.."))))
+
+(defun Filename.directory-of (file-or-dir)
+  "Get the directory of a path.  If a file, give the enclosing dir.
+If a dir, return the dir"
+  (if (null file-or-dir) (error "Filename.directory-of: %s" file-or-dir)
+    (let ((res (if (file-directory-p file-or-dir)
+                   file-or-dir
+                 (Shell.dirname file-or-dir))))
+      (assert (file-directory-p res))
+      (Shell.readlink res))))
+
+(defun Filename.default-directory ()
+  (Filename.strip-final-slash default-directory))
+
+(provide 'jane-filename)

File elisp/jane/jane-hashtbl.el

+;;----------------------------------------------------------------------------;;
+;; Hash tables                                                                ;;
+;;----------------------------------------------------------------------------;;
+
+(require 'jane-lexical)
+(require 'jane-list)
+
+(defun Hashtbl.to-alist (tbl)
+  (let ((data nil))
+    (maphash (lambda (k v) (setq data (cons (cons k v) data))) tbl)
+    (reverse data)))
+
+(defun Hashtbl.of-alist (l)
+  (let ((tbl (make-hash-table :test 'equal)))
+    (dolist (x l) (puthash (car x) (cdr x) tbl))
+    tbl))
+
+(defun Hashtbl.keys (tbl)
+  (List.map 'car (Hashtbl.to-alist tbl)))
+
+(defun Hashtbl.data (tbl)
+  (List.map 'cdr (Hashtbl.to-alist tbl)))
+
+(defunl Hashtbl.iter (f tbl)
+  (maphash f tbl))
+
+(provide 'jane-hashtbl)

File elisp/jane/jane-hg.el

+
+;;----------------------------------------------------------------------------;;
+;; Hg                                                                         ;;
+;;----------------------------------------------------------------------------;;
+
+(require 'dired)
+
+(defun Hg.resolve-file ()
+  (interactive)
+  "Run 'hg resolve -m' on the current file"
+  (let* ((file (buffer-file-name (current-buffer))))
+    (shell-command (format "hg resolve -m %s" file))))
+
+(defun Hg.resolve-file-dired ()
+  (interactive)
+  "Run 'hg resolve -m' on the current file in a dired buffer"
+  (let* ((file (dired-file-name-at-point)))
+    (shell-command (format "hg resolve -m %s" file))))
+
+;; Keep aliases for backward compatiblity
+(defalias 'hg-resolve-file 'Hg.resolve-file)
+(defalias 'hg-resolve-file-dired 'Hg.resolve-file-dired)
+
+(provide 'jane-hg)

File elisp/jane/jane-lexical.el

+
+;;----------------------------------------------------------------------------;;
+;; Lexical scope                                                              ;;
+;;----------------------------------------------------------------------------;;
+
+(require 'cl)
+
+;; Conventions due to dynamic scope hell.
+;;
+;; We must be careful with function arguments and local variables due to dynamic scope.
+;; (defun List.iter (f l)
+;;   (mapc f l)
+;;   nil)
+;;
+;; (defun List.iteri (f l)
+;;   (let ((ctr 0))
+;;     (List.iter (lambda (b)
+;;                  (funcall f ctr b)
+;;                  (setq ctr (+ ctr 1))) l)))
+;;
+;; This definition of List.iteri fails.  In (List.iteri g l)
+;; `f' is bound to g in the beginning of the body of List.iteri, but when List.iter
+;; is called, f gets rebound to (lambda (b) ...).  Thus the funcall fails
+;; because it expects only 1 argument.
+;;
+;; For example
+;;
+;; (let ((ctr 0))
+;;   (List.iteri (lambda (i x) (setq ctr (+ ctr i x))) '(1 1 1 1 1))
+;;   (assert (equal ctr 15)))
+;;
+;; This test fails, as `ctr' is rebound in the body of List.iteri.
+;;
+;; To avoid this, for any higher-order function we use `letl'
+;; to define local variables and `defunl' to define the function.
+
+(defmacro defunl (name arglist &rest body)
+  "Lexical defun.  Not for use with interactive functions"
+  (declare (indent defun))
+  (let* (;; remove &optional and &rest
+         (args (remove-if
+                (lambda (s) (equal (substring (symbol-name s) 0 1) "&"))
+                arglist))
+         (args (mapcar (lambda (arg) (list arg arg)) args))
+         ;; put the doc string before the lexical-let
+         (doc_body (if (and (> (length body) 1)
+                            (stringp (car body)))
+                       `(,(car body) . ,(cdr body))
+                     `(nil . ,body)))
+         (doc (car doc_body))
+         (body (cdr doc_body)))
+    `(defun ,name ,arglist
+       ,(if doc doc)
+       (lexical-let
+           ,args
+         ,@body))))
+;; (macroexpand '(defunl f (x y) (+ x y)))
+;; (macroexpand '(defunl f (x y) "abc" (+ x y)))
+
+(def-edebug-spec defunl
+  (&define name lambda-list
+           [&optional stringp]   ; Match the doc string, if present.
+           [&optional ("interactive" interactive)]
+           def-body))
+
+(defmacro letl (varlist &rest body)
+  (declare (indent 1))
+  `(lexical-let ,varlist ,@body))
+;; (macroexpand '(letl ((x 5)) (+ x x)))
+;; (letl ((x 5)) (+ x x))
+
+(def-edebug-spec letl
+  ((&rest
+    &or symbolp (gate symbolp &optional form))
+   body))
+
+(defmacro letl* (varlist &rest body)
+  (declare (indent 1))
+  (declare (debug (form &rest form)))
+  `(lexical-let* ,varlist ,@body))
+
+(def-edebug-spec letl*
+  ((&rest
+    &or symbolp (gate symbolp &optional form))
+   body))
+
+;; (font-lock-add-keywords
+;;  'emacs-lisp-mode
+;;  '(("\\<\\(defunl\\)" 1 font-lock-keyword-face)
+;;    ("\\<\\(letl\\*?\\)" 1 font-lock-keyword-face))
+;;  t)
+
+(provide 'jane-lexical)

File elisp/jane/jane-lib.el

-
-;; This file contains utilities for emacs-lisp programming with the
-;; function naming conventions of OCaml code at Jane Street.  The most
-;; important features are `defunl' and `letl' for defining lexically
-;; scoped functions.
-
-;;; NOTES:
-;;
-;; Conventions due to dynamic scope hell.
-;;
-;; We must be careful with function arguments and local variables due to dynamic scope.
-;; (defun List.iter (f l)
-;;   (mapc f l)
-;;   nil)
-;;
-;; (defun List.iteri (f l)
-;;   (let ((ctr 0))
-;;     (List.iter (lambda (b)
-;;                  (funcall f ctr b)
-;;                  (setq ctr (+ ctr 1))) l)))
-;;
-;; This definition of List.iteri fails.  In (List.iteri g l)
-;; `f' is bound to g in the beginning of the body of List.iteri, but when List.iter
-;; is called, f gets rebound to (lambda (b) ...).  Thus the funcall fails
-;; because it expects only 1 argument.
-;;
-;; For example
-;;
-;; (defun List.iteri (f l)
-;;   (let ((ctr 0))
-;;     (List.iter (lambda (x)
-;;                  (funcall f ctr x)
-;;                  (setq ctr (+ ctr 1))) l)))
-;;
-;; (let ((ctr 0))
-;;   (List.iteri (lambda (i x) (setq ctr (+ ctr i x))) '(1 1 1 1 1))
-;;   (Jane.test ctr 15))
-;;
-;; This test fails, as `ctr' is rebound in the body of List.iteri.
-;;
-;; To avoid this, for any higher-order function we use `letl'
-;; to define local variables and `defunl' to define the function.
-
-;; Don't show warnings that cl is being used at runtime
-;; Using the cl package at runtime is considered bad style among
-;; purist emacs-lisp hackers.
-;; http://www.gnu.org/software/emacs/manual/html_node/cl/Overview.html
-;; In particular:
-;;
-;;   Please note: the CL functions are not standard parts of the Emacs Lisp name
-;;   space, so it is legitimate for users to define them with other, conflicting
-;;   meanings. To avoid conflicting with those user activities, we have a policy that
-;;   packages installed in Emacs must not load CL at run time. (It is ok for them to
-;;   load CL at compile time only, with eval-when-compile, and use the macros it
-;;   provides.) If you are writing packages that you plan to distribute and invite
-;;   widespread use for, you might want to observe the same rule.
-;;
-;; I don't think there's any reason to reimplement efficient folds just
-;; to avoid importing cl.  It seems to be another internecine war
-;; among Emacs factions.
-
-(require 'bytecomp)
-(setq byte-compile-warnings (remove 'cl-functions byte-compile-warning-types))
-(require 'cl)
-(require 'sendmail)
-(require 'ert)
-
-(declare-function find-if "cl-seq")
-(declare-function remove-if "cl-seq")
-(declare-function remove-if-not "cl-seq")
-(declare-function set-difference "cl-seq")
-(declare-function reduce "cl-seq")
-(declare-function auto-revert-mode "autorevert")
-
-
-;;----------------------------------------------------------------------------;;
-;; Testing                                                                    ;;
-;;----------------------------------------------------------------------------;;