dotfiles

My personal shell configs and stuff
git clone git://git.alex.balgavy.eu/dotfiles.git
Log | Files | Refs | Submodules | README | LICENSE

commit dea864b68d8190a846691f2a7d986e695415ffd9
parent 48b51497af322ccfdaa9d90a4db7c70b03b073b2
Author: Alex Balgavy <a.balgavy@gmail.com>
Date:   Wed,  9 Oct 2019 01:27:24 -0400

emacs: because it supports SML

Former-commit-id: c2fb88ef303f7b08c4402b7aa2675e4d979f6105
Diffstat:
Aemacs/emacs | 56++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aemacs/emacs.d/sml-mode-5.0/BUGS | 11+++++++++++
Aemacs/emacs.d/sml-mode-5.0/ChangeLog | 573+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aemacs/emacs.d/sml-mode-5.0/INSTALL | 39+++++++++++++++++++++++++++++++++++++++
Aemacs/emacs.d/sml-mode-5.0/Makefile | 176+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aemacs/emacs.d/sml-mode-5.0/NEWS | 137+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aemacs/emacs.d/sml-mode-5.0/README | 19+++++++++++++++++++
Aemacs/emacs.d/sml-mode-5.0/TODO | 46++++++++++++++++++++++++++++++++++++++++++++++
Aemacs/emacs.d/sml-mode-5.0/makefile.pkg | 15+++++++++++++++
Aemacs/emacs.d/sml-mode-5.0/sml-mode-startup.el | 59+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aemacs/emacs.d/sml-mode-5.0/sml-mode.el | 1436+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aemacs/emacs.d/sml-mode-5.0/sml-mode.info | 908+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aemacs/emacs.d/sml-mode-5.0/sml-mode.spec | 67+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aemacs/emacs.d/sml-mode-5.0/sml-mode.texi | 1161+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aemacs/emacs.d/sml-mode-5.0/sml-oldindent.el | 713+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aemacs/emacs.d/sml-mode-5.0/sml-proc.el | 784+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aemacs/emacs.d/sml-mode-5.0/testcases.sml | 563+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aemacs/emacs.d/themes/cyberpunk-theme.el | 844+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aemacs/emacs.d/themes/dracula-theme.el | 458+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
19 files changed, 8065 insertions(+), 0 deletions(-)

diff --git a/emacs/emacs b/emacs/emacs @@ -0,0 +1,56 @@ +;; SML mode +(setq load-path (cons "/Users/alex/.emacs.d/sml-mode-5.0" load-path)) +(load "sml-mode-startup") +(setenv "PATH" (concat "/usr/local/smlnj-110.73/bin:" (getenv "PATH"))) +(setq exec-path (cons "/usr/local/smlnj-110.73/bin" exec-path)) + +;; Set the shell +(setq-default explicit-shell-file-name "/bin/bash") + +;; Set themes +(add-to-list 'custom-theme-load-path "~/.emacs.d/themes") +(load-theme 'cyberpunk t) + +;; Let me press 'y'/'n' to answer yes-or-no questions +(fset 'yes-or-no-p 'y-or-n-p) + +;; Show matching parens +(show-paren-mode 1) + +;; Fuzzy file matching +(setq ido-enable-flex-matching t) +(setq ido-everywhere t) +(ido-mode 1) + +;; Keep all backup files in ~/.emacs.d/backup +(setq backup-directory-alist + `(("." . ,(concat user-emacs-directory "backup/"))) + tramp-backup-directory-alist backup-directory-alist) + +;; Some version control for backups +(custom-set-variables + '(version-control t)) + +(custom-set-variables + ;; custom-set-variables was added by Custom. + ;; If you edit it by hand, you could mess it up, so be careful. + ;; Your init file should contain only one such instance. + ;; If there is more than one, they won't work right. + '(ansi-color-names-vector + ["#242424" "#e5786d" "#95e454" "#cae682" "#8ac6f2" "#333366" "#ccaa8f" "#f6f3e8"]) + '(blink-cursor-mode t) + '(blink-matching-paren t) + '(custom-safe-themes + (quote + ("1a232652b04b68380b1cff7ceeb62787b4eb43df826a97c67831c50b0c0d1451" "3fd57a3dc99eb0e2ec438555cf801572f649c79513d3a8da7980ab54cf66121b" default))) + '(xterm-mouse-mode t)) +(custom-set-faces + ;; custom-set-faces was added by Custom. + ;; If you edit it by hand, you could mess it up, so be careful. + ;; Your init file should contain only one such instance. + ;; If there is more than one, they won't work right. + '(menu ((t (:background "red" :inverse-video nil :slant italic)))) + '(tty-menu-disabled-face ((t (:background "color-238" :foreground "color-16")))) + '(tty-menu-enabled-face ((t (:background "red" :foreground "white" :weight bold)))) + '(tty-menu-selected-face ((t (:background "magenta" :foreground "white"))))) + diff --git a/emacs/emacs.d/sml-mode-5.0/BUGS b/emacs/emacs.d/sml-mode-5.0/BUGS @@ -0,0 +1,11 @@ +-*- text -*- + +Here are the current known bugs. +If you find any other, send it to <monnier@iro.umontreal.ca>. + +* M-x next-error and other compile.el support doesn't work on XEmacs. + +* indentation of a declaration after a long `datatype' is slow. + +* buggy indentation samples + Try `make test' to see the known problems in testcases.sml diff --git a/emacs/emacs.d/sml-mode-5.0/ChangeLog b/emacs/emacs.d/sml-mode-5.0/ChangeLog @@ -0,0 +1,573 @@ +2012-04-11 Stefan Monnier <monnier@iro.umontreal.ca> + + Merge sml-defs.el into sml-mode.el. + * sml-mode.el: Merge code from sml-defs.el. + Remove ":group 'sml" since they're now redundant. + * makefile.pkg (ELFILES): Adjust. + +2012-04-11 Stefan Monnier <monnier@iro.umontreal.ca> + + * sml-mode.el (sml-mark-function): New implementation using SMIE. + * sml-defs.el (sml-mode-map): Use backtab. + Remove leftover unused sml-drag-region binding. + +2012-04-11 Stefan Monnier <monnier@iro.umontreal.ca> + + Use SMIE by default and make sml-oldindent optional. + * sml-mode.el: Only load sml-oldindent if necessary. + (sml-use-smie): Default to t. + (sml-smie-datatype-|-p): Better handle incomplete datatype branch. + (sml-mode): Use prog-mode. Setup electric-layout and electric-indent. + (sml-mode-variables): Always setup SMIE if possible. + (sml-imenu-create-index, sml-funname-of-and, sml-electric-pipe) + (sml-beginning-of-defun, sml-defuse-symdata-at-point) + (sml-yacc-font-lock-keywords, sml-yacc-indentation): + Avoid sml-oldindent functions. + (sml-find-forward): Move from sml-oldindent and re-implement. + (sml-electric-semi): Use self-insert-command so electric-layout and + electric-indent can do their job. + (sml-smie-find-matching-starter, sml-find-matching-starter) + (sml-smie-skip-siblings, sml-skip-siblings): New functions. + * sml-oldindent.el (sml-starters-indent-after, sml-exptrail-syms): + Remove, unused. + (sml-find-forward): Move back to sml-mode.el. + (sml-old-find-matching-starter): Rename from sml-find-matching-starter. + (sml-old-skip-siblings): Move&rename from sml-mode:sml-skip-siblings. + +2012-04-11 Stefan Monnier <monnier@iro.umontreal.ca> + + Move non-SMIE indentation code to a separate file. + * sml-oldindent.el: Rename from sml-move.el. + * makefile.pkg (ELFILES): Adjust. + * sml-mode.el (sml-indent-line, sml-find-comment-indent) + (sml-calculate-indentation, sml-bolp, sml-first-starter-p) + (sml-indent-starter, sml-indent-relative, sml-indent-pipe) + (sml-find-forward, sml-indent-arg, sml-get-indent, sml-dangling-sym) + (sml-delegated-indent, sml-get-sym-indent, sml-indent-default) + (sml-current-indentation, sml-find-matching-starter): + Move to sml-oldindent.el. + (comment-quote-nested, compilation-error-regexp-alist): Declare. + + * sml-defs.el (sml-begin-syms, sml-begin-syms-re) + (sml-sexp-head-symbols-re, sml-preproc-alist, sml-indent-rule) + (sml-starters-indent-after, sml-delegate, sml-symbol-indent) + (sml-open-paren, sml-close-paren, sml-agglomerate-re) + (sml-exptrail-syms): Move to sml-oldindent.el. + +2012-04-11 Stefan Monnier <monnier@iro.umontreal.ca> + + Get rid of ancient compatibility and small utility file. + * sml-proc.el (inferior-sml-mode-map): Don't use defmap. + * sml-move.el (sml-internal-syntax-table): Don't use defsyntax. + * sml-mode.el (sml-syntax-prop-table): Don't use defsyntax. + (sml-electric-space): `last-command-char' -> `last-command-event'. + (sml-defuse-jump-to-def): Don't use goto-line from Elisp. + * sml-defs.el (sml-mode-map): Don't use defmap. + (sml-mode-syntax-table): Don't use defsyntax. + (sml-preproc-alist, sml-builtin-nested-comments-flag): + Move from sml-util.el. + * sml-compat.el, sml-utils.el: Remove. + * makefile.pkg (ELFILES): Update. + +2012-04-11 Stefan Monnier <monnier@iro.umontreal.ca> + + Add SMIE support. + * .bzrignore: New file. + * makefile.pkg (test): Use sml-mode-startup. + + * sml-mode.el (sml-use-smie): New config var. + (sml-smie-grammar, sml-indent-separator-outdent): New vars. + (sml-smie-rules, sml-smie-definitional-equal-p) + (sml-smie-non-nested-of-p, sml-smie-datatype-|-p) + (sml-smie-forward-token-1, sml-smie-forward-token) + (sml-smie-backward-token-1, sml-smie-backward-token): New functions. + (sml-mode): Don't set forward-sexp-function. + (sml-mode-variables): Set it here instead, and setup SMIE instead + if applicable. + +2010-03-04 Stefan Monnier <monnier@iro.umontreal.ca> + + * Release version 4.1. + + * sml-mode.el: Don't setup load-path here any more. + * Makefile ($(PACKAGE)-startup.el): Recreate from scratch every time. + Setup load-path. + (dist): Try to update it to use Svn rather than CVS. + +2007-11-08 Stefan Monnier <monnier@iro.umontreal.ca> + + * sml-proc.el (inferior-sml-next-error-hook): Make it match one + more format. + +2007-10-31 Stefan Monnier <monnier@iro.umontreal.ca> + + * testcases.sml: Add (old) buggy case from Christopher Dutchyn. + + * sml-proc.el (inferior-sml-font-lock-keywords): Don't add + error-regexps if compile.el already highlights them anyway. + + * sml-mode.el (sml-font-lock-symbols-alist): Fix char for "not". + +2007-10-31 Stefan Monnier <monnier@iro.umontreal.ca> + + * sml-mode.el (sml-def-skeleton): If possible, only expand for + lower-case abbrevs and not inside strings or comments. + (sml-mlton-typecheck): Typo. + + * sml-proc.el (sml-proc-comint-input-filter-function): New function. + (inferior-sml-mode): Use it. + (sml-update-cursor): Don't forget errors here any more. + +2007-10-31 Stefan Monnier <monnier@iro.umontreal.ca> + + * sml-util.el (defmap, defsyntax): Avoid defconst. + (flatten): Remove. + + * sml-mode.el (sml-calculate-indentation): Avoid previous-line. + (sml-keywords-regexp): Avoid the need for `flatten'. + (sml-defuse-jump-to-def): Fix typo. + + * sml-defs.el (sml-syms-re): Don't use `flatten'. + (sml-sexp-head-symbols-re, sml-starters-indent-after) + (sml-non-nested-of-starter-re): Avoid the need for `flatten'. + + * sml-proc.el (inferior-sml-next-error-hook): New fun. + (inferior-sml-mode): Use it. + +2007-06-29 Stefan Monnier <monnier@iro.umontreal.ca> + + * sml-mode.el (sml-mlton-error-regexp-alist): New var. + (sml-mlton-typecheck): Use it. + (compilation-error-regexp-alist): Add entries after loading "compile" + so that M-x compile works. + + * sml-proc.el (inferior-sml-mode): Make TAB add a " rather than a space + at the end of a file name. + +2007-06-14 Stefan Monnier <monnier@iro.umontreal.ca> + + * sml-mode.el (sml-mode-variables): Set comment-quote-nested instead of + comment-nested. Set comment-end-skip. + (sml-first-starter-p): New function. + (sml-indent-starter): Use it to fix an indentation bug. + (sml-mlton-command, sml-mlton-mainfile): New vars. + (sml-mlton-typecheck): New command. + (sml-defuse-file): New var. + (sml-defuse-def-regexp, sml-defuse-use-regexp-format): New consts. + (sml-defuse-file, sml-defuse-symdata-at-point): New functions. + (sml-defuse-set-file, sml-defuse-jump-to-def): New commands. + +2005-11-20 Stefan Monnier <monnier@iro.umontreal.ca> + + * sml-move.el (sml-find-match-forward): Avoid infinite looping if the + construct is not properly closed (yet). + +2005-11-16 Stefan Monnier <monnier@iro.umontreal.ca> + + * sml-defs.el (sml-mode-menu): Remove left over obsolete entries. + + * sml-proc.el (inferior-sml-mode): Preserve the menu-bar of the + compilation minor mode, if any. + +2004-11-24 Stefan Monnier <monnier@iro.umontreal.ca> + + * Release version 4.0. + +2004-11-23 Stefan Monnier <monnier@iro.umontreal.ca> + + * sml-mode.el (sml-font-lock-symbols-alist): Add yet more silly entries. + +2004-11-15 Stefan Monnier <monnier@iro.umontreal.ca> + + * sml-mode.el (sml-font-lock-symbols-alist): Add entries for >= and <=. + (sml-font-lock-symbols-alist): Add entries for simple type variables. + (sml-font-lock-compose-symbol): Add support for non-punctuation syms. + +2004-11-14 Stefan Monnier <monnier@iro.umontreal.ca> + + * sml-move.el (sml-backward-sexp, sml-forward-sexp): Remove unused var. + + * sml-mode.el (sml-calculate-indentation): Remove unused var. + (sml-get-indent): Change first arg's meaning. + (sml-get-sym-indent): Adjust call. + (sml-forms-menu): Simplify. + (sml-font-lock-symbols, sml-font-lock-symbols-alist): New vars. + (sml-font-lock-compose-symbol, sml-font-lock-symbols-keywords): + New funs. + (sml-font-lock-keywords): Use them. + + * sml-compat.el (temp-directory): Get rid of warning. + + * Makefile (install_startup): Don't add to load-path any more. + + * sml-proc.el (sml-make-error): Use match-string. + (sml-error-regexp-alist): Merge regexps. + (sml-update-cursor): Check sml-temp-file is non-nil. + +2004-04-21 Stefan Monnier <monnier@iro.umontreal.ca> + + * sml-proc.el (sml-error-regexp-alist): Use new compile.el features + if available. + (sml-send-region): Remove unused var `file'. + (sml-drag-region): Remove unused function. + (sml-update-cursor): Use compilation-fake-loc if available. + (compilation-goto-locus): Only advise if necessary. + + * sml-mode.el: Add self to load-path in sml-mode-startup.el. + (sml-def-skeleton): Try to use the new `system' abbrev flag. + +2004-04-04 Stefan Monnier <monnier@iro.umontreal.ca> + + * testcases.sml: Add a nasty case that is still wrong. + + * sml-proc.el (sml-error-regexp-alist): Tune the regexp for sml/nj. + + * sml-mode.el (sml-mode): Better handle paragraphs in comments. + (sml-mode-variables): Clean up paragraph settings. + (sml-electric-pipe): Fix a boundary bug. + (sml-indent-starter, sml-get-sym-indent, sml-find-matching-starter): + Fix indentation algorithm. Can't remember what it was about. + This code is nasty, I just can't understand what's doing what. + (completion-ignored-extensions): Add the new .cm directory. + +2003-12-09 Stefan Monnier <monnier@iro.umontreal.ca> + + * sml-defs.el (sml-mode-menu): Fix typo. Use std names. + (sml-begin-syms-re): Reduce redundancy. + +2001-09-18 Stefan Monnier <monnier@cs.yale.edu> + + * sml-mode.el (sml-tyvarseq-re): Fix typo. + +2001-07-20 Stefan Monnier <monnier@cs.yale.edu> + + * sml-mode.el (sml-rightalign-and): New defcustom. + (sml-tyvarseq-re): New var. + (sml-font-lock-keywords): Use it. + (sml-imenu-create-index): Don't get confused by tyvarseq's. + (sml-mode-variables): Don't set `comment-column'. + (sml-funname-of-and): New function. + (sml-electric-pipe): Use it. + (sml-find-comment-indent): Try to ignore comment-markers in strings. + (sml-calculate-indentation): Handle closing parens specially. + (sml-indent-pipe): Recognize the case where `and' defines a datatype. + (sml-dangling-sym): Make it work if the symbol is an open-paren. + (sml-indent-default): Change the behavior when preceded by `end', + although I'm not quite sure why. + Understand dangling open-parens. + Properly skip *all* subexpressions of lower precedence. + Allow use of sml-symbol-indent to outdent lines starting with , or ;. + (sml-insert-form): Use preceding-char to avoid bug at bobp. + +2001-07-19 Stefan Monnier <monnier@cs.yale.edu> + + * sml-proc.el (sml-proc-buffer): Save excursion when calling run-sml. + + * sml-move.el (sml-syntax-prec): Split ; and , from `in' and `with'. + + * sml-mode.texi: Put the entry in `Emacs' rather than `Editors'. + + * sml-mode.spec (BuildArch): Simplify call to `install-info'. + + * sml-defs.el (sml-mode-menu): Add an explicit t for always-active. + (sml-symbol-indent): Add entries for , and ; and turn into defcustom. + + * sml-compat.el: Add more stuff. It might help for Emacs-19.34. + + * makefile.pkg (test): Use elisp files in current dir. + +2000-12-24 Stefan Monnier <monnier@cs.yale.edu> + + * Release version 3.9.5. + + * Makefile (install): Also install .el files. + (dist): Don't rely on $CVSROOT. + + * sml-mode.el: Require `skeleton'. + (sml-mode): Add the menu for XEmacs. Make sure @ is a valid skeleton. + (sml-comment-indent): Remove. + (sml-mode-variables): Don't set comment-indent-function. + (sml-def-skeleton): Nop if skeletons aren't available. + (skeletons): Use `> _' and `@'. + (sml-forms-menu): Don't bother with easy-menu-filter-return crap. + (sml-cm-mode-syntax-table, sml-cm-font-lock-keywords): New vars. + (sml-cm-mode): Use define-derived-mode rather than define-generic-mode. + (sml-lex-font-lock-keywords, sml-lex-font-lock-defaults): New vars. + (sml-yacc-font-lock-keywords): Use sml-lex-font-lock-keywords. + Refine pattern to recognize the %prec keyword. + (sml-yacc-font-lock-defaults): Fix typo. + + * sml-proc.el (inferior-sml-mode): Disable next-error for XEmacs. + + * sml-util.el (defsyntax): Don't forget to eval `doc'. + + * sml-mode.spec: Simplify. + + * sml-defs.el (sml-mode-menu): Remove bogus entry for sml-mode-version. + +2000-10-06 Stefan Monnier <monnier@cs.yale.edu> + + * sml-mode.el: Make the toplevel closer to usual practice. + (sml-imenu-regexp, sml-imenu-create-index): New var and fun. + (sml-mode): Use them. + (sml-beginning-of-defun): Add `and' as function-leader. + (sml-lex-mode): New trivial mode. + (sml-yacc-bnf-face, sml-yacc-indent-action, sml-yacc-indent-pipe) + (sml-yacc-indent-term, sml-yacc-font-lock-keywords) + (sml-yacc-font-lock-defaults): New vars. + (sml-yacc-indent-line, sml-yacc-indentation, sml-yacc-mode): New funs. + + * sml-mode.texi: Added yours truly to the list of authors. + + * sml-mode.spec: New file. + + * sml-defs.el (sml-outline-regexp): Slightly improved regexp. + +2000-08-24 Stefan Monnier <monnier@cs.yale.edu> + + * sml-proc.el (inferior-sml-mode-map): Don't inherit from sml-bindings. + Add the binding for C-c C-l explicitly instead. + (sml-run): Look in cwd (but only if the command has slashes). + + * sml-mode.el (sml-mode-abbrev-table): Remove (created by + define-derived-mode). + (sml-mode): Setup add-log's current-defun-function. + (sml-indent-line): Never indent to a negative level. + (sml-skip-siblings, sml-beginning-of-defun, sml-max-name-components) + (sml-current-fun-name): New funs and vars for add-log support. + (sml-comment-indent): Simplify. + (sml-def-skeleton): Also create the skeleton as an abbrev. + (skeletons): New for "struct", "sig", "val", "fn" and "fun". + (sml-electric-space): Rewrite to use abbrev's machinery. + + * sml-defs.el (sml-mode-map): Merge with sml-bindings. + (sml-bindings): Remove. + +2000-02-22 Stefan Monnier <monnier@cs.yale.edu> + + * sml-mode.el (sml-find-matching-starter): Use syms instead of a RE. + (sml-indent-default): Use symbol membership rather than a regexp. + Also, use `sym-indent' instead of (current-column). + This fixes a problem with a hanging `structure Foo = (struct|let)' + (due to `structure' having a sml-indent-rule, as opposed to `fun'). + Hopefully it won't introduce other problems. + (sml-font-lock-keywords): Match vars `val x : int' also. + (sml-electric-pipe): Update to the new `sml-find-matching-starter' and + return a sensible default instead of raising an error in case of + unexpected situations. + (sml-indent-line): Ignore errors and keep the cursor where it is. + (sml-calculate-indentation, sml-indent-pipe): Use syms instead of REs. + + * sml-defs.el (sml-starters-re, sml-pipehead-re): Remove. + + * testcases.sml: New file. + + * makefile.pkg (test): New target to run the test suite. + +2000-02-18 Stefan Monnier <monnier@cs.yale.edu> + + * *.el: Pass through checkdoc and use `eval-when-compile' whenever + possible for (require 'cl). + +2000-02-18 Stefan Monnier <monnier@cs.yale.edu> + + * sml-util.el (make-temp-dir, make-temp-file, temp-file-dir) + (delete-temp-dirs): Replace by the make-temp-file from Emacs-21. + (custom-create-map): Add :group arg and allow key to be a list. + (define-major-mode): Remove (use define-derived-mode instead). + (sml-builtin-nested-comments-flag): New var. + (concatq): Remove. + + * sml-proc.el (sml-host-name): New var. + (sml-make-file-name): Replace by `sml-compile-commands'. + (sml-config-file): New var. + (sml-compile-commands-alist): New var. + (inferior-sml-load-hook): Remove. + (sml-buffer): Query if the current buffer is not a *sml*. + (inferior-sml-mode): Use minor-mode-overriding-map-alist to disable + compilation-minor-mode's keybindings. + (run-sml): Turn into an alias for sml-run. + (sml-run): Query the user for the command. If prefix is set (or if + default value is not null) query for args and host. + Use `split-string' rather than our own function. + Run cmd on another host if requested and pass it an init file. + Pop to the buffer at the end. + (sml-args-to-list): Remove. + (sml-compile): Look for special files (sml-compile-command-alist) in + the current dir (and its parents) to choose a default command. + Remember the command for next time in the same buffer. + Make the `cd' explicit in the command so the user can change it. + (sml-make-error): Fix for when `endline' is absent. + + * sml-mode.el: Pass it through checkdoc. + (sml-mode-version): Remove. + (sml-load-hook): Remove. + (sml-mode-info): Use `info' rather than `Info-goto-node'. + (sml-keywords-regexp): Add "o". + (sml-syntax-prop-table): Use `defsyntax'. + (sml-font-lock-syntactic-keywords): Only use nested comments if supported. + (sml-mode): Use `define-derived-mode'. + (sml-electric-pipe): `sml-indent-line' -> `indent-according-to-mode'. + (sml-indent-line): Use `indent-line-to'. + (sml-cm-mode): New mode for CM files. + + * Makefile: Update. + + * sml-mode-startup.el: Remove since it's now auto-generated. + + * sml-defs.el (sml-bindings): Remove left over C-c` binding. + (sml-mode-map): Add binding for sml-drag-region (was in sml-proc.el). + (sml-mode-syntax-table): Only use nested comments if supported. + (sml-mode-menu): Use next-error rather than the old sml-next-error. + (sml-pipehead-re): Remove "of". + + * sml-compat.el (set-keymap-parents): Make sure it also works when + called with a single keymap rather than a list. + (temporary-file-directory): Add a default definition for XEmacs. + (make-temp-file): New function. + +1999-08-11 Stefan Monnier <monnier@cs.yale.edu> + + * Release version 3.9.3. + + * sml-mode.texi: Somewhat update the doc. + +1999-08-09 Stefan Monnier <monnier@cs.yale.edu> + + * Makefile: Update to the version of pcl-cvs. + + * sml-proc.el: Eliminate some old unused code. + + * sml-defs.el,sml-mode.el,sml-proc.el: Add simple customize support. + +1999-07-07 Stefan Monnier <monnier@cs.yale.edu> + + * sml-proc.el (sml-update-cursor): Make sure it also works if + compile.el is fixed to uses a marker. + + * sml-mode.el (sml-indent): Fix the `fixindent'. + +1999-06-22 Stefan Monnier <monnier@cs.yale.edu> + + * sml-mode-startup.el: Fix to fulfill autoload.el assumptions. + +1999-06-21 Stefan Monnier <monnier@cs.yale.edu> + + * sml-defs.el (sml-bindings): Remove bindings for TAB and M-C-\. + +1999-06-19 Stefan Monnier <monnier@cs.yale.edu> + + * sml-mode.el (sml-font-lock-keywords): Skip type vars in "fun 'a myfn" + (sml-calculate-indentation): Add a hack to allow the user to manually + override the indentation algorithm with a magic comment. + + * sml-mode-startup.el: Update the autoloads automatically. + +1999-06-19 Stefan Monnier <monnier@cs.yale.edu> + + * Release version 3.9.2 + + * sml-proc.el (sml-error-regexp-alist): Fix the pathological + font-locking on long lines. + + * sml-move.el (sml-forward-sexp): Slightly improved. + +1999-06-17 Stefan Monnier <monnier@cs.yale.edu> + + * sml-mode.el (sml-insert-form): Only add a space if needed. + (sml-electric-space): New command bound to M-SPC. + + * sml-defs.el (sml-close-paren): Add a second field that specifies when + not to delegate. Only used for `else'. + +1999-06-16 Stefan Monnier <monnier@cs.yale.edu> + + * sml-move.el (sml-(for|back)ward-sym): Distinguish between + operator "=" and syntax for definitions "d=". + + * sml-defs.el (sml-indent-starters, sml-delegate): Simplify. + (sml-symbol-indent): Add outdentation for `fn' and generalize it to + also work for `of' and `in' and `end'. + + * sml-mode.el (sml-nested-if-indent): Reintroduce as well as the + special casing code for it. + (sml-indent-relative): Generalize treatment of `of', `in', `end', ... + (sml-electric-pipe): Remove the slow behavior and add smarts for the + never-used type-variable arguments for function definitions. + +1999-06-15 Stefan Monnier <monnier@cs.yale.edu> + + * sml-defs.el (sml-mode-menu), sml-mode.el (sml-forms-menu): + Make the menu dynamically. + + * sml-mode.el (sml-form-<foo>): Use skeletons. + (sml-calculate-indentation): Add `with' indentation. + +1999-06-14 Stefan Monnier <monnier@cs.yale.edu> + + * sml-move.el (sml-(for|back)ward-sym): Now also return the string + if any and take care of the "op" special keyword. + (sml-op-prec): Setup an alist for the infix operators. + + * version 3.9.1: sent to Roland McGrath. + +1999-06-13 Stefan Monnier <monnier@cs.yale.edu> + + * sml-smlnj.el, sml-mosml.el, sml-poly-ml.el: Remove. + + * sml-proc.el (...): Get rid of sml-next-error by spicing up the + interface with compile.el so that intervals can be displayed. + `sml-overlay' is kept (and moved from sml-mode to sml-proc where it + belongs) but is made redundant in the case of transient-mark-mode. + +1999-06-12 Stefan Monnier <monnier@cs.yale.edu> + + * sml-proc.el (sml-prompt-regexp): More general regexp to catch mosml, + smlnj as well as polyml prompts. + (sml-update-cursor, sml-send-command, inferior-sml-mode): + Make it work with compile.el's `next-error'. + (sml-temp-threshold): Drop: always use a temp file. + +1999-06-10 Stefan Monnier <monnier@cs.yale.edu> + + * sml-move.el (sml-op-prec): Update the list of default infix ops + based on sml/nj's source files. + +1999-06-08 Stefan Monnier <monnier@cs.yale.edu> + + * sml-proc.el (sml-run): Remove dubious code to take care of a + supposedly special case in order not to send "" when args=nil. + +1999-06-07 Stefan Monnier <monnier@cs.yale.edu> + + * sml-mode.el (sml-font-lock-syntactic-keywords): Add syntactic + fontification for the ' \"' case (exhibited by lexgen.sml). + +1999-06-07 Stefan Monnier <monnier@cs.yale.edu> + + * ALL: The new indentation begins to work. v3_9_0 + +1999-05-29 Stefan Monnier <monnier@cs.yale.edu> + + * sml-defs.el (sml-mode-syntax-table): Add ~ of prefix-syntax. + + * sml-mode.el (sml-find-match-indent): (nilp sml-type-of-indent) is + only applied if the `let' is alone at the end of the line. + (sml-type-of-indent): Default changed to `nil'. + +1999-05-28 Stefan Monnier <monnier@cs.yale.edu> + + * sml-mode.el (sml-font-lock-keywords): Change _ and ' back to word + syntax for font-locking. + +1999-05-27 Stefan Monnier <monnier@cs.yale.edu> + + * sml-mode.el (sml-font-lock-syntactic-keywords): Finally got the + matching of let...end working. + (sml-electric-pipe): Take a fun sexp (symbol) rather than a fun word. + +1998-10-26 Stefan Monnier <monnier@cs.yale.edu> + + * sml-mode.el (sml-font-lock-syntactic-keywords): + Add syntactic-keywords to support nested comments. + diff --git a/emacs/emacs.d/sml-mode-5.0/INSTALL b/emacs/emacs.d/sml-mode-5.0/INSTALL @@ -0,0 +1,39 @@ +SML-MODE shouldn't require any special external support package, +as far as I can rememebr. Just a recent copy of Emacs or XEmacs. + +Installation of the program +=================================== + + 1. Edit the file `Makefile' to reflect the situation at your site. + The only things you have to change is the definition of `lispdir' + and `infodir'. The elisp files will be copied to `lispdir', and + the info file to `infodir'. + + 2. Have some sorbet. + + 3. Type `make install' in the source directory. This will byte-compile + all `.el' files and copy all into the directory you specified in step + 1. It will also copy the info files (and add a corresponding entry to + the info-dir file if install-info can be found). + + If you only want to create the compiled elisp files, you can just type + `make elcfiles' instead. + + 4. Edit the file `site-start.el' in your emacs lisp directory (usually + `/usr/local/share/emacs/site-lisp' or something similar) and make it + load the file `sml-mode-startup.el'. It contains a couple of + `auto-load's that facilitates the use of sml-mode. Alternatively, you + can just use `make install_startup'. If you're only installing it for + yourself rather than for the whole system, then use something like + `make install_startup startupfile=$HOME/.emacs'. + + 5. If you had copied the contents of a previous sml-mode-startup.el file to + your site-start.el (or .emacs), you might want to remove that. + + +How to make typeset documentation from the TeXinfo manual +========================================================= + + If you have TeX installed at your site, you can make a typeset version of +the manual typing ``make dvi''. If you prefer a postscript version of this +file, just use ``make postscript''. diff --git a/emacs/emacs.d/sml-mode-5.0/Makefile b/emacs/emacs.d/sml-mode-5.0/Makefile @@ -0,0 +1,176 @@ +# Makefile for emacs-lisp package + +# Copyright (C) 1998, 1999, 2004, 2007, 2010 Stefan Monnier <monnier@gnu.org> + +# This file is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation; either version 3, or (at your option) any +# later version. + +# This file is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# for more details. + +# You should have received a copy of the GNU General Public License +# along with GNU Emacs; see the file COPYING. If not, write to +# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + +# load the package-specific settings +include makefile.pkg + +# set up the usual installation paths +prefix = /usr/local +datadir = $(prefix)/share + +# the directory where you install third-party emacs packges +lispdir = $(datadir)/emacs/site-lisp + +# the directory where the .elc files will be installed +elcdir = $(lispdir)/$(PACKAGE) +# the directory where the .el files will be installed +eldir = $(elcdir) + +# the file where the initialization goes. +#startupfile = $(HOME/.emacs +startupfile = $(lispdir)/site-start.el + +# the directory where you installed the elib .elc files. +# This is only needed if your site-start.el (or default.el) does not +# set up elib correctly. +elibdir = $(lispdir)/elib + +# the directory where you install the info doc +infodir = $(prefix)/info +docdir = $(prefix)/doc + +EMACS = emacs +MAKEINFO= makeinfo +TEXI2DVI= texi2dvi +SHELL = /bin/sh +DVIPS = dvips +CP = cp +RM = rm -f +MKDIR = mkdir -p +ETAGS = etags + +###################################################################### +### No changes below this line should be necessary ### +###################################################################### + +ELFLAGS = --eval '(setq load-path (append (list "." "$(elibdir)" "$(lispdir)") load-path))' +ELC = $(EMACS) -batch $(ELFLAGS) -f batch-byte-compile + +ELCFILES = $(ELFILES:.el=.elc) + +TEXEXTS = *.cps *.fns *.kys *.vr *.tp *.pg *.log *.aux *.toc *.cp *.ky *.fn + +.SUFFIXES: .elc .el .info .ps .dvi .texi +.PHONY: elcfiles info clean distclean default +.PHONY: install_startup install_elc install install_el install_info +.PHONY: dvi postscript + +.el.elc: + $(ELC) $< + +.texi.info: + $(MAKEINFO) $< + +.texi.dvi: + $(TEXI2DVI) $< + +.dvi.ps: + $(DVIPS) -f $< >$@ + +###################################################################### + +default: elcfiles + +elcfiles: $(ELCFILES) +info: $(PACKAGE).info + +install_elc: $(ELCFILES) $(PACKAGE)-startup.el + $(MKDIR) $(elcdir) + for f in $(ELCFILES) $(PACKAGE)-startup.el; do \ + $(CP) $$f $(elcdir)/$$f ;\ + done + +install_el: + $(MKDIR) $(eldir) + for f in $(ELFILES); do \ + $(CP) $$f $(eldir)/$$f ;\ + done + +install_info: $(PACKAGE).info + $(MKDIR) $(infodir) + $(CP) *.info* $(infodir)/ + -[ ! -w $(infodir)/dir ] \ + || install-info --info-dir=$(infodir)/dir $(PACKAGE).info + +install_startup: + $(MKDIR) $(lispdir) + @if grep $(PACKAGE) $(lispdir)/site-start.el >/dev/null 2>&1 || \ + grep $(PACKAGE) $(startupfile) >/dev/null 2>&1 || \ + grep $(PACKAGE) $(lispdir)/default.el >/dev/null 2>&1; \ + then \ + echo "**********************************************************" ;\ + echo "*** It seems you already have some setup code" ;\ + echo "*** for $(PACKAGE) in your startup files." ;\ + echo "*** Check that it properly loads \"$(PACKAGE)-startup\"" ;\ + echo "**********************************************************" ;\ + else \ + echo 'echo ";; load $(PACKAGE) setup code" >>$(startupfile)' ;\ + echo ";; load $(PACKAGE) setup code" >>$(startupfile) ;\ + echo 'echo "(load \"$(elcdir)/$(PACKAGE)-startup\")" >>$(startupfile)' ;\ + echo "(load \"$(elcdir)/$(PACKAGE)-startup\")" >>$(startupfile) ;\ + fi + +postscript: $(PACKAGE).ps +dvi: $(PACKAGE).dvi +install_dvi: dvi + $(MKDIR) $(docdir) + $(CP) `find . -type f -name '*.dvi' -print` $(docdir)/ + +install: install_elc install_info install_startup install_el + +clean: + $(RM) *~ core .\#* $(TEXEXTS) + +TAGS tags: + $(ETAGS) $(ELFILES) + +distclean: clean + $(RM) *.elc *.dvi *.info* *.ps + +###################################################################### +### don't look below ### +###################################################################### + +$(PACKAGE)-startup.el: $(ELFILES) + echo "\ + ;;; $@ --- automatically extracted autoloads\n\ + ;;; Code:\n\ + (add-to-list 'load-path\n\ + (or (file-name-directory load-file-name) (car load-path)))\n\ + " >$@ + $(EMACS) --batch --eval '(setq generated-autoload-file "'`pwd`'/$@")' -f batch-update-autoloads "." + +## + +#TAG = $(shell echo v$(VERSION) | tr '.' '_') +URL=$(shell sed -n -e '5p' .svn/entries) +TAG=$(shell dirname "$(URL)")/releases/$(PACKAGE)-$(VERSION) +ftpdir=/u/monnier/html/elisp/ +cvsmodule=$(shell cat CVS/Repository) +cvsroot=$(shell cat CVS/Root) + +dist: + svn cp . "$(TAG)" &&\ + svn export "$(TAG)" "$(TMP)/$(PACKAGE)-$(VERSION)" &&\ + cd "$(TMP)/$(PACKAGE)-$(VERSION)" &&\ + $(MAKE) info $(PACKAGE)-startup.el &&\ + cd .. &&\ + ztar $(PACKAGE)-$(VERSION) &&\ + rm -rf $(PACKAGE)-$(VERSION) + mv $(TMP)/$(PACKAGE)-$(VERSION).tar.gz $(ftpdir)/ + ln -sf $(PACKAGE)-$(VERSION).tar.gz $(ftpdir)/$(PACKAGE).tar.gz diff --git a/emacs/emacs.d/sml-mode-5.0/NEWS b/emacs/emacs.d/sml-mode-5.0/NEWS @@ -0,0 +1,137 @@ +Changes since 4.1: + +* New indentation code using SMIE when available. + +* `sml-back-to-outer-indent' is now on S-tab (aka `backtab') rather than M-tab. + +* Support for electric-layout-mode and electric-indent-mode. + +* `sml-mark-defun' tries to be more clever. + +* A single file (sml-mode.el) is needed unless you want to use an interactive + process like SML/NJ, or if your Emacs does not provide SMIE. + +Changes since 4.0: + +* Switch to GPLv3+. + +* When possible (i.e. running under Emacs>=23), be case-sensitive when + expanding abbreviations, and don't expand them in comments and strings. + +* When you `next-error' to a type error, highlight the actual parts of the + types that differ. + +* Flush the recorded errors not only upon sml-compile and friends, but also + when typing commands directly at the prompt. + +* New command sml-mlton-typecheck. + +* Simple support to parse errors and warnings in MLton's output. + +* Simple support for MLton's def-use files. + +Changes since 3.9.5: + +* No need to add the dir to your load-path any more. + The sml-mode-startup.el file does it for you. + +* Symbols like -> can be displayed as real arrows. See sml-font-lock-symbols. + +* Fix some incompatibilities with the upcoming Emacs-21.4. + +* Indentation rules improved. New customizable variable + `sml-rightalign-and'. Also `sml-symbol-indent' is now customizable. + +Changes since 3.9.3: + +* New add-log support (try C-x 4 a from within an SML function). + +* Imenu support + +* sml-bindings has disappeared. + +* The code skeletons are now abbrevs as well. + +* A new *sml* process is sent the content of sml-config-file (~/.sml-proc.sml) + if it exists. + +* `sml-compile' works yet a bit differently. The command can begin + with `cd "path";' and it will be replaced by OS.FileSys.chDir. + +* run-sml now pops up the new buffer. It can also run the command on another + machine. And it always prompts for the command name. Use a prefix + argument if you want to give args or to specify a host on which + to run the command. + +* mouse-2 to yank in *sml* should work again (but won't work for next-error + any more). + +* New major-modes sml-cm-mode, sml-lex-mode and sml-yacc-mode. + +* sml-load-hook has disappeared as has inferior-sml-load-hook. + +* sml-mode-startup.el is now automatically generated and you're supposed to + `load' it from .emacs or site-start.el. + +* Minor bug fixes. + +Changes since 3.3: + +* the sml-drag-* commands have disappeared. + +* added a little bit of `customize' support. Many of the customization + variables for indentation are still in flux, so they are not customize'd. + +* proformas have been replaced by skeletons. it's mostly the same as + before (the layout has slightly changed, tho). The main difference + is that the indentation relies on the major-mode indentation so it + is implicitly customized, which makes more sense to me. + Also I added an electric space M-SPC that will call the corresponding + skeleton if any matches the immediately preceding symbol. Basically + that allows you to type `l e t M-SPC' to call the `let' skeleton. + +* M-C-f and M-C-b try to be smart and jump around let..end and such blocks. + It's probably either too smart or not smart enough, tho. + +* there is no more sml-<compiler>.el since the code should work for "all" + known compilers. If your favorite compiler doesn't seem to work right + send me a sample session. + +* hilite support has disappeared and font-lock and menu support is now built-in. + +* the indentation algorithm is inherently much slower. I've tried to ensure + the slowness never manifests itself in practice, but if you find a case + where the indentation doesn't feel instantaneous, tell me. + +* function arguments get properly indented (yes, madam). + +* the indentation has been majorly reworked. The list of changes is too long. + Many customizations have disappeared, some may reappear depending on the + feedback I get. The indentation should now "always" work right, so + tell me when it doesn't. + +* nested comments are only properly handled if you have a nested-comments + aware Emacs (I don't know of any yet) or if you turn on font-lock. + +* provide `sml-compile' which does something similat to `compile' except it + passes the command to an inferior-sml process. Also it has an additional + hack to look for sml-make-file-name in parent directories and cd to it + before sending the command (handy for CM.make() when the sources.cm file + is not in the current directory). This hack is very ad-hoc and quite + misleading for people who don't use CM. I.e. the default is not safe. + +* sml-send-region and friends now always use a temp file. The temp file + management has been made a little more secure. + +* the overlay is now turned off by default. Instead the region is activated, + so that transient-mark-mode will end up highlighting the error just like + the overlay used to do. + +* sml-proc uses compile.el for error parsing. This mostly means that instead + of C-c ` you want to use the standard C-x `. It also means that error + formats for any compiler can be added more easily. + +* The special frame handling has been thrown out because it doesn't interact + well with Emacs' own similar feature. I believe XEmacs still doesn't provide + such a feature, so if you miss it, either switch to Emacs or (convince + someone else to) add it to XEmacs. diff --git a/emacs/emacs.d/sml-mode-5.0/README b/emacs/emacs.d/sml-mode-5.0/README @@ -0,0 +1,19 @@ +SML-MODE is a major Emacs mode for editing Standard ML. +It provides syntax highlighting and automatic indentation and +comes with sml-proc which allows interaction with an inferior SML +interactive loop. + +This release should work on any recent version of Emacs or XEmacs. +If it doesn't: complain. + +Some more or less out of date documentation can be found in TeXinfo format. + +Check the INSTALL file for installation instructions. +Check the NEWS file for a list of changes in this version. +Check the BUGS and TODO file before sending me bug reports and requests for +enhancements. + +Send any complaint/question/praise/ice-cream to me, + + + Stefan Monnier <monnier@iro.umontreal.ca> diff --git a/emacs/emacs.d/sml-mode-5.0/TODO b/emacs/emacs.d/sml-mode-5.0/TODO @@ -0,0 +1,46 @@ +* file-name completion in sml-cm-mode. + +* Don't always jump to the *sml* buffer when you send a snippet of code. + +* Fix inferior-sml-mode's TAB completion of filenames so it doesn't append + a space. + +* Improve support for MLton's def-use info (see http://mlton.org/Emacs) + +* Add an sml-mlb-mode for ML Basis files (see http://mlton.org/Emacs) + +* make `M-x sml-compile' more generic. + +* allow specifying indentation of dependent keywords (how to indent `in' + relative to `let', for example). + +* recognize irrefutable patterns (with "Capital"-heuristics, for example: + a regexp like "\\([(),]\\|[_a-z][_a-z0-9]*\\)+"). + This can then be used to allow indenting like + + (fn x => + some expressions) + +* take advantage of text after-the-line (when available) for indentation. + +* obey fixity directives. + +* dangling `case e' in stuff like + + fun myfunction x = case x + of bla => + | bli => + +* deal with CPS kind of code ??? + + function1 (arg1, arg2, fn v1 => + function2 (arg2, fn v2 => + function3 (arg5, arg3, arg8, fn v3 => + function4 (v1, v2, v3)))) + + or even just + + F.LET (v1, foo, + F.LET (v2, bar, + F.LET (v3, baz, + F.RET [v1, v2, v3]))) diff --git a/emacs/emacs.d/sml-mode-5.0/makefile.pkg b/emacs/emacs.d/sml-mode-5.0/makefile.pkg @@ -0,0 +1,15 @@ +PACKAGE = sml-mode +ELFILES = sml-mode.el sml-proc.el sml-oldindent.el + +default: elcfiles + +TESTCASE = testcases.sml + +test: + $(RM) $(TESTCASE).new + $(EMACS) --batch \ + --eval "(load \"$$(pwd)/sml-mode-startup\")" \ + $(TESTCASE) \ + --eval '(indent-region (point-min) (point-max) nil)' \ + --eval '(write-region (point-min) (point-max) "$(TESTCASE).new")' + diff -u -B $(TESTCASE) $(TESTCASE).new diff --git a/emacs/emacs.d/sml-mode-5.0/sml-mode-startup.el b/emacs/emacs.d/sml-mode-5.0/sml-mode-startup.el @@ -0,0 +1,59 @@ +;;; sml-mode-startup.el --- automatically extracted autoloads +;;; Code: +(add-to-list 'load-path + (or (file-name-directory load-file-name) (car load-path))) + +;;;### (autoloads (sml-yacc-mode sml-lex-mode sml-cm-mode sml-mode) +;;;;;; "sml-mode" "sml-mode.el" (20358 8148)) +;;; Generated autoloads from sml-mode.el + +(add-to-list 'auto-mode-alist '("\\.s\\(ml\\|ig\\)\\'" . sml-mode)) + +(autoload 'sml-mode "sml-mode" "\ +\\<sml-mode-map>Major mode for editing ML code. +This mode runs `sml-mode-hook' just before exiting. +\\{sml-mode-map} + +\(fn)" t nil) + +(add-to-list 'completion-ignored-extensions ".cm/") + +(add-to-list 'auto-mode-alist '("\\.cm\\'" . sml-cm-mode)) + +(autoload 'sml-cm-mode "sml-mode" "\ +Major mode for SML/NJ's Compilation Manager configuration files. + +\(fn)" t nil) + +(autoload 'sml-lex-mode "sml-mode" "\ +Major Mode for editing ML-Lex files. + +\(fn)" t nil) + +(add-to-list 'auto-mode-alist '("\\.grm\\'" . sml-yacc-mode)) + +(autoload 'sml-yacc-mode "sml-mode" "\ +Major Mode for editing ML-Yacc files. + +\(fn)" t nil) + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "sml-mode" '("font-lock-type-def-face" "font-lock-module-def-face" "font-lock-interface-def-face"))) + +;;;*** + +;;;### (autoloads nil "sml-oldindent" "sml-oldindent.el" (20358 8148)) +;;; Generated autoloads from sml-oldindent.el + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "sml-oldindent" '("sml-"))) + +;;;*** + +;;;### (autoloads nil "sml-proc" "sml-proc.el" (20358 8148)) +;;; Generated autoloads from sml-proc.el + +(autoload 'run-sml "sml-proc" nil t) + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "sml-proc" '("sml-" "inferior-sml-" "font-lock-" "run-sml" "switch-to-sml"))) + +;;;*** + diff --git a/emacs/emacs.d/sml-mode-5.0/sml-mode.el b/emacs/emacs.d/sml-mode-5.0/sml-mode.el @@ -0,0 +1,1436 @@ +;;; sml-mode.el --- Major mode for editing (Standard) ML + +;; Copyright (C) 1999,2000,2004,2007,2010-2012 Stefan Monnier +;; Copyright (C) 1994-1997 Matthew J. Morley +;; Copyright (C) 1989 Lars Bo Nielsen + +;; Author: Lars Bo Nielsen +;; Olin Shivers +;; Fritz Knabe (?) +;; Steven Gilmore (?) +;; Matthew Morley <mjm@scs.leeds.ac.uk> (aka <matthew@verisity.com>) +;; Matthias Blume <blume@cs.princeton.edu> (aka <blume@kurims.kyoto-u.ac.jp>) +;; (Stefan Monnier) <monnier@iro.umontreal.ca> +;; Maintainer: (Stefan Monnier) <monnier@iro.umontreal.ca> +;; Keywords: SML + +;; This file is not part of GNU Emacs, but it is distributed under the +;; same conditions. + +;; This program is free software; you can redistribute it and/or +;; modify it under the terms of the GNU General Public License as +;; published by the Free Software Foundation; either version 3, or (at +;; your option) any later version. + +;; This program is distributed in the hope that it will be useful, but +;; WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +;; General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs; see the file COPYING. If not, write to the +;; Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + +;;; Commentary: + +;;; HISTORY + +;; Still under construction: History obscure, needs a biographer as +;; well as a M-x doctor. Change Log on request. + +;; Hacked by Olin Shivers for comint from Lars Bo Nielsen's sml.el. + +;; Hacked by Matthew Morley to incorporate Fritz Knabe's hilite and +;; font-lock patterns, some of Steven Gilmore's (reduced) easy-menus, +;; and numerous bugs and bug-fixes. + +;;; DESCRIPTION + +;; See accompanying info file: sml-mode.info + +;;; FOR YOUR .EMACS FILE + +;; If sml-mode.el lives in some non-standard directory, you must tell +;; emacs where to get it. This may or may not be necessary: + +;; (add-to-list 'load-path "~jones/lib/emacs/") + +;; Then to access the commands autoload sml-mode with that command: + +;; (load "sml-mode-startup") + +;; sml-mode-hook is run whenever a new sml-mode buffer is created. + +;; Finally, there are inferior-sml-{mode,load}-hooks -- see comments +;; in sml-proc.el. For much more information consult the mode's *info* +;; tree. + +;;; Code: + +(eval-when-compile (require 'cl)) +(require 'smie nil 'noerror) + +(condition-case nil (require 'skeleton) (error nil)) + +(defgroup sml () + "Editing SML code." + :group 'languages) + +;;; VARIABLES CONTROLLING INDENTATION + +(defcustom sml-indent-level 4 + "Indentation of blocks in ML (see also `sml-indent-rule')." + :type '(integer)) + +(defcustom sml-indent-args sml-indent-level + "Indentation of args placed on a separate line." + :type '(integer)) + +;; (defvar sml-indent-align-args t +;; "*Whether the arguments should be aligned.") + +;; (defvar sml-case-indent nil +;; "*How to indent case-of expressions. +;; If t: case expr If nil: case expr of +;; of exp1 => ... exp1 => ... +;; | exp2 => ... | exp2 => ... + +;; The first seems to be the standard in SML/NJ, but the second +;; seems nicer...") + +(defcustom sml-electric-semi-mode nil + "If non-nil, `\;' will self insert, reindent the line, and do a newline. +If nil, just insert a `\;'. (To insert while t, do: \\[quoted-insert] \;)." + :type 'boolean) +(when (fboundp 'electric-layout-mode) + (make-obsolete-variable 'sml-electric-semi-mode + 'electric-layout-mode "Emacs-24")) + +(defcustom sml-rightalign-and t + "If non-nil, right-align `and' with its leader. +If nil: If t: + datatype a = A datatype a = A + and b = B and b = B" + :type 'boolean) + +;;; OTHER GENERIC MODE VARIABLES + +(defvar sml-mode-info "sml-mode" + "*Where to find Info file for `sml-mode'. +The default assumes the info file \"sml-mode.info\" is on Emacs' info +directory path. If it is not, either put the file on the standard path +or set the variable `sml-mode-info' to the exact location of this file + + (setq sml-mode-info \"/usr/me/lib/info/sml-mode\") + +in your .emacs file. You can always set it interactively with the +set-variable command.") + +(defvar sml-mode-hook nil + "*Run upon entering `sml-mode'. +This is a good place to put your preferred key bindings.") + +;;; CODE FOR SML-MODE + +(defun sml-mode-info () + "Command to access the TeXinfo documentation for `sml-mode'. +See doc for the variable `sml-mode-info'." + (interactive) + (require 'info) + (condition-case nil + (info sml-mode-info) + (error (progn + (describe-variable 'sml-mode-info) + (message "Can't find it... set this variable first!"))))) + + +;;; Autoload functions -- no-doc is another idea cribbed from AucTeX! + +(let ((sml-no-doc + "This function is part of sml-proc, and has not yet been loaded. +Full documentation will be available after autoloading the function.")) + + (autoload 'sml-compile "sml-proc" sml-no-doc t) + (autoload 'sml-load-file "sml-proc" sml-no-doc t) + (autoload 'switch-to-sml "sml-proc" sml-no-doc t) + (autoload 'sml-send-region "sml-proc" sml-no-doc t) + (autoload 'sml-send-buffer "sml-proc" sml-no-doc t)) + +;; font-lock setup + +(defvar sml-outline-regexp + ;; `st' and `si' are to match structure and signature. + " \\|s[ti]\\|[ \t]*\\(let[ \t]+\\)?\\(fun\\|and\\)\\>" + "Regexp matching a major heading. +This actually can't work without extending `outline-minor-mode' with the +notion of \"the end of an outline\".") + +;; +;; Internal defines +;; + +(defvar sml-mode-map + (let ((map (make-sparse-keymap))) + ;; Smarter cursor movement. + ;; (define-key map [remap forward-sexp] 'sml-user-forward-sexp) + ;; (define-key map [remap backward-sexp] 'sml-user-backward-sexp) + ;; Text-formatting commands: + (define-key map "\C-c\C-m" 'sml-insert-form) + (define-key map "\C-c\C-i" 'sml-mode-info) + (define-key map "\M-|" 'sml-electric-pipe) + (define-key map "\M-\ " 'sml-electric-space) + (define-key map "\;" 'sml-electric-semi) + (define-key map [backtab] 'sml-back-to-outer-indent) + ;; Process commands added to sml-mode-map -- these should autoload. + (define-key map "\C-c\C-l" 'sml-load-file) + (define-key map "\C-c\C-c" 'sml-compile) + (define-key map "\C-c\C-s" 'switch-to-sml) + (define-key map "\C-c\C-r" 'sml-send-region) + (define-key map "\C-c\C-b" 'sml-send-buffer) + map) + "The keymap used in `sml-mode'.") + +(defconst sml-builtin-nested-comments-flag + (ignore-errors + (not (equal (let ((st (make-syntax-table))) + (modify-syntax-entry ?\* ". 23n" st) st) + (let ((st (make-syntax-table))) + (modify-syntax-entry ?\* ". 23" st) st)))) + "Non-nil means this Emacs understands the `n' in syntax entries.") + +(defvar sml-mode-syntax-table + (let ((st (make-syntax-table))) + (modify-syntax-entry ?\* (if sml-builtin-nested-comments-flag + ". 23n" ". 23") st) + (modify-syntax-entry ?\( "()1" st) + (modify-syntax-entry ?\) ")(4" st) + (mapc (lambda (c) (modify-syntax-entry c "_" st)) "._'") + (mapc (lambda (c) (modify-syntax-entry c "." st)) ",;") + ;; `!' is not really a prefix-char, oh well! + (mapc (lambda (c) (modify-syntax-entry c "'" st)) "~#!") + (mapc (lambda (c) (modify-syntax-entry c "." st)) "%&$+-/:<=>?@`^|") + st) + "The syntax table used in `sml-mode'.") + + +(easy-menu-define sml-mode-menu sml-mode-map "Menu used in `sml-mode'." + '("SML" + ("Process" + ["Start default ML compiler" run-sml t] + ["-" nil nil] + ["run CM.make" sml-compile t] + ["load ML source file" sml-load-file t] + ["switch to ML buffer" switch-to-sml t] + ["--" nil nil] + ["send buffer contents" sml-send-buffer t] + ["send region" sml-send-region t] + ["send paragraph" sml-send-function t] + ["goto next error" next-error (featurep 'sml-proc)] + ["---" nil nil] + ;; ["Standard ML of New Jersey" sml-smlnj (fboundp 'sml-smlnj)] + ;; ["Poly/ML" sml-poly-ml (fboundp 'sml-poly-ml)] + ;; ["Moscow ML" sml-mosml (fboundp 'sml-mosml)] + ["Help for Inferior ML" (describe-function 'inferior-sml-mode) + :active (featurep 'sml-proc)]) + ["electric pipe" sml-electric-pipe t] + ["insert SML form" sml-insert-form t] + ("Forms" :filter sml-forms-menu) + ("Format/Mode Variables" + ["indent region" indent-region t] + ["outdent" sml-back-to-outer-indent t] + ;; ["-" nil nil] + ;; ["set indent-level" sml-indent-level t] + ;; ["set pipe-indent" sml-pipe-indent t] + ;; ["--" nil nil] + ;; ["toggle type-of-indent" sml-type-of-indent t] + ;; ["toggle nested-if-indent" sml-nested-if-indent t] + ;; ["toggle electric-semi-mode" sml-electric-semi-mode t] + ) + ["-----" nil nil] + ["SML mode help (brief)" describe-mode t] + ["SML mode *info*" sml-mode-info t] + ["Remove overlay" (sml-error-overlay 'undo) + :visible (or (and (boundp 'sml-error-overlay) + sml-error-overlay) + (not (fboundp 'compilation-fake-loc))) + :active (and (boundp 'sml-error-overlay) + (overlayp sml-error-overlay) + (overlay-start sml-error-overlay)) + ])) + +;; Make's sure they appear in the menu bar when sml-mode-map is active. +;; On the hook for XEmacs only -- see easy-menu-add in auc-menu.el. +;; (defun sml-mode-menu-bar () +;; "Make sure menus appear in the menu bar as well as under mouse 3." +;; (and (eq major-mode 'sml-mode) +;; (easy-menu-add sml-mode-menu sml-mode-map))) +;; (add-hook 'sml-mode-hook 'sml-mode-menu-bar) + +;; +;; regexps +;; + +(defun sml-syms-re (syms) + (concat "\\<" (regexp-opt syms t) "\\>")) + +;; + +(defconst sml-module-head-syms + '("signature" "structure" "functor" "abstraction")) + + +(defconst sml-=-starter-syms + (list* "|" "val" "fun" "and" "datatype" "type" "abstype" "eqtype" + sml-module-head-syms) + "Symbols that can be followed by a `='.") +(defconst sml-=-starter-re + (concat "\\S.|\\S.\\|" (sml-syms-re (cdr sml-=-starter-syms))) + "Symbols that can be followed by a `='.") + +(defconst sml-non-nested-of-starter-re + (sml-syms-re '("datatype" "abstype" "exception")) + "Symbols that can introduce an `of' that shouldn't behave like a paren.") + +(defconst sml-starters-syms + (append sml-module-head-syms + '("abstype" "datatype" "exception" "fun" + "local" "infix" "infixr" "sharing" "nonfix" + "open" "type" "val" "and" + "withtype" "with")) + "The starters of new expressions.") + +(defconst sml-pipeheads + '("|" "of" "fun" "fn" "and" "handle" "datatype" "abstype") + "A `|' corresponds to one of these.") + +(defconst sml-keywords-regexp + (sml-syms-re '("abstraction" "abstype" "and" "andalso" "as" "before" "case" + "datatype" "else" "end" "eqtype" "exception" "do" "fn" + "fun" "functor" "handle" "if" "in" "include" "infix" + "infixr" "let" "local" "nonfix" "of" "op" "open" "orelse" + "overload" "raise" "rec" "sharing" "sig" "signature" + "struct" "structure" "then" "type" "val" "where" "while" + "with" "withtype" "o")) + "A regexp that matches any and all keywords of SML.") + +(defconst sml-tyvarseq-re + "\\(\\('+\\(\\sw\\|\\s_\\)+\\|(\\([,']\\|\\sw\\|\\s_\\|\\s-\\)+)\\)\\s-+\\)?") + +;;; Font-lock settings ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defcustom sml-font-lock-symbols nil + "Display \\ and -> and such using symbols in fonts. +This may sound like a neat trick, but be extra careful: it changes the +alignment and can thus lead to nasty surprises w.r.t layout. +If t, try to use whichever font is available. Otherwise you can +set it to a particular font of your preference among `japanese-jisx0208' +and `unicode'." + :type '(choice (const nil) + (const t) + (const unicode) + (const japanese-jisx0208))) + +(defconst sml-font-lock-symbols-alist + (append + ;; The symbols can come from a JIS0208 font. + (and (fboundp 'make-char) (charsetp 'japanese-jisx0208) + (memq sml-font-lock-symbols '(t japanese-jisx0208)) + (list (cons "fn" (make-char 'japanese-jisx0208 38 75)) + (cons "andalso" (make-char 'japanese-jisx0208 34 74)) + (cons "orelse" (make-char 'japanese-jisx0208 34 75)) + ;; (cons "as" (make-char 'japanese-jisx0208 34 97)) + (cons "not" (make-char 'japanese-jisx0208 34 76)) + (cons "div" (make-char 'japanese-jisx0208 33 96)) + ;; (cons "*" (make-char 'japanese-jisx0208 33 95)) + (cons "->" (make-char 'japanese-jisx0208 34 42)) + (cons "=>" (make-char 'japanese-jisx0208 34 77)) + (cons "<-" (make-char 'japanese-jisx0208 34 43)) + (cons "<>" (make-char 'japanese-jisx0208 33 98)) + (cons ">=" (make-char 'japanese-jisx0208 33 102)) + (cons "<=" (make-char 'japanese-jisx0208 33 101)) + (cons "..." (make-char 'japanese-jisx0208 33 68)) + ;; Some greek letters for type parameters. + (cons "'a" (make-char 'japanese-jisx0208 38 65)) + (cons "'b" (make-char 'japanese-jisx0208 38 66)) + (cons "'c" (make-char 'japanese-jisx0208 38 67)) + (cons "'d" (make-char 'japanese-jisx0208 38 68)) + )) + ;; Or a unicode font. + (and (fboundp 'decode-char) + (memq sml-font-lock-symbols '(t unicode)) + (list (cons "fn" (decode-char 'ucs 955)) + (cons "andalso" (decode-char 'ucs 8896)) + (cons "orelse" (decode-char 'ucs 8897)) + ;; (cons "as" (decode-char 'ucs 8801)) + (cons "not" (decode-char 'ucs 172)) + (cons "div" (decode-char 'ucs 247)) + (cons "*" (decode-char 'ucs 215)) + (cons "o" (decode-char 'ucs 9675)) + (cons "->" (decode-char 'ucs 8594)) + (cons "=>" (decode-char 'ucs 8658)) + (cons "<-" (decode-char 'ucs 8592)) + (cons "<>" (decode-char 'ucs 8800)) + (cons ">=" (decode-char 'ucs 8805)) + (cons "<=" (decode-char 'ucs 8804)) + (cons "..." (decode-char 'ucs 8943)) + ;; (cons "::" (decode-char 'ucs 8759)) + ;; Some greek letters for type parameters. + (cons "'a" (decode-char 'ucs 945)) + (cons "'b" (decode-char 'ucs 946)) + (cons "'c" (decode-char 'ucs 947)) + (cons "'d" (decode-char 'ucs 948)) + )))) + +(defun sml-font-lock-compose-symbol (alist) + "Compose a sequence of ascii chars into a symbol. +Regexp match data 0 points to the chars." + ;; Check that the chars should really be composed into a symbol. + (let* ((start (match-beginning 0)) + (end (match-end 0)) + (syntaxes (if (eq (char-syntax (char-after start)) ?w) + '(?w) '(?. ?\\)))) + (if (or (memq (char-syntax (or (char-before start) ?\ )) syntaxes) + (memq (char-syntax (or (char-after end) ?\ )) syntaxes) + (memq (get-text-property start 'face) + '(font-lock-doc-face font-lock-string-face + font-lock-comment-face))) + ;; No composition for you. Let's actually remove any composition + ;; we may have added earlier and which is now incorrect. + (remove-text-properties start end '(composition)) + ;; That's a symbol alright, so add the composition. + (compose-region start end (cdr (assoc (match-string 0) alist))))) + ;; Return nil because we're not adding any face property. + nil) + +(defun sml-font-lock-symbols-keywords () + (when (fboundp 'compose-region) + (let ((alist nil)) + (dolist (x sml-font-lock-symbols-alist) + (when (and (if (fboundp 'char-displayable-p) + (char-displayable-p (cdr x)) + t) + (not (assoc (car x) alist))) ;Not yet in alist. + (push x alist))) + (when alist + `((,(regexp-opt (mapcar 'car alist) t) + (0 (sml-font-lock-compose-symbol ',alist)))))))) + +;; The font lock regular expressions. + +(defconst sml-font-lock-keywords + `(;;(sml-font-comments-and-strings) + (,(concat "\\<\\(fun\\|and\\)\\s-+" sml-tyvarseq-re "\\(\\sw+\\)\\s-+[^ \t\n=]") + (1 font-lock-keyword-face) + (6 font-lock-function-name-face)) + (,(concat "\\<\\(\\(data\\|abs\\|with\\|eq\\)?type\\)\\s-+" sml-tyvarseq-re "\\(\\sw+\\)") + (1 font-lock-keyword-face) + (7 font-lock-type-def-face)) + ("\\<\\(val\\)\\s-+\\(\\sw+\\>\\s-*\\)?\\(\\sw+\\)\\s-*[=:]" + (1 font-lock-keyword-face) + ;;(6 font-lock-variable-def-face nil t) + (3 font-lock-variable-name-face)) + ("\\<\\(structure\\|functor\\|abstraction\\)\\s-+\\(\\sw+\\)" + (1 font-lock-keyword-face) + (2 font-lock-module-def-face)) + ("\\<\\(signature\\)\\s-+\\(\\sw+\\)" + (1 font-lock-keyword-face) + (2 font-lock-interface-def-face)) + + (,sml-keywords-regexp . font-lock-keyword-face) + ,@(sml-font-lock-symbols-keywords)) + "Regexps matching standard SML keywords.") + +(defface font-lock-type-def-face + '((t (:bold t))) + "Font Lock mode face used to highlight type definitions." + :group 'font-lock-highlighting-faces) +(defvar font-lock-type-def-face 'font-lock-type-def-face + "Face name to use for type definitions.") + +(defface font-lock-module-def-face + '((t (:bold t))) + "Font Lock mode face used to highlight module definitions." + :group 'font-lock-highlighting-faces) +(defvar font-lock-module-def-face 'font-lock-module-def-face + "Face name to use for module definitions.") + +(defface font-lock-interface-def-face + '((t (:bold t))) + "Font Lock mode face used to highlight interface definitions." + :group 'font-lock-highlighting-faces) +(defvar font-lock-interface-def-face 'font-lock-interface-def-face + "Face name to use for interface definitions.") + +;; +;; Code to handle nested comments and unusual string escape sequences +;; + +(defvar sml-syntax-prop-table + (let ((st (make-syntax-table))) + (modify-syntax-entry ?\\ "." st) + (modify-syntax-entry ?* "." st) + st) + "Syntax table for text-properties") + +;; For Emacsen that have no built-in support for nested comments +(defun sml-get-depth-st () + (save-excursion + (let* ((disp (if (eq (char-before) ?\)) (progn (backward-char) -1) nil)) + (_ (backward-char)) + (disp (if (eq (char-before) ?\() (progn (backward-char) 0) disp)) + (pt (point))) + (when disp + (let* ((depth + (save-match-data + (if (re-search-backward "\\*)\\|(\\*" nil t) + (+ (or (get-char-property (point) 'comment-depth) 0) + (case (char-after) (?\( 1) (?* 0)) + disp) + 0))) + (depth (if (> depth 0) depth))) + (put-text-property pt (1+ pt) 'comment-depth depth) + (when depth sml-syntax-prop-table)))))) + +(defconst sml-font-lock-syntactic-keywords + `(("^\\s-*\\(\\\\\\)" (1 ',sml-syntax-prop-table)) + ,@(unless sml-builtin-nested-comments-flag + '(("(?\\(\\*\\))?" (1 (sml-get-depth-st))))))) + +(defconst sml-font-lock-defaults + '(sml-font-lock-keywords nil nil ((?_ . "w") (?' . "w")) nil + (font-lock-syntactic-keywords . sml-font-lock-syntactic-keywords))) + + +;;; Indentation with SMIE + +(defvar sml-use-smie t) + +(defconst sml-smie-grammar + (when (fboundp 'smie-prec2->grammar) + ;; We have several problem areas where SML's syntax can't be handled by an + ;; operator precedence grammar: + ;; + ;; "= A before B" is "= A) before B" if this is the + ;; `boolean-=' but it is "= (A before B)" if it's the `definitional-='. + ;; We can work around the problem by tweaking the lexer to return two + ;; different tokens for the two different kinds of `='. + ;; "of A | B" in a "case" we want "of (A | B, but in a `datatype' + ;; we want "of A) | B". + ;; "= A | B" can be "= A ) | B" if the = is from a "fun" definition, + ;; but it is "= (A | B" if it is a `datatype' definition (of course, if + ;; the previous token introducing the = is `and', deciding whether + ;; it's a datatype or a function requires looking even further back). + ;; "functor foo (...) where type a = b = ..." the first `=' looks very much + ;; like a `definitional-=' even tho it's just an equality constraint. + ;; Currently I don't even try to handle `where' at all. + (smie-prec2->grammar + (smie-merge-prec2s + (smie-bnf->prec2 + '((exp ("if" exp "then" exp "else" exp) + ("case" exp "of" branches) + ("let" decls "in" cmds "end") + ("struct" decls "end") + ("sig" decls "end") + (sexp) + (sexp "handle" branches) + ("fn" sexp "=>" exp)) + ;; "simple exp"s are the ones that can appear to the left of `handle'. + (sexp (sexp ":" type) ("(" exps ")") + (sexp "orelse" sexp) + (marg ":>" type) + (sexp "andalso" sexp)) + (cmds (cmds ";" cmds) (exp)) + (exps (exps "," exps) (exp)) ; (exps ";" exps) + (branches (sexp "=>" exp) (branches "|" branches)) + ;; Operator precedence grammars handle separators much better then + ;; starters/terminators, so let's pretend that let/fun are separators. + (decls (sexp "d=" exp) + (sexp "d=" databranches) + (funbranches "|" funbranches) + (sexp "=of" type) ;After "exception". + ;; FIXME: Just like PROCEDURE in Pascal and Modula-2, this + ;; interacts poorly with the other constructs since I + ;; can't make "local" a separator like fun/val/type/... + ("local" decls "in" decls "end") + ;; (decls "local" decls "in" decls "end") + (decls "functor" decls) + (decls "signature" decls) + (decls "structure" decls) + (decls "type" decls) + (decls "open" decls) + (decls "and" decls) + (decls "infix" decls) + (decls "infixr" decls) + (decls "nonfix" decls) + (decls "abstype" decls) + (decls "datatype" decls) + (decls "exception" decls) + (decls "fun" decls) + (decls "val" decls)) + (type (type "->" type) + (type "*" type)) + (funbranches (sexp "d=" exp)) + (databranches (sexp "=of" type) (databranches "d|" databranches)) + ;; Module language. + ;; (mexp ("functor" marg "d=" mexp) + ;; ("structure" marg "d=" mexp) + ;; ("signature" marg "d=" mexp)) + (marg (marg ":" type) (marg ":>" type)) + (toplevel (decls) (exp) (toplevel ";" toplevel))) + ;; '(("local" . opener)) + ;; '((nonassoc "else") (right "handle")) + '((nonassoc "of") (assoc "|")) ; "case a of b => case c of d => e | f" + '((nonassoc "handle") (assoc "|")) ; Idem for "handle". + '((assoc "->") (assoc "*")) + '((assoc "val" "fun" "type" "datatype" "abstype" "open" "infix" "infixr" + "nonfix" "functor" "signature" "structure" "exception" + ;; "local" + ) + (assoc "and")) + '((assoc "orelse") (assoc "andalso") (nonassoc ":")) + '((assoc ";")) '((assoc ",")) '((assoc "d|"))) + + (smie-precs->prec2 + '((nonassoc "andalso") ;To anchor the prec-table. + (assoc "before") ;0 + (assoc ":=" "o") ;3 + (nonassoc ">" ">=" "<>" "<" "<=" "=") ;4 + (assoc "::" "@") ;5 + (assoc "+" "-" "^") ;6 + (assoc "/" "*" "quot" "rem" "div" "mod") ;7 + (nonassoc " -dummy- "))) ;Bogus anchor at the end. + )))) + +(defvar sml-indent-separator-outdent 2) + +(defun sml-smie-rules (kind token) + ;; I much preferred the pcase version of the code, especially while + ;; edebugging the code. But that will have to wait until we get rid of + ;; support for Emacs-23. + (case kind + (:elem (case token + (basic sml-indent-level) + (args sml-indent-args))) + (:list-intro (member token '("fn"))) + (:after + (cond + ((equal token "struct") 0) + ((equal token "=>") (if (smie-rule-hanging-p) 0 2)) + ((equal token "in") (if (smie-rule-parent-p "local") 0)) + ((equal token "of") 3) + ((member token '("(" "{" "[")) (if (not (smie-rule-hanging-p)) 2)) + ((equal token "else") (if (smie-rule-hanging-p) 0)) ;; (:next "if" 0) + ((member token '("|" "d|" ";" ",")) (smie-rule-separator kind)) + ((equal token "d=") + (if (and (smie-rule-parent-p "val") (smie-rule-next-p "fn")) -3)))) + (:before + (cond + ((equal token "=>") (if (smie-rule-parent-p "fn") 3)) + ((equal token "of") 1) + ;; In case the language is extended to allow a | directly after of. + ((and (equal token "|") (smie-rule-prev-p "of")) 1) + ((member token '("|" "d|" ";" ",")) (smie-rule-separator kind)) + ;; Treat purely syntactic block-constructs as being part of their parent, + ;; when the opening statement is hanging. + ((member token '("let" "(" "[" "{")) + (if (smie-rule-hanging-p) (smie-rule-parent))) + ;; Treat if ... else if ... as a single long syntactic construct. + ;; Similarly, treat fn a => fn b => ... as a single construct. + ((member token '("if" "fn")) + (and (not (smie-rule-bolp)) + (smie-rule-prev-p (if (equal token "if") "else" "=>")) + (smie-rule-parent))) + ((equal token "and") + ;; FIXME: maybe "and" (c|sh)ould be handled as an smie-separator. + (cond + ((smie-rule-parent-p "datatype") (if sml-rightalign-and 5 0)) + ((smie-rule-parent-p "fun" "val") 0))) + ((equal token "d=") + (cond + ((smie-rule-parent-p "datatype") (if (smie-rule-bolp) 2)) + ((smie-rule-parent-p "structure" "signature") 0))) + ;; Indent an expression starting with "local" as if it were starting + ;; with "fun". + ((equal token "local") (smie-indent-keyword "fun")) + ;; FIXME: type/val/fun/... are separators but "local" is not, even though + ;; it appears in the same list. Try to fix up the problem by hand. + ;; ((or (equal token "local") + ;; (equal (cdr (assoc token smie-grammar)) + ;; (cdr (assoc "fun" smie-grammar)))) + ;; (let ((parent (save-excursion (smie-backward-sexp)))) + ;; (when (or (and (equal (nth 2 parent) "local") + ;; (null (car parent))) + ;; (progn + ;; (setq parent (save-excursion (smie-backward-sexp "fun"))) + ;; (eq (car parent) (nth 1 (assoc "fun" smie-grammar))))) + ;; (goto-char (nth 1 parent)) + ;; (cons 'column (smie-indent-virtual))))) + )))) + +(defun sml-smie-definitional-equal-p () + "Figure out which kind of \"=\" this is. +Assumes point is right before the = sign." + ;; The idea is to look backward for the first occurrence of a token that + ;; requires a definitional "=" and then see if there's such a definitional + ;; equal between that token and ourselves (in which case we're not + ;; a definitional = ourselves). + ;; The "search for =" is naive and will match "=>" and "<=", but it turns + ;; out to be OK in practice because such tokens very rarely (if ever) appear + ;; between the =-starter and the corresponding definitional equal. + ;; One known problem case is code like: + ;; "functor foo (structure s : S) where type t = s.t =" + ;; where the "type t = s.t" is mistaken for a type definition. + (let ((re (concat "\\(" sml-=-starter-re "\\)\\|="))) + (save-excursion + (and (re-search-backward re nil t) + (or (match-beginning 1) + ;; If we first hit a "=", then that = is probably definitional + ;; and we're an equality, but not necessarily. One known + ;; problem case is code like: + ;; "functor foo (structure s : S) where type t = s.t =" + ;; where the first = is more like an equality (tho it doesn't + ;; matter much) and the second is definitional. + ;; + ;; FIXME: The test below could be used to recognize that the + ;; second = is not a mere equality, but that's not enough to + ;; parse the construct properly: we'd need something + ;; like a third kind of = token for structure definitions, in + ;; order for the parser to be able to skip the "type t = s.t" + ;; as a sub-expression. + ;; + ;; (and (not (looking-at "=>")) + ;; (not (eq ?< (char-before))) ;Not a <= + ;; (re-search-backward re nil t) + ;; (match-beginning 1) + ;; (equal "type" (buffer-substring (- (match-end 1) 4) + ;; (match-end 1)))) + ))))) + +(defun sml-smie-non-nested-of-p () + ;; FIXME: Maybe datatype-|-p makes this nested-of business unnecessary. + "Figure out which kind of \"of\" this is. +Assumes point is right before the \"of\" symbol." + (save-excursion + (and (re-search-backward (concat "\\(" sml-non-nested-of-starter-re + "\\)\\|\\<case\\>") nil t) + (match-beginning 1)))) + +(defun sml-smie-datatype-|-p () + "Figure out which kind of \"|\" this is. +Assumes point is right before the | symbol." + (save-excursion + (forward-char 1) ;Skip the |. + (let ((after-type-def + '("|" "of" "in" "datatype" "and" "exception" "abstype" "infix" + "infixr" "nonfix" "local" "val" "fun" "structure" "functor" + "signature"))) + (or (member (sml-smie-forward-token-1) after-type-def) ;Skip the tag. + (member (sml-smie-forward-token-1) after-type-def))))) + +(defun sml-smie-forward-token-1 () + (forward-comment (point-max)) + (buffer-substring-no-properties + (point) + (progn + (or (/= 0 (skip-syntax-forward "'w_")) + (skip-syntax-forward ".'")) + (point)))) + +(defun sml-smie-forward-token () + (let ((sym (sml-smie-forward-token-1))) + (cond + ((equal "op" sym) + (concat "op " (sml-smie-forward-token-1))) + ((member sym '("|" "of" "=")) + ;; The important lexer for indentation's performance is the backward + ;; lexer, so for the forward lexer we delegate to the backward one. + (save-excursion (sml-smie-backward-token))) + (t sym)))) + +(defun sml-smie-backward-token-1 () + (forward-comment (- (point))) + (buffer-substring-no-properties + (point) + (progn + (or (/= 0 (skip-syntax-backward ".'")) + (skip-syntax-backward "'w_")) + (point)))) + +(defun sml-smie-backward-token () + (let ((sym (sml-smie-backward-token-1))) + (unless (zerop (length sym)) + ;; FIXME: what should we do if `sym' = "op" ? + (let ((point (point))) + (if (equal "op" (sml-smie-backward-token-1)) + (concat "op " sym) + (goto-char point) + (cond + ((string= sym "=") (if (sml-smie-definitional-equal-p) "d=" "=")) + ((string= sym "of") (if (sml-smie-non-nested-of-p) "=of" "of")) + ((string= sym "|") (if (sml-smie-datatype-|-p) "d|" "|")) + (t sym))))))) + +;;;; +;;;; Imenu support +;;;; + +(defvar sml-imenu-regexp + (concat "^[ \t]*\\(let[ \t]+\\)?" + (regexp-opt (append sml-module-head-syms + '("and" "fun" "datatype" "abstype" "type")) t) + "\\>")) + +(defun sml-imenu-create-index () + (let (alist) + (goto-char (point-max)) + (while (re-search-backward sml-imenu-regexp nil t) + (save-excursion + (let ((kind (match-string 2)) + (column (progn (goto-char (match-beginning 2)) (current-column))) + (location + (progn (goto-char (match-end 0)) + (forward-comment (point-max)) + (when (looking-at sml-tyvarseq-re) + (goto-char (match-end 0))) + (point))) + (name (sml-smie-forward-token))) + ;; Eliminate trivial renamings. + (when (or (not (member kind '("structure" "signature"))) + (progn (search-forward "=") + (forward-comment (point-max)) + (looking-at "sig\\|struct"))) + (push (cons (concat (make-string (/ column 2) ?\ ) name) location) + alist))))) + alist)) + +;;; MORE CODE FOR SML-MODE + +;;;###autoload +(add-to-list 'auto-mode-alist '("\\.s\\(ml\\|ig\\)\\'" . sml-mode)) + +(unless (fboundp 'prog-mode) (defalias 'prog-mode 'fundamental-mode)) +(defvar comment-quote-nested) +(defvar electric-indent-chars) +(defvar electric-layout-rules) + +;;;###autoload +(define-derived-mode sml-mode prog-mode "SML" + "\\<sml-mode-map>Major mode for editing ML code. +This mode runs `sml-mode-hook' just before exiting. +\\{sml-mode-map}" + (set (make-local-variable 'font-lock-defaults) sml-font-lock-defaults) + (set (make-local-variable 'outline-regexp) sml-outline-regexp) + (set (make-local-variable 'imenu-create-index-function) + 'sml-imenu-create-index) + (set (make-local-variable 'add-log-current-defun-function) + 'sml-current-fun-name) + ;; Treat paragraph-separators in comments as paragraph-separators. + (set (make-local-variable 'paragraph-separate) + (concat "\\([ \t]*\\*)?\\)?\\(" paragraph-separate "\\)")) + (set (make-local-variable 'require-final-newline) t) + (set (make-local-variable 'electric-indent-chars) + (cons ?\; (if (boundp 'electric-indent-chars) + electric-indent-chars '(?\n)))) + (set (make-local-variable 'electric-layout-rules) + `((?\; . ,(lambda () + (save-excursion + (skip-chars-backward " \t;") + (unless (or (bolp) + (progn (skip-chars-forward " \t;") + (eolp))) + 'after)))))) + ;; For XEmacs + (easy-menu-add sml-mode-menu) + ;; Compatibility. FIXME: we should use `-' in Emacs-CVS. + (unless (boundp 'skeleton-positions) (set (make-local-variable '@) nil)) + (sml-mode-variables)) + +(defun sml-mode-variables () + (set-syntax-table sml-mode-syntax-table) + (setq local-abbrev-table sml-mode-abbrev-table) + ;; Setup indentation and sexp-navigation. + (when (fboundp 'smie-setup) + (smie-setup sml-smie-grammar #'sml-smie-rules + :backward-token #'sml-smie-backward-token + :forward-token #'sml-smie-forward-token)) + (unless (and sml-use-smie (fboundp 'smie-setup)) + (set (make-local-variable 'forward-sexp-function) 'sml-user-forward-sexp) + (set (make-local-variable 'indent-line-function) 'sml-indent-line)) + (set (make-local-variable 'parse-sexp-ignore-comments) t) + (set (make-local-variable 'comment-start) "(* ") + (set (make-local-variable 'comment-end) " *)") + (set (make-local-variable 'comment-start-skip) "(\\*+\\s-*") + (set (make-local-variable 'comment-end-skip) "\\s-*\\*+)") + ;; No need to quote nested comments markers. + (set (make-local-variable 'comment-quote-nested) nil)) + +(defun sml-funname-of-and () + "Name of the function this `and' defines, or nil if not a function. +Point has to be right after the `and' symbol and is not preserved." + (forward-comment (point-max)) + (if (looking-at sml-tyvarseq-re) (goto-char (match-end 0))) + (let ((sym (sml-smie-forward-token))) + (forward-comment (point-max)) + (unless (or (member sym '(nil "d=")) + (member (sml-smie-forward-token) '("d="))) + sym))) + +(defun sml-find-forward (re) + (while (progn (forward-comment (point-max)) + (not (looking-at re))) + (or (ignore-errors (forward-sexp 1) t) (forward-char 1)))) + +(defun sml-electric-pipe () + "Insert a \"|\". +Depending on the context insert the name of function, a \"=>\" etc." + ;; FIXME: Make it a skeleton. + (interactive) + (unless (save-excursion (skip-chars-backward "\t ") (bolp)) (insert "\n")) + (insert "| ") + (let ((text + (save-excursion + (backward-char 2) ;back over the just inserted "| " + (let ((sym (sml-find-matching-starter sml-pipeheads + ;; (sml-op-prec "|" 'back) + ))) + (sml-smie-forward-token) + (forward-comment (point-max)) + (cond + ((string= sym "|") + (let ((f (sml-smie-forward-token))) + (sml-find-forward "\\(=>\\|=\\||\\)\\S.") + (cond + ((looking-at "|") "") ;probably a datatype + ((looking-at "=>") " => ") ;`case', or `fn' or `handle' + ((looking-at "=") (concat f " = "))))) ;a function + ((string= sym "and") + ;; could be a datatype or a function + (setq sym (sml-funname-of-and)) + (if sym (concat sym " = ") "")) + ;; trivial cases + ((string= sym "fun") + (while (and (setq sym (sml-smie-forward-token)) + (string-match "^'" sym)) + (forward-comment (point-max))) + (concat sym " = ")) + ((member sym '("case" "handle" "fn" "of")) " => ") + ;;((member sym '("abstype" "datatype")) "") + (t "")))))) + + (insert text) + (indent-according-to-mode) + (beginning-of-line) + (skip-chars-forward "\t |") + (skip-syntax-forward "w") + (skip-chars-forward "\t ") + (when (eq ?= (char-after)) (backward-char)))) + +(defun sml-electric-semi () + "Insert a \;. +If variable `sml-electric-semi-mode' is t, indent the current line, insert +a newline, and indent." + (interactive) + (self-insert-command 1) + (if sml-electric-semi-mode + (reindent-then-newline-and-indent))) + +;;; Misc + +(defun sml-mark-function () + "Mark the surrounding function. Or try to at least." + (interactive) + (if (not (fboundp 'smie-setup)) + (mark-paragraph) + ;; FIXME: Provide beginning-of-defun-function so mark-defun "just works". + (let ((start (point))) + (sml-beginning-of-defun) + (let ((beg (point))) + (smie-forward-sexp 'halfsexp) + (if (or (< start beg) (> start (point))) + (progn + (goto-char start) + (mark-paragraph)) + (push-mark nil t t) + (goto-char beg)))))) + +(defun sml-back-to-outer-indent () + "Unindents to the next outer level of indentation." + (interactive) + (save-excursion + (beginning-of-line) + (skip-chars-forward "\t ") + (let ((start-column (current-column)) + (indent (current-column))) + (if (> start-column 0) + (progn + (save-excursion + (while (>= indent start-column) + (if (re-search-backward "^[^\n]" nil t) + (setq indent (current-indentation)) + (setq indent 0)))) + (backward-delete-char-untabify (- start-column indent))))))) + +(defun sml-smie-find-matching-starter (syms) + (let ((halfsexp nil) + tok) + ;;(sml-smie-forward-token) + (while (not (or (bobp) + (member (nth 2 (setq tok (smie-backward-sexp halfsexp))) + syms))) + (cond + ((null (car tok)) nil) + ((numberp (car tok)) (setq halfsexp 'half)) + (t (goto-char (cadr tok))))) + (if (nth 2 tok) (goto-char (cadr tok))) + (nth 2 tok))) + +(defun sml-find-matching-starter (syms) + (cond + ((and sml-use-smie (fboundp 'smie-backward-sexp)) + (sml-smie-find-matching-starter syms)) + ((fboundp 'sml-old-find-matching-starter) + (sml-old-find-matching-starter syms)))) + +(defun sml-smie-skip-siblings () + (let (tok) + (while (and (not (bobp)) + (progn (setq tok (smie-backward-sexp 'half)) + (cond + ((null (car tok)) t) + ((numberp (car tok)) t) + (t nil))))) + (if (nth 2 tok) (goto-char (cadr tok))) + (nth 2 tok))) + +(defun sml-skip-siblings () + (cond + ((and sml-use-smie (fboundp 'smie-backward-sexp)) + (sml-smie-skip-siblings)) + ((fboundp 'sml-old-skip-siblings) + (sml-old-skip-siblings)) + (t (up-list -1)))) + +(defun sml-beginning-of-defun () + (let ((sym (sml-find-matching-starter sml-starters-syms))) + (if (member sym '("fun" "and" "functor" "signature" "structure" + "abstraction" "datatype" "abstype")) + (save-excursion (sml-smie-forward-token) (forward-comment (point-max)) + (sml-smie-forward-token)) + ;; We're inside a "non function declaration": let's skip all other + ;; declarations that we find at the same level and try again. + (sml-skip-siblings) + ;; Obviously, let's not try again if we're at bobp. + (unless (bobp) (sml-beginning-of-defun))))) + +(defcustom sml-max-name-components 3 + "Maximum number of components to use for the current function name." + :type 'integer) + +(defun sml-current-fun-name () + (save-excursion + (let ((count sml-max-name-components) + fullname name) + (end-of-line) + (while (and (> count 0) + (setq name (sml-beginning-of-defun))) + (decf count) + (setq fullname (if fullname (concat name "." fullname) name)) + ;; Skip all other declarations that we find at the same level. + (sml-skip-siblings)) + fullname))) + + +;;; INSERTING PROFORMAS (COMMON SML-FORMS) + +(defvar sml-forms-alist nil + "*Alist of code templates. +You can extend this alist to your heart's content. For each additional +template NAME in the list, declare a keyboard macro or function (or +interactive command) called 'sml-form-NAME'. +If 'sml-form-NAME' is a function it takes no arguments and should +insert the template at point\; if this is a command it may accept any +sensible interactive call arguments\; keyboard macros can't take +arguments at all. Apropos keyboard macros, see `name-last-kbd-macro' +and `sml-addto-forms-alist'. +`sml-forms-alist' understands let, local, case, abstype, datatype, +signature, structure, and functor by default.") + +(defmacro sml-def-skeleton (name interactor &rest elements) + (when (fboundp 'define-skeleton) + (let ((fsym (intern (concat "sml-form-" name)))) + ;; TODO: don't do the expansion in comments and strings. + `(progn + (add-to-list 'sml-forms-alist ',(cons name fsym)) + (condition-case err + ;; Try to use the new `system' flag. + (define-abbrev sml-mode-abbrev-table ,name "" ',fsym nil 'system) + (wrong-number-of-arguments + (define-abbrev sml-mode-abbrev-table ,name "" ',fsym))) + (when (fboundp 'abbrev-put) + (let ((abbrev (abbrev-symbol ,name sml-mode-abbrev-table))) + (abbrev-put abbrev :case-fixed t) + (abbrev-put abbrev :enable-function + (lambda () (not (nth 8 (syntax-ppss))))))) + (define-skeleton ,fsym + ,(format "SML-mode skeleton for `%s..' expressions" name) + ,interactor + ,(concat name " ") > + ,@elements))))) +(put 'sml-def-skeleton 'lisp-indent-function 2) + +(sml-def-skeleton "let" nil + @ "\nin " > _ "\nend" >) + +(sml-def-skeleton "if" nil + @ " then " > _ "\nelse " > _) + +(sml-def-skeleton "local" nil + @ "\nin" > _ "\nend" >) + +(sml-def-skeleton "case" "Case expr: " + str "\nof " > _ " => ") + +(sml-def-skeleton "signature" "Signature name: " + str " =\nsig" > "\n" > _ "\nend" >) + +(sml-def-skeleton "structure" "Structure name: " + str " =\nstruct" > "\n" > _ "\nend" >) + +(sml-def-skeleton "functor" "Functor name: " + str " () : =\nstruct" > "\n" > _ "\nend" >) + +(sml-def-skeleton "datatype" "Datatype name and type params: " + str " =" \n) + +(sml-def-skeleton "abstype" "Abstype name and type params: " + str " =" \n _ "\nwith" > "\nend" >) + +;; + +(sml-def-skeleton "struct" nil + _ "\nend" >) + +(sml-def-skeleton "sig" nil + _ "\nend" >) + +(sml-def-skeleton "val" nil + @ " = " > _) + +(sml-def-skeleton "fn" nil + @ " =>" > _) + +(sml-def-skeleton "fun" nil + @ " =" > _) + +;; + +(defun sml-forms-menu (menu) + (mapcar (lambda (x) (vector (car x) (cdr x) t)) + sml-forms-alist)) + +(defvar sml-last-form "let") + +(defun sml-electric-space () + "Expand a symbol into an SML form, or just insert a space. +If the point directly precedes a symbol for which an SML form exists, +the corresponding form is inserted." + (interactive) + (let ((abbrev-mode (not abbrev-mode)) + (last-command-event ?\ ) + ;; Bind `this-command' to fool skeleton's special abbrev handling. + (this-command 'self-insert-command)) + (call-interactively 'self-insert-command))) + +(defun sml-insert-form (name newline) + "Interactive short-cut to insert the NAME common ML form. +If a prefix argument is given insert a NEWLINE and indent first, or +just move to the proper indentation if the line is blank\; otherwise +insert at point (which forces indentation to current column). + +The default form to insert is 'whatever you inserted last time' +\(just hit return when prompted\)\; otherwise the command reads with +completion from `sml-forms-alist'." + (interactive + (list (completing-read + (format "Form to insert: (default %s) " sml-last-form) + sml-forms-alist nil t nil) + current-prefix-arg)) + ;; default is whatever the last insert was... + (if (string= name "") (setq name sml-last-form) (setq sml-last-form name)) + (unless (or (not newline) + (save-excursion (beginning-of-line) (looking-at "\\s-*$"))) + (insert "\n")) + (unless (/= ?w (char-syntax (preceding-char))) (insert " ")) + (let ((f (cdr (assoc name sml-forms-alist)))) + (cond + ((commandp f) (command-execute f)) + (f (funcall f)) + (t (error "Undefined form: %s" name))))) + +;; See also macros.el in emacs lisp dir. + +(defun sml-addto-forms-alist (name) + "Assign a name to the last keyboard macro defined. +Argument NAME is transmogrified to sml-form-NAME which is the symbol +actually defined. + +The symbol's function definition becomes the keyboard macro string. + +If that works, NAME is added to `sml-forms-alist' so you'll be able to +reinvoke the macro through \\[sml-insert-form]. You might want to save +the macro to use in a later editing session -- see `insert-kbd-macro' +and add these macros to your .emacs file. + +See also `edit-kbd-macro' which is bound to \\[edit-kbd-macro]." + (interactive "sName for last kbd macro (\"sml-form-\" will be added): ") + (when (string= name "") (error "No command name given")) + (let ((fsym (intern (concat "sml-form-" name)))) + (name-last-kbd-macro fsym) + (message "Macro bound to %s" fsym) + (add-to-list 'sml-forms-alist (cons name fsym)))) + +;;; +;;; MLton support +;;; + +(defvar sml-mlton-command "mlton" + "Command to run MLton. Can include arguments.") + +(defvar sml-mlton-mainfile nil) + +(defconst sml-mlton-error-regexp-alist + ;; I wish they just changed MLton to use one of the standard + ;; error formats. + `(("^\\(?:Error\\|\\(Warning\\)\\): \\(.+\\) \\([0-9]+\\)\\.\\([0-9]+\\)\\.$" + 2 3 4 + ;; If subgroup 1 matched, then it's a warning, otherwise it's an error. + ,@(if (fboundp 'compilation-fake-loc) '((1)))))) + +(defvar compilation-error-regexp-alist) +(eval-after-load "compile" + '(dolist (x sml-mlton-error-regexp-alist) + (add-to-list 'compilation-error-regexp-alist x))) + +(defun sml-mlton-typecheck (mainfile) + "typecheck using MLton." + (interactive + (list (if (and mainfile (not current-prefix-arg)) + mainfile + (read-file-name "Main file: ")))) + (save-some-buffers) + (require 'compile) + (dolist (x sml-mlton-error-regexp-alist) + (add-to-list 'compilation-error-regexp-alist x)) + (with-current-buffer (find-file-noselect mainfile) + (compile (concat sml-mlton-command + " -stop tc " ;Stop right after type checking. + (shell-quote-argument + (file-relative-name buffer-file-name)))))) + +;;; +;;; MLton's def-use info. +;;; + +(defvar sml-defuse-file nil) + +(defun sml-defuse-file () + (or sml-defuse-file (sml-defuse-set-file))) + +(defun sml-defuse-set-file () + "Specify the def-use file to use." + (interactive) + (setq sml-defuse-file (read-file-name "Def-use file: "))) + +(defun sml-defuse-symdata-at-point () + (save-excursion + (sml-smie-forward-token) + (let ((symname (sml-smie-backward-token))) + (if (equal symname "op") + (save-excursion (setq symname (sml-smie-forward-token)))) + (when (string-match "op " symname) + (setq symname (substring symname (match-end 0))) + (forward-word) + (forward-comment (point-max))) + (list symname + ;; Def-use files seem to count chars, not columns. + ;; We hope here that they don't actually count bytes. + ;; Also they seem to start counting at 1. + (1+ (- (point) (progn (beginning-of-line) (point)))) + (save-restriction + (widen) (1+ (count-lines (point-min) (point)))) + buffer-file-name)))) + +(defconst sml-defuse-def-regexp + "^[[:alpha:]]+ \\([^ \n]+\\) \\(.+\\) \\([0-9]+\\)\\.\\([0-9]+\\)$") +(defconst sml-defuse-use-regexp-format "^ %s %d\\.%d $") + +(defun sml-defuse-jump-to-def () + "Jump to the definition corresponding to the symbol at point." + (interactive) + (let ((symdata (sml-defuse-symdata-at-point))) + (if (null (car symdata)) + (error "Not on a symbol") + (with-current-buffer (find-file-noselect (sml-defuse-file)) + (goto-char (point-min)) + (unless (re-search-forward + (format sml-defuse-use-regexp-format + (concat "\\(?:" + ;; May be an absolute file name. + (regexp-quote (nth 3 symdata)) + "\\|" + ;; Or a relative file name. + (regexp-quote (file-relative-name + (nth 3 symdata))) + "\\)") + (nth 2 symdata) + (nth 1 symdata)) + nil t) + ;; FIXME: This is typically due to editing: any minor editing will + ;; mess everything up. We should try to fail more gracefully. + (error "Def-use info not found")) + (unless (re-search-backward sml-defuse-def-regexp nil t) + ;; This indicates a bug in this code. + (error "Internal failure while looking up def-use")) + (unless (equal (match-string 1) (nth 0 symdata)) + ;; FIXME: This again is most likely due to editing. + (error "Incoherence in the def-use info found")) + (let ((line (string-to-number (match-string 3))) + (char (string-to-number (match-string 4)))) + (pop-to-buffer (find-file-noselect (match-string 2))) + (goto-char (point-min)) + (forward-line (1- line)) + (forward-char (1- char))))))) + +;;; +;;; SML/NJ's Compilation Manager support +;;; + +(defvar sml-cm-mode-syntax-table sml-mode-syntax-table) +(defvar sml-cm-font-lock-keywords + `(,(concat "\\<" (regexp-opt '("library" "group" "is" "structure" + "functor" "signature" "funsig") t) + "\\>"))) +;;;###autoload +(add-to-list 'completion-ignored-extensions ".cm/") +;; This was used with the old compilation manager. +(add-to-list 'completion-ignored-extensions "CM/") +;;;###autoload +(add-to-list 'auto-mode-alist '("\\.cm\\'" . sml-cm-mode)) +;;;###autoload +(define-derived-mode sml-cm-mode fundamental-mode "SML-CM" + "Major mode for SML/NJ's Compilation Manager configuration files." + (local-set-key "\C-c\C-c" 'sml-compile) + (set (make-local-variable 'font-lock-defaults) + '(sml-cm-font-lock-keywords nil t nil nil))) + +;;; +;;; ML-Lex support +;;; + +(defvar sml-lex-font-lock-keywords + (append + '(("^%\\sw+" . font-lock-builtin-face) + ("^%%" . font-lock-module-def-face)) + sml-font-lock-keywords)) +(defconst sml-lex-font-lock-defaults + (cons 'sml-lex-font-lock-keywords (cdr sml-font-lock-defaults))) + +;;;###autoload +(define-derived-mode sml-lex-mode sml-mode "SML-Lex" + "Major Mode for editing ML-Lex files." + (set (make-local-variable 'font-lock-defaults) sml-lex-font-lock-defaults)) + +;;; +;;; ML-Yacc support +;;; + +(defface sml-yacc-bnf-face + '((t (:foreground "darkgreen"))) + "Face used to highlight (non)terminals in `sml-yacc-mode'.") +(defvar sml-yacc-bnf-face 'sml-yacc-bnf-face) + +(defcustom sml-yacc-indent-action 16 + "Indentation column of the opening paren of actions." + :type 'integer) + +(defcustom sml-yacc-indent-pipe nil + "Indentation column of the pipe char in the BNF. +If nil, align it with `:' or with previous cases." + :type 'integer) + +(defcustom sml-yacc-indent-term nil + "Indentation column of the (non)term part. +If nil, align it with previous cases." + :type 'integer) + +(defvar sml-yacc-font-lock-keywords + (cons '("^\\(\\sw+\\s-*:\\|\\s-*|\\)\\(\\s-*\\sw+\\)*\\s-*\\(\\(%\\sw+\\)\\s-+\\sw+\\|\\)" + (0 (save-excursion + (save-match-data + (goto-char (match-beginning 0)) + (unless (or (re-search-forward "\\<of\\>" (match-end 0) 'move) + (progn (forward-comment (point-max)) + (not (looking-at "(")))) + sml-yacc-bnf-face)))) + (4 font-lock-builtin-face t t)) + sml-lex-font-lock-keywords)) +(defconst sml-yacc-font-lock-defaults + (cons 'sml-yacc-font-lock-keywords (cdr sml-font-lock-defaults))) + +(defun sml-yacc-indent-line () + "Indent current line of ML-Yacc code." + (let ((savep (> (current-column) (current-indentation))) + (indent (max (or (ignore-errors (sml-yacc-indentation)) 0) 0))) + (if savep + (save-excursion (indent-line-to indent)) + (indent-line-to indent)))) + +(defun sml-yacc-indentation () + (save-excursion + (back-to-indentation) + (or (and (looking-at "%\\|\\(\\sw\\|\\s_\\)+\\s-*:") 0) + (when (save-excursion + (condition-case nil (progn (up-list -1) nil) (scan-error t))) + ;; We're outside an action. + (cond + ;; Special handling of indentation inside %term and %nonterm + ((save-excursion + (and (re-search-backward "^%\\(\\sw+\\)" nil t) + (member (match-string 1) '("term" "nonterm")))) + (if (numberp sml-yacc-indent-term) sml-yacc-indent-term + (let ((offset (if (looking-at "|") -2 0))) + (forward-line -1) + (looking-at "\\s-*\\(%\\sw*\\||\\)?\\s-*") + (goto-char (match-end 0)) + (+ offset (current-column))))) + ((looking-at "(") sml-yacc-indent-action) + ((looking-at "|") + (if (numberp sml-yacc-indent-pipe) sml-yacc-indent-pipe + (backward-sexp 1) + (while (progn (forward-comment (- (point))) + (/= 0 (skip-syntax-backward "w_")))) + (forward-comment (- (point))) + (if (not (looking-at "\\s-$")) + (1- (current-column)) + (skip-syntax-forward " ") + (- (current-column) 2)))))) + ;; default to SML rules + (cond + ((and sml-use-smie (fboundp 'smie-indent-calculate)) + (smie-indent-calculate)) + ((fboundp 'sml-calculate-indentation) (sml-calculate-indentation)))))) + +;;;###autoload +(add-to-list 'auto-mode-alist '("\\.grm\\'" . sml-yacc-mode)) +;;;###autoload +(define-derived-mode sml-yacc-mode sml-mode "SML-Yacc" + "Major Mode for editing ML-Yacc files." + (set (make-local-variable 'indent-line-function) 'sml-yacc-indent-line) + (set (make-local-variable 'font-lock-defaults) sml-yacc-font-lock-defaults)) + +(provide 'sml-mode) + +(unless (and sml-use-smie (fboundp 'smie-setup)) + (require 'sml-oldindent)) + +;;; sml-mode.el ends here diff --git a/emacs/emacs.d/sml-mode-5.0/sml-mode.info b/emacs/emacs.d/sml-mode-5.0/sml-mode.info @@ -0,0 +1,908 @@ +This is sml-mode.info, produced by makeinfo version 4.13 from +sml-mode.texi. + +INFO-DIR-SECTION Emacs +START-INFO-DIR-ENTRY +* sml:(sml-mode). Emacs mode for editing SML +END-INFO-DIR-ENTRY + + +File: sml-mode.info, Node: Top, Next: Copying, Prev: (dir), Up: (dir) + +1 SML Mode Info +*************** + +You are looking at the top node of the Info tree documenting SML-MODE +(Version $Name$). Not all functions are documented here, but those that +aren't you probably won't miss. All commands and settable variables +have built-in documentation, as per usual Emacs conventions. + +* Menu: + +* Copying:: You can copy SML mode +* Introduction:: Setting things up +* SML Mode:: Editing SML source +* Interaction Mode:: Running ML processes +* Configuration:: Menus, highlighting, setting defaults + +Indexes +* Command Index:: Commands you can invoke +* Variable Index:: Variables you can set +* Key Index:: Default keybindings + +Introduction +* Contributors:: Who did what +* Getting Started:: What to tell Emacs +* Getting Help:: How Emacs can help + +SML Mode +* Basics:: On entering SML mode +* Indentation:: Prettying SML text +* Magic Insertion:: Templates and electric keys +* SML Mode Defaults:: Variables controlling indentation + +Interaction Mode +* Running ML:: Commands to run the ML compiler in a buffer +* ML Interaction:: Sending program fragments to the compiler +* Tracking Errors:: Finding reported syntax errors +* Process Defaults:: Setting defaults for process interaction + +Configuration +* Hooks:: Creating hooks +* Key Bindings:: Binding commands to keys +* Highlighting:: Syntax colouring +* Advanced Topics:: You may need to speak Emacs Lisp + + +File: sml-mode.info, Node: Copying, Next: Introduction, Prev: Top, Up: Top + +2 Copying +********* + +You can freely copy, modify and redistribute SML mode because it's made +available under the liberal terms of the GNU General Public License. + + GNU General Public License as published by the Free Software +Foundation; either version 3, or (at your option) any later version. + + SML mode is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General +Public License for more details. + + You should have received a copy of the GNU General Public License +along with GNU Emacs; see the file COPYING. If not, write to the Free +Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + + +File: sml-mode.info, Node: Introduction, Next: SML Mode, Prev: Copying, Up: Top + +3 Introduction +************** + +SML mode is a major mode for Emacs for editing Standard ML. It has some +novel bugs, and some nice features: + + * Automatic indentation of sml code--a number of variables to + customise the indentation. + + * Easy insertion for commonly used templates like let, local, + signature, and structure declarations, with minibuffer prompting + for types and expressions. + + * Magic pipe insertion: `|' automatically determines if it is used + in a case or fun construct, and indents the next line as + appropriate, inserting `=>' or the name of the function. + + * Inferior shell for running ML. There's no need to leave Emacs, + just keep on editing while the compiler runs in another window. + + * Automatic "use file" in the inferior shell--you can send files, + buffers, or regions of code to the ML subprocess. + + * Menus, and syntax and keyword highlighting supported for Emacs 19 + and derivatives. + + * Parsing errors from the inferior shell, and repositioning the + source with next-error--just like in c-mode. + + * SML mode can be easily configured to work with a number of Standard + ML compilers, and other SML based tools. + +* Menu: + +* Contributors:: Who did what +* Getting Started:: What to tell Emacs +* Getting Help:: How Emacs can help + + +File: sml-mode.info, Node: Contributors, Next: Getting Started, Prev: Introduction, Up: Introduction + +3.1 Contributors to the SML mode +================================ + +Contributions to the package are welcome. I have limited time to work +on this project, but I will gladly add any code that you contribute to +me to this package. + + Although the history of sml-mode is obscure, it seems that the +following persons have made contributions to sml-mode: + + * Lars Bo Nielsen wrote the original version of the code, providing + the sml editing mode and the inferior-sml support. + + * Olin Shivers (`shivers@ai.mit.edu') hacked the inferior-sml support + to use comint and call the whole thing ml-mode. + + * Steven Gilmore supposedly provided some early attempt at menubar + support. + + * Matthew J. Morley (`matthew@verisity.com') was maintainer for a + long time (until version 3.4) and provided many additions and + fixes in all areas. + + * Frederick Knabe (`knabe@ecrc.de') provided the original code for + font-lock and hilite support as well as for proper handling of + nested comments and of all the string escape sequences. + + * Matthias Blume (`blume@kurims.kyoto-u.ac.jp') provided a sml-make + which was replaced by sml-compile. + + * Monnier Stefan (`monnier@iro.umontreal.ca') completely reworked the + indentation engine as well as most of the rest of the code and is + the current maintainer since after version 3.4. + + + +File: sml-mode.info, Node: Getting Started, Next: Getting Help, Prev: Contributors, Up: Introduction + +3.2 Getting started +=================== + +With luck your system administrator will have installed SML mode +somewhere convenient, so it will just magically all work--you can skip +the rest of this getting started section. Otherwise you will need to +tell Emacs where to find all the SML mode `.el' files, and when to use +them. The where is addressed by locating the Lisp code on your Emacs +Lisp load path--you may have to create a directory for this, say +`/home/mjm/elisp', and then insert the following lines in your +`/home/mjm/.emacs' file: + + (add-to-list 'load-path "/home/mjm/elisp") + (autoload 'sml-mode "sml-mode" "Major mode for editing SML." t) + (autoload 'run-sml "sml-proc" "Run an inferior SML process." t) + +The first line adjusts Emacs' internal search path so it can locate the +Lisp source you have copied to that directory; the second and third +lines tell Emacs to load the code automatically when it is needed. You +can then switch any Emacs buffer into SML mode by entering the command + + M-x sml-mode + +It is usually more convenient to have Emacs automatically place the +buffer in SML mode whenever you visit a file containing ML programs. +The simplest way of achieving this is to put something like + + (add-to-list 'auto-mode-alist '("\\.\\(sml\\|sig\\)\\'" . sml-mode)) + +also in your `.emacs' file. Subsequently (after a restart), any files +with these extensions will be placed in SML mode buffers when you visit +them. + + You may want to pre-compile the `sml-*.el' files (`M-x +byte-compile-file') for greater speed--byte compiled code loads and +runs somewhat faster. + + +File: sml-mode.info, Node: Getting Help, Prev: Getting Started, Up: Introduction + +3.3 Help! +========= + +You're reading it. Apart from the on-line info tree (`C-h i' is the +Emacs key to enter the `info' system--you should follow the brief +tutorial if this is unfamiliar), there are further details on specific +commands in their documentation strings. Only the most useful SML mode +commands are documented in the info tree: to find out more use Emacs' +help facilities. + + Briefly, to get help on a specific function use `C-h f' and enter +the command name. All (almost all, then) SML mode commands begin with +`sml-', so if you type this and press <TAB> (for completion) you will +get a list of all commands. Another way is to use `C-h a' and enter the +string `sml'. This is command apropos; it will list all commands with +that sub-string in their names, and any key binding they may have in +the current buffer. Command apropos gives a one-line synopsis of what +each command does. + + Some commands are also variables--such things are allowed in Lisp, if +not in ML! *Note Command Index::, for a list of (info) documented +functions. *Note Variable Index::, for a list of user settable variables +to control the behaviour of SML mode. + + Before accessing this information on-line from within Emacs you may +have to set the variable `sml-mode-info'. Put in your `.emacs' file +something like: + + (setq sml-mode-info "/home/mjm/info/sml-mode.info") + +When different from the default this variable should be a string giving +the absolute name of the `.info' file. Then `C-c C-i' in SML mode +(i.e., the command `M-x sml-mode-info') will bring up the manual. This +help is also accessible from the menu. (Resetting this variable will +not be necessary if your site administrator has been kind enough to +install SML mode and its attendant documentation in the Emacs +hierarchy.) + + +File: sml-mode.info, Node: SML Mode, Next: Interaction Mode, Prev: Introduction, Up: Top + +4 Editing with SML Mode +*********************** + +Now SML mode provides just a few additional editing commands. Most of +the work has gone into implementing the indentation algorithm which, if +you think about it, has to be complicated for a language like ML. *Note +Indentation Defaults: SML Mode Defaults, for details on how to control +some of the behaviour of the indentation algorithm. Principal goodies +are the `electric pipe' feature, and the ability to insert common SML +forms (macros or templates). + +* Menu: + +* Basics:: On entering SML mode +* Indentation:: Prettying SML text +* Magic Insertion:: Templates and electric keys +* SML Mode Defaults:: Variables controlling indentation + + +File: sml-mode.info, Node: Basics, Next: Indentation, Prev: SML Mode, Up: SML Mode + +4.1 On entering SML mode +======================== + + + + -- Command: sml-mode + This switches a buffer into SML mode. This is a _major mode_ in + Emacs. To get out of SML mode the buffer's major mode must be set + to something else, like text-mode. *Note Getting Started::, for + details on how to set this up automatically when visiting an SML + file. + + Emacs is all hooks of course. A hook is a variable: if the variable +is non-nil it binds a list of Emacs Lisp functions to be run in some +order (usually left to right). You can customise SML mode with these +hooks: + + -- Hook: sml-mode-hook + Default: `nil' + + This is run every time a new SML mode buffer is created (or if you + type `M-x sml-mode'). This is one place to put your preferred key + bindings. *Note Configuration::, for some examples. + + +File: sml-mode.info, Node: Indentation, Next: Magic Insertion, Prev: Basics, Up: SML Mode + +4.2 Automatic indentation +========================= + +ML is a complicated language to parse, let alone compile. The +indentation algorithm is a little wooden (for some tastes), and the best +advice is not to fight it! There are several variables that can be +adjusted to control the indentation algorithm (*note Customising SML +Mode: SML Mode Defaults, below). + + -- Command: indent-for-tab-command + Key: <TAB> + + This command indents the current line. If you set the indentation + of the previous line by hand, `indent-for-tab-command' will indent + relative to this setting. + + -- Command: indent-region + Key: `C-M-\' + + Indent the current region. Be patient if the region is large (like + the whole buffer). + + -- Command: sml-back-to-outer-indent + Key: `M-<TAB>' + + Unindents the line to the next outer level of indentation. + + Further indentation commands that Emacs provides (generically, for +all modes) that you may like to recall: + + - `M-x newline-and-indent' + + On <LFD> by default. Insert a newline, then indent according to + the major mode. *Note Indentation for Programs: (emacs)Program + Indent, for details. + + - `M-x indent-rigidly' + + On `C-x <TAB>' by default. Moves all lines in the region right by + its argument (left, for negative arguments). *Note Indentation: + (emacs)Indentation. + + - `M-x indent-for-comment' + + On `M-;' by default. Indent this line's comment to comment + column, or insert an empty comment. *Note Comment Commands: + (emacs)Comment Commands. + + - `M-x indent-new-comment-line' + + On `M-<LFD>' by default. Break line at point and indent, + continuing comment if within one. *Note Multi-Line Comments: + (emacs)Multi-Line Comments. + + As with other language modes, `M-;' gives you a comment at the end +of the current line. The column where the comment starts is determined +by the variable `comment-column'--default is 40, but it can be changed +with `set-comment-column' (on `C-x ;' by default). + + +File: sml-mode.info, Node: Magic Insertion, Next: SML Mode Defaults, Prev: Indentation, Up: SML Mode + +4.3 Electric features +===================== + +Electric keys are generally pretty irritating, so those provided by SML +mode are fairly muted. The only truly electric key is `;', and this has +to be enabled to take effect. + + -- Command: sml-electric-pipe + Key: `M-|' + + When the point is in a `case' statement this opens a new line, + indents and inserts `| =>' leaving point just before the double + arrow; if the enclosing construct is a `fun' declaration, the + newline is indented and the function name copied at the + appropriate column. Generally, try it whenever a `|' is + wanted--you'll like it! + + -- Command: sml-electric-space + Key: `M-SPC' + + When the point is after a keyword like `let', this inserts the + corresponding predefined skeleton if one exists. Else it just + inserts a space. Another way to insert those skeletons is to use + `sml-insert-form', described below. + + -- Command: sml-electric-semi + Key: `;' + + Just inserts a semi-colon, usually. The behaviour of this command + is governed by the variable `sml-electric-semi-mode'. + + -- Variable: sml-electric-semi-mode + Default: `nil' + + If this variable is `nil', `sml-electric-semi' just inserts a + semi-colon, otherwise it inserts a semi-colon and a newline, and + indents the newline for SML. + + -- Command: sml-insert-form + Key: `C-c <RET>' + + Interactive short-cut to insert common ML forms (a.k.a. macros, or + templates). Recognised forms are `let', `local', `case', `abstype', + `datatype', `signature', `structure', and `functor'. Except for + `let' and `local', these will prompt for appropriate parameters + like functor name and signature, etc.. This command prompts in the + mini-buffer, with completion. + + By default `C-c <RET>' will insert at point, with the indentation + of the current column; if you give a prefix argument (i.e., `C-u + C-c <RET>') the command will insert a newline first, indent, and + then insert the template. + + `sml-insert-form' is also extensible: see *note Configuration:: for +further details. + + +File: sml-mode.info, Node: SML Mode Defaults, Prev: Magic Insertion, Up: SML Mode + +4.4 Indentation defaults +======================== + +Several variables try to control the indentation algorithm and other +features of SML mode. Most of them are still in flux so they are not +described here yet. If the default values are not acceptable you can +set these variables permanently in your `.emacs' file. *Note +Configuration::, for details and examples. + + -- Variable: sml-indent-level + Default: `4' + + This variable controls the block indentation level. + + +File: sml-mode.info, Node: Interaction Mode, Next: Configuration, Prev: SML Mode, Up: Top + +5 Running ML under Emacs +************************ + +The most useful feature of SML mode is that it provides a convenient +interface to the compiler. How serious users of ML put up with a +teletype interface to the compiler is beyond me... but perhaps there +are other interfaces to compilers that require one to part with serious +money. Such remarks can quickly become dated--in this case, let's hope +so! + + Anyway, SML mode provides an interaction mode, `inferior-sml-mode', +where the compiler runs in a separate buffer in a window or frame of +its own. You can use this buffer just like a terminal, but it's usually +more convenient to mark some text in the SML mode buffer and have Emacs +communicate with the sub-process. The features discussed below are +syntax-independent, so they should work with a wide range of ML-like +tools and compilers. *Note Process Defaults::, for some hints. + + `inferior-sml-mode' is a specialisation of the `comint' package that +comes with Emacs and XEmacs. + +* Menu: + +* Running ML:: Commands to run the ML compiler in a buffer +* ML Interaction:: Sending program fragments to the compiler +* Tracking Errors:: Finding reported syntax errors +* Process Defaults:: Setting defaults for process interaction + + +File: sml-mode.info, Node: Running ML, Next: ML Interaction, Prev: Interaction Mode, Up: Interaction Mode + +5.1 Starting the compiler +========================= + +Start your favourite ML compiler with the command + + M-x run-sml + +This creates a process interaction buffer that inherits some key +bindings from SML mode and from `comint' (*note Shell Mode: +(emacs)Shell Mode.). Starting the ML compiler adds some functions to +SML mode buffers so that program text can be communicated between +editor and compiler (*note ML Interaction::). + + The name of the ML compiler is the first thing you should know how to +specify: + + -- Variable: sml-program-name + Default: `"sml"' + + The program to run as ML. You might need to specify the full path + name of the program. + + -- Variable: sml-default-arg + Default: `""' + + Useful for Poly/ML users who may supply a database file, or others + who have wrappers for setting various options around the command + to run the compiler. Moscow ML people might set this to `"-P + full"', etc.. + + The variable `sml-program-name' is a string holding the name of the +program _as you would type it at the shell_. You can always choose a +program different to the default by invoking + + C-u M-x run-sml + +With the prefix argument Emacs will prompt for the command name and any +command line arguments to pass to the compiler. Thereafter Emacs will +use this new name as the default, but for a permanent change you should +set this in your `.emacs' with, e.g.: + + (setq sml-program-name "nj-sml") + + -- Command: run-sml + Launches ML as an inferior process in another buffer; if an ML + process already exists, just switch to the process buffer. A + prefix argument allows you to edit the command line to specify the + program, and any command line options. + + -- Hook: inferior-sml-mode-hook + Default: `nil' + + `M-x run-sml' runs `comint-mode-hook' and `inferior-sml-mode-hook' + hooks in that order, but _after_ the compiler is started. Use + `inferior-sml-mode-hook' to set any `comint' buffer-local + configurations for SML mode you like. + + -- Command: switch-to-sml + Key: `C-c C-s' + + Switch from the SML buffer to the interaction buffer. By default + point will be placed at the end of the process buffer, but a + prefix argument will leave point wherever it was before. If you + try `C-c C-s' before an ML process has been started, you'll just + get an error message to the effect that there's no current process + buffer. + + -- Command: sml-cd + When started, the ML compiler's default working directory is the + current buffer's default directory. This command allows the working + directory to be changed, if the compiler can do this. The variable + `sml-cd-command' specifies the compiler command to invoke (*note + Process Defaults::). + + +File: sml-mode.info, Node: ML Interaction, Next: Tracking Errors, Prev: Running ML, Up: Interaction Mode + +5.2 Speaking to the compiler +============================ + +Several commands are defined for sending program fragments to the +running compiler. Each of the following commands takes a prefix argument +that will switch the input focus to the process buffer afterwards +(leaving point at the end of the buffer): + + -- Command: sml-load-file + Key: `C-c C-l' + + Send a `use file' command to the current ML process. The variable + `sml-use-command' is used to define the correct template for the + command to invoke (*note Process Defaults::). The default file is + the file associated with the current buffer, or the last file + loaded if you are in the interaction buffer. + + -- Command: sml-send-region + Key: `C-c C-r' + + Send the current region of text in the SML buffer. + `sml-send-region-and-go' is a similar command for you to bind in + SML mode if you wish: it'll send the region and then switch-to-sml. + + -- Command: sml-send-buffer + Key: `C-c C-b' + + Send the contents of the current buffer to ML. + + +File: sml-mode.info, Node: Tracking Errors, Next: Process Defaults, Prev: ML Interaction, Up: Interaction Mode + +5.3 Finding errors +================== + +SML mode provides one customisable function for locating the source +position of errors reported by the compiler. This should work whether +you type `use "puzzle.sml";' into the interaction buffer, or use one of +the mechanisms provided for sending programs directly to the +compiler--*note ML Interaction::. + + -- Command: next-error + Key: `C-x`' + + Jump to the source location of the next error reported by the + compiler. All the usual error-navigation commands are available, + see *note Compilation Mode: (emacs)Compilation Mode. + + +File: sml-mode.info, Node: Process Defaults, Prev: Tracking Errors, Up: Interaction Mode + +5.4 Process defaults +==================== + +The process interaction code is independent of the compiler used, +deliberately, so SML mode will work with a variety of ML compilers and +ML-based tools. There are therefore a number of variables that may need +to be set correctly before SML mode can speak to the compiler. Things +are by default set up for Standard ML of New Jersey, but switching to a +new system is quite easy. + + -- Variable: sml-use-command + Default: `"use \"%s\""' + + Use file command template. Emacs will replace the `%s' with a file + name. Note that Emacs requires double quote characters inside + strings to be quoted with a backslash. + + -- Variable: sml-cd-command + Default: `"OS.FileSys.chDir \"%s\""' + + Compiler command to change the working directory. Not all ML + systems support this feature (well, Edinburgh (core) ML didn't), + but they should. + + -- Variable: sml-prompt-regexp + Default: `"^[-=>#] *"' + + Matches the ML compiler's prompt: `comint' uses this for various + purposes. + + To customise error reportage for different ML compilers you need to +set two further variables before `next-error' can be useful: + + -- Variable: sml-error-regexp-alist + Alist that specifies how to match errors in compiler output. Each + elt has the form (REGEXP FILE-IDX LINE-IDX [COLUMN-IDX + FILE-FORMAT...]) If REGEXP matches, the FILE-IDX'th subexpression + gives the file name, and the LINE-IDX'th subexpression gives the + line number. If COLUMN-IDX is given, the COLUMN-IDX'th + subexpression gives the column number on that line. If any + FILE-FORMAT is given, each is a format string to produce a file + name to try; %s in the string is replaced by the text matching the + FILE-IDX'th subexpression. + + +File: sml-mode.info, Node: Configuration, Prev: Interaction Mode, Up: Top + +6 Configuration Summary +*********************** + +This (sort of pedagogic) section gives more information on how to +configure SML mode: menus, key bindings, hooks and highlighting are +discussed, along with a few other random topics. + +* Menu: + +* Hooks:: Creating them +* Key Bindings:: Binding commands to keys +* Highlighting:: Syntax colouring +* Advanced Topics:: You may need to speak Emacs Lisp + + +File: sml-mode.info, Node: Hooks, Next: Key Bindings, Prev: Configuration, Up: Configuration + +6.1 Hooks +========= + +One way to set SML mode variables (*note Indentation Defaults: SML Mode +Defaults.), and other defaults, is through the `sml-mode-hook' in your +`.emacs'. A simple example: + + (defun my-sml-mode-hook () "Local defaults for SML mode" + (setq sml-indent-level 2) ; conserve on horizontal space + (setq words-include-escape t) ; \ loses word break status + (setq indent-tabs-mode nil)) ; never ever indent with tabs + (add-hook 'sml-mode-hook 'my-sml-mode-hook) + The body of `my-sml-mode-hook' is a sequence of assignments. In this +case it is not really necessary to set `sml-indent-level' in a hook +because this variable is global (most SML mode variables are). With +similar effect: + + (setq sml-indent-level 2) + anywhere in your `.emacs' file. The variable `indent-tabs-mode' is +automatically made local to the current buffer whenever it is set +explicitly, so it _must_ be set in a hook if you always want SML mode +to behave like this. + + Another hook is `inferior-sml-mode-hook'. This can be used to +control the behaviour of the interaction buffer through various +variables meaningful to `comint'-based packages: + + (defun my-inf-sml-mode-hook () "Local defaults for inferior SML mode" + (add-hook 'comint-output-filter-functions 'comint-truncate-buffer) + (setq comint-scroll-show-maximum-output t) + (setq comint-input-autoexpand nil)) + (add-hook 'inferior-sml-mode-hook 'my-inf-sml-mode-hook) + Again, the body is a sequence of assignments. Unless you run several +ML compilers simultaneously under one Emacs, this hook will normally +only get run once. You might want to look up the documentation (`C-h v' +and `C-h f') for these buffer-local `comint' things. + + +File: sml-mode.info, Node: Key Bindings, Next: Highlighting, Prev: Hooks, Up: Configuration + +6.2 Key bindings +================ + +Customisation (in Emacs) usually entails putting favourite commands on +easily remembered keys. Two `keymaps' are defined in SML mode: one is +effective in program text buffers (`sml-mode-map') and the other is +effective in interaction buffers (`inferior-sml-mode-map'). The +initial design ensures that (many of) the default key bindings from the +former keymap will also be available in the latter (e.g., `C-c`'). + + Type `C-h m' in an SML mode buffer to find the default key bindings +(and similarly in an ML interaction buffer), and use the hooks provided +to install your preferred key bindings. Given that the keymaps are +global (variables): + + (defun my-sml-mode-hook () "Global defaults for SML mode" + (define-key sml-mode-map "\C-cd" 'sml-cd)) + (add-hook 'sml-mode-hook 'my-sml-mode-hook) + This has the effect of binding `sml-cd' to the key `C-c d'. If you +want the same behaviour from `C-c d' in the ML buffer: + + (defun my-inf-sml-mode-hook () "Global defaults for inferior SML mode" + (define-key inferior-sml-mode-map "\C-cd" 'sml-cd) + ;; NB. for SML/NJ '96 + (setq sml-cd-command "OS.FileSys.chDir \"%s\"")) + (add-hook 'inferior-sml-mode-hook 'my-inf-sml-mode-hook) + + There is nothing to stop you rebuilding the entire keymap for SML +mode and the ML interaction buffer in your `.emacs' of course: SML mode +won't define `sml-mode-map' or `inferior-sml-mode-map' if you have +already done so. + + +File: sml-mode.info, Node: Highlighting, Next: Advanced Topics, Prev: Key Bindings, Up: Configuration + +6.3 Syntax colouring +==================== + +Highlighting is very handy for picking out keywords in the program text, +spotting misspelled kewyords, and, if you have Emacs' `ps-print' +package installed (you usually do these days), obtaining pretty, even +colourful code listings--quite properly for your colourful ML programs. + + The indentation scheme (strangely enough) also relies on the +highlighting code to properly handle nested comments, which is yet +another reason to turn on highlighting. To turn on highlighting, use +either of: + + M-x font-lock-mode + (add-hook 'sml-mode-hook 'turn-on-font-lock) + (global-font-lock-mode 1) + + The first will turn it on in the current buffer. The second will +turn it on in all sml-mode buffers. The last will turn it on +everywhere. This is valid for Emacs but maybe not for XEmacs. Check +font-lock documentation if you encounter problems. + + +File: sml-mode.info, Node: Advanced Topics, Prev: Highlighting, Up: Configuration + +6.4 Advanced Topics +=================== + + _These forms are bloody useless; can't we have better ones?_ + + +You can indeed. `sml-insert-form' is extensible so all you need to do +is create the macros yourself. Define a _keybord macro_ (`C-x (' +<something> `C-x )') and give it a suitable name: +`sml-addto-forms-alist' prompts for a name, say `NAME', and binds the +macro `sml-form-NAME'. Thereafter `C-c <RET> NAME' will insert the +macro at point, and `C-u C-c <RET> NAME' will insert the macro after a +`newline-and-indent'. If you want to keep your macros from one editing +session to the next, go to your `.emacs' file and call +`insert-kbd-macro'; you'll need to add `NAME' to `sml-forms-alist' +permanently yourself: + + (defun my-sml-mode-hook () "Global defaults for SML mode" + ;; whatever else you do + (add-to-list 'sml-forms-alist '("NAME" . FUNCTION))) + + If you want to create templates like `case' that prompt for +parameters you'll have to do some Lisp programming. The `skeleton' +package is a good stating point. Better yet, you can reuse the +wrappers used by sml-mode itself in your sml-mode-hook: + + (add-hook 'sml-mode-hook + (lambda () + (sml-def-skeleton "case" "Case expr: " + str " of" \n _ " => "))) + + This will redefine `case' in order to leave the `of' on the first +line. See the documentation of `skeleton-insert' to get a better +understanding of how this works. + + +_I hate that indentation algorithm; can't I tweak it?_ + + +Ah, yes, of course, but this manual will not tell you how. + + +_Can SML mode handle more than one compiler running at once?_ + + Sure, just rename the `*sml*' buffer and then use `run-sml' as usual. + + +_What needs to be done to support other ML compilers?_ + + +Not much really. Just add the right regular expressions to +`sml-error-regexp-alist' and that should be all. + + +File: sml-mode.info, Node: Command Index, Next: Variable Index, Up: Top + +Command Index +************* + ++* Menu: + +* indent-for-tab-command: Indentation. (line 13) +* indent-region: Indentation. (line 20) +* inferior-sml-mode: Interaction Mode. (line 21) +* next-error: Tracking Errors. (line 13) +* run-sml: Running ML. (line 47) +* sml-back-to-outer-indent: Indentation. (line 26) +* sml-cd: Running ML. (line 71) +* sml-electric-pipe: Magic Insertion. (line 11) +* sml-electric-semi: Magic Insertion. (line 29) +* sml-electric-space: Magic Insertion. (line 21) +* sml-indent-level: SML Mode Defaults. (line 13) +* sml-insert-form: Magic Insertion. (line 42) +* sml-load-file: ML Interaction. (line 12) +* sml-mode: Basics. (line 9) +* sml-mode-info: Getting Help. (line 31) +* sml-send-buffer: ML Interaction. (line 28) +* sml-send-region: ML Interaction. (line 21) +* sml-send-region-and-go: ML Interaction. (line 21) +* switch-to-sml: Running ML. (line 61) + + +File: sml-mode.info, Node: Variable Index, Next: Key Index, Prev: Command Index, Up: Top + +Variable Index +************** + ++* Menu: + +* inferior-sml-mode-hook: Running ML. (line 53) +* sml-cd-command: Process Defaults. (line 21) +* sml-default-arg: Running ML. (line 26) +* sml-electric-semi-mode: Magic Insertion. (line 35) +* sml-error-regexp-alist: Process Defaults. (line 37) +* sml-indent-level: SML Mode Defaults. (line 13) +* sml-mode-hook: Basics. (line 21) +* sml-mode-info: Getting Help. (line 31) +* sml-program-name: Running ML. (line 20) +* sml-prompt-regexp: Process Defaults. (line 28) +* sml-use-command: Process Defaults. (line 14) + + +File: sml-mode.info, Node: Key Index, Prev: Variable Index, Up: Top + +Key Index +********* + ++* Menu: + +* ;: Magic Insertion. (line 29) +* <LFD>: Indentation. (line 35) +* <TAB>: Indentation. (line 13) +* C-c <RET>: Magic Insertion. (line 42) +* C-c C-b: ML Interaction. (line 28) +* C-c C-i: Getting Help. (line 31) +* C-c C-l: ML Interaction. (line 12) +* C-c C-r: ML Interaction. (line 21) +* C-c C-s: Running ML. (line 61) +* C-M-\: Indentation. (line 20) +* C-x ;: Indentation. (line 57) +* C-x <TAB>: Indentation. (line 41) +* C-x`: Tracking Errors. (line 13) +* M-;: Indentation. (line 47) +* M-<LFD>: Indentation. (line 53) +* M-<TAB>: Indentation. (line 26) +* M-SPC: Magic Insertion. (line 21) +* M-|: Magic Insertion. (line 11) + + + +Tag Table: +Node: Top187 +Node: Copying1782 +Node: Introduction2595 +Node: Contributors4011 +Node: Getting Started5484 +Node: Getting Help7192 +Node: SML Mode9060 +Node: Basics9868 +Node: Indentation10787 +Node: Magic Insertion12897 +Node: SML Mode Defaults15115 +Node: Interaction Mode15676 +Node: Running ML17025 +Node: ML Interaction19894 +Node: Tracking Errors21047 +Node: Process Defaults21750 +Node: Configuration23633 +Node: Hooks24141 +Node: Key Bindings25998 +Node: Highlighting27574 +Node: Advanced Topics28579 +Node: Command Index30523 +Node: Variable Index32039 +Node: Key Index32991 + +End Tag Table diff --git a/emacs/emacs.d/sml-mode-5.0/sml-mode.spec b/emacs/emacs.d/sml-mode-5.0/sml-mode.spec @@ -0,0 +1,67 @@ +%define lispdir %{_datadir}/emacs/site-lisp +%define startupfile %{lispdir}/site-start.el + +Summary: Emacs mode for editing Standard ML source code +Name: sml-mode +Version: $Name$ +Release: 0.1 +Group: Applications/Editors +Copyright: GPL +Packager: Stefan Monnier +Source: http://iro.umontreal.ca/~monnier/elisp/%{name}.tar.gz +Buildroot: %{_tmppath}/%{name}-buildroot +BuildPreReq: emacs >= 20 xemacs >= 21 +BuildArch: noarch + +%description +SML-MODE is a major Emacs mode for editing Standard ML. It provides +syntax highlighting and automatic indentation and comes with sml-proc +which allows interaction with an inferior SML interactive loop. + +%prep +%setup -q -n %{name} + +%install +make install \ + prefix=%{buildroot}%{_prefix} \ + infodir=%{buildroot}%{_infodir} \ + lispdir=%{buildroot}%{lispdir} +gzip -9f %{buildroot}%{lispdir}/sml-mode/*.el + +texi2pdf sml-mode.texi + +%post +cat >> %{lispdir}/site-start.el <<EOF +;; sml-mode-start +;; This section was automatically generated by rpm +(load "sml-mode-startup") +;; End of automatically generated section +;; sml-mode-end +EOF + +/sbin/install-info %{_infodir}/sml-mode.info.gz %{_infodir}/dir + +%postun +ed -s %{lispdir}/site-start.el <<EOF +/^;; sml-mode-start$/,/^;; sml-mode-end$/d +wq +EOF + +/sbin/install-info --delete %{_infodir}/sml-mode.info.gz %{_infodir}/dir \ + --section=Emacs \ + --entry="* SML: (sml-mode). Editing & Running Standard ML from Emacs" + +%clean +rm -rf %{buildroot} + +%files +%defattr(-,root,root) +%doc BUGS ChangeLog INSTALL NEWS README TODO +%doc sml-mode.texi sml-mode.pdf +%doc %{_infodir}/*.info* +%dir %{lispdir}/%{name} +%{lispdir}/%{name}/*.elc +%{lispdir}/%{name}/*.el +%{lispdir}/%{name}/*.el.* + +%changelog diff --git a/emacs/emacs.d/sml-mode-5.0/sml-mode.texi b/emacs/emacs.d/sml-mode-5.0/sml-mode.texi @@ -0,0 +1,1161 @@ +\input texinfo @c -*-texinfo-*- + +@comment "@(#)$Name$:$Id$" + +@comment Documentation for the GNU Emacs SML mode. +@comment Copyright (C) 1997-1999 Matthew J.@: Morley + +@comment This file is part of the sml-mode distribution. + +@comment sml-mode is free software; you can redistribute it and/or modify +@comment it under the terms of the GNU General Public License as published by +@comment the Free Software Foundation; either version 3 of the License, +@comment or (at your option) any later version. + +@comment sml-mode is distributed in the hope that it will be useful, +@comment but WITHOUT ANY WARRANTY; without even the implied warranty of +@comment MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +@comment GNU General Public License for more details. + +@comment You should have received a copy of the GNU General Public License +@comment along with sml-mode; see the file COPYING. If not, write to +@comment the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + +@setfilename sml-mode.info +@settitle SML mode - The Emacs SML editing mode +@dircategory Emacs +@direntry +* sml:(sml-mode). Emacs mode for editing SML +@end direntry +@setchapternewpage on + +@titlepage +@sp 5 +@center @titlefont{Editing and Running Standard ML} +@center @titlefont{under GNU Emacs} +@sp 5 +@center {SML mode, Version $Name$} +@center {August 1999} +@sp 2 +@author Authors: Matthew J.@: Morley and Stefan Monnier + +@page +@vskip 0pt plus 1filll +Copyright @copyright{} (Anon) + +@sp 1 +@noindent +GNU General Public License as published by the Free Software Foundation; +either version 3, or (at your option) any later version. + +@sp 1 +@noindent +SML mode is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General +Public License for more details. + +@sp 1 +@noindent +You should have received a copy of the GNU General Public License along +with GNU Emacs; see the file COPYING. If not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + +@end titlepage + +@setchapternewpage off +@headings double + +@c ============================================================ TOP NODE + +@node Top, Copying, (dir), (dir) + +@ifinfo +@chapter SML Mode Info + +@c == Top, Copying, (dir), (dir) ======================================= + +@noindent +You are looking at the top node of the Info tree documenting +@sc{sml-mode} (Version $Name$). Not all functions are documented here, but +those that aren't you probably won't miss. All commands and settable +variables have built-in documentation, as per usual Emacs conventions. +@end ifinfo + +@menu +* Copying:: You can copy SML mode +* Introduction:: Setting things up +* SML Mode:: Editing SML source +* Interaction Mode:: Running ML processes +* Configuration:: Menus, highlighting, setting defaults + +Indexes +* Command Index:: Commands you can invoke +* Variable Index:: Variables you can set +* Key Index:: Default keybindings + +Introduction +* Contributors:: Who did what +* Getting Started:: What to tell Emacs +* Getting Help:: How Emacs can help + +SML Mode +* Basics:: On entering SML mode +* Indentation:: Prettying SML text +* Magic Insertion:: Templates and electric keys +* SML Mode Defaults:: Variables controlling indentation + +Interaction Mode +* Running ML:: Commands to run the ML compiler in a buffer +* ML Interaction:: Sending program fragments to the compiler +* Tracking Errors:: Finding reported syntax errors +* Process Defaults:: Setting defaults for process interaction + +Configuration +* Hooks:: Creating hooks +* Key Bindings:: Binding commands to keys +* Highlighting:: Syntax colouring +* Advanced Topics:: You may need to speak Emacs Lisp +@end menu + + +@c ============================================================= COPYING + +@node Copying, Introduction, Top, Top + +@ifinfo +@chapter Copying + +@c == Copying, Introduction, Top, Top ================================== + +@noindent +You can freely copy, modify and redistribute SML mode because it's +made available under the liberal terms of the GNU General Public +License. + +GNU General Public License as published by the Free Software Foundation; +either version 3, or (at your option) any later version. + +SML mode is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General +Public License for more details. + +You should have received a copy of the GNU General Public License along +with GNU Emacs; see the file COPYING. If not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + +@end ifinfo + + + + +@c ======================================================== INTRODUCTION + +@node Introduction, SML Mode, Copying, Top + +@chapter Introduction + +@c == Introduction, SML Mode, Copying, Top ============================= + + +@noindent +SML mode is a major mode for Emacs for editing Standard ML. It has +some novel bugs, and some nice features: + +@itemize @bullet +@item +Automatic indentation of sml code---a number of variables to customise +the indentation. +@item +Easy insertion for commonly used templates like let, local, signature, +and structure declarations, with minibuffer prompting for types and +expressions. +@item +Magic pipe insertion: @code{|} automatically determines if it is used +in a case or fun construct, and indents the next line as appropriate, +inserting @code{=>} or the name of the function. +@item +Inferior shell for running ML. There's no need to leave Emacs, just keep +on editing while the compiler runs in another window. +@item +Automatic ``use file'' in the inferior shell---you can send files, +buffers, or regions of code to the ML subprocess. +@item +Menus, and syntax and keyword highlighting supported for Emacs 19 and +derivatives. +@item +Parsing errors from the inferior shell, and repositioning the +source with next-error---just like in c-mode. +@item +SML mode can be easily configured to work with a number of Standard +ML compilers, and other SML based tools. +@end itemize + +@menu +* Contributors:: Who did what +* Getting Started:: What to tell Emacs +* Getting Help:: How Emacs can help +@end menu + + + +@c ======================================================== CONTRIBUTORS + +@node Contributors, Getting Started, Introduction, Introduction + +@section Contributors to the SML mode +@cindex Contributors +@cindex Authors + +Contributions to the package are welcome. I have limited time to work +on this project, but I will gladly add any code that you contribute to +me to this package. + +Although the history of sml-mode is obscure, it seems that +the following persons have made contributions to sml-mode: + +@itemize @bullet +@item +Lars Bo Nielsen wrote the original version of the code, providing the +sml editing mode and the inferior-sml support. + +@item +Olin Shivers (@samp{shivers@@ai.mit.edu}) hacked the inferior-sml support +to use comint and call the whole thing ml-mode. + +@item +Steven Gilmore supposedly provided some early attempt at menubar support. + +@item +Matthew J. Morley (@samp{matthew@@verisity.com}) was maintainer for +a long time (until version 3.4) and provided many additions and fixes in +all areas. + +@item +Frederick Knabe (@samp{knabe@@ecrc.de}) provided the original code for +font-lock and hilite support as well as for proper handling of nested +comments and of all the string escape sequences. + +@item +Matthias Blume (@samp{blume@@kurims.kyoto-u.ac.jp}) provided a sml-make +which was replaced by sml-compile. + +@item +Monnier Stefan (@samp{monnier@@iro.umontreal.ca}) completely reworked the +indentation engine as well as most of the rest of the code and is +the current maintainer since after version 3.4. + +@end itemize + + +@c ===================================================== GETTING STARTED + +@node Getting Started, Getting Help, Contributors, Introduction + +@section Getting started + +@c == Getting Started, Getting Help, Contributors, Introduction ======== + + +@noindent +With luck your system administrator will have installed SML mode +somewhere convenient, so it will just magically all work---you can +skip the rest of this getting started section. Otherwise you will need +to tell Emacs where to find all the SML mode @file{.el} files, and +when to use them. The where is addressed by locating the Lisp code on +your Emacs Lisp load path---you may have to create a directory for this, +say @file{/home/mjm/elisp}, and then insert the following lines in your +@file{/home/mjm/.emacs} file: + +@lisp +(add-to-list 'load-path "/home/mjm/elisp") +(autoload 'sml-mode "sml-mode" "Major mode for editing SML." t) +(autoload 'run-sml "sml-proc" "Run an inferior SML process." t) +@end lisp + +@noindent +The first line adjusts Emacs' internal search path so it can locate the +Lisp source you have copied to that directory; the second and third +lines tell Emacs to load the code automatically when it is needed. You +can then switch any Emacs buffer into SML mode by entering the command + +@example +M-x sml-mode +@end example + +@noindent +It is usually more convenient to have Emacs automatically place the +buffer in SML mode whenever you visit a file containing ML +programs. The simplest way of achieving this is to put something like + +@lisp +(add-to-list 'auto-mode-alist '("\\.\\(sml\\|sig\\)\\'" . sml-mode)) +@end lisp + +@noindent +also in your @file{.emacs} file. Subsequently (after a restart), any +files with these extensions will be placed in SML mode buffers when +you visit them. + + +You may want to pre-compile the @file{sml-*.el} files (@kbd{M-x +byte-compile-file}) for greater speed---byte compiled code loads and +runs somewhat faster. + + +@c ======================================================== GETTING HELP + +@node Getting Help, , Getting Started, Introduction + +@section Help! + +@c == Getting Help, , Getting Started, Introduction ==================== + + +@noindent +You're reading it. Apart from the on-line info tree (@kbd{C-h i} is the +Emacs key to enter the @code{info} system---you should follow the brief +tutorial if this is unfamiliar), there are further details on specific +commands in their documentation strings. Only the most useful +SML mode commands are documented in the info tree: to find out more +use Emacs' help facilities. + +Briefly, to get help on a specific function use @kbd{C-h f} and enter +the command name. All (almost all, then) SML mode commands begin +with @code{sml-}, so if you type this and press @key{TAB} (for +completion) you will get a list of all commands. Another way is to use +@kbd{C-h a} and enter the string @code{sml}. This is command apropos; it +will list all commands with that sub-string in their names, and any key +binding they may have in the current buffer. Command apropos gives a +one-line synopsis of what each command does. + +Some commands are also variables---such things are allowed in Lisp, if +not in ML! @xref{Command Index}, for a list of (info) documented +functions. @xref{Variable Index}, for a list of user settable variables +to control the behaviour of SML mode. + +Before accessing this information on-line from within Emacs you may have +to set the variable @code{sml-mode-info}. Put in your @file{.emacs} file +something like: + +@vindex sml-mode-info +@findex sml-mode-info +@kindex @kbd{C-c C-i} +@lisp +(setq sml-mode-info "/home/mjm/info/sml-mode.info") +@end lisp + +@noindent +When different from the default this variable should be a string giving +the absolute name of the @file{.info} file. Then @kbd{C-c C-i} in +SML mode (i.e., the command @kbd{M-x sml-mode-info}) will bring up +the manual. This help is also accessible from the menu. (Resetting this +variable will not be necessary if your site administrator has been kind +enough to install SML mode and its attendant documentation in the +Emacs hierarchy.) + + +@c ============================================================ SML MODE + +@node SML Mode, Interaction Mode, Introduction, Top + +@chapter Editing with SML Mode + +@c == SML Mode, Interaction Mode, Introduction, Top ==================== + + +@noindent +Now SML mode provides just a few additional editing commands. Most of +the work has gone into implementing the indentation algorithm which, if +you think about it, has to be complicated for a language like +ML. @xref{SML Mode Defaults,,Indentation Defaults}, for details on how +to control some of the behaviour of the indentation algorithm. Principal +goodies are the `electric pipe' feature, and the ability to insert +common SML forms (macros or templates). + +@menu +* Basics:: On entering SML mode +* Indentation:: Prettying SML text +* Magic Insertion:: Templates and electric keys +* SML Mode Defaults:: Variables controlling indentation +@end menu + + +@c ============================================================== BASICS + +@node Basics, Indentation, SML Mode, SML Mode + +@section On entering SML mode + +@c == Basics, Indentation, SML Mode, SML Mode ========================== + +@noindent + + +@deffn Command sml-mode +This switches a buffer into SML mode. This is a @emph{major mode} in +Emacs. To get out of SML mode the buffer's major mode must be set to +something else, like @t{text-mode}. @xref{Getting Started}, for details +on how to set this up automatically when visiting an SML file. +@end deffn + +Emacs is all hooks of course. A hook is a variable: if the variable is +non-nil it binds a list of Emacs Lisp functions to be run in some order +(usually left to right). You can customise SML mode with these +hooks: + + +@defvr Hook sml-mode-hook +Default: @code{nil} + +This is run every time a new SML mode buffer is created (or if you +type @kbd{M-x sml-mode}). This is one place to put your preferred key +bindings. @xref{Configuration}, for some examples. +@end defvr + + +@c ========================================================= INDENTATION + +@node Indentation, Magic Insertion, Basics, SML Mode + +@section Automatic indentation + +@c == Indentation, Magic Insertion, Basics, SML Mode =================== + + +@noindent +ML is a complicated language to parse, let alone compile. The +indentation algorithm is a little wooden (for some tastes), and the best +advice is not to fight it! There are several variables that can be +adjusted to control the indentation algorithm (@pxref{SML Mode +Defaults,,Customising SML Mode}, below). + + +@deffn Command indent-for-tab-command +Key: @key{TAB} +@kindex @key{TAB} + +This command indents the current line. If you set the indentation of the +previous line by hand, @code{indent-for-tab-command} will indent relative to +this setting. +@end deffn + + +@deffn Command indent-region +Key: @kbd{C-M-\} +@kindex @kbd{C-M-\} + +Indent the current region. Be patient if the region is large (like the +whole buffer). +@end deffn + + +@deffn Command sml-back-to-outer-indent +Key: @kbd{M-@key{TAB}} +@kindex @kbd{M-@key{TAB}} + +Unindents the line to the next outer level of indentation. +@end deffn + + + +Further indentation commands that Emacs provides (generically, for all +modes) that you may like to recall: + +@itemize @minus +@item +@kbd{M-x newline-and-indent} + +On @key{LFD} by default. +@kindex @key{LFD} +Insert a newline, then indent according to the major mode. @xref{Program +Indent,,Indentation for Programs,emacs,The Emacs Editor Manual}, for +details. + +@item +@kbd{M-x indent-rigidly} + +On @kbd{C-x @key{TAB}} by default. +@kindex @kbd{C-x @key{TAB}} +Moves all lines in the region right by its argument (left, for negative +arguments). @xref{Indentation,,,emacs,The Emacs Editor Manual}. + +@item +@kbd{M-x indent-for-comment} + +On @kbd{M-;} by default. +@kindex @kbd{M-;} +Indent this line's comment to comment column, or insert an empty +comment. @xref{Comment Commands,,,emacs,The Emacs Editor +Manual}. + +@item +@kbd{M-x indent-new-comment-line} + +On @kbd{M-@key{LFD}} by default. +@kindex @kbd{M-@key{LFD}} +Break line at point and indent, continuing comment if within one. +@xref{Multi-Line Comments,,,emacs,The Emacs Editor Manual}. +@end itemize + +@kindex @kbd{C-x ;} +As with other language modes, @kbd{M-;} gives you a comment at the end +of the current line. The column where the comment starts is determined +by the variable @code{comment-column}---default is 40, but it can be +changed with @code{set-comment-column} (on @kbd{C-x ;} by default). + + +@c ===================================================== MAGIC INSERTION + +@node Magic Insertion, SML Mode Defaults, Indentation, SML Mode + +@section Electric features + +@c == Magic Insertion, SML Mode Defaults, Indentation, SML Mode ======== + + +@noindent +Electric keys are generally pretty irritating, so those provided by +SML mode are fairly muted. The only truly electric key is @kbd{;}, +and this has to be enabled to take effect. + + +@deffn Command sml-electric-pipe +Key: @kbd{M-|} +@kindex @kbd{M-|} + +When the point is in a `case' statement this opens a new line, indents +and inserts @code{| =>} leaving point just before the double arrow; if +the enclosing construct is a `fun' declaration, the newline is indented +and the function name copied at the appropriate column. Generally, try +it whenever a @code{|} is wanted---you'll like it! +@end deffn + +@deffn Command sml-electric-space +Key: @kbd{M-SPC} +@kindex @kbd{M-SPC} + +When the point is after a keyword like `let', this inserts the +corresponding predefined skeleton if one exists. Else it just inserts a +space. Another way to insert those skeletons is to use +@code{sml-insert-form}, described below. +@end deffn + +@deffn Command sml-electric-semi +Key: @kbd{;} +@kindex @kbd{;} + +Just inserts a semi-colon, usually. The behaviour of this command is +governed by the variable @code{sml-electric-semi-mode}. +@end deffn + + +@defvr Variable sml-electric-semi-mode +Default: @code{nil} + +If this variable is @code{nil}, @code{sml-electric-semi} just inserts a +semi-colon, otherwise it inserts a semi-colon and a newline, and indents +the newline for SML. +@end defvr + + +@deffn Command sml-insert-form +Key: @kbd{C-c @key{RET}} +@kindex @kbd{C-c @key{RET}} + +Interactive short-cut to insert common ML forms (a.k.a.@: macros, or +templates). Recognised forms are `let', `local', `case', `abstype', +`datatype', `signature', `structure', and `functor'. Except for `let' +and `local', these will prompt for appropriate parameters like functor +name and signature, etc.. This command prompts in the mini-buffer, with +completion. + +By default @kbd{C-c @key{RET}} will insert at point, with the +indentation of the current column; if you give a prefix argument (i.e., +@kbd{C-u C-c @key{RET}}) the command will insert a newline first, +indent, and then insert the template. +@end deffn + +@code{sml-insert-form} is also extensible: see @ref{Configuration} for +further details. + + + +@c ======================================================= MODE DEFAULTS + +@node SML Mode Defaults, , Magic Insertion, SML Mode + +@section Indentation defaults + +@c == SML Mode Defaults, , Magic Insertion, SML Mode =================== + + +@noindent +Several variables try to control the indentation algorithm and other +features of SML mode. Most of them are still in flux so they are not +described here yet. +If the default values are not acceptable you can set these variables +permanently in your @file{.emacs} file. @xref{Configuration}, for +details and examples. + + +@defvr Variable sml-indent-level +@findex sml-indent-level +Default: @code{4} + +This variable controls the block indentation level. +@end defvr + +@c end vtable + + +@c ========================================================= INTERACTION + +@node Interaction Mode, Configuration, SML Mode, Top + +@chapter Running ML under Emacs + +@c == Interaction Mode, Configuration, SML Mode, Top =================== + + +@noindent +The most useful feature of SML mode is that it provides a convenient +interface to the compiler. How serious users of ML put up with a +teletype interface to the compiler is beyond me@.@.@. but perhaps there +are other interfaces to compilers that require one to part with serious +money. Such remarks can quickly become dated---in this case, let's hope +so! + +Anyway, SML mode provides an interaction mode, +@code{inferior-sml-mode}, where the compiler runs in a separate buffer +in a window or frame of its own. You can use this buffer just like a +terminal, but it's usually more convenient to mark some text in the +SML mode buffer and have Emacs communicate with the sub-process. The +features discussed below are syntax-independent, so they should work +with a wide range of ML-like tools and compilers. @xref{Process +Defaults}, for some hints. + +@findex inferior-sml-mode +@code{inferior-sml-mode} is a specialisation of the @file{comint} +package that comes with Emacs and XEmacs. + + +@menu +* Running ML:: Commands to run the ML compiler in a buffer +* ML Interaction:: Sending program fragments to the compiler +* Tracking Errors:: Finding reported syntax errors +* Process Defaults:: Setting defaults for process interaction +@end menu + + + +@c ========================================================== RUNNING ML + +@node Running ML, ML Interaction, Interaction Mode, Interaction Mode + +@section Starting the compiler + +@c == Running ML, ML Interaction, Interaction Mode, Interaction Mode == + +@noindent +Start your favourite ML compiler with the command + +@example +@kbd{M-x run-sml} +@end example + +@noindent +This creates a process interaction buffer that inherits some key +bindings from SML mode and from @file{comint} (@pxref{Shell Mode, , +, emacs, The Emacs Editor Manual}). Starting the ML compiler adds some +functions to SML mode buffers so that program text can be +communicated between editor and compiler (@pxref{ML Interaction}). + +The name of the ML compiler is the first thing you should know how to +specify: + + +@defvar sml-program-name +Default: @code{"sml"} + +The program to run as ML. You might need to specify the full path name +of the program. +@end defvar + + +@defvar sml-default-arg +Default: @code{""} + +Useful for Poly/ML users who may supply a database file, or others who +have wrappers for setting various options around the command to run the +compiler. Moscow ML people might set this to @code{"-P full"}, etc.. +@end defvar + +The variable @code{sml-program-name} is a string holding the name +of the program @emph{as you would type it at the shell}. You +can always choose a program different to the default by invoking + +@example +@kbd{C-u M-x run-sml} +@end example + +@noindent +With the prefix argument Emacs will prompt for the command name and any +command line arguments to pass to the compiler. Thereafter Emacs will +use this new name as the default, but for a permanent change you should +set this in your @file{.emacs} with, e.g.: + +@lisp +(setq sml-program-name "nj-sml") +@end lisp + + +@deffn Command run-sml +Launches ML as an inferior process in another buffer; if an ML process +already exists, just switch to the process buffer. A prefix argument +allows you to edit the command line to specify the program, and any +command line options. +@end deffn + + +@defvr Hook inferior-sml-mode-hook +Default: @code{nil} + +@kbd{M-x run-sml} runs @code{comint-mode-hook} and +@code{inferior-sml-mode-hook} hooks in that order, but @emph{after} the +compiler is started. Use @code{inferior-sml-mode-hook} to set any +@code{comint} buffer-local configurations for SML mode you like. +@end defvr + + +@deffn Command switch-to-sml +Key: @kbd{C-c C-s} +@kindex @kbd{C-c C-s} + +Switch from the SML buffer to the interaction buffer. By default point +will be placed at the end of the process buffer, but a prefix argument +will leave point wherever it was before. If you try @kbd{C-c C-s} before +an ML process has been started, you'll just get an error message to the +effect that there's no current process buffer. +@end deffn + + +@deffn Command sml-cd +When started, the ML compiler's default working directory is the +current buffer's default directory. This command allows the working +directory to be changed, if the compiler can do this. The variable +@code{sml-cd-command} specifies the compiler command to invoke +(@pxref{Process Defaults}). +@end deffn + + +@c ======================================================== SENDING TEXT + +@node ML Interaction, Tracking Errors, Running ML, Interaction Mode + +@section Speaking to the compiler + +@c == ML Interaction, Tracking Errors, Running ML, Interaction Mode ==== + + +@noindent +Several commands are defined for sending program fragments to the +running compiler. Each of the following commands takes a prefix argument +that will switch the input focus to the process buffer afterwards +(leaving point at the end of the buffer): + + +@deffn Command sml-load-file +Key: @kbd{C-c C-l} +@kindex @kbd{C-c C-l} + +Send a `use file' command to the current ML process. The variable +@code{sml-use-command} is used to define the correct template for the +command to invoke (@pxref{Process Defaults}). The default file is the +file associated with the current buffer, or the last file loaded if you +are in the interaction buffer. +@end deffn + + + +@deffn Command sml-send-region +@findex sml-send-region-and-go +Key: @kbd{C-c C-r} +@kindex @kbd{C-c C-r} + +Send the current region of text in the SML buffer. +@code{sml-send-region-and-go} is a similar command for you to bind in +SML mode if you wish: it'll send the region and then switch-to-sml. +@end deffn + +@c @deffn Command sml-send-function +@c @findex sml-send-function-and-go + +@c Send the enclosing `function' definition. Contrary to the suggestive +@c name, this command @emph{does not} try to determine the extent of the +@c function definition because that is too difficult with ML. Instead +@c this just sends the enclosing @emph{paragraph} (delimited by blank +@c lines or form-feed characters). +@c @end deffn + +@deffn Command sml-send-buffer +Key: @kbd{C-c C-b} +@kindex @kbd{C-c C-b} + +Send the contents of the current buffer to ML. +@end deffn + +@c ===================================================== TRACKING ERRORS + +@node Tracking Errors, Process Defaults, ML Interaction, Interaction Mode + +@section Finding errors + +@c == Tracking Errors, Process Defaults, ML Interaction, Interaction Mode + + +@noindent +SML mode provides one customisable function for locating the source +position of errors reported by the compiler. This should work whether +you type @code{use "puzzle.sml";} into the interaction buffer, or use +one of the mechanisms provided for sending programs directly to the +compiler---@pxref{ML Interaction}. + + +@deffn Command next-error +@findex next-error +Key: @kbd{C-x`} +@kindex @kbd{C-x`} + +Jump to the source location of the next error reported by the compiler. +All the usual error-navigation commands are available, see +@pxref{Compilation Mode, , , emacs, The Emacs Editor Manual}. +@end deffn + + +@c ==================================================== PROCESS DEFAULTS + +@node Process Defaults, , Tracking Errors, Interaction Mode + +@section Process defaults + +@c == Process Defaults, , Tracking Errors, Interaction Mode ============ + +@noindent +The process interaction code is independent of the compiler used, +deliberately, so SML mode will work with a variety of ML compilers +and ML-based tools. There are therefore a number of variables that may +need to be set correctly before SML mode can speak to the compiler. +Things are by default set up for Standard ML of New Jersey, but +switching to a new system is quite easy. + + + +@defvar sml-use-command +Default: @code{"use \"%s\""} + +Use file command template. Emacs will replace the @code{%s} with a file +name. Note that Emacs requires double quote characters inside strings +to be quoted with a backslash. +@end defvar + + +@defvar sml-cd-command +Default: @code{"OS.FileSys.chDir \"%s\""} + +Compiler command to change the working directory. Not all ML systems +support this feature (well, Edinburgh (core) ML didn't), but they +should. +@end defvar + + +@defvar sml-prompt-regexp +Default: @code{"^[-=>#] *"} + +Matches the ML compiler's prompt: @file{comint} uses this for various +purposes. +@end defvar + + +To customise error reportage for different ML compilers you need to set +two further variables before @code{next-error} can be useful: + + +@defvar sml-error-regexp-alist + +Alist that specifies how to match errors in compiler output. +Each elt has the form (REGEXP FILE-IDX LINE-IDX [COLUMN-IDX FILE-FORMAT...]) +If REGEXP matches, the FILE-IDX'th subexpression gives the file name, and +the LINE-IDX'th subexpression gives the line number. If COLUMN-IDX is +given, the COLUMN-IDX'th subexpression gives the column number on that line. +If any FILE-FORMAT is given, each is a format string to produce a file name to +try; %s in the string is replaced by the text matching the FILE-IDX'th +subexpression. +@end defvar + + +@c A typical way of (re)setting these variables correctly is to put +@c something in your @file{.emacs} file that resembles + +@c @example +@c (setq sml-use-command "PolyML.use \"%s\"") +@c (setq sml-prompt-regexp "^[>#] *") +@c @end example + +@c ======================================================= CONFIGURATION + +@node Configuration, , Interaction Mode, Top + +@chapter Configuration Summary + +@c @footnote{@url{http://www.ahl.co.uk/}} +@c @footnote{@url{http://www.dina.kvl.dk/~sestoft/mosml.html}} + +@noindent +This (sort of pedagogic) section gives more information on how to +configure SML mode: menus, key bindings, hooks and highlighting are +discussed, along with a few other random topics. + +@menu +* Hooks:: Creating them +* Key Bindings:: Binding commands to keys +* Highlighting:: Syntax colouring +* Advanced Topics:: You may need to speak Emacs Lisp +@end menu + + +@c =============================================================== HOOKS + +@node Hooks, Key Bindings, Configuration, Configuration + +@section Hooks + +@c == Hooks, Key Bindings, Configuration, Configuration ================ + + +@noindent +One way to set SML mode variables (@pxref{SML Mode +Defaults,,Indentation Defaults}), and other defaults, is through the +@code{sml-mode-hook} in your @file{.emacs}. A simple example: + +@lisp +(defun my-sml-mode-hook () "Local defaults for SML mode" + (setq sml-indent-level 2) ; conserve on horizontal space + (setq words-include-escape t) ; \ loses word break status + (setq indent-tabs-mode nil)) ; never ever indent with tabs +(add-hook 'sml-mode-hook 'my-sml-mode-hook) +@end lisp +@noindent +The body of @code{my-sml-mode-hook} is a sequence of assignments. In this +case it is not really necessary to set @code{sml-indent-level} in a hook +because this variable is global (most SML mode variables are). With +similar effect: + +@lisp +(setq sml-indent-level 2) +@end lisp +@noindent +anywhere in your @file{.emacs} file. The variable @code{indent-tabs-mode} is +automatically made local to the current buffer whenever it is set +explicitly, so it @emph{must} be set in a hook if you always want +SML mode to behave like this. + +Another hook is @code{inferior-sml-mode-hook}. This can be used to +control the behaviour of the interaction buffer through various +variables meaningful to @file{comint}-based packages: + +@lisp +(defun my-inf-sml-mode-hook () "Local defaults for inferior SML mode" + (add-hook 'comint-output-filter-functions 'comint-truncate-buffer) + (setq comint-scroll-show-maximum-output t) + (setq comint-input-autoexpand nil)) +(add-hook 'inferior-sml-mode-hook 'my-inf-sml-mode-hook) +@end lisp +@noindent +Again, the body is a sequence of assignments. Unless you run several ML +compilers simultaneously under one Emacs, this hook will normally only +get run once. You might want to look up the documentation (@kbd{C-h v} +and @kbd{C-h f}) for these buffer-local @code{comint} things. + + +@c ======================================================== Key Bindings + +@node Key Bindings, Highlighting, Hooks, Configuration + +@section Key bindings + +@noindent +Customisation (in Emacs) usually entails putting favourite commands on +easily remembered keys. Two `keymaps' are defined in SML mode: one +is effective in program text buffers (@code{sml-mode-map}) and the other +is effective in interaction buffers (@code{inferior-sml-mode-map}). +The initial design ensures that (many of) the default key bindings from +the former keymap will also be available in the latter (e.g., +@kbd{C-c`}). + +Type @kbd{C-h m} in an SML mode buffer to find the default key +bindings (and similarly in an ML interaction buffer), and use the hooks +provided to install your preferred key bindings. Given that the keymaps +are global (variables): + +@lisp +(defun my-sml-mode-hook () "Global defaults for SML mode" + (define-key sml-mode-map "\C-cd" 'sml-cd)) +(add-hook 'sml-mode-hook 'my-sml-mode-hook) +@end lisp +@noindent +This has the effect of binding @code{sml-cd} to the key @kbd{C-c d}. +If you want the same behaviour from @kbd{C-c d} in the ML buffer: + +@lisp +(defun my-inf-sml-mode-hook () "Global defaults for inferior SML mode" + (define-key inferior-sml-mode-map "\C-cd" 'sml-cd) + ;; NB. for SML/NJ '96 + (setq sml-cd-command "OS.FileSys.chDir \"%s\"")) +(add-hook 'inferior-sml-mode-hook 'my-inf-sml-mode-hook) +@end lisp + +There is nothing to stop you rebuilding the entire keymap for +SML mode and the ML interaction buffer in your @file{.emacs} of +course: SML mode won't define @code{sml-mode-map} or +@code{inferior-sml-mode-map} if you have already done so. + + +@c ======================================================== Highlighting + +@node Highlighting, Advanced Topics, Key Bindings, Configuration + +@section Syntax colouring + + +@noindent +Highlighting is very handy for picking out keywords in the program text, +spotting misspelled kewyords, and, if you have Emacs' @file{ps-print} +package installed (you usually do these days), obtaining pretty, even +colourful code listings---quite properly for your colourful ML programs. + +The indentation scheme (strangely enough) also relies on the +highlighting code to properly handle nested comments, which is yet +another reason to turn on highlighting. To turn on highlighting, +use either of: + +@lisp +M-x font-lock-mode +(add-hook 'sml-mode-hook 'turn-on-font-lock) +(global-font-lock-mode 1) +@end lisp + +The first will turn it on in the current buffer. +The second will turn it on in all sml-mode buffers. +The last will turn it on everywhere. +This is valid for Emacs but maybe not for XEmacs. Check font-lock +documentation if you encounter problems. + +@c ===================================================== ADVANCED TOPICS + +@node Advanced Topics, , Highlighting, Configuration + +@section Advanced Topics + +@flushright +@emph{These forms are bloody useless; can't we have better ones?} +@end flushright + +@sp 1 +@noindent +You can indeed. @code{sml-insert-form} is extensible so all you need to +do is create the macros yourself. Define a @emph{keybord macro} +(@kbd{C-x (} <something> @kbd{C-x )}) and give it a suitable name: +@code{sml-addto-forms-alist} prompts for a name, say @code{NAME}, and +binds the macro @code{sml-form-NAME}. Thereafter @kbd{C-c @key{RET} +NAME} will insert the macro at point, and @kbd{C-u C-c @key{RET} NAME} +will insert the macro after a @code{newline-and-indent}. If you want to +keep your macros from one editing session to the next, go to your +@file{.emacs} file and call @code{insert-kbd-macro}; you'll need +to add @code{NAME} to @code{sml-forms-alist} permanently yourself: + +@lisp +(defun my-sml-mode-hook () "Global defaults for SML mode" + ;; whatever else you do + (add-to-list 'sml-forms-alist '("NAME" . FUNCTION))) +@end lisp + +If you want to create templates like `case' that prompt for parameters +you'll have to do some Lisp programming. The @code{skeleton} package is +a good stating point. Better yet, you can reuse the wrappers used by +sml-mode itself in your sml-mode-hook: + +@lisp +(add-hook 'sml-mode-hook + (lambda () + (sml-def-skeleton "case" "Case expr: " + str " of" \n _ " => "))) +@end lisp + +This will redefine `case' in order to leave the `of' on the first line. +See the documentation of @code{skeleton-insert} to get a better +understanding of how this works. + +@sp 1 +@flushright +@emph{I hate that indentation algorithm; can't I tweak it?} +@end flushright + +@sp 1 +@noindent +Ah, yes, of course, but this manual will not tell you how. + + +@sp 1 +@flushright +@emph{Can SML mode handle more than one compiler running at once?} +@end flushright + +Sure, just rename the @samp{*sml*} buffer and then use @code{run-sml} +as usual. + +@sp 1 +@flushright +@emph{What needs to be done to support other ML compilers?} +@end flushright + +@sp 1 +@noindent +Not much really. Just add the right regular expressions to +@code{sml-error-regexp-alist} and that should be all. + + +@c ======================================================= COMMAND INDEX + +@headings singleafter + +@node Command Index, Variable Index, , Top + +@unnumbered Command Index + +@printindex fn + +@c ====================================================== VARIABLE INDEX + +@c node Variable Index, , Command Index, Top +@node Variable Index, Key Index, Command Index, Top + +@unnumbered Variable Index + +@c == Variable Index, Key Index, Command Index, Top ==================== + +@printindex vr + +@c =========================================================== KEY INDEX + +@node Key Index, , Variable Index, Top + +@unnumbered Key Index + +@c == Key Index, , Variable Index, Top ================================= + +@printindex ky + +@contents +@bye diff --git a/emacs/emacs.d/sml-mode-5.0/sml-oldindent.el b/emacs/emacs.d/sml-mode-5.0/sml-oldindent.el @@ -0,0 +1,713 @@ +;;; sml-oldindent.el --- Navigation and indentation for SML without SMIE + +;; Copyright (C) 1999,2000,2004,2007,2012 Stefan Monnier <monnier@gnu.org> +;; +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 3 of the License, or +;; (at your option) any later version. +;; +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. +;; +;; You should have received a copy of the GNU General Public License +;; along with this program; if not, write to the Free Software +;; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + +;;; Commentary: + + +;;; Code: + +(eval-when-compile (require 'cl)) +(require 'sml-mode) + +(defun sml-preproc-alist (al) + "Expand an alist AL where keys can be lists of keys into a normal one." + (apply #'nconc + (mapcar (lambda (x) + (let ((k (car x)) + (v (cdr x))) + (if (consp k) + (mapcar (lambda (y) (cons y v)) k) + (list x)))) + al))) + +(defconst sml-begin-syms + '("let" "abstype" "local" "struct" "sig") + "Symbols matching the `end' symbol.") + +(defconst sml-begin-syms-re + (sml-syms-re sml-begin-syms) + "Symbols matching the `end' symbol.") + +;; (defconst sml-user-begin-symbols-re +;; (sml-syms-re '("let" "abstype" "local" "struct" "sig" "in" "with")) +;; "Symbols matching (loosely) the `end' symbol.") + +(defconst sml-sexp-head-symbols-re + (sml-syms-re `("let" "abstype" "local" "struct" "sig" "in" "with" + "if" "then" "else" "case" "of" "fn" "fun" "val" "and" + "datatype" "type" "exception" "open" "infix" "infixr" "nonfix" + ,@sml-module-head-syms + "handle" "raise")) + "Symbols starting an sexp.") + +;; (defconst sml-not-arg-start-re +;; (sml-syms-re '("in" "of" "end" "andalso")) +;; "Symbols that can't be found at the head of an arg.") + +;; (defconst sml-not-arg-re +;; (sml-syms-re '("in" "of" "end" "andalso")) +;; "Symbols that should not be confused with an arg.") + +(defconst sml-indent-rule + (sml-preproc-alist + `(("struct" . 0) + (,sml-module-head-syms "d=" 0) + ("local" "in" 0) + ;;("of" . (3 nil)) + ;;("else" . (sml-indent-level 0)) + ;;(("in" "fun" "and" "of") . (sml-indent-level nil)) + ("if" "else" 0) + (,sml-=-starter-syms nil) + (("abstype" "case" "datatype" "if" "then" "else" "sharing" "infix" "infixr" + "let" "local" "nonfix" "open" "raise" "sig" "struct" "type" "val" "while" + "do" "with" "withtype"))))) + +(defconst sml-delegate + (sml-preproc-alist + `((("of" "else" "then" "d=") . (not (sml-bolp))) + ("in" . t))) + "Words which might delegate indentation to their parent.") + +(defcustom sml-symbol-indent + '(("fn" . -3) + ("of" . 1) + ("|" . -2) + ("," . -2) + (";" . -2) + ;;("in" . 1) + ("d=" . 2)) + "Special indentation alist for some symbols. +An entry like (\"in\" . 1) indicates that a line starting with the +symbol `in' should be indented one char further to the right. +This is only used in a few specific cases, so it does not work +for all symbols and in all lines starting with the given symbol." + :group 'sml + :type '(repeat (cons string integer))) + +(defconst sml-open-paren + (sml-preproc-alist + `((,(list* "with" "in" sml-begin-syms) ,sml-begin-syms-re "\\<end\\>"))) + "Symbols that should behave somewhat like opening parens.") + +(defconst sml-close-paren + `(("in" "\\<l\\(ocal\\|et\\)\\>") + ("with" "\\<abstype\\>") + ("withtype" "\\<\\(abs\\|data\\)type\\>") + ("end" ,sml-begin-syms-re) + ("then" "\\<if\\>") + ("else" "\\<if\\>" (sml-bolp)) + ("of" "\\<case\\>") + ("d=" nil)) + "Symbols that should behave somewhat like close parens.") + +(defconst sml-agglomerate-re "\\<else[ \t]+if\\>" + "Regexp of compound symbols (pairs of symbols to be considered as one).") + +(defvar sml-internal-syntax-table + (let ((st (make-syntax-table sml-mode-syntax-table))) + (modify-syntax-entry ?_ "w" st) + (modify-syntax-entry ?' "w" st) + (modify-syntax-entry ?. "w" st) + ;; Treating `~' as a word constituent is not quite right, but + ;; close enough. Think about 12.3E~2 for example. Also `~' on its + ;; own *is* a nonfix symbol. + (modify-syntax-entry ?~ "w" st) + st) + "Syntax table used for internal sml-mode operation.") + +;;; +;;; various macros +;;; + +(defmacro sml-with-ist (&rest r) + (let ((ost-sym (make-symbol "oldtable"))) + `(let ((,ost-sym (syntax-table)) + (case-fold-search nil) + (parse-sexp-lookup-properties t) + (parse-sexp-ignore-comments t)) + (unwind-protect + (progn (set-syntax-table sml-internal-syntax-table) . ,r) + (set-syntax-table ,ost-sym))))) +(def-edebug-spec sml-with-ist t) + +(defmacro sml-move-if (&rest body) + (let ((pt-sym (make-symbol "point")) + (res-sym (make-symbol "result"))) + `(let ((,pt-sym (point)) + (,res-sym ,(cons 'progn body))) + (unless ,res-sym (goto-char ,pt-sym)) + ,res-sym))) +(def-edebug-spec sml-move-if t) + +(defmacro sml-point-after (&rest body) + `(save-excursion + ,@body + (point))) +(def-edebug-spec sml-point-after t) + +;; + +(defvar sml-op-prec + (sml-preproc-alist + '(("before" . 0) + ((":=" "o") . 3) + ((">" ">=" "<>" "<" "<=" "=") . 4) + (("::" "@") . 5) + (("+" "-" "^") . 6) + (("/" "*" "quot" "rem" "div" "mod") . 7))) + "Alist of SML infix operators and their precedence.") + +(defconst sml-syntax-prec + (sml-preproc-alist + `((("in" "with") . 10) + ((";" ",") . 20) + (("=>" "d=" "=of") . (65 . 40)) + ("|" . (47 . 30)) + (("case" "of" "fn") . 45) + (("if" "then" "else" "while" "do" "raise") . 50) + ("handle" . 60) + ("orelse" . 70) + ("andalso" . 80) + ((":" ":>") . 90) + ("->" . 95) + (,(cons "end" sml-begin-syms) . 10000))) + "Alist of pseudo-precedence of syntactic elements.") + +(defun sml-op-prec (op dir) + "Return the precedence of OP or nil if it's not an infix. +DIR should be set to BACK if you want to precedence w.r.t the left side + and to FORW for the precedence w.r.t the right side. +This assumes that we are `looking-at' the OP." + (when op + (let ((sprec (cdr (assoc op sml-syntax-prec)))) + (cond + ((consp sprec) (if (eq dir 'back) (car sprec) (cdr sprec))) + (sprec sprec) + (t + (let ((prec (cdr (assoc op sml-op-prec)))) + (when prec (+ prec 100)))))))) + +;; + +(defun sml-forward-spaces () (forward-comment 100000)) +(defun sml-backward-spaces () (forward-comment -100000)) + + +;; +;; moving forward around matching symbols +;; + +(defun sml-looking-back-at (re) + (save-excursion + (when (= 0 (skip-syntax-backward "w_")) (backward-char)) + (looking-at re))) + +(defun sml-find-match-forward (this match) + "Only works for word matches." + (let ((level 1) + (forward-sexp-function nil) + (either (concat this "\\|" match))) + (while (and (not (eobp)) (> level 0)) + (forward-sexp 1) + (while (not (or (eobp) (sml-looking-back-at either))) + (condition-case () (forward-sexp 1) (error (forward-char 1)))) + (setq level + (cond + ((sml-looking-back-at this) (1+ level)) + ((sml-looking-back-at match) (1- level)) + (t (error "Unbalanced"))))) + t)) + +(defun sml-find-match-backward (this match) + (let ((level 1) + (forward-sexp-function nil) + (either (concat this "\\|" match))) + (while (> level 0) + (backward-sexp 1) + (while (not (or (bobp) (looking-at either))) + (condition-case () (backward-sexp 1) (error (backward-char 1)))) + (setq level + (cond + ((looking-at this) (1+ level)) + ((looking-at match) (1- level)) + (t (error "Unbalanced"))))) + t)) + +;;; +;;; Read a symbol, including the special "op <sym>" case +;;; + +(defmacro sml-move-read (&rest body) + (let ((pt-sym (make-symbol "point"))) + `(let ((,pt-sym (point))) + ,@body + (when (/= (point) ,pt-sym) + (buffer-substring-no-properties (point) ,pt-sym))))) +(def-edebug-spec sml-move-read t) + +(defun sml-poly-equal-p () + (< (sml-point-after (re-search-backward sml-=-starter-re nil 'move)) + (sml-point-after (re-search-backward "=" nil 'move)))) + +(defun sml-nested-of-p () + (< (sml-point-after + (re-search-backward sml-non-nested-of-starter-re nil 'move)) + (sml-point-after (re-search-backward "\\<case\\>" nil 'move)))) + +(defun sml-forward-sym-1 () + (or (/= 0 (skip-syntax-forward "'w_")) + (/= 0 (skip-syntax-forward ".'")))) +(defun sml-forward-sym () + (let ((sym (sml-move-read (sml-forward-sym-1)))) + (cond + ((equal "op" sym) + (sml-forward-spaces) + (concat "op " (or (sml-move-read (sml-forward-sym-1)) ""))) + ((equal sym "=") + (save-excursion + (sml-backward-sym-1) + (if (sml-poly-equal-p) "=" "d="))) + ((equal sym "of") + (save-excursion + (sml-backward-sym-1) + (if (sml-nested-of-p) "of" "=of"))) + ;; ((equal sym "datatype") + ;; (save-excursion + ;; (sml-backward-sym-1) + ;; (sml-backward-spaces) + ;; (if (eq (preceding-char) ?=) "=datatype" sym))) + (t sym)))) + +(defun sml-backward-sym-1 () + (or (/= 0 (skip-syntax-backward ".'")) + (/= 0 (skip-syntax-backward "'w_")))) +(defun sml-backward-sym () + (let ((sym (sml-move-read (sml-backward-sym-1)))) + (when sym + ;; FIXME: what should we do if `sym' = "op" ? + (let ((point (point))) + (sml-backward-spaces) + (if (equal "op" (sml-move-read (sml-backward-sym-1))) + (concat "op " sym) + (goto-char point) + (cond + ((string= sym "=") (if (sml-poly-equal-p) "=" "d=")) + ((string= sym "of") (if (sml-nested-of-p) "of" "=of")) + ;; ((string= sym "datatype") + ;; (save-excursion (sml-backward-spaces) + ;; (if (eq (preceding-char) ?=) "=datatype" sym))) + (t sym))))))) + + +(defun sml-backward-sexp (prec) + "Move one sexp backward if possible, or one char else. +Returns t if the move indeed moved through one sexp and nil if not. +PREC is the precedence currently looked for." + (let ((parse-sexp-lookup-properties t) + (parse-sexp-ignore-comments t)) + (sml-backward-spaces) + (let* ((op (sml-backward-sym)) + (op-prec (sml-op-prec op 'back)) + match) + (cond + ((not op) + (let ((point (point))) + (ignore-errors (let ((forward-sexp-function nil)) (backward-sexp 1))) + (if (/= point (point)) t (ignore-errors (backward-char 1)) nil))) + ;; stop as soon as precedence is smaller than `prec' + ((and prec op-prec (>= prec op-prec)) nil) + ;; special rules for nested constructs like if..then..else + ((and (or (not prec) (and prec op-prec)) + (setq match (second (assoc op sml-close-paren)))) + (sml-find-match-backward (concat "\\<" op "\\>") match)) + ;; don't back over open-parens + ((assoc op sml-open-paren) nil) + ;; infix ops precedence + ((and prec op-prec) (< prec op-prec)) + ;; [ prec = nil ] a new operator, let's skip the sexps until the next + (op-prec (while (sml-move-if (sml-backward-sexp op-prec))) t) + ;; special symbols indicating we're getting out of a nesting level + ((string-match sml-sexp-head-symbols-re op) nil) + ;; if the op was not alphanum, then we still have to do the backward-sexp + ;; this reproduces the usual backward-sexp, but it might be bogus + ;; in this case since !@$% is a perfectly fine symbol + (t t))))) ;(or (string-match "\\sw" op) (sml-backward-sexp prec)) + +(defun sml-forward-sexp (prec) + "Moves one sexp forward if possible, or one char else. +Returns T if the move indeed moved through one sexp and NIL if not." + (let ((parse-sexp-lookup-properties t) + (parse-sexp-ignore-comments t)) + (sml-forward-spaces) + (let* ((op (sml-forward-sym)) + (op-prec (sml-op-prec op 'forw)) + match) + (cond + ((not op) + (let ((point (point))) + (ignore-errors (let ((forward-sexp-function nil)) (forward-sexp 1))) + (if (/= point (point)) t (forward-char 1) nil))) + ;; stop as soon as precedence is smaller than `prec' + ((and prec op-prec (>= prec op-prec)) nil) + ;; special rules for nested constructs like if..then..else + ((and (or (not prec) (and prec op-prec)) + (setq match (cdr (assoc op sml-open-paren)))) + (sml-find-match-forward (first match) (second match))) + ;; don't forw over close-parens + ((assoc op sml-close-paren) nil) + ;; infix ops precedence + ((and prec op-prec) (< prec op-prec)) + ;; [ prec = nil ] a new operator, let's skip the sexps until the next + (op-prec (while (sml-move-if (sml-forward-sexp op-prec))) t) + ;; special symbols indicating we're getting out of a nesting level + ((string-match sml-sexp-head-symbols-re op) nil) + ;; if the op was not alphanum, then we still have to do the backward-sexp + ;; this reproduces the usual backward-sexp, but it might be bogus + ;; in this case since !@$% is a perfectly fine symbol + (t t))))) ;(or (string-match "\\sw" op) (sml-backward-sexp prec)) + +(defun sml-in-word-p () + (and (eq ?w (char-syntax (or (char-before) ? ))) + (eq ?w (char-syntax (or (char-after) ? ))))) + +(defun sml-user-backward-sexp (&optional count) + "Like `backward-sexp' but tailored to the SML syntax." + (interactive "p") + (unless count (setq count 1)) + (sml-with-ist + (let ((point (point))) + (if (< count 0) (sml-user-forward-sexp (- count)) + (when (sml-in-word-p) (forward-word 1)) + (dotimes (i count) + (unless (sml-backward-sexp nil) + (goto-char point) + (error "Containing expression ends prematurely"))))))) + +(defun sml-user-forward-sexp (&optional count) + "Like `forward-sexp' but tailored to the SML syntax." + (interactive "p") + (unless count (setq count 1)) + (sml-with-ist + (let ((point (point))) + (if (< count 0) (sml-user-backward-sexp (- count)) + (when (sml-in-word-p) (backward-word 1)) + (dotimes (i count) + (unless (sml-forward-sexp nil) + (goto-char point) + (error "Containing expression ends prematurely"))))))) + +;;(defun sml-forward-thing () +;; (if (= ?w (char-syntax (char-after))) (forward-word 1) (forward-char 1))) + +(defun sml-backward-arg () (sml-backward-sexp 1000)) +(defun sml-forward-arg () (sml-forward-sexp 1000)) + +(provide 'sml-move) + +(defvar sml-rightalign-and) +(defvar sml-indent-args) +(defvar sml-indent-level) + +(defun sml-indent-line () + "Indent current line of ML code." + (interactive) + (let ((savep (> (current-column) (current-indentation))) + (indent (max (or (ignore-errors (sml-calculate-indentation)) 0) 0))) + (if savep + (save-excursion (indent-line-to indent)) + (indent-line-to indent)))) + +(defun sml-find-comment-indent () + (save-excursion + (let ((depth 1)) + (while (> depth 0) + (if (re-search-backward "(\\*\\|\\*)" nil t) + (cond + ;; FIXME: That's just a stop-gap. + ((eq (get-text-property (point) 'face) 'font-lock-string-face)) + ((looking-at "*)") (incf depth)) + ((looking-at comment-start-skip) (decf depth))) + (setq depth -1))) + (if (= depth 0) + (1+ (current-column)) + nil)))) + +(defun sml-calculate-indentation () + (save-excursion + (beginning-of-line) (skip-chars-forward "\t ") + (sml-with-ist + ;; Indentation for comments alone on a line, matches the + ;; proper indentation of the next line. + (when (looking-at "(\\*") (sml-forward-spaces)) + (let (data + (sym (save-excursion (sml-forward-sym)))) + (or + ;; Allow the user to override the indentation. + (when (looking-at (concat ".*" (regexp-quote comment-start) + "[ \t]*fixindent[ \t]*" + (regexp-quote comment-end))) + (current-indentation)) + + ;; Continued comment. + (and (looking-at "\\*") (sml-find-comment-indent)) + + ;; Continued string ? (Added 890113 lbn) + (and (looking-at "\\\\") + (or (save-excursion (forward-line -1) + (if (looking-at "[\t ]*\\\\") + (current-indentation))) + (save-excursion + (if (re-search-backward "[^\\\\]\"" nil t) + (1+ (current-column)) + 0)))) + + ;; Closing parens. Could be handled below with `sml-indent-relative'? + (and (looking-at "\\s)") + (save-excursion + (skip-syntax-forward ")") + (backward-sexp 1) + (if (sml-dangling-sym) + (sml-indent-default 'noindent) + (current-column)))) + + (and (setq data (assoc sym sml-close-paren)) + (sml-indent-relative sym data)) + + (and (member sym sml-starters-syms) + (sml-indent-starter sym)) + + (and (string= sym "|") (sml-indent-pipe)) + + (sml-indent-arg) + (sml-indent-default)))))) + +(defsubst sml-bolp () + (save-excursion (skip-chars-backward " \t|") (bolp))) + +(defun sml-first-starter-p () + "Non-nil if starter at point is immediately preceded by let/local/in/..." + (save-excursion + (let ((sym (unless (save-excursion (sml-backward-arg)) + (sml-backward-spaces) + (sml-backward-sym)))) + (if (member sym '(";" "d=")) (setq sym nil)) + sym))) + +(defun sml-indent-starter (orig-sym) + "Return the indentation to use for a symbol in `sml-starters-syms'. +Point should be just before the symbol ORIG-SYM and is not preserved." + (let ((sym (unless (save-excursion (sml-backward-arg)) + (sml-backward-spaces) + (sml-backward-sym)))) + (if (member sym '(";" "d=")) (setq sym nil)) + (if sym (sml-get-sym-indent sym) + ;; FIXME: this can take a *long* time !! + (setq sym (sml-old-find-matching-starter sml-starters-syms)) + (if (or (sml-first-starter-p) + ;; Don't align with `and' because it might be specially indented. + (and (or (equal orig-sym "and") (not (equal sym "and"))) + (sml-bolp))) + (+ (current-column) + (if (and sml-rightalign-and (equal orig-sym "and")) + (- (length sym) 3) 0)) + (sml-indent-starter orig-sym))))) + +(defun sml-indent-relative (sym data) + (save-excursion + (sml-forward-sym) (sml-backward-sexp nil) + (unless (second data) (sml-backward-spaces) (sml-backward-sym)) + (+ (or (cdr (assoc sym sml-symbol-indent)) 0) + (sml-delegated-indent)))) + +(defun sml-indent-pipe () + (let ((sym (sml-old-find-matching-starter sml-pipeheads + (sml-op-prec "|" 'back)))) + (when sym + (if (string= sym "|") + (if (sml-bolp) (current-column) (sml-indent-pipe)) + (let ((pipe-indent (or (cdr (assoc "|" sml-symbol-indent)) -2))) + (when (or (member sym '("datatype" "abstype")) + (and (equal sym "and") + (save-excursion + (forward-word 1) + (not (sml-funname-of-and))))) + (re-search-forward "=")) + (sml-forward-sym) + (sml-forward-spaces) + (+ pipe-indent (current-column))))))) + +(defun sml-indent-arg () + (and (save-excursion (ignore-errors (sml-forward-arg))) + ;;(not (looking-at sml-not-arg-re)) + ;; looks like a function or an argument + (sml-move-if (sml-backward-arg)) + ;; an argument + (if (save-excursion (not (sml-backward-arg))) + ;; a first argument + (+ (current-column) sml-indent-args) + ;; not a first arg + (while (and (/= (current-column) (current-indentation)) + (sml-move-if (sml-backward-arg)))) + (unless (save-excursion (sml-backward-arg)) + ;; all earlier args are on the same line + (sml-forward-arg) (sml-forward-spaces)) + (current-column)))) + +(defun sml-get-indent (data sym) + (let (d) + (cond + ((not (listp data)) data) + ((setq d (member sym data)) (cadr d)) + ((and (consp data) (not (stringp (car data)))) (car data)) + (t sml-indent-level)))) + +(defun sml-dangling-sym () + "Non-nil if the symbol after point is dangling. +The symbol can be an SML symbol or an open-paren. \"Dangling\" means that +it is not on its own line but is the last element on that line." + (save-excursion + (and (not (sml-bolp)) + (< (sml-point-after (end-of-line)) + (sml-point-after (or (sml-forward-sym) (skip-syntax-forward "(")) + (sml-forward-spaces)))))) + +(defun sml-delegated-indent () + (if (sml-dangling-sym) + (sml-indent-default 'noindent) + (sml-move-if (backward-word 1) + (looking-at sml-agglomerate-re)) + (current-column))) + +(defun sml-get-sym-indent (sym &optional style) + "Find the indentation for the SYM we're `looking-at'. +If indentation is delegated, point will move to the start of the parent. +Optional argument STYLE is currently ignored." + (assert (equal sym (save-excursion (sml-forward-sym)))) + (save-excursion + (let ((delegate (and (not (equal sym "end")) (assoc sym sml-close-paren))) + (head-sym sym)) + (when (and delegate (not (eval (third delegate)))) + ;;(sml-find-match-backward sym delegate) + (sml-forward-sym) (sml-backward-sexp nil) + (setq head-sym + (if (second delegate) + (save-excursion (sml-forward-sym)) + (sml-backward-spaces) (sml-backward-sym)))) + + (let ((idata (assoc head-sym sml-indent-rule))) + (when idata + ;;(if (or style (not delegate)) + ;; normal indentation + (let ((indent (sml-get-indent (cdr idata) sym))) + (when indent (+ (sml-delegated-indent) indent))) + ;; delgate indentation to the parent + ;;(sml-forward-sym) (sml-backward-sexp nil) + ;;(let* ((parent-sym (save-excursion (sml-forward-sym))) + ;; (parent-indent (cdr (assoc parent-sym sml-indent-starters)))) + ;; check the special rules + ;;(+ (sml-delegated-indent) + ;; (or (sml-get-indent (cdr indent-data) 1 'strict) + ;; (sml-get-indent (cdr parent-indent) 1 'strict) + ;; (sml-get-indent (cdr indent-data) 0) + ;; (sml-get-indent (cdr parent-indent) 0)))))))) + ))))) + +(defun sml-indent-default (&optional noindent) + (let* ((sym-after (save-excursion (sml-forward-sym))) + (_ (sml-backward-spaces)) + (sym-before (sml-backward-sym)) + (sym-indent (and sym-before (sml-get-sym-indent sym-before))) + (indent-after (or (cdr (assoc sym-after sml-symbol-indent)) 0))) + (when (equal sym-before "end") + ;; I don't understand what's really happening here, but when + ;; it's `end' clearly, we need to do something special. + (forward-word 1) + (setq sym-before nil sym-indent nil)) + (cond + (sym-indent + ;; the previous sym is an indentation introducer: follow the rule + (if noindent + ;;(current-column) + sym-indent + (+ sym-indent indent-after))) + ;; If we're just after a hanging open paren. + ((and (eq (char-syntax (preceding-char)) ?\() + (save-excursion (backward-char) (sml-dangling-sym))) + (backward-char) + (sml-indent-default)) + (t + ;; default-default + (let* ((prec-after (sml-op-prec sym-after 'back)) + (prec (or (sml-op-prec sym-before 'back) prec-after 100))) + ;; go back until you hit a symbol that has a lower prec than the + ;; "current one", or until you backed over a sym that has the same prec + ;; but is at the beginning of a line. + (while (and (not (sml-bolp)) + (while (sml-move-if (sml-backward-sexp (1- prec)))) + (not (sml-bolp))) + (while (sml-move-if (sml-backward-sexp prec)))) + (if noindent + ;; the `noindent' case does back over an introductory symbol + ;; such as `fun', ... + (progn + (sml-move-if + (sml-backward-spaces) + (member (sml-backward-sym) sml-starters-syms)) + (current-column)) + ;; Use `indent-after' for cases such as when , or ; should be + ;; outdented so that their following terms are aligned. + (+ (if (progn + (if (equal sym-after ";") + (sml-move-if + (sml-backward-spaces) + (member (sml-backward-sym) sml-starters-syms))) + (and sym-after (not (looking-at sym-after)))) + indent-after 0) + (current-column)))))))) + + +;; maybe `|' should be set to word-syntax in our temp syntax table ? +(defun sml-current-indentation () + (save-excursion + (beginning-of-line) + (skip-chars-forward " \t|") + (current-column))) + + +(defun sml-old-find-matching-starter (syms &optional prec) + (let (sym) + (ignore-errors + (while + (progn (sml-backward-sexp prec) + (setq sym (save-excursion (sml-forward-sym))) + (not (or (member sym syms) (bobp))))) + (if (member sym syms) sym)))) + +(defun sml-old-skip-siblings () + (while (and (not (bobp)) (sml-backward-arg)) + (sml-old-find-matching-starter sml-starters-syms)) + (when (looking-at "in\\>\\|local\\>") + ;; Skip over `local...in' and continue. + (forward-word 1) + (sml-backward-sexp nil) + (sml-old-skip-siblings))) + +(provide 'sml-oldindent) + +;;; sml-oldindent.el ends here diff --git a/emacs/emacs.d/sml-mode-5.0/sml-proc.el b/emacs/emacs.d/sml-mode-5.0/sml-proc.el @@ -0,0 +1,784 @@ +;;; sml-proc.el --- Comint based interaction mode for Standard ML. + +;; Copyright (C) 1999,2000,2003,2004,2005,2007,2012 Stefan Monnier +;; Copyright (C) 1994-1997 Matthew J. Morley +;; Copyright (C) 1989 Lars Bo Nielsen + +;; ==================================================================== + +;; This file is not part of GNU Emacs, but it is distributed under the +;; same conditions. + +;; This program is free software; you can redistribute it and/or +;; modify it under the terms of the GNU General Public License as +;; published by the Free Software Foundation; either version 3, or (at +;; your option) any later version. + +;; This program is distributed in the hope that it will be useful, but +;; WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +;; General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs; see the file COPYING. If not, write to the +;; Free Software Foundation, 675 Mass Ave, Cambridge, MA 0139, USA. +;; (See sml-mode.el for HISTORY.) + +;; ==================================================================== + +;; [MJM 10/94] Separating this from sml-mode means sml-mode will run +;; under 18.59 (or anywhere without comint, if there are such places). +;; See sml-mode.el for further information. + +;;; Commentary: + +;; Inferior-sml-mode is for interacting with an ML process run under +;; emacs. This uses the comint package so you get history, expansion, +;; backup and all the other benefits of comint. Interaction is +;; achieved by M-x run-sml which starts a sub-process under emacs. You may +;; need to set this up for autoloading in your .emacs: + +;; (autoload 'run-sml "sml-proc" "Run an inferior ML process." t) + +;; Exactly what process is governed by the variable sml-program-name +;; -- just "sml" by default. If you give a prefix argument (C-u M-x +;; run-sml) you will be prompted for a different program to execute from +;; the default -- if you just hit RETURN you get the default anyway -- +;; along with the option to specify any command line arguments. Once +;; you select the ML program name in this manner, it remains the +;; default (unless you set in a hook, or otherwise). + +;; NOTE: inferior-sml-mode-hook is run AFTER the ML program has been +;; launched. inferior-sml-load-hook is run only when sml-proc.el is +;; loaded into Emacs. + +;; When running an ML process some further key-bindings are effective +;; in sml-mode buffer(s). C-c C-s (switch-to-sml) will split the +;; screen into two windows if necessary and place you in the ML +;; process buffer. In the interaction buffer, C-c C-s is bound to the +;; `sml' command by default (in case you need to restart). + +;; C-c C-l (sml-load-file) will load an SML source file into the +;; inferior process, C-c C-r (sml-send-region) will send the current +;; region of text to the ML process, etc. Given a prefix argument to +;; these commands will switch you from the SML buffer to the ML +;; process buffer as well as sending the text. If you get errors +;; reported by the compiler, C-x ` (next-error) will step through +;; the errors with you. + +;; NOTE. There is only limited support for this as it obviously +;; depends on the compiler's error messages being recognised by the +;; mode. Error reporting is currently only geared up for SML/NJ, +;; Moscow ML, and Poly/ML. For other compilers, add the relevant +;; regexp to sml-error-regexp-alist and send it to me. + +;; To send pieces of code to the underlying compiler, we never send the text +;; directly but use a temporary file instead. This breaks if the compiler +;; does not understand `use', but has the benefit of allowing better error +;; reporting. + +;; Bugs: + +;; Todo: + +;; - Keep improving `sml-compile'. +;; - ignore warnings (if requested) for next-error + +;;; Code: + +(eval-when-compile (require 'cl)) +(require 'sml-mode) +(require 'comint) +(require 'compile) + +(defgroup sml-proc () + "Interacting with an SML process." + :group 'sml) + +(defcustom sml-program-name "sml" + "Program to run as ML." + :type '(string)) + +(defcustom sml-default-arg "" + "Default command line option to pass, if any." + :type '(string)) + +(defcustom sml-host-name "" + "Host on which to run ML." + :type '(string)) + +(defcustom sml-config-file "~/.smlproc.sml" + "File that should be fed to the ML process when started." + :type '(string)) + +(defcustom sml-compile-command "CM.make()" + "The command used by default by `sml-compile'. +See also `sml-compile-commands-alist'.") + +(defcustom sml-compile-commands-alist + '(("CMB.make()" . "all-files.cm") + ("CMB.make()" . "pathconfig") + ("CM.make()" . "sources.cm") + ("use \"load-all\"" . "load-all")) + "Commands used by default by `sml-compile'. +Each command is associated with its \"main\" file. +It is perfectly OK to associate several files with a command or several +commands with the same file.") + +(defvar inferior-sml-mode-hook nil + "*This hook is run when the inferior ML process is started. +All buffer local customisations for the interaction buffers go here.") + +(defvar sml-error-overlay nil + "*Non-nil means use an overlay to highlight errorful code in the buffer. +The actual value is the name of a face to use for the overlay. +Instead of setting this variable to 'region, you can also simply keep +it NIL and use (transient-mark-mode) which will provide similar +benefits (but with several side effects).") + +(defvar sml-buffer nil + "*The current ML process buffer. + +MULTIPLE PROCESS SUPPORT (Whoever wants multi-process support anyway?) +===================================================================== +`sml-mode' supports, in a fairly simple fashion, running multiple ML +processes. To run multiple ML processes, you start the first up with +\\[sml]. It will be in a buffer named *sml*. Rename this buffer with +\\[rename-buffer]. You may now start up a new process with another +\\[sml]. It will be in a new buffer, named *sml*. You can switch +between the different process buffers with \\[switch-to-buffer]. + +NB *sml* is just the default name for the buffer. It actually gets +it's name from the value of `sml-program-name' -- *poly*, *smld*,... + +If you have more than one ML process around, commands that send text +from source buffers to ML processes -- like `sml-send-function' or +`sml-send-region' -- have to choose a process to send it to. This is +determined by the global variable `sml-buffer'. Suppose you have three +inferior ML's running: + Buffer Process + sml #<process sml> + mosml #<process mosml> + *sml* #<process sml<2>> +If you do a \\[sml-send-function] command on some ML source code, +what process do you send it to? + +- If you're in a process buffer (sml, mosml, or *sml*), you send it to + that process (usually makes sense only to `sml-load-file'). +- If you're in some other buffer (e.g., a source file), you send it to + the process attached to buffer `sml-buffer'. + +This process selection is performed by function `sml-proc' which looks +at the value of `sml-buffer' -- which must be a Lisp buffer object, or +a string \(or nil\). + +Whenever \\[sml] fires up a new process, it resets `sml-buffer' to be +the new process's buffer. If you only run one process, this will do +the right thing. If you run multiple processes, you can change +`sml-buffer' to another process buffer with \\[set-variable], or +use the command \\[sml-buffer] in the interaction buffer of choice.") + + +;;; ALL STUFF THAT DEFAULTS TO THE SML/NJ COMPILER (0.93) + +(defvar sml-use-command "use \"%s\"" + "*Template for loading a file into the inferior ML process. +Set to \"use \\\"%s\\\"\" for SML/NJ or Edinburgh ML; +set to \"PolyML.use \\\"%s\\\"\" for Poly/ML, etc.") + +(defvar sml-cd-command "OS.FileSys.chDir \"%s\"" + "*Command template for changing working directories under ML. +Set this to nil if your compiler can't change directories. + +The format specifier \"%s\" will be converted into the directory name +specified when running the command \\[sml-cd].") + +(defcustom sml-prompt-regexp "^[-=>#] *" + "Regexp used to recognise prompts in the inferior ML process." + :type '(regexp)) + +(defvar sml-error-regexp-alist + `( ;; Poly/ML messages + ("^\\(Error\\|Warning:\\) in '\\(.+\\)', line \\([0-9]+\\)" 2 3) + ;; Moscow ML + ("^File \"\\([^\"]+\\)\", line \\([0-9]+\\)\\(-\\([0-9]+\\)\\)?, characters \\([0-9]+\\)-\\([0-9]+\\):" 1 2 5) + ;; SML/NJ: the file-pattern is anchored to avoid + ;; pathological behavior with very long lines. + ("^[-= ]*\\(.*[^\n)]\\)\\( (.*)\\)?:\\([0-9]+\\)\\.\\([0-9]+\\)\\(-\\([0-9]+\\)\\.\\([0-9]+\\)\\)? \\(Error\\|Warnin\\(g\\)\\): .*" 1 + ,@(if (fboundp 'compilation-fake-loc) ;New compile.el. + '((3 . 6) (4 . 7) (9)) + '(sml-make-error 3 4 6 7))) + ;; SML/NJ's exceptions: see above. + ("^ +\\(raised at: \\)?\\(.+\\):\\([0-9]+\\)\\.\\([0-9]+\\)\\(-\\([0-9]+\\)\\.\\([0-9]+\\)\\)" 2 + ,@(if (fboundp 'compilation-fake-loc) ;New compile.el. + '((3 . 6) (4 . 7)) + '(sml-make-error 3 4 6 7)))) + "Alist that specifies how to match errors in compiler output. +See `compilation-error-regexp-alist' for a description of the format.") + +;; font-lock support +(defconst inferior-sml-font-lock-keywords + `(;; prompt and following interactive command + ;; FIXME: Actually, this should already be taken care of by comint. + (,(concat "\\(" sml-prompt-regexp "\\)\\(.*\\)") + (1 font-lock-prompt-face) + (2 font-lock-command-face keep)) + ;; CM's messages + ("^\\[\\(.*GC #.*\n\\)*.*\\]" . font-lock-comment-face) + ;; SML/NJ's irritating GC messages + ("^GC #.*" . font-lock-comment-face) + ;; error messages + ,@(unless (fboundp 'compilation-fake-loc) + (mapcar (lambda (ra) (cons (car ra) 'font-lock-warning-face)) + sml-error-regexp-alist))) + "Font-locking specification for inferior SML mode.") + +(defface font-lock-prompt-face + '((t (:bold t))) + "Font Lock mode face used to highlight prompts." + :group 'font-lock-highlighting-faces) +(defvar font-lock-prompt-face 'font-lock-prompt-face + "Face name to use for prompts.") + +(defface font-lock-command-face + '((t (:bold t))) + "Font Lock mode face used to highlight interactive commands." + :group 'font-lock-highlighting-faces) +(defvar font-lock-command-face 'font-lock-command-face + "Face name to use for interactive commands.") + +(defconst inferior-sml-font-lock-defaults + '(inferior-sml-font-lock-keywords nil nil nil nil)) + + +;;; CODE + +(defvar inferior-sml-mode-map + (let ((map (make-sparse-keymap))) + (set-keymap-parent map comint-mode-map) + (define-key map "\C-c\C-s" 'run-sml) + (define-key map "\C-c\C-l" 'sml-load-file) + (define-key map "\t" + (if (fboundp 'completion-at-point) + 'completion-at-point 'comint-dynamic-complete)) + map) + "Keymap for inferior-sml mode") + +;; buffer-local + +(defvar sml-temp-file nil) +;;(defvar sml-error-file nil) ; file from which the last error came +(defvar sml-error-cursor nil) ; ditto + +(defun sml-proc-buffer () + "Return the current ML process buffer. +or the current buffer if it is in `inferior-sml-mode'. Raises an error +if the variable `sml-buffer' does not appear to point to an existing +buffer." + (or (and (eq major-mode 'inferior-sml-mode) (current-buffer)) + (and sml-buffer + (let ((buf (get-buffer sml-buffer))) + ;; buffer-name returns nil if the buffer has been killed + (and buf (buffer-name buf) buf))) + ;; no buffer found, make a new one + (save-excursion (call-interactively 'run-sml)))) + +(defun sml-buffer (echo) + "Make the current buffer the current `sml-buffer' if that is sensible. +Lookup variable `sml-buffer' to see why this might be useful. +If prefix argument ECHO is set, then it only reports on the current state." + (interactive "P") + (when (not echo) + (setq sml-buffer + (if (eq major-mode 'inferior-sml-mode) (current-buffer) + (read-buffer "Set ML process buffer to: " nil t)))) + (message "ML process buffer is now %s." + (or (ignore-errors (buffer-name (get-buffer sml-buffer))) + "undefined"))) + +(defun sml-proc () + "Return the current ML process. See variable `sml-buffer'." + (assert (eq major-mode 'inferior-sml-mode)) + (or (get-buffer-process (current-buffer)) + (progn (call-interactively 'run-sml) + (get-buffer-process (current-buffer))))) + +(defun sml-proc-comint-input-filter-function (str) + ;; `compile.el' in Emacs-22 fails to notice that file location info from + ;; errors should be recomputed afresh (without using stale info from + ;; earlier compilations). We used to cause a refresh in sml-send-string, + ;; but this doesn't catch the case when the user types commands directly + ;; at the prompt. + (compilation-forget-errors) ;Has to run before compilation-fake-loc. + (if (and (fboundp 'compilation-fake-loc) sml-temp-file) + (compilation-fake-loc (cdr sml-temp-file) (car sml-temp-file))) + str) + +(defun inferior-sml-next-error-hook () + ;; Try to recognize SML/NJ type error message and to highlight finely the + ;; difference between the two types (in case they're large, it's not + ;; always obvious to spot it). + ;; + ;; Sample messages: + ;; + ;; Data.sml:31.9-33.33 Error: right-hand-side of clause doesn't agree with function result type [tycon mismatch] + ;; expression: Hstring + ;; result type: Hstring * int + ;; in declaration: + ;; des2hs = (fn SYM_ID hs => hs + ;; | SYM_OP hs => hs + ;; | SYM_CHR hs => hs) + ;; Data.sml:35.44-35.63 Error: operator and operand don't agree [tycon mismatch] + ;; operator domain: Hstring * Hstring + ;; operand: (Hstring * int) * (Hstring * int) + ;; in expression: + ;; HSTRING.ieq (h1,h2) + ;; vparse.sml:1861.6-1922.14 Error: case object and rules don't agree [tycon mismatch] + ;; rule domain: STConstraints list list option + ;; object: STConstraints list option + ;; in expression: + (save-current-buffer + (when (and (derived-mode-p 'sml-mode 'inferior-sml-mode) + (boundp 'next-error-last-buffer) + (bufferp next-error-last-buffer) + (set-buffer next-error-last-buffer) + (derived-mode-p 'inferior-sml-mode) + ;; The position of `point' is not guaranteed :-( + (looking-at (concat ".*\\[tycon mismatch\\]\n" + " \\(operator domain\\|expression\\|rule domain\\): +"))) + (ignore-errors (require 'smerge-mode)) + (if (not (fboundp 'smerge-refine-subst)) + (remove-hook 'next-error-hook 'inferior-sml-next-error-hook) + (save-excursion + (let ((b1 (match-end 0)) + e1 b2 e2) + (when (re-search-forward "\n in \\(expression\\|declaration\\):\n" + nil t) + (setq e2 (match-beginning 0)) + (when (re-search-backward + "\n \\(operand\\|result type\\|object\\): +" + b1 t) + (setq e1 (match-beginning 0)) + (setq b2 (match-end 0)) + (smerge-refine-subst b1 e1 b2 e2 + '((face . smerge-refined-change))))))))))) + +(define-derived-mode inferior-sml-mode comint-mode "Inferior-SML" + "Major mode for interacting with an inferior ML process. + +The following commands are available: +\\{inferior-sml-mode-map} + +An ML process can be fired up (again) with \\[sml]. + +Customisation: Entry to this mode runs the hooks on `comint-mode-hook' +and `inferior-sml-mode-hook' (in that order). + +Variables controlling behaviour of this mode are + +`sml-program-name' (default \"sml\") + Program to run as ML. + +`sml-use-command' (default \"use \\\"%s\\\"\") + Template for loading a file into the inferior ML process. + +`sml-cd-command' (default \"System.Directory.cd \\\"%s\\\"\") + ML command for changing directories in ML process (if possible). + +`sml-prompt-regexp' (default \"^[\\-=] *\") + Regexp used to recognise prompts in the inferior ML process. + +You can send text to the inferior ML process from other buffers containing +ML source. + `switch-to-sml' switches the current buffer to the ML process buffer. + `sml-send-function' sends the current *paragraph* to the ML process. + `sml-send-region' sends the current region to the ML process. + + Prefixing the sml-send-<whatever> commands with \\[universal-argument] + causes a switch to the ML process buffer after sending the text. + +For information on running multiple processes in multiple buffers, see +documentation for variable `sml-buffer'. + +Commands: +RET after the end of the process' output sends the text from the + end of process to point. +RET before the end of the process' output copies the current line + to the end of the process' output, and sends it. +DEL converts tabs to spaces as it moves back. +TAB file name completion, as in shell-mode, etc.." + (setq comint-prompt-regexp sml-prompt-regexp) + (sml-mode-variables) + + ;; We have to install it globally, 'cause it's run in the *source* buffer :-( + (add-hook 'next-error-hook 'inferior-sml-next-error-hook) + + ;; Make TAB add a " rather than a space at the end of a file name. + (set (make-local-variable 'comint-completion-addsuffix) '(?/ . ?\")) + (add-hook 'comint-input-filter-functions + 'sml-proc-comint-input-filter-function nil t) + + (set (make-local-variable 'font-lock-defaults) + inferior-sml-font-lock-defaults) + ;; For sequencing through error messages: + (set (make-local-variable 'sml-error-cursor) (point-max-marker)) + (set-marker-insertion-type sml-error-cursor nil) + + ;; Compilation support (used for `next-error'). + ;; The keymap of compilation-minor-mode is too unbearable, so we + ;; just can't use the minor-mode if we can't override the map. + (when (boundp 'minor-mode-overriding-map-alist) + (set (make-local-variable 'compilation-error-regexp-alist) + sml-error-regexp-alist) + (compilation-minor-mode 1) + ;; Eliminate compilation-minor-mode's map. + (let ((map (make-sparse-keymap))) + (dolist (keys '([menu-bar] [follow-link])) + ;; Preserve some of the bindings. + (define-key map keys (lookup-key compilation-minor-mode-map keys))) + (add-to-list 'minor-mode-overriding-map-alist + (cons 'compilation-minor-mode map))) + ;; I'm sure people might kill me for that + (setq compilation-error-screen-columns nil) + (make-local-variable 'sml-endof-error-alist)) + ;;(make-local-variable 'sml-error-overlay) + + (setq mode-line-process '(": %s"))) + +;;; FOR RUNNING ML FROM EMACS + +;;;###autoload +(autoload 'run-sml "sml-proc" nil t) +(defalias 'run-sml 'sml-run) +(defun sml-run (cmd arg &optional host) + "Run the program CMD with given arguments ARG. +The command is run in buffer *CMD* using mode `inferior-sml-mode'. +If the buffer already exists and has a running process, then +just go to this buffer. + +This updates `sml-buffer' to the new buffer. +You can have several inferior M(or L process running, but only one (> s +current one -- given by `sml-buffer' (qv). + +If a prefix argument is used, the user is also prompted for a HOST +on which to run CMD using `remote-shell-program'. + +\(Type \\[describe-mode] in the process buffer for a list of commands.)" + (interactive + (list + (read-string "ML command: " sml-program-name) + (if (or current-prefix-arg (> (length sml-default-arg) 0)) + (read-string "Any args: " sml-default-arg) + sml-default-arg) + (if (or current-prefix-arg (> (length sml-host-name) 0)) + (read-string "On host: " sml-host-name) + sml-host-name))) + (let* ((pname (file-name-nondirectory cmd)) + (args (if (equal arg "") () (split-string arg))) + (file (when (and sml-config-file (file-exists-p sml-config-file)) + sml-config-file))) + ;; and this -- to keep these as defaults even if + ;; they're set in the mode hooks. + (setq sml-program-name cmd) + (setq sml-default-arg arg) + (setq sml-host-name host) + ;; For remote execution, use `remote-shell-program' + (when (> (length host) 0) + (setq args (list* host "cd" default-directory ";" cmd args)) + (setq cmd remote-shell-program)) + ;; go for it + (let ((exec-path (if (file-name-directory cmd) + ;; If the command has slashes, make sure we + ;; first look relative to the current directory. + ;; Emacs-21 does it for us, but not Emacs-20. + (cons default-directory exec-path) exec-path))) + (setq sml-buffer (apply 'make-comint pname cmd file args))) + + (pop-to-buffer sml-buffer) + ;;(message (format "Starting \"%s\" in background." pname)) + (inferior-sml-mode) + (goto-char (point-max)) + sml-buffer)) + +(defun switch-to-sml (eobp) + "Switch to the ML process buffer. +Move point to the end of buffer unless prefix argument EOBP is set." + (interactive "P") + (pop-to-buffer (sml-proc-buffer)) + (unless eobp + (push-mark (point) t) + (goto-char (point-max)))) + +;; Fakes it with a "use <temp-file>;" if necessary. + +(defun sml-send-region (start end &optional and-go) + "Send current region START..END to the inferior ML process. +Prefix AND-GO argument means switch-to-sml afterwards. + +The region is written out to a temporary file and a \"use <temp-file>\" command +is sent to the compiler. +See variables `sml-use-command'." + (interactive "r\nP") + (if (= start end) + (message "The region is zero (ignored)") + (let* ((buf (sml-proc-buffer)) + (marker (copy-marker start)) + (tmp (make-temp-file "sml"))) + (write-region start end tmp nil 'silently) + (with-current-buffer buf + (when sml-temp-file + (ignore-errors (delete-file (car sml-temp-file))) + (set-marker (cdr sml-temp-file) nil)) + (setq sml-temp-file (cons tmp marker)) + (sml-send-string (format sml-use-command tmp) nil and-go))))) + +;; This is quite bogus, so it isn't bound to a key by default. +;; Anyone coming up with an algorithm to recognise fun & local +;; declarations surrounding point will do everyone a favour! + +(defun sml-send-function (&optional and-go) + "Send current paragraph to the inferior ML process. +With a prefix argument AND-GO switch to the sml buffer as well +\(cf. `sml-send-region'\)." + (interactive "P") + (save-excursion + (sml-mark-function) + (sml-send-region (point) (mark))) + (if and-go (switch-to-sml nil))) + +(defvar sml-source-modes '(sml-mode) + "*Used to determine if a buffer contains ML source code. +If it's loaded into a buffer that is in one of these major modes, it's +considered an ML source file by `sml-load-file'. Used by these commands +to determine defaults.") + +(defun sml-send-buffer (&optional and-go) + "Send buffer to inferior shell running ML process. +With a prefix argument AND-GO switch to the sml buffer as well +\(cf. `sml-send-region'\)." + (interactive "P") + (if (memq major-mode sml-source-modes) + (sml-send-region (point-min) (point-max) and-go))) + +;; Since sml-send-function/region take an optional prefix arg, these +;; commands are redundant. But they are kept around for the user to +;; bind if she wishes, since its easier to type C-c r than C-u C-c C-r. + +(defun sml-send-region-and-go (start end) + "Send current region START..END to the inferior ML process, and go there." + (interactive "r") + (sml-send-region start end t)) + +(defun sml-send-function-and-go () + "Send current paragraph to the inferior ML process, and go there." + (interactive) + (sml-send-function t)) + +;;; LOADING AND IMPORTING SOURCE FILES: + +(defvar sml-prev-dir/file nil + "Cache for (DIRECTORY . FILE) pair last. +Set in `sml-load-file' and `sml-cd' commands. +Used to determine the default in the next `ml-load-file'.") + +(defun sml-load-file (&optional and-go) + "Load an ML file into the current inferior ML process. +With a prefix argument AND-GO switch to sml buffer as well. + +This command uses the ML command template `sml-use-command' to construct +the command to send to the ML process\; a trailing \"\;\\n\" will be added +automatically." + (interactive "P") + (let ((file (car (comint-get-source + "Load ML file: " sml-prev-dir/file sml-source-modes t)))) + (with-current-buffer (sml-proc-buffer) + ;; Check if buffer needs saved. Should (save-some-buffers) instead? + (comint-check-source file) + (setq sml-prev-dir/file + (cons (file-name-directory file) (file-name-nondirectory file))) + (sml-send-string (format sml-use-command file) nil and-go)))) + +(defun sml-cd (dir) + "Change the working directory of the inferior ML process. +The default directory of the process buffer is changed to DIR. If the +variable `sml-cd-command' is non-nil it should be an ML command that will +be executed to change the compiler's working directory\; a trailing +\"\;\\n\" will be added automatically." + (interactive "DSML Directory: ") + (let ((dir (expand-file-name dir))) + (with-current-buffer (sml-proc-buffer) + (sml-send-string (format sml-cd-command dir) t) + (setq default-directory dir)) + (setq sml-prev-dir/file (cons dir nil)))) + +(defun sml-send-string (str &optional print and-go) + (let ((proc (sml-proc)) + (str (concat str ";\n")) + (win (get-buffer-window (current-buffer) 'visible))) + (when win (select-window win)) + (goto-char (point-max)) + (when print (insert str)) + (sml-update-cursor) + (set-marker (process-mark proc) (point-max)) + (setq compilation-last-buffer (current-buffer)) + (comint-send-string proc str) + (when and-go (switch-to-sml nil)))) + +(defun sml-compile (command &optional and-go) + "Pass a COMMAND to the SML process to compile the current program. + +You can then use the command \\[next-error] to find the next error message +and move to the source code that caused it. + +Interactively, prompts for the command if `compilation-read-command' is +non-nil. With prefix arg, always prompts. + +Prefix arg AND-GO also means to `switch-to-sml' afterwards." + (interactive + (let* ((dir default-directory) + (cmd "cd \".")) + ;; look for files to determine the default command + (while (and (stringp dir) + (dolist (cf sml-compile-commands-alist 1) + (when (file-exists-p (expand-file-name (cdr cf) dir)) + (setq cmd (concat cmd "\"; " (car cf))) (return nil)))) + (let ((newdir (file-name-directory (directory-file-name dir)))) + (setq dir (unless (equal newdir dir) newdir)) + (setq cmd (concat cmd "/..")))) + (setq cmd + (cond + ((local-variable-p 'sml-compile-command) sml-compile-command) + ((string-match "^\\s-*cd\\s-+\"\\.\"\\s-*;\\s-*" cmd) + (substring cmd (match-end 0))) + ((string-match "^\\s-*cd\\s-+\"\\(\\./\\)" cmd) + (replace-match "" t t cmd 1)) + ((string-match ";" cmd) cmd) + (t sml-compile-command))) + ;; code taken from compile.el + (if (or compilation-read-command current-prefix-arg) + (list (read-from-minibuffer "Compile command: " + cmd nil nil '(compile-history . 1))) + (list cmd)))) + ;; ;; now look for command's file to determine the directory + ;; (setq dir default-directory) + ;; (while (and (stringp dir) + ;; (dolist (cf sml-compile-commands-alist t) + ;; (when (and (equal cmd (car cf)) + ;; (file-exists-p (expand-file-name (cdr cf) dir))) + ;; (return nil)))) + ;; (let ((newdir (file-name-directory (directory-file-name dir)))) + ;; (setq dir (unless (equal newdir dir) newdir)))) + ;; (setq dir (or dir default-directory)) + ;; (list cmd dir))) + (set (make-local-variable 'sml-compile-command) command) + (save-some-buffers (not compilation-ask-about-save) nil) + (let ((dir default-directory)) + (when (string-match "^\\s-*cd\\s-+\"\\([^\"]+\\)\"\\s-*;" command) + (setq dir (match-string 1 command)) + (setq command (replace-match "" t t command))) + (setq dir (expand-file-name dir)) + (with-current-buffer (sml-proc-buffer) + (setq default-directory dir) + (sml-send-string (concat (format sml-cd-command dir) "; " command) + t and-go)))) + +;;; PARSING ERROR MESSAGES + +;; This should need no modification to support other compilers. + +;; Update the buffer-local error-cursor in proc-buffer to be its +;; current proc mark. + +(defvar sml-endof-error-alist nil) + +(defun sml-update-cursor () + ;; Update buffer local variable. + (set-marker sml-error-cursor (1- (process-mark (sml-proc)))) + (setq sml-endof-error-alist nil) + ;; This is now done in comint-input-filter-functions. + ;; (compilation-forget-errors) ;Has to run before compilation-fake-loc. + ;; (if (and (fboundp 'compilation-fake-loc) sml-temp-file) + ;; (compilation-fake-loc (cdr sml-temp-file) (car sml-temp-file))) + (if (markerp compilation-parsing-end) + (set-marker compilation-parsing-end sml-error-cursor) + (setq compilation-parsing-end sml-error-cursor))) + +(defun sml-make-error (f c) + (let ((err (point-marker)) + (linenum (string-to-number c)) + (filename (list (first f) (second f))) + (column (string-to-number (match-string (third f))))) + ;; record the end of error, if any + (when (fourth f) + (let ((endlinestr (match-string (fourth f)))) + (when endlinestr + (let* ((endline (string-to-number endlinestr)) + (endcol (string-to-number + (or (match-string (fifth f)) "0"))) + (linediff (- endline linenum))) + (push (list err linediff (if (= 0 linediff) (- endcol column) endcol)) + sml-endof-error-alist))))) + ;; build the error descriptor + (if (string= (car sml-temp-file) (first f)) + ;; special case for code sent via sml-send-region + (let ((marker (cdr sml-temp-file))) + (with-current-buffer (marker-buffer marker) + (goto-char marker) + (forward-line (1- linenum)) + (forward-char (1- column)) + ;; A pair of markers is the right thing to return, but some + ;; code in compile.el doesn't like it (when we reach the end + ;; of the errors). So we could try to avoid it, but we don't + ;; because that doesn't work correctly if the current buffer + ;; has unsaved modifications. And it's fixed in Emacs-21. + ;; (if buffer-file-name + ;; (list err buffer-file-name + ;; (count-lines (point-min) (point)) (current-column)) + (cons err (point-marker)))) ;; ) + ;; taken from compile.el + (list err filename linenum column)))) + +(unless (fboundp 'compilation-fake-loc) +(defadvice compilation-goto-locus (after sml-endof-error activate) + (let* ((next-error (ad-get-arg 0)) + (err (car next-error)) + (pos (cdr next-error)) + (endof (with-current-buffer (marker-buffer err) + (assq err sml-endof-error-alist)))) + (if (not endof) (sml-error-overlay 'undo) + (with-current-buffer (marker-buffer pos) + (goto-char pos) + (let ((linediff (second endof)) + (coldiff (third endof))) + (when (> 0 linediff) (forward-line linediff)) + (forward-char coldiff)) + (sml-error-overlay nil pos (point)) + (push-mark nil t (not sml-error-overlay)) + (goto-char pos)))))) + +(defun sml-error-overlay (undo &optional beg end) + "Move `sml-error-overlay' to the text region in the current buffer. +If the buffer-local variable `sml-error-overlay' is +non-nil it should be an overlay \(or extent, in XEmacs speak\)\; this +function moves the overlay over the current region. If the optional +BUFFER argument is given, move the overlay in that buffer instead of +the current buffer. + +Called interactively, the optional prefix argument UNDO indicates that +the overlay should simply be removed: \\[universal-argument] \ +\\[sml-error-overlay]." + (interactive "P") + (when sml-error-overlay + (unless (overlayp sml-error-overlay) + (let ((ol sml-error-overlay)) + (setq sml-error-overlay (make-overlay (point) (point))) + (overlay-put sml-error-overlay 'face (if (symbolp ol) ol 'region)))) + (if undo (delete-overlay sml-error-overlay) + ;; If active regions, signals mark not active if no region set. + (move-overlay sml-error-overlay + (or beg (region-beginning)) (or end (region-end)) + (current-buffer))))) + +(provide 'sml-proc) + +;;; sml-proc.el ends here diff --git a/emacs/emacs.d/sml-mode-5.0/testcases.sml b/emacs/emacs.d/sml-mode-5.0/testcases.sml @@ -0,0 +1,563 @@ +(* Copyright 1999,2004,2007,2010-2012 Stefan Monnier <monnier@gnu.org> *) + +(* sml-mode here treats the second `=' as an equal op because it + * thinks it's seeing something like "... type t = (s.t = ...)". FIXME! *) +functor foo (structure s : S) where type t = s.t = +struct (* fixindent *) +val bar = fn a1 a2 a3 + a5 a6 + a4 => 1 +val rec bar = + fn a1 a2 a3 + a5 a6 a4 => 1 +val bar = + fn a1 a2 a3 + a5 a6 + a4 => (1 + ;( + w + , + s + , + s + , s , a , + a + , s , a , + a + ) + ;( + w + ,s + ,a + ) + ;( + w + , s + , a + ) + ;( w + , s + , a + ) + ;( w + ,s + ,a + ) + ;3 + + a + * 4 + + let val x = 3 + in toto + end + + if a then + b + else + c + ;4) + +val ber = 1; +val sdfg = 1 +val tut = fn (x,y) z y e r => + body +val tut = fn (x,y) => fn z y => fn e r => + body +val tut = fn (x,y) + z + y e + r => + body +val tut = + (let + local + val x = 1 in val x = x end + val a = 1 val b = 2 + local val x = 1 in val x = x end + local val x = 1 in val x = x end + local val x = 1 in val x = x end (* fixindent *) + local val x = 1 in val x = x end + val c = 3 + in + let + val x = 3 + in + x + a * b + * c + end + end) + +val x = + (* From "Christopher Dutchyn" <cdutchyn@cs.ubc.ca> *) + (case foo of + (* This is actually not valid SML anyway. *) + | BAR => baz + | BAR => baz) + + +val x = + (x := 1; + x := 2; + (* Testing obedience to user overrides: *) + x := 3; (* fixindent *) + case x of + FOO => 1 + | BAR => + 2; + case x of + FOO => 1 + | BAR => + case y of + FAR => 2 + | FRA => 3; + hello); + +datatype foobar + = FooB of int + | FooA of bool * int +datatype foo = FOO | BAR of baz + and baz = BAZ | QUUX of foo + +fun toto = if a + then + b + else c + +datatype foo = FOO + | BAR of baz + and baz = BAZ (* fixindent *) + | QUUX of foo + and b = g + +datatype foo = datatype M.foo +val _ = 42 val x = 5 + +signature S = S' where type foo = int +val _ = 42 + +val foo = [ + "blah" + , let val x = f 42 in g (x,x,44) end +] + +val foo = [ + "blah", + let val x = f 42 in g (x,x,44) end +] + +val foo = + [ + "blah", + let val x = f 42 in g (x,x,44) end + ] + +val foo = [ "blah" + , let val x = f 42 in g (x,x,44) end + , foldl (fn ((p,q),s) => g (p,q,Vector.length q) ^ ":" ^ s) + "" (Beeblebrox.masterCountList mlist2) + , if null mlist2 then ";" else "" + ] + +fun foo (true::rest) = 1 + 2 * foo rest + | foo (false::rest) + = let val _ = 1 in 2 end + + 2 + * foo rest + +val x = if foo then + 1 + else if bar then + 2 + else + 3 +val y = if foo + then 1 + else if foo + then 2 (* Could also be indented by a basic offset. *) + else 3 + +val yt = 4 + +val x = + (if a then b else c; + case M.find(m,f) + of SOME(fl, filt) => + F.APP(F.VAR fl, OU.filter filt vs) + | NONE + => le + | NONE => + le + | NONE => le; + x := x + 1; + (case foo + of a => f + )) + +val y = ( + let fun f1 = + let fun g1 x = 2 + fun g2 y = 4 + local fun toto y = 1 + (* val x = 5 *) + in + fun g3 z = z + end + in toto + end + in a;( ( let + val f =1 + in + toto + end + ) + ) + foo("(*") + * 2; + end; + + let + in a + ; b + end; + + let + in + a + + b + + c + ; b + end; + + let + in if a then + b + else + c + end; + + let + in case a of + F => 1 + | D => 2 + end; + + let + in case a + of F => 1 + | D => 2 + end; + + let + in if a then b else + c + end; + + let + in if a then b + else + c + end) +end; + +structure Foo = struct +val x = 1 +end + +structure Foo = struct val x = 1 + end + +signature FSPLIT = +sig + type flint = FLINT.prog + val split: flint -> flint * flint option +end + +structure FSplit :> FSPLIT = +struct + +local + structure F = FLINT + structure S = IntRedBlackSet + structure M = FLINTIntMap + structure O = Option + structure OU = OptUtils + structure FU = FlintUtil + structure LT = LtyExtern + structure PO = PrimOp + structure PP = PPFlint + structure CTRL = FLINT_Control +in + +val say = Control_Print.say +fun bug msg = ErrorMsg.impossible ("FSplit: "^msg) +fun buglexp (msg,le) = (say "\n"; PP.printLexp le; say " "; bug msg) +fun bugval (msg,v) = (say "\n"; PP.printSval v; say " "; bug msg) +fun assert p = if p then () else bug ("assertion failed") + +type flint = F.prog +val mklv = LambdaVar.mkLvar +val cplv = LambdaVar.dupLvar + +fun S_rmv(x, s) = S.delete(s, x) handle NotFound => s + +fun addv (s,F.VAR lv) = S.add(s, lv) + | addv (s,_) = s +fun addvs (s,vs) = foldl (fn (v,s) => addv(s, v)) s vs +fun rmvs (s,lvs) = foldl (fn (l,s) => S_rmv(l, s)) s lvs + +exception Unknown + +fun split (fdec as (fk,f,args,body)) = let + val {getLty,addLty,...} = Recover.recover (fdec, false) + + val m = Intmap.new(64, Unknown) + fun addpurefun f = Intmap.add m (f, false) + fun funeffect f = (Intmap.map m f) handle Uknown => true + +(* sexp: env -> lexp -> (leE, leI, fvI, leRet) + * - env: IntSetF.set current environment + * - lexp: lexp expression to split + * - leRet: lexp the core return expression of lexp + * - leE: lexp -> lexp recursively split lexp: leE leRet == lexp + * - leI: lexp option inlinable part of lexp (if any) + * - fvI: IntSetF.set free variables of leI: FU.freevars leI == fvI + * + * sexp splits the lexp into an expansive part and an inlinable part. + * The inlinable part is guaranteed to be side-effect free. + * The expansive part doesn't bother to eliminate unused copies of + * elements copied to the inlinable part. + * If the inlinable part cannot be constructed, leI is set to F.RET[]. + * This implies that fvI == S.empty, which in turn prevents us from + * mistakenly adding anything to leI. + *) +fun sexp env lexp = (* fixindent *) + let + (* non-side effecting binds are copied to leI if exported *) + fun let1 (le,lewrap,lv,vs,effect) = + let val (leE,leI,fvI,leRet) = sexp (S.add(env, lv)) le + val leE = lewrap o leE + in if effect orelse not (S.member(fvI, lv)) + then (leE, leI, fvI, leRet) + else (leE, lewrap leI, addvs(S_rmv(lv, fvI), vs), leRet) + end + + in case lexp + (* we can completely move both RET and TAPP to the I part *) + of F.RECORD (rk,vs,lv,le as F.RET [F.VAR lv']) => + if lv' = lv + then (fn e => e, lexp, addvs(S.empty, vs), lexp) + else (fn e => e, le, S.singleton lv', le) + | F.RET vs => + (fn e => e, lexp, addvs(S.empty, vs), lexp) + | F.TAPP (F.VAR tf,tycs) => + (fn e => e, lexp, S.singleton tf, lexp) + + (* recursive splittable lexps *) + | F.FIX (fdecs,le) => sfix env (fdecs, le) + | F.TFN (tfdec,le) => stfn env (tfdec, le) + + (* binding-lexps *) + | F.CON (dc,tycs,v,lv,le) => + let1(le, fn e => F.CON(dc, tycs, v, lv, e), lv, [v], false) + | F.RECORD (rk,vs,lv,le) => + let1(le, fn e => F.RECORD(rk, vs, lv, e), lv, vs, false) + | F.SELECT (v,i,lv,le) => + let1(le, fn e => F.SELECT(v, i, lv, e), lv, [v], false) + | F.PRIMOP (po,vs,lv,le) => + let1(le, fn e => F.PRIMOP(po, vs, lv, e), lv, vs, PO.effect(#2 po)) + + (* IMPROVEME: lvs should not be restricted to [lv] *) + | F.LET(lvs as [lv],body as F.TAPP (v,tycs),le) => + let1(le, fn e => F.LET(lvs, body, e), lv, [v], false) + | F.LET (lvs as [lv],body as F.APP (v as F.VAR f,vs),le) => + let1(le, fn e => F.LET(lvs, body, e), lv, v::vs, funeffect f) + + | F.SWITCH (v,ac,[(dc as F.DATAcon(_,_,lv),le)],NONE) => + let1(le, fn e => F.SWITCH(v, ac, [(dc, e)], NONE), lv, [v], false) + + | F.LET (lvs,body,le) => + let val (leE,leI,fvI,leRet) = sexp (S.union(S.addList(S.empty, lvs), env)) le + in (fn e => F.LET(lvs, body, leE e), leI, fvI, leRet) + end + + (* useless sophistication *) + | F.APP (F.VAR f,args) => + if funeffect f + then (fn e => e, F.RET[], S.empty, lexp) + else (fn e => e, lexp, addvs(S.singleton f, args), lexp) + + (* other non-binding lexps result in unsplittable functions *) + | (F.APP _ | F.TAPP _) => bug "strange (T)APP" + | (F.SWITCH _ | F.RAISE _ | F.BRANCH _ | F.HANDLE _) => + (fn e => e, F.RET[], S.empty, lexp) + end + +(* Functions definitions fall into the following categories: + * - inlinable: if exported, copy to leI + * - (mutually) recursive: don't bother + * - non-inlinable non-recursive: split recursively *) +and sfix env (fdecs,le) = + let val nenv = S.union(S.addList(S.empty, map #2 fdecs), env) + val (leE,leI,fvI,leRet) = sexp nenv le + val nleE = fn e => F.FIX(fdecs, leE e) + in case fdecs + of [({inline=inl as (F.IH_ALWAYS | F.IH_MAYBE _),...},f,args,body)] => + let val min = case inl of F.IH_MAYBE(n,_) => n | _ => 0 + in if not(S.member(fvI, f)) orelse min > !CTRL.splitThreshold + then (nleE, leI, fvI, leRet) + else (nleE, F.FIX(fdecs, leI), + rmvs(S.union(fvI, FU.freevars body), + f::(map #1 args)), + leRet) + end + | [fdec as (fk as {cconv=F.CC_FCT,...},_,_,_)] => + sfdec env (leE,leI,fvI,leRet) fdec + + | _ => (nleE, leI, fvI, leRet) + end + +and sfdec env (leE,leI,fvI,leRet) (fk,f,args,body) = + let val benv = S.union(S.addList(S.empty, map #1 args), env) + val (bodyE,bodyI,fvbI,bodyRet) = sexp benv body + in case bodyI + of F.RET[] => + (fn e => F.FIX([(fk, f, args, bodyE bodyRet)], e), + leI, fvI, leRet) + | _ => + let val fvbIs = S.listItems(S.difference(fvbI, benv)) + val (nfk,fkE) = OU.fk_wrap(fk, NONE) + + (* fdecE *) + val fE = cplv f + val fErets = (map F.VAR fvbIs) + val bodyE = bodyE(F.RET fErets) + (* val tmp = mklv() + val bodyE = bodyE(F.RECORD(F.RK_STRUCT, map F.VAR fvbIs, + tmp, F.RET[F.VAR tmp])) *) + val fdecE = (fkE, fE, args, bodyE) + val fElty = LT.ltc_fct(map #2 args, map getLty fErets) + val _ = addLty(fE, fElty) + + (* fdecI *) + val fkI = {inline=F.IH_ALWAYS, cconv=F.CC_FCT, + known=true, isrec=NONE} + val argsI = + (map (fn lv => (lv, getLty(F.VAR lv))) fvbIs) @ args + val fdecI as (_,fI,_,_) = FU.copyfdec(fkI,f,argsI,bodyI) + val _ = addpurefun fI + + (* nfdec *) + val nargs = map (fn (v,t) => (cplv v, t)) args + val argsv = map (fn (v,t) => F.VAR v) nargs + val nbody = + let val lvs = map cplv fvbIs + in F.LET(lvs, F.APP(F.VAR fE, argsv), + F.APP(F.VAR fI, (map F.VAR lvs)@argsv)) + end + (* let val lv = mklv() + in F.LET([lv], F.APP(F.VAR fE, argsv), + F.APP(F.VAR fI, (F.VAR lv)::argsv)) + end *) + val nfdec = (nfk, f, nargs, nbody) + + (* and now, for the whole F.FIX *) + fun nleE e = + F.FIX([fdecE], F.FIX([fdecI], F.FIX([nfdec], leE e))) + + in if not(S.member(fvI, f)) then (nleE, leI, fvI, leRet) + else (nleE, + F.FIX([fdecI], F.FIX([nfdec], leI)), + S.add(S.union(S_rmv(f, fvI), S.intersection(env, fvbI)), fE), + leRet) + end + end + +(* TFNs are kinda like FIX except there's no recursion *) +and stfn env (tfdec as (tfk,tf,args,body),le) = + let val (bodyE,bodyI,fvbI,bodyRet) = + if #inline tfk = F.IH_ALWAYS + then (fn e => body, body, FU.freevars body, body) + else sexp env body + val nenv = S.add(env, tf) + val (leE,leI,fvI,leRet) = sexp nenv le + in case (bodyI, S.listItems(S.difference(fvbI, env))) + of ((F.RET _ | F.RECORD(_,_,_,F.RET _)),_) => + (* split failed *) + (fn e => F.TFN((tfk, tf, args, bodyE bodyRet), leE e), + leI, fvI, leRet) + | (_,[]) => + (* everything was split out *) + let val ntfdec = ({inline=F.IH_ALWAYS}, tf, args, bodyE bodyRet) + val nlE = fn e => F.TFN(ntfdec, leE e) + in if not(S.member(fvI, tf)) then (nlE, leI, fvI, leRet) + else (nlE, F.TFN(ntfdec, leI), + S_rmv(tf, S.union(fvI, fvbI)), leRet) + end + | (_,fvbIs) => + let (* tfdecE *) + val tfE = cplv tf + val tfEvs = map F.VAR fvbIs + val bodyE = bodyE(F.RET tfEvs) + val tfElty = LT.lt_nvpoly(args, map getLty tfEvs) + val _ = addLty(tfE, tfElty) + + (* tfdecI *) + val tfkI = {inline=F.IH_ALWAYS} + val argsI = map (fn (v,k) => (cplv v, k)) args + (* val tmap = ListPair.map (fn (a1,a2) => + * (#1 a1, LT.tcc_nvar(#1 a2))) + * (args, argsI) *) + val bodyI = FU.copy tmap M.empty + (F.LET(fvbIs, F.TAPP(F.VAR tfE, map #2 tmap), + bodyI)) + (* F.TFN *) + fun nleE e = + F.TFN((tfk, tfE, args, bodyE), + F.TFN((tfkI, tf, argsI, bodyI), leE e)) + + in if not(S.member(fvI, tf)) then (nleE, leI, fvI, leRet) + else (nleE, + F.TFN((tfkI, tf, argsI, bodyI), leI), + S.add(S.union(S_rmv(tf, fvI), S.intersection(env, fvbI)), tfE), + leRet) + end + end + +(* here, we use B-decomposition, so the args should not be + * considered as being in scope *) +val (bodyE,bodyI,fvbI,bodyRet) = sexp S.empty body +in case (bodyI, bodyRet) + of (F.RET _,_) => ((fk, f, args, bodyE bodyRet), NONE) + | (_,F.RECORD (rk,vs,lv,F.RET[lv'])) => + let val fvbIs = S.listItems fvbI + + (* fdecE *) + val bodyE = bodyE(F.RECORD(rk, vs@(map F.VAR fvbIs), lv, F.RET[lv'])) + val fdecE as (_,fE,_,_) = (fk, cplv f, args, bodyE) + + (* fdecI *) + val argI = mklv() + val argLtys = (map getLty vs) @ (map (getLty o F.VAR) fvbIs) + val argsI = [(argI, LT.ltc_str argLtys)] + val (_,bodyI) = foldl (fn (lv,(n,le)) => + (n+1, F.SELECT(F.VAR argI, n, lv, le))) + (length vs, bodyI) fvbIs + val fdecI as (_,fI,_,_) = FU.copyfdec (fk, f, argsI, bodyI) + + val nargs = map (fn (v,t) => (cplv v, t)) args + in + (fdecE, SOME fdecI) + (* ((fk, f, nargs, + F.FIX([fdecE], + F.FIX([fdecI], + F.LET([argI], + F.APP(F.VAR fE, map (F.VAR o #1) nargs), + F.APP(F.VAR fI, [F.VAR argI]))))), + NONE) *) + end + + | _ => (fdec, NONE) (* sorry, can't do that *) +(* (PPFlint.printLexp bodyRet; bug "couldn't find the returned record") *) + +end + +end +end diff --git a/emacs/emacs.d/themes/cyberpunk-theme.el b/emacs/emacs.d/themes/cyberpunk-theme.el @@ -0,0 +1,844 @@ +;;; cyberpunk-theme.el --- Cyberpunk Color Theme + +;; Copyright 2012-2018, Nicholas M. Van Horn + +;; Author: Nicholas M. Van Horn <nvanhorn@protonmail.com> +;; Homepage: https://github.com/n3mo/cyberpunk-theme.el +;; Keywords: color theme cyberpunk +;; Version: 1.21 + +;; This file is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 2, or (at your option) +;; any later version. + +;; This file is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs; see the file COPYING. If not, write to +;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +;; Boston, MA 02111-1307, USA. +;; + +;; "and he'd still see the matrix in his sleep, bright lattices of logic +;; unfolding across that colorless void..." +;; William Gibson, Neuromancer. + +;;; Commentary: + +;; This theme is a port of Sam Aaron's overtone/emacs-live theme of the +;; same name (https://github.com/overtone/emacs-live). The original theme +;; was designed for use with the color-theme package. This theme adopts +;; the new built-in theme support deftheme. Additionally, this +;; theme strives to offer as many mode-specific customizations as +;; possible, with further tweaks that suit my fancy. + +(deftheme cyberpunk "The Cyberpunk color theme") + +(defcustom cyberpunk-transparent-background nil + "Make transparent background in terminal. (Workaround)") + +(let ((class '((class color) (min-colors 89))) + ;; Cyberpunk palette + (cyberpunk-fg "#dcdccc") + (cyberpunk-bg-1 "#2b2b2b") + (cyberpunk-bg-05 "#383838") + (cyberpunk-bg "#000000") + (cyberpunk-bg+1 "#4f4f4f") + (cyberpunk-bg+2 "#5f5f5f") + (cyberpunk-bg+3 "#6f6f6f") + (cyberpunk-red+1 "#dca3a3") + (cyberpunk-red "#ff0000") + (cyberpunk-red-1 "#8b0000") + (cyberpunk-red-2 "#8b0000") + (cyberpunk-red-3 "#9c6363") + (cyberpunk-red-4 "#8c5353") + (cyberpunk-red-5 "#7F073F") + (cyberpunk-pink "#ff69b4") + (cyberpunk-pink-1 "#ff1493") + (cyberpunk-pink-2 "#cd1076") + (cyberpunk-orange-2 "#FF6400") + (cyberpunk-orange-1 "#ff8c00") ;; DarkOrange + (cyberpunk-orange "#ffa500") + (cyberpunk-yellow "#ffff00") + (cyberpunk-yellow-1 "#FBDE2D") + (cyberpunk-yellow-2 "#d0bf8f") + (cyberpunk-yellow-3 "#D8FA3C") + (cyberpunk-yellow-4 "#E9C062") + (cyberpunk-yellow-5 "#ffd700") + (cyberpunk-green-2 "#006400") + (cyberpunk-green-1 "#2e8b57") + (cyberpunk-green "#00ff00") + (cyberpunk-green+1 "#61CE3C") + (cyberpunk-green+2 "#9fc59f") + (cyberpunk-green+3 "#afd8af") + (cyberpunk-green+4 "#bfebbf") + (cyberpunk-cyan "#93e0e3") + (cyberpunk-blue+1 "#94bff3") + (cyberpunk-blue "#0000ff") ;; blue + (cyberpunk-blue-1 "#7b68ee") ;; medium slate blue + (cyberpunk-blue-2 "#6a5acd") ;; slate blue + (cyberpunk-blue-3 "#add8e6") ;; light blue + (cyberpunk-blue-4 "#b2dfee") ;; LightBlue2 + (cyberpunk-blue-5 "#4c83ff") + (cyberpunk-blue-6 "#96CBFE") + (cyberpunk-blue-7 "#00ffff") + (cyberpunk-blue-8 "#4F94CD") + (cyberpunk-magenta "#dc8cc3") + (cyberpunk-black (if (and cyberpunk-transparent-background + (not (display-graphic-p)) + (eq system-type 'darwin)) + "ARGBBB000000" + "#000000")) + (cyberpunk-black-2 "#0C1021") + (cyberpunk-black-3 "#0A0A0A") + (cyberpunk-gray "#d3d3d3") + (cyberpunk-gray-2 "#8B8989") + (cyberpunk-gray-3 "#919191") + (cyberpunk-gray-4 "#999999") + (cyberpunk-gray-5 "#333333") + (cyberpunk-gray-6 "#1A1A1A") + (cyberpunk-gray-7 "#4D4D4D") + (cyberpunk-gray-8 "#262626") + (cyberpunk-white "#ffffff") + (cyberpunk-white-2 "#F8F8F8") + (cyberpunk-white-3 "#fffafa")) + + (custom-theme-set-faces + 'cyberpunk + '(button ((t (:underline t)))) + `(link ((,class (:foreground ,cyberpunk-yellow :underline t :weight bold)))) + `(link-visited ((,class (:foreground ,cyberpunk-yellow-2 :underline t :weight normal)))) + `(blue ((,class (:foreground ,cyberpunk-blue)))) + `(bold ((,class (:bold t)))) + `(border-glyph ((,class (nil)))) + `(buffers-tab ((,class (:background ,cyberpunk-black-2 :foreground ,cyberpunk-white-2)))) + + ;;; basic coloring + `(default ((,class (:foreground ,cyberpunk-gray :background ,cyberpunk-black)))) + `(cursor ((,class (:background ,cyberpunk-fg)))) + `(escape-glyph-face ((,class (:foreground ,cyberpunk-red)))) + `(fringe ((,class (:foreground ,cyberpunk-fg :background ,cyberpunk-bg-1)))) + `(header-line ((,class (:foreground ,cyberpunk-yellow + :background ,cyberpunk-bg-1 + :box (:line-width -1 :style released-button))))) + `(highlight ((,class (:background ,cyberpunk-gray-5)))) + + ;;; compilation + `(compilation-column-face ((,class (:foreground ,cyberpunk-yellow)))) + `(compilation-enter-directory-face ((,class (:foreground ,cyberpunk-green)))) + `(compilation-error-face ((,class (:foreground ,cyberpunk-red-1 :weight bold :underline t)))) + `(compilation-face ((,class (:foreground ,cyberpunk-fg)))) + `(compilation-info-face ((,class (:foreground ,cyberpunk-blue)))) + `(compilation-info ((,class (:foreground ,cyberpunk-green+4 :underline t)))) + `(compilation-leave-directory-face ((,class (:foreground ,cyberpunk-green)))) + `(compilation-line-face ((,class (:foreground ,cyberpunk-yellow)))) + `(compilation-line-number ((,class (:foreground ,cyberpunk-yellow)))) + `(compilation-message-face ((,class (:foreground ,cyberpunk-blue)))) + `(compilation-warning-face ((,class (:foreground ,cyberpunk-yellow-1 :weight bold :underline t)))) + + ;;; grep + `(grep-context-face ((,class (:foreground ,cyberpunk-black :background ,cyberpunk-pink-1)))) + `(grep-error-face ((,class (:foreground ,cyberpunk-red :weight bold :underline t)))) + `(grep-hit-face ((,class (:foreground ,cyberpunk-black :background ,cyberpunk-red)))) + `(grep-match-face ((,class (:foreground ,cyberpunk-black :background ,cyberpunk-pink-1)))) + `(match ((,class (:background ,cyberpunk-black :foreground ,cyberpunk-pink-1)))) + + + ;;; multiple-cursors + `(mc/cursor-face ((,class (:inverse-video nil, :background ,cyberpunk-pink :foreground ,cyberpunk-black)))) + + ;; faces used by isearch + `(isearch ((,class (:foreground ,cyberpunk-black :background ,cyberpunk-pink-1)))) + `(isearch-fail ((,class (:background ,cyberpunk-red-1)))) + + `(lazy-highlight ((,class (:foreground ,cyberpunk-black :background ,cyberpunk-yellow)))) + `(query-replace ((,class (:background ,cyberpunk-gray-5)))) + `(Highline-face ((,class (:background ,cyberpunk-green-1)))) + `(left-margin ((,class (nil)))) + `(toolbar ((,class (nil)))) + `(text-cursor ((,class (:background ,cyberpunk-yellow :foreground ,cyberpunk-black)))) + + `(menu ((,class (:foreground ,cyberpunk-fg :background ,cyberpunk-bg)))) + `(minibuffer-prompt ((,class (:foreground ,cyberpunk-green+1 :background ,cyberpunk-black)))) + `(mode-line + ((,class (:foreground ,cyberpunk-blue-5 + :background ,cyberpunk-gray-5 + :box (:line-width -1 :color ,cyberpunk-blue-5))))) + ;; `(mode-line-buffer-id ((,class (:foreground ,cyberpunk-yellow :weight bold)))) + `(mode-line-inactive + ((,class (:foreground ,cyberpunk-gray-7 + :background ,cyberpunk-gray-6 + :box (:line-width -1 :color ,cyberpunk-blue-5))))) + `(region ((,class (:background ,cyberpunk-red-5)))) + `(secondary-selection ((,class (:background ,cyberpunk-bg+2)))) + `(trailing-whitespace ((,class (:background ,cyberpunk-red)))) + `(vertical-border ((,class (:foreground ,cyberpunk-gray-5 :background ,cyberpunk-black)))) + + ;;; font lock + `(font-lock-builtin-face ((,class (:foreground ,cyberpunk-blue-5)))) + `(font-lock-comment-face ((,class (:foreground ,cyberpunk-gray-2 :italic t)))) + ;; `(font-lock-comment-delimiter-face ((,class (:foreground ,cyberpunk-green)))) + `(font-lock-constant-face ((,class (:foreground ,cyberpunk-blue-6)))) + ;; `(font-lock-doc-face ((,class (:foreground ,cyberpunk-green+1)))) + `(font-lock-doc-face ((,class (:foreground ,cyberpunk-yellow-1)))) + `(font-lock-function-name-face ((,class (:foreground ,cyberpunk-pink-1)))) + `(font-lock-keyword-face ((,class (:foreground ,cyberpunk-blue-5)))) + ;; `(font-lock-negation-char-face ((,class (:foreground ,cyberpunk-fg)))) + `(font-lock-preprocessor-face ((,class (:foreground ,cyberpunk-gray-3)))) + `(font-lock-string-face ((,class (:foreground ,cyberpunk-green+1)))) + `(font-lock-type-face ((,class (:foreground ,cyberpunk-green+3)))) + `(font-lock-variable-name-face ((,class (:foreground ,cyberpunk-pink)))) + `(font-lock-warning-face ((,class (:foreground ,cyberpunk-pink)))) + `(font-lock-reference-face ((,class (:foreground ,cyberpunk-gray)))) + `(font-lock-regexp-grouping-backslash ((,class (:foreground ,cyberpunk-yellow-4)))) + `(font-lock-regexp-grouping-construct ((,class (:foreground ,cyberpunk-red)))) + + `(c-annotation-face ((,class (:inherit font-lock-constant-face)))) + + `(gui-element ((,class (:background ,cyberpunk-gray-5 :foreground ,cyberpunk-blue-6)))) + + ;;; newsticker + ;; These are currently placeholders that probably look terrible. + ;; Someone who uses newsticker is welcome to change these + `(newsticker-date-face ((,class (:foreground ,cyberpunk-fg)))) + `(newsticker-default-face ((,class (:foreground ,cyberpunk-fg)))) + `(newsticker-enclosure-face ((,class (:foreground ,cyberpunk-green+3)))) + `(newsticker-extra-face ((,class (:foreground ,cyberpunk-bg+2 :height 0.8)))) + `(newsticker-feed-face ((,class (:foreground ,cyberpunk-fg)))) + `(newsticker-immortal-item-face ((,class (:foreground ,cyberpunk-green)))) + `(newsticker-new-item-face ((,class (:foreground ,cyberpunk-blue)))) + `(newsticker-obsolete-item-face ((,class (:foreground ,cyberpunk-red)))) + `(newsticker-old-item-face ((,class (:foreground ,cyberpunk-bg+3)))) + `(newsticker-statistics-face ((,class (:foreground ,cyberpunk-fg)))) + `(newsticker-treeview-face ((,class (:foreground ,cyberpunk-fg)))) + `(newsticker-treeview-immortal-face ((,class (:foreground ,cyberpunk-green)))) + `(newsticker-treeview-listwindow-face ((,class (:foreground ,cyberpunk-fg)))) + `(newsticker-treeview-new-face ((,class (:foreground ,cyberpunk-blue :weight bold)))) + `(newsticker-treeview-obsolete-face ((,class (:foreground ,cyberpunk-red)))) + `(newsticker-treeview-old-face ((,class (:foreground ,cyberpunk-bg+3)))) + `(newsticker-treeview-selection-face ((,class (:foreground ,cyberpunk-yellow)))) + + ;;; external + + ;; full-ack + `(ack-separator ((,class (:foreground ,cyberpunk-fg)))) + `(ack-file ((,class (:foreground ,cyberpunk-blue)))) + `(ack-line ((,class (:foreground ,cyberpunk-yellow)))) + `(ack-match ((,class (:foreground ,cyberpunk-orange :background ,cyberpunk-bg-1 :weigth bold)))) + + ;; auctex + `(font-latex-bold ((,class (:inherit bold)))) + `(font-latex-warning ((,class (:inherit font-lock-warning)))) + `(font-latex-sedate ((,class (:foreground ,cyberpunk-yellow :weight bold)))) + `(font-latex-string ((,class (:foreground ,cyberpunk-green)))) + `(font-latex-title-4 ((,class (:inherit variable-pitch :weight bold)))) + `(font-latex-sectioning-0 ((,class (:foreground ,cyberpunk-blue :background ,cyberpunk-black :scale 1.5)))) + `(font-latex-sectioning-1 ((,class (:foreground ,cyberpunk-blue :background ,cyberpunk-black :scale 1.5)))) + + ;; auto-complete + `(ac-completion-face ((,class (:background ,cyberpunk-gray-2 :underline t)))) + `(ac-candidate-face ((,class (:background ,cyberpunk-gray-4 :foreground ,cyberpunk-black)))) + `(ac-selection-face ((,class (:background ,cyberpunk-pink-1 :foreground ,cyberpunk-black)))) + `(popup-tip-face ((,class (:background ,cyberpunk-gray-5 :foreground ,cyberpunk-white)))) + `(popup-scroll-bar-foreground-face ((,class (:background ,cyberpunk-black-3)))) + `(popup-scroll-bar-background-face ((,class (:background ,cyberpunk-gray-5)))) + `(popup-isearch-match ((,class (:background ,cyberpunk-black :foreground ,cyberpunk-pink-1)))) + + `(window-number-face ((,class (:background ,cyberpunk-gray-6 :foreground ,cyberpunk-blue-5)))) + + ;; company-mode + `(company-tooltip ((,class (:background ,cyberpunk-gray-2 :foreground ,cyberpunk-yellow)))) + `(company-tooltip-common ((,class (:inherit company-tooltip :foreground ,cyberpunk-blue)))) + `(company-tooltip-common-selection ((,class (:inherit company-tooltip-selection :foreground ,cyberpunk-blue)))) + `(company-tooltip-selection ((,class (:foreground ,cyberpunk-black :background ,cyberpunk-pink-1)))) + `(company-tooltip-annotation ((,class (:inherit company-tooltip :foreground ,cyberpunk-black-3)))) + `(company-scrollbar-fg ((,class (:background ,cyberpunk-black-3)))) + `(company-scrollbar-bg ((,class (:background ,cyberpunk-gray-5)))) + `(company-preview ((,class (:foreground ,cyberpunk-gray :background ,cyberpunk-pink-1)))) + `(company-preview-common ((,class (:foreground ,cyberpunk-gray :background ,cyberpunk-pink-1)))) + + ;; diff + `(diff-added ((,class (:foreground ,cyberpunk-green)))) + `(diff-changed ((,class (:foreground ,cyberpunk-yellow)))) + `(diff-removed ((,class (:foreground ,cyberpunk-red)))) + `(diff-header ((,class (:background ,cyberpunk-bg+2)))) + `(diff-file-header ((,class (:background ,cyberpunk-bg+2 :foreground ,cyberpunk-fg :bold t)))) + + ;; ediff + `(ediff-current-diff-Ancestor ((,class (:foreground ,cyberpunk-fg :background ,cyberpunk-pink)))) + `(ediff-current-diff-A ((,class (:foreground ,cyberpunk-fg :background ,cyberpunk-bg-05)))) + `(ediff-current-diff-B ((,class (:foreground ,cyberpunk-fg :background ,cyberpunk-bg+1)))) + `(ediff-current-diff-C ((,class (:foreground ,cyberpunk-fg :background ,cyberpunk-bg+2)))) + `(ediff-even-diff-Ancestor ((,class (:foreground ,cyberpunk-white :background ,cyberpunk-bg-05)))) + `(ediff-even-diff-A ((,class (:foreground ,cyberpunk-white :background ,cyberpunk-bg+1)))) + `(ediff-even-diff-B ((,class (:foreground ,cyberpunk-white :background ,cyberpunk-bg+2)))) + `(ediff-even-diff-C ((,class (:foreground ,cyberpunk-white :background ,cyberpunk-bg+3)))) + `(ediff-fine-diff-Ancestor ((,class (:foreground ,cyberpunk-black :background ,cyberpunk-pink)))) + `(ediff-fine-diff-A ((,class (:foreground ,cyberpunk-black :background ,cyberpunk-blue-5)))) + `(ediff-fine-diff-B ((,class (:foreground ,cyberpunk-black :background ,cyberpunk-blue-5)))) + `(ediff-fine-diff-C ((,class (:foreground ,cyberpunk-black :background ,cyberpunk-blue-5)))) + `(ediff-odd-diff-Ancestor ((,class (:foreground ,cyberpunk-black :background ,cyberpunk-gray-2)))) + `(ediff-odd-diff-A ((,class (:foreground ,cyberpunk-black :background ,cyberpunk-gray-3)))) + `(ediff-odd-diff-B ((,class (:foreground ,cyberpunk-black :background ,cyberpunk-gray-4)))) + `(ediff-odd-diff-C ((,class (:foreground ,cyberpunk-black :background ,cyberpunk-gray)))) + + ;; ert + `(ert-test-result-expected ((,class (:foreground ,cyberpunk-green+4 :background ,cyberpunk-bg)))) + `(ert-test-result-unexpected ((,class (:foreground ,cyberpunk-red :background ,cyberpunk-bg)))) + + ;; eshell + `(eshell-prompt ((,class (:foreground ,cyberpunk-blue-5 :weight bold)))) + `(eshell-ls-archive ((,class (:foreground ,cyberpunk-magenta :weight bold)))) + `(eshell-ls-backup ((,class (:inherit font-lock-comment)))) + `(eshell-ls-clutter ((,class (:inherit font-lock-comment)))) + `(eshell-ls-directory ((,class (:foreground ,cyberpunk-blue+1 :weight bold)))) + `(eshell-ls-executable ((,class (:foreground ,cyberpunk-red+1 :weight bold)))) + `(eshell-ls-unreadable ((,class (:foreground ,cyberpunk-fg)))) + `(eshell-ls-missing ((,class (:inherit font-lock-warning)))) + `(eshell-ls-product ((,class (:inherit font-lock-doc)))) + `(eshell-ls-special ((,class (:foreground ,cyberpunk-yellow :weight bold)))) + `(eshell-ls-symlink ((,class (:foreground ,cyberpunk-cyan :weight bold)))) + + ;; flymake + `(flymake-errline ((,class (:foreground ,cyberpunk-red-1 :weight bold :underline t)))) + `(flymake-warnline ((,class (:foreground ,cyberpunk-yellow-1 :weight bold :underline t)))) + + ;; flyspell + `(flyspell-duplicate ((,class (:foreground ,cyberpunk-yellow-1 :weight bold :underline t)))) + `(flyspell-incorrect ((,class (:foreground ,cyberpunk-orange-2 :weight bold :underline t)))) + + ;; erc + `(erc-action-face ((,class (:inherit erc-default-face)))) + `(erc-bold-face ((,class (:weight bold)))) + `(erc-current-nick-face ((,class (:foreground ,cyberpunk-blue :weight bold)))) + `(erc-dangerous-host-face ((,class (:inherit font-lock-warning)))) + `(erc-default-face ((,class (:foreground ,cyberpunk-fg)))) + `(erc-direct-msg-face ((,class (:inherit erc-default)))) + `(erc-error-face ((,class (:inherit font-lock-warning)))) + `(erc-fool-face ((,class (:inherit erc-default)))) + `(erc-highlight-face ((,class (:inherit hover-highlight)))) + `(erc-input-face ((,class (:foreground ,cyberpunk-yellow)))) + `(erc-keyword-face ((,class (:foreground ,cyberpunk-blue :weight bold)))) + `(erc-nick-default-face ((,class (:foreground ,cyberpunk-yellow :weight bold)))) + `(erc-my-nick-face ((,class (:foreground ,cyberpunk-red :weigth bold)))) + `(erc-nick-msg-face ((,class (:inherit erc-default)))) + `(erc-notice-face ((,class (:foreground ,cyberpunk-green)))) + `(erc-pal-face ((,class (:foreground ,cyberpunk-orange :weight bold)))) + `(erc-prompt-face ((,class (:foreground ,cyberpunk-orange :background ,cyberpunk-bg :weight bold)))) + `(erc-timestamp-face ((,class (:foreground ,cyberpunk-green+1)))) + `(erc-underline-face ((t (:underline t)))) + + ;; gnus + `(gnus-group-mail-1 ((,class (:bold t :inherit gnus-group-mail-1-empty)))) + `(gnus-group-mail-1-empty ((,class (:inherit gnus-group-news-1-empty)))) + `(gnus-group-mail-2 ((,class (:bold t :inherit gnus-group-mail-2-empty)))) + `(gnus-group-mail-2-empty ((,class (:inherit gnus-group-news-2-empty)))) + `(gnus-group-mail-3 ((,class (:bold t :inherit gnus-group-mail-3-empty)))) + `(gnus-group-mail-3-empty ((,class (:inherit gnus-group-news-3-empty)))) + `(gnus-group-mail-4 ((,class (:bold t :inherit gnus-group-mail-4-empty)))) + `(gnus-group-mail-4-empty ((,class (:inherit gnus-group-news-4-empty)))) + `(gnus-group-mail-5 ((,class (:bold t :inherit gnus-group-mail-5-empty)))) + `(gnus-group-mail-5-empty ((,class (:inherit gnus-group-news-5-empty)))) + `(gnus-group-mail-6 ((,class (:bold t :inherit gnus-group-mail-6-empty)))) + `(gnus-group-mail-6-empty ((,class (:inherit gnus-group-news-6-empty)))) + `(gnus-group-mail-low ((,class (:bold t :inherit gnus-group-mail-low-empty)))) + `(gnus-group-mail-low-empty ((,class (:inherit gnus-group-news-low-empty)))) + `(gnus-group-news-1 ((,class (:bold t :inherit gnus-group-news-1-empty)))) + `(gnus-group-news-2 ((,class (:bold t :inherit gnus-group-news-2-empty)))) + `(gnus-group-news-3 ((,class (:bold t :inherit gnus-group-news-3-empty)))) + `(gnus-group-news-4 ((,class (:bold t :inherit gnus-group-news-4-empty)))) + `(gnus-group-news-5 ((,class (:bold t :inherit gnus-group-news-5-empty)))) + `(gnus-group-news-6 ((,class (:bold t :inherit gnus-group-news-6-empty)))) + `(gnus-group-news-low ((,class (:bold t :inherit gnus-group-news-low-empty)))) + `(gnus-header-content ((,class (:inherit message-header-other)))) + `(gnus-header-from ((,class (:inherit message-header-from)))) + `(gnus-header-name ((,class (:inherit message-header-name)))) + `(gnus-header-newsgroups ((,class (:inherit message-header-other)))) + `(gnus-header-subject ((,class (:inherit message-header-subject)))) + `(gnus-summary-cancelled ((,class (:foreground ,cyberpunk-orange)))) + `(gnus-summary-high-ancient ((,class (:foreground ,cyberpunk-blue)))) + `(gnus-summary-high-read ((,class (:foreground ,cyberpunk-green :weight bold)))) + `(gnus-summary-high-ticked ((,class (:foreground ,cyberpunk-orange :weight bold)))) + `(gnus-summary-high-unread ((,class (:foreground ,cyberpunk-fg :weight bold)))) + `(gnus-summary-low-ancient ((,class (:foreground ,cyberpunk-blue)))) + `(gnus-summary-low-read ((t (:foreground ,cyberpunk-green)))) + `(gnus-summary-low-ticked ((,class (:foreground ,cyberpunk-orange :weight bold)))) + `(gnus-summary-low-unread ((,class (:foreground ,cyberpunk-fg)))) + `(gnus-summary-normal-ancient ((,class (:foreground ,cyberpunk-blue+1)))) + `(gnus-summary-normal-read ((,class (:foreground ,cyberpunk-green)))) + `(gnus-summary-normal-ticked ((,class (:foreground ,cyberpunk-orange :weight bold)))) + `(gnus-summary-normal-unread ((,class (:foreground ,cyberpunk-fg)))) + `(gnus-summary-selected ((,class (:foreground ,cyberpunk-yellow :weight bold)))) + `(gnus-cite-1 ((,class (:foreground ,cyberpunk-yellow-2)))) + `(gnus-cite-10 ((,class (:foreground ,cyberpunk-yellow-1)))) + `(gnus-cite-11 ((,class (:foreground ,cyberpunk-yellow)))) + `(gnus-cite-2 ((,class (:foreground ,cyberpunk-blue-1)))) + `(gnus-cite-3 ((,class (:foreground ,cyberpunk-blue-2)))) + `(gnus-cite-4 ((,class (:foreground ,cyberpunk-green+2)))) + `(gnus-cite-5 ((,class (:foreground ,cyberpunk-green+1)))) + `(gnus-cite-6 ((,class (:foreground ,cyberpunk-green)))) + `(gnus-cite-7 ((,class (:foreground ,cyberpunk-red)))) + `(gnus-cite-8 ((,class (:foreground ,cyberpunk-red-1)))) + `(gnus-cite-9 ((,class (:foreground ,cyberpunk-red-2)))) + `(gnus-group-news-1-empty ((,class (:foreground ,cyberpunk-yellow)))) + `(gnus-group-news-2-empty ((,class (:foreground ,cyberpunk-green+3)))) + `(gnus-group-news-3-empty ((,class (:foreground ,cyberpunk-green+1)))) + `(gnus-group-news-4-empty ((,class (:foreground ,cyberpunk-blue-2)))) + `(gnus-group-news-5-empty ((,class (:foreground ,cyberpunk-blue-3)))) + `(gnus-group-news-6-empty ((,class (:foreground ,cyberpunk-bg+2)))) + `(gnus-group-news-low-empty ((,class (:foreground ,cyberpunk-bg+2)))) + `(gnus-signature ((,class (:foreground ,cyberpunk-yellow)))) + `(gnus-x ((,class (:background ,cyberpunk-fg :foreground ,cyberpunk-bg)))) + + ;; helm + `(helm-header + ((,class (:foreground ,cyberpunk-green + :background ,cyberpunk-bg + :underline nil + :box nil)))) + `(helm-source-header + ((,class (:foreground ,cyberpunk-yellow + :background ,cyberpunk-bg-1 + :underline nil + :weight bold + :box (:line-width -1 :style released-button))))) + `(helm-selection ((,class (:background ,cyberpunk-bg-1 :underline nil)))) + `(helm-selection-line ((,class (:background ,cyberpunk-bg+1)))) + `(helm-visible-mark ((,class (:foreground ,cyberpunk-bg :background ,cyberpunk-yellow-2)))) + `(helm-candidate-number ((,class (:foreground ,cyberpunk-green+4 :background ,cyberpunk-bg-1)))) + `(helm-ff-directory ((,class (:foreground ,cyberpunk-pink :background ,cyberpunk-bg)))) + `(helm-ff-dotted-directory ((,class (:foreground ,cyberpunk-pink :background ,cyberpunk-bg)))) + + ;; hl-line-mode + `(hl-sexp-face ((,class (:background ,cyberpunk-gray-5)))) + `(hl-line-face ((,class (:background ,cyberpunk-gray-5)))) + + ;; ido-mode + `(ido-first-match ((,class (:foreground ,cyberpunk-pink-1 :background ,cyberpunk-black)))) + `(ido-only-match ((,class (:foreground ,cyberpunk-pink-1 :background ,cyberpunk-black)))) + `(ido-subdir ((,class (:foreground ,cyberpunk-gray-4 :backgroun ,cyberpunk-black)))) + `(ido-indicator ((,class (:foreground ,cyberpunk-black :background ,cyberpunk-pink-1)))) + + ;; js2-mode + `(js2-warning-face ((,class (:underline ,cyberpunk-orange)))) + `(js2-error-face ((,class (:foreground ,cyberpunk-red :weight bold)))) + `(js2-jsdoc-tag-face ((,class (:foreground ,cyberpunk-green-1)))) + `(js2-jsdoc-type-face ((,class (:foreground ,cyberpunk-green+2)))) + `(js2-jsdoc-value-face ((,class (:foreground ,cyberpunk-green+3)))) + `(js2-function-param-face ((,class (:foreground ,cyberpunk-green+3)))) + `(js2-external-variable-face ((,class (:foreground ,cyberpunk-orange)))) + + ;; jabber-mode + `(jabber-roster-user-away ((,class (:foreground ,cyberpunk-green+2)))) + `(jabber-roster-user-online ((,class (:foreground ,cyberpunk-blue-1)))) + `(jabber-roster-user-dnd ((,class (:foreground ,cyberpunk-red+1)))) + `(jabber-rare-time-face ((,class (:foreground ,cyberpunk-green+1)))) + `(jabber-chat-prompt-local ((,class (:foreground ,cyberpunk-blue-1)))) + `(jabber-chat-prompt-foreign ((,class (:foreground ,cyberpunk-red+1)))) + `(jabber-activity-face((,class (:foreground ,cyberpunk-red+1)))) + `(jabber-activity-personal-face ((,class (:foreground ,cyberpunk-blue+1)))) + `(jabber-title-small ((,class (:height 1.1 :weight bold)))) + `(jabber-title-medium ((,class (:height 1.2 :weight bold)))) + `(jabber-title-large ((,class (:height 1.3 :weight bold)))) + + ;; linum-mode + `(linum ((,class (:foreground ,cyberpunk-green+2 :background ,cyberpunk-bg)))) + + ;;linum-relative + `(linum-relative-current-face ((,class (:inherit linum :foreground ,cyberpunk-white :weight bold)))) + + ;; magit + ;; magit headings and diffs + `(magit-section-highlight ((t (:background ,cyberpunk-bg+1)))) + `(magit-section-heading ((t (:foreground ,cyberpunk-blue+1 :weight bold)))) + `(magit-section-heading-selection ((t (:foreground ,cyberpunk-red+1 :weight bold)))) + `(magit-diff-file-heading ((t (:weight bold)))) + `(magit-diff-file-heading-highlight ((t (:background ,cyberpunk-bg+2 :weight bold)))) + `(magit-diff-file-heading-selection ((t (:background ,cyberpunk-bg+2 + :foreground ,cyberpunk-blue-6 :weight bold)))) + `(magit-diff-hunk-heading ((t (:background ,cyberpunk-bg)))) + `(magit-diff-hunk-heading-highlight ((t (:background ,cyberpunk-bg+1)))) + `(magit-diff-hunk-heading-selection ((t (:background ,cyberpunk-bg+1 + :foreground ,cyberpunk-blue-6)))) + `(magit-diff-lines-heading ((t (:background ,cyberpunk-blue-6 + :foreground ,cyberpunk-bg+1)))) + `(magit-diff-added ((t (:foreground ,cyberpunk-blue-5)))) + `(magit-diff-added-highlight ((t (:inherit magit-diff-added :weight bold)))) + `(magit-diff-removed ((t (:foreground ,cyberpunk-magenta)))) + `(magit-diff-removed-highlight ((t (:inherit magit-diff-removed :weight bold)))) + `(magit-diff-context ((t (:foreground ,cyberpunk-gray)))) + `(magit-diff-context-highlight ((t (:inherit magit-diff-context :weight bold)))) + `(magit-diffstat-added ((t (:inherit magit-diff-added)))) + `(magit-diffstat-removed ((t (:inherit magit-diff-removed)))) + ;; magit popup + `(magit-popup-heading ((t (:foreground ,cyberpunk-pink-1 :weight bold)))) + `(magit-popup-key ((t (:foreground ,cyberpunk-blue+1 :weight bold)))) + `(magit-popup-argument ((t (:foreground ,cyberpunk-blue-4 :weight bold)))) + `(magit-popup-disabled-argument ((t (:foreground ,cyberpunk-fg :weight normal)))) + `(magit-popup-option-value ((t (:foreground ,cyberpunk-blue-2 :weight bold)))) + ;; ;; magit process + `(magit-process-ok ((t (:foreground ,cyberpunk-green+1 :weight bold)))) + `(magit-process-ng ((t (:foreground ,cyberpunk-pink-2 :weight bold)))) + ;; ;; magit log + `(magit-log-author ((t (:foreground ,cyberpunk-pink)))) + `(magit-log-date ((t (:foreground ,cyberpunk-gray)))) + `(magit-log-graph ((t (:foreground ,cyberpunk-white-2)))) + ;; ;; magit sequence + `(magit-sequence-pick ((t (:foreground ,cyberpunk-magenta)))) + `(magit-sequence-stop ((t (:foreground ,cyberpunk-green+1)))) + `(magit-sequence-part ((t (:foreground ,cyberpunk-pink-1)))) + `(magit-sequence-head ((t (:foreground ,cyberpunk-blue+1)))) + `(magit-sequence-drop ((t (:foreground ,cyberpunk-orange)))) + `(magit-sequence-done ((t (:foreground ,cyberpunk-gray-2)))) + `(magit-sequence-onto ((t (:foreground ,cyberpunk-gray-2)))) + ;; ;; magit bisect + `(magit-bisect-good ((t (:foreground ,cyberpunk-green+1)))) + `(magit-bisect-skip ((t (:foreground ,cyberpunk-pink-1)))) + `(magit-bisect-bad ((t (:foreground ,cyberpunk-orange)))) + ;; ;; magit blame + `(magit-blame-heading ((t (:background ,cyberpunk-bg+1 :foreground ,cyberpunk-green)))) + `(magit-blame-hash ((t (:background ,cyberpunk-bg+1 :foreground ,cyberpunk-green)))) + `(magit-blame-name ((t (:background ,cyberpunk-bg+1 :foreground ,cyberpunk-pink-1)))) + `(magit-blame-date ((t (:background ,cyberpunk-bg+1 :foreground ,cyberpunk-yellow-1)))) + `(magit-blame-summary ((t (:background ,cyberpunk-bg+1 :foreground ,cyberpunk-blue-4 + :weight bold)))) + ;; ;; magit references etc + `(magit-dimmed ((t (:foreground ,cyberpunk-bg+3)))) + `(magit-hash ((t (:foreground ,cyberpunk-bg+1)))) + `(magit-tag ((t (:foreground ,cyberpunk-pink-1 :weight bold)))) + `(magit-branch-remote ((t (:foreground ,cyberpunk-green+2 :weight bold)))) + `(magit-branch-local ((t (:foreground ,cyberpunk-blue+1 :weight bold)))) + `(magit-branch-current ((t (:foreground ,cyberpunk-green :weight bold :box t)))) + `(magit-head ((t (:foreground ,cyberpunk-blue :weight bold)))) + `(magit-refname ((t (:background ,cyberpunk-bg+2 :foreground ,cyberpunk-fg :weight bold)))) + `(magit-refname-stash ((t (:background ,cyberpunk-bg+2 :foreground ,cyberpunk-fg :weight bold)))) + `(magit-refname-wip ((t (:background ,cyberpunk-bg+2 :foreground ,cyberpunk-fg :weight bold)))) + `(magit-signature-good ((t (:foreground ,cyberpunk-green)))) + `(magit-signature-bad ((t (:foreground ,cyberpunk-red)))) + `(magit-signature-untrusted ((t (:foreground ,cyberpunk-yellow)))) + `(magit-cherry-unmatched ((t (:foreground ,cyberpunk-cyan)))) + `(magit-cherry-equivalent ((t (:foreground ,cyberpunk-magenta)))) + `(magit-reflog-commit ((t (:foreground ,cyberpunk-green)))) + `(magit-reflog-amend ((t (:foreground ,cyberpunk-magenta)))) + `(magit-reflog-merge ((t (:foreground ,cyberpunk-green)))) + `(magit-reflog-checkout ((t (:foreground ,cyberpunk-blue)))) + `(magit-reflog-reset ((t (:foreground ,cyberpunk-red)))) + `(magit-reflog-rebase ((t (:foreground ,cyberpunk-magenta)))) + `(magit-reflog-cherry-pick ((t (:foreground ,cyberpunk-green)))) + `(magit-reflog-remote ((t (:foreground ,cyberpunk-cyan)))) + `(magit-reflog-other ((t (:foreground ,cyberpunk-cyan)))) + + `(eval-sexp-fu-flash ((,class (:background ,cyberpunk-gray-8 :foreground ,cyberpunk-pink-2)))) + + ;; message-mode + `(message-cited-text ((,class (:inherit font-lock-comment)))) + `(message-header-name ((,class (:foreground ,cyberpunk-blue-5)))) + `(message-header-other ((,class (:foreground ,cyberpunk-green)))) + `(message-header-to ((,class (:foreground ,cyberpunk-pink-1 :weight bold)))) + `(message-header-from ((,class (:foreground ,cyberpunk-yellow :weight bold)))) + `(message-header-cc ((,class (:foreground ,cyberpunk-yellow :weight bold)))) + `(message-header-newsgroups ((,class (:foreground ,cyberpunk-yellow :weight bold)))) + `(message-header-subject ((,class (:foreground ,cyberpunk-orange :weight bold)))) + `(message-header-xheader ((,class (:foreground ,cyberpunk-green)))) + `(message-mml ((,class (:foreground ,cyberpunk-yellow :weight bold)))) + `(message-separator ((,class (:inherit font-lock-comment)))) + + ;; mew + `(mew-face-header-subject ((,class (:foreground ,cyberpunk-orange)))) + `(mew-face-header-from ((,class (:foreground ,cyberpunk-yellow)))) + `(mew-face-header-date ((,class (:foreground ,cyberpunk-green)))) + `(mew-face-header-to ((,class (:foreground ,cyberpunk-red)))) + `(mew-face-header-key ((,class (:foreground ,cyberpunk-green)))) + `(mew-face-header-private ((,class (:foreground ,cyberpunk-green)))) + `(mew-face-header-important ((,class (:foreground ,cyberpunk-blue)))) + `(mew-face-header-marginal ((,class (:foreground ,cyberpunk-fg :weight bold)))) + `(mew-face-header-warning ((,class (:foreground ,cyberpunk-red)))) + `(mew-face-header-xmew ((,class (:foreground ,cyberpunk-green)))) + `(mew-face-header-xmew-bad ((,class (:foreground ,cyberpunk-red)))) + `(mew-face-body-url ((,class (:foreground ,cyberpunk-orange)))) + `(mew-face-body-comment ((,class (:foreground ,cyberpunk-fg :slant italic)))) + `(mew-face-body-cite1 ((,class (:foreground ,cyberpunk-green)))) + `(mew-face-body-cite2 ((,class (:foreground ,cyberpunk-blue)))) + `(mew-face-body-cite3 ((,class (:foreground ,cyberpunk-orange)))) + `(mew-face-body-cite4 ((,class (:foreground ,cyberpunk-yellow)))) + `(mew-face-body-cite5 ((,class (:foreground ,cyberpunk-red)))) + `(mew-face-mark-review ((,class (:foreground ,cyberpunk-blue)))) + `(mew-face-mark-escape ((,class (:foreground ,cyberpunk-green)))) + `(mew-face-mark-delete ((,class (:foreground ,cyberpunk-red)))) + `(mew-face-mark-unlink ((,class (:foreground ,cyberpunk-yellow)))) + `(mew-face-mark-refile ((,class (:foreground ,cyberpunk-green)))) + `(mew-face-mark-unread ((,class (:foreground ,cyberpunk-red-2)))) + `(mew-face-eof-message ((,class (:foreground ,cyberpunk-green)))) + `(mew-face-eof-part ((,class (:foreground ,cyberpunk-yellow)))) + + ;; mic-paren + `(paren-face-match ((,class (:foreground ,cyberpunk-cyan :background ,cyberpunk-bg :weight bold)))) + `(paren-face-mismatch ((,class (:foreground ,cyberpunk-bg :background ,cyberpunk-magenta :weight bold)))) + `(paren-face-no-match ((,class (:foreground ,cyberpunk-bg :background ,cyberpunk-red :weight bold)))) + + ;; nav + `(nav-face-heading ((,class (:foreground ,cyberpunk-yellow)))) + `(nav-face-button-num ((,class (:foreground ,cyberpunk-cyan)))) + `(nav-face-dir ((,class (:foreground ,cyberpunk-green)))) + `(nav-face-hdir ((,class (:foreground ,cyberpunk-red)))) + `(nav-face-file ((,class (:foreground ,cyberpunk-fg)))) + `(nav-face-hfile ((,class (:foreground ,cyberpunk-red-4)))) + + ;; mumamo + `(mumamo-background-chunk-major ((,class (:background ,cyberpunk-black)))) + `(mumamo-background-chunk-submode1 ((,class (:background ,cyberpunk-black)))) + `(mumamo-background-chunk-submode2 ((,class (:background ,cyberpunk-bg+2)))) + `(mumamo-background-chunk-submode3 ((,class (:background ,cyberpunk-bg+3)))) + `(mumamo-background-chunk-submode4 ((,class (:background ,cyberpunk-bg+1)))) + + ;; org-mode + `(org-document-title ((,class (:foreground ,cyberpunk-blue-3 :background ,cyberpunk-black :weight bold :height 1.5)))) + `(org-document-info ((,class (:foreground ,cyberpunk-blue-3 :background ,cyberpunk-black :weight bold)))) + `(org-document-info-keyword ((,class (:foreground ,cyberpunk-gray-2 :background ,cyberpunk-black)))) + `(org-agenda-date-today + ((,class (:foreground ,cyberpunk-orange-2 :slant italic :weight bold))) t) + `(org-agenda-structure + ((,class (:inherit font-lock-comment-face)))) + `(org-archived ((,class (:slant italic)))) + `(org-checkbox ((,class (:background ,cyberpunk-gray-2 :foreground ,cyberpunk-black + :box (:line-width 1 :style released-button))))) + `(org-date ((,class (:foreground ,cyberpunk-blue-7 :underline t)))) + `(org-done ((,class (:bold t :weight bold :foreground ,cyberpunk-green + :box (:line-width 1 :style none))))) + `(org-todo ((,class (:bold t :foreground ,cyberpunk-orange :weight bold + :box (:line-width 1 :style none))))) + `(org-level-1 ((,class (:foreground ,cyberpunk-pink-1 :height 1.3)))) + `(org-level-2 ((,class (:foreground ,cyberpunk-yellow :height 1.2)))) + `(org-level-3 ((,class (:foreground ,cyberpunk-blue-5 :height 1.1)))) + `(org-level-4 ((,class (:foreground ,cyberpunk-green)))) + `(org-level-5 ((,class (:foreground ,cyberpunk-orange)))) + `(org-level-6 ((,class (:foreground ,cyberpunk-pink)))) + `(org-level-7 ((,class (:foreground ,cyberpunk-green+3)))) + `(org-level-8 ((,class (:foreground ,cyberpunk-blue-1)))) + `(org-link ((,class (:foreground ,cyberpunk-blue-6 :underline t)))) + `(org-tag ((,class (:bold t :weight bold)))) + `(org-column ((,class (:background ,cyberpunk-gray-7 :foreground ,cyberpunk-black)))) + `(org-column-title ((,class (:background ,cyberpunk-gray-7 :underline t :weight bold)))) + `(org-block ((,class (:foreground ,cyberpunk-fg :background ,cyberpunk-bg-05)))) + `(org-block-begin-line + ((,class (:foreground "#008ED1" :background ,cyberpunk-bg-1)))) + `(org-block-background ((,class (:background ,cyberpunk-bg-05)))) + `(org-block-end-line + ((,class (:foreground "#008ED1" :background ,cyberpunk-bg-1)))) + + ;; `(org-deadline-announce ((,class (:foreground ,cyberpunk-red-1)))) + ;; `(org-scheduled ((,class (:foreground ,cyberpunk-green+4)))) + ;; `(org-scheduled-previously ((,class (:foreground ,cyberpunk-red-4)))) + ;; `(org-scheduled-today ((,class (:foreground ,cyberpunk-blue+1)))) + ;; `(org-special-keyword ((,class (:foreground ,cyberpunk-yellow-1)))) + ;; `(org-table ((,class (:foreground ,cyberpunk-green+2)))) + ;; `(org-time-grid ((,class (:foreground ,cyberpunk-orange)))) + ;; `(org-upcoming-deadline ((,class (:inherit font-lock-keyword-face)))) + ;; `(org-warning ((,class (:bold t :foreground ,cyberpunk-red :weight bold :underline nil)))) + ;; `(org-formula ((,class (:foreground ,cyberpunk-yellow-2)))) + ;; `(org-headline-done ((,class (:foreground ,cyberpunk-green+3)))) + ;; `(org-hide ((,class (:foreground ,cyberpunk-bg-1)))) + + ;; outline + `(outline-8 ((,class (:inherit default)))) + `(outline-7 ((,class (:inherit outline-8 :height 1.0)))) + `(outline-6 ((,class (:inherit outline-7 :height 1.0)))) + `(outline-5 ((,class (:inherit outline-6 :height 1.0)))) + `(outline-4 ((,class (:inherit outline-5 :height 1.0)))) + `(outline-3 ((,class (:inherit outline-4 :height 1.0)))) + `(outline-2 ((,class (:inherit outline-3 :height 1.0)))) + `(outline-1 ((,class (:inherit outline-2 :height 1.0)))) + + ;; emms + `(emms-browser-year/genre-face ((,class (:foreground ,cyberpunk-blue-3 :height 1.0)))) + `(emms-browser-artist-face ((,class (:foreground ,cyberpunk-pink-1 :height 1.0)))) + `(emms-browser-composer-face ((,class (:foreground ,cyberpunk-blue-3 :height 1.0)))) + `(emms-browser-performer-face ((,class (:foreground ,cyberpunk-blue-3 :height 1.0)))) + `(emms-browser-album-face ((,class (:foreground ,cyberpunk-yellow :height 1.0)))) + `(emms-browser-track-face ((,class (:foreground ,cyberpunk-blue-5 :height 1.0)))) + + ;; Calfw + `(cfw:face-title ((,class (:foreground ,cyberpunk-pink-1 :weight bold :height 1.8)))) + `(cfw:face-header ((,class (:foreground ,cyberpunk-yellow-5 :weight bold)))) + `(cfw:face-sunday ((,class (:foreground ,cyberpunk-red :weight bold)))) + `(cfw:face-saturday ((,class (:foreground ,cyberpunk-green :weight bold)))) + `(cfw:face-holiday ((,class (:foreground ,cyberpunk-pink-2 :weight bold)))) + `(cfw:face-grid ((,class (:foreground ,cyberpunk-gray-3)))) + `(cfw:face-default-content ((,class (:foreground ,cyberpunk-cyan)))) + `(cfw:face-periods ((,class (:foreground ,cyberpunk-cyan :weight bold)))) + `(cfw:face-day-title ((,class (:foreground ,cyberpunk-fg)))) + `(cfw:face-default-day ((,class (:foreground ,cyberpunk-fg :weight bold)))) + `(cfw:face-annotation ((,class (:foreground ,cyberpunk-gray)))) + `(cfw:face-disable ((,class (:foreground ,cyberpunk-gray-2 :weight bold)))) + `(cfw:face-today-title ((,class (:foreground ,cyberpunk-blue :background ,cyberpunk-magenta)))) + `(cfw:face-today ((,class (:foreground ,cyberpunk-fg :weight bold)))) + `(cfw:face-select ((,class (:background ,cyberpunk-bg+2)))) + `(cfw:face-toolbar ((,class (:background ,cyberpunk-blue-8)))) + `(cfw:face-toolbar-button-off ((,class (:foreground ,cyberpunk-white :background ,cyberpunk-blue-8 :weight bold)))) + `(cfw:face-toolbar-button-on ((,class (:foreground ,cyberpunk-white :background ,cyberpunk-orange-1 :weight bold)))) + + ;; racket-mode + `(racket-keyword-argument-face ((t (:inherit font-lock-constant-face)))) + `(racket-selfeval-face ((t (:inherit font-lock-type-face)))) + + ;; rainbow-delimiters + `(rainbow-delimiters-depth-1-face ((,class (:foreground ,cyberpunk-red-1)))) + `(rainbow-delimiters-depth-2-face ((,class (:foreground ,cyberpunk-green-2)))) + `(rainbow-delimiters-depth-3-face ((,class (:foreground ,cyberpunk-pink-1)))) + `(rainbow-delimiters-depth-4-face ((,class (:foreground ,cyberpunk-yellow)))) + `(rainbow-delimiters-depth-5-face ((,class (:foreground ,cyberpunk-green)))) + `(rainbow-delimiters-depth-6-face ((,class (:foreground ,cyberpunk-blue-3)))) + `(rainbow-delimiters-depth-7-face ((,class (:foreground ,cyberpunk-orange)))) + `(rainbow-delimiters-depth-8-face ((,class (:foreground ,cyberpunk-blue-2)))) + `(rainbow-delimiters-depth-9-face ((,class (:foreground ,cyberpunk-gray)))) + `(rainbow-delimiters-depth-10-face ((,class (:foreground ,cyberpunk-white)))) + `(rainbow-delimiters-depth-11-face ((,class (:foreground ,cyberpunk-blue+1)))) + `(rainbow-delimiters-depth-12-face ((,class (:foreground ,cyberpunk-red-4)))) + + ;; rpm-mode + `(rpm-spec-dir-face ((,class (:foreground ,cyberpunk-green)))) + `(rpm-spec-doc-face ((,class (:foreground ,cyberpunk-green)))) + `(rpm-spec-ghost-face ((,class (:foreground ,cyberpunk-red)))) + `(rpm-spec-macro-face ((,class (:foreground ,cyberpunk-yellow)))) + `(rpm-spec-obsolete-tag-face ((,class (:foreground ,cyberpunk-red)))) + `(rpm-spec-package-face ((,class (:foreground ,cyberpunk-red)))) + `(rpm-spec-section-face ((,class (:foreground ,cyberpunk-yellow)))) + `(rpm-spec-tag-face ((,class (:foreground ,cyberpunk-blue)))) + `(rpm-spec-var-face ((,class (:foreground ,cyberpunk-red)))) + + ;; rst-mode + `(rst-level-1-face ((,class (:foreground ,cyberpunk-orange)))) + `(rst-level-2-face ((,class (:foreground ,cyberpunk-green+1)))) + `(rst-level-3-face ((,class (:foreground ,cyberpunk-blue-1)))) + `(rst-level-4-face ((,class (:foreground ,cyberpunk-yellow-2)))) + `(rst-level-5-face ((,class (:foreground ,cyberpunk-cyan)))) + `(rst-level-6-face ((,class (:foreground ,cyberpunk-green-1)))) + + ;; show-paren + `(show-paren-mismatch ((,class (:foreground ,cyberpunk-red-3 :background ,cyberpunk-black)))) + `(show-paren-match ((,class (:foreground ,cyberpunk-black :background ,cyberpunk-pink-1)))) + + `(naeu-green-face ((,class (:foreground ,cyberpunk-green :background ,cyberpunk-black)))) + `(naeu-pink-face ((,class (:foreground ,cyberpunk-pink-1 :background ,cyberpunk-black)))) + `(naeu-blue-face ((,class (:foreground ,cyberpunk-blue-1 :background ,cyberpunk-black)))) + `(naeu-orange-face ((,class (:foreground ,cyberpunk-yellow-1 :background ,cyberpunk-black)))) + `(naeu-red-face ((,class (:foreground ,cyberpunk-orange :background ,cyberpunk-black)))) + `(naeu-grey-face ((,class (:foreground ,cyberpunk-gray-7 :background ,cyberpunk-black)))) + + ;; SLIME + `(slime-repl-inputed-output-face ((,class (:foreground ,cyberpunk-red)))) + + ;;; ansi-term + `(term-color-black ((,class (:foreground ,cyberpunk-bg + :background ,cyberpunk-bg-1)))) + `(term-color-red ((,class (:foreground ,cyberpunk-red-2 + :background ,cyberpunk-red-4)))) + `(term-color-green ((,class (:foreground ,cyberpunk-green + :background ,cyberpunk-green+2)))) + `(term-color-yellow ((,class (:foreground ,cyberpunk-orange + :background ,cyberpunk-yellow)))) + `(term-color-blue ((,class (:foreground ,cyberpunk-blue-1 + :background ,cyberpunk-blue-4)))) + `(term-color-magenta ((,class (:foreground ,cyberpunk-magenta + :background ,cyberpunk-red)))) + `(term-color-cyan ((,class (:foreground ,cyberpunk-cyan + :background ,cyberpunk-blue)))) + `(term-color-white ((,class (:foreground ,cyberpunk-fg + :background ,cyberpunk-bg-1)))) + `(term-default-fg-color ((,class (:inherit term-color-white)))) + `(term-default-bg-color ((,class (:inherit term-color-black)))) + + ;; volatile-highlights + `(vhl/default-face ((,class (:background ,cyberpunk-gray-5)))) + + `(undo-tree-visualizer-active-branch-face ((,class (:foreground ,cyberpunk-pink-1 :background ,cyberpunk-black)))) + + ;; whitespace-mode + `(whitespace-space ((,class (:background ,cyberpunk-bg :foreground ,cyberpunk-bg+1)))) + `(whitespace-hspace ((,class (:background ,cyberpunk-bg :foreground ,cyberpunk-bg+1)))) + `(whitespace-tab ((,class (:background ,cyberpunk-bg :foreground ,cyberpunk-red)))) + `(whitespace-newline ((,class (:foreground ,cyberpunk-bg+1)))) + `(whitespace-trailing ((,class (:foreground ,cyberpunk-red :background ,cyberpunk-bg)))) + `(whitespace-line ((,class (:background ,cyberpunk-bg-05 :foreground ,cyberpunk-magenta)))) + `(whitespace-space-before-tab ((,class (:background ,cyberpunk-orange :foreground ,cyberpunk-orange)))) + `(whitespace-indentation ((,class (:background ,cyberpunk-yellow :foreground ,cyberpunk-red)))) + `(whitespace-empty ((,class (:background ,cyberpunk-yellow :foreground ,cyberpunk-red)))) + `(whitespace-space-after-tab ((,class (:background ,cyberpunk-yellow :foreground ,cyberpunk-red)))) + + ;; wanderlust + `(wl-highlight-folder-few-face ((,class (:foreground ,cyberpunk-red-2)))) + `(wl-highlight-folder-many-face ((,class (:foreground ,cyberpunk-red-1)))) + `(wl-highlight-folder-path-face ((,class (:foreground ,cyberpunk-orange)))) + `(wl-highlight-folder-unread-face ((,class (:foreground ,cyberpunk-blue)))) + `(wl-highlight-folder-zero-face ((,class (:foreground ,cyberpunk-fg)))) + `(wl-highlight-folder-unknown-face ((,class (:foreground ,cyberpunk-blue)))) + `(wl-highlight-message-citation-header ((,class (:foreground ,cyberpunk-red-1)))) + `(wl-highlight-message-cited-text-1 ((,class (:foreground ,cyberpunk-red)))) + `(wl-highlight-message-cited-text-2 ((,class (:foreground ,cyberpunk-green+2)))) + `(wl-highlight-message-cited-text-3 ((,class (:foreground ,cyberpunk-blue)))) + `(wl-highlight-message-cited-text-4 ((,class (:foreground ,cyberpunk-blue+1)))) + `(wl-highlight-message-header-contents-face ((,class (:foreground ,cyberpunk-green)))) + `(wl-highlight-message-headers-face ((,class (:foreground ,cyberpunk-red+1)))) + `(wl-highlight-message-important-header-contents ((,class (:foreground ,cyberpunk-green+2)))) + `(wl-highlight-message-header-contents ((,class (:foreground ,cyberpunk-green+1)))) + `(wl-highlight-message-important-header-contents2 ((,class (:foreground ,cyberpunk-green+2)))) + `(wl-highlight-message-signature ((,class (:foreground ,cyberpunk-green)))) + `(wl-highlight-message-unimportant-header-contents ((,class (:foreground ,cyberpunk-fg)))) + `(wl-highlight-summary-answered-face ((,class (:foreground ,cyberpunk-blue)))) + `(wl-highlight-summary-disposed-face ((,class (:foreground ,cyberpunk-fg + :slant italic)))) + `(wl-highlight-summary-new-face ((,class (:foreground ,cyberpunk-blue)))) + `(wl-highlight-summary-normal-face ((,class (:foreground ,cyberpunk-fg)))) + `(wl-highlight-summary-thread-top-face ((,class (:foreground ,cyberpunk-yellow)))) + `(wl-highlight-thread-indent-face ((,class (:foreground ,cyberpunk-magenta)))) + `(wl-highlight-summary-refiled-face ((,class (:foreground ,cyberpunk-fg)))) + `(wl-highlight-summary-displaying-face ((,class (:underline t :weight bold)))) + + ;; which-func-mode + `(which-func ((,class (:foreground ,cyberpunk-green+4)))) + + ;; yasnippet + `(yas/field-highlight-face ((,class (:background ,cyberpunk-pink-1 :foreground ,cyberpunk-black)))) + + ;; enh-ruby-mode enh-ruby-op-face + `(enh-ruby-op-face ((,class (:foreground ,cyberpunk-blue-7)))) + `(enh-ruby-heredoc-delimiter-face ((,class (:foreground ,cyberpunk-green+2)))) + `(enh-ruby-string-delimiter-face ((,class (:foreground ,cyberpunk-green+2)))) + `(enh-ruby-regexp-delimiter-face ((,class (:foreground ,cyberpunk-blue-1)))) + + ;; yascroll + `(yascroll:thumb-text-area ((,class (:background ,cyberpunk-bg-1)))) + `(yascroll:thumb-fringe ((,class (:background ,cyberpunk-bg-1 :foreground ,cyberpunk-bg-1)))) + + ;; customize + `(custom-button ((,class (:box (:line-width 2 :style released-button) + :background ,cyberpunk-bg-05 :foreground ,cyberpunk-fg)))) + `(custom-button-unraised ((,class (:background ,cyberpunk-bg-05 :foreground ,cyberpunk-fg)))) + ) + + ;;; custom theme variables + (custom-theme-set-variables + 'cyberpunk + `(ansi-color-names-vector [,cyberpunk-bg ,cyberpunk-red-2 ,cyberpunk-green ,cyberpunk-orange + ,cyberpunk-blue-1 ,cyberpunk-magenta ,cyberpunk-cyan ,cyberpunk-fg]) + ;; fill-column-indicator + `(fci-rule-color ,cyberpunk-bg-05))) + +;;;###autoload +(when load-file-name + (add-to-list 'custom-theme-load-path + (file-name-as-directory (file-name-directory load-file-name)))) + +(provide-theme 'cyberpunk) + +;; Local Variables: +;; no-byte-compile: t +;; indent-tabs-mode: nil +;; eval: (when (fboundp 'rainbow-mode) (rainbow-mode +1)) +;; End: + +;;; cyberpunk-theme.el ends here. diff --git a/emacs/emacs.d/themes/dracula-theme.el b/emacs/emacs.d/themes/dracula-theme.el @@ -0,0 +1,458 @@ +;;; dracula-theme.el --- Dracula Theme + +;; Copyright 2015-present, All rights reserved +;; +;; Code licensed under the MIT license + +;; Author: film42 +;; Version: 1.5.1 +;; Package-Requires: ((emacs "24")) +;; URL: https://github.com/dracula/emacs + +;;; Commentary: + +;; A dark color theme available for a number of editors. + +;;; Code: +(require 'cl-lib) +(deftheme dracula) + +(let ((colors '((fg1 "#f8f8f2") ; Assigment form: VARIABLE COLOR [TTY-COLOR] + (fg2 "#e2e2dc") + (fg3 "#ccccc7") + (fg4 "#b6b6b2") + (bg1 "#282a36" "#000000") + (bg2 "#373844") + (bg3 "#464752") + (bg4 "#565761") + (bg5 "#44475a") + (bg6 "#b45bcf") + (key2 "#0189cc") + (key3 "#ff79c6") + (builtin "#ffb86c") + (keyword "#ff79c6") + (const "#8be9fd") + (comment "#6272a4") + (func "#50fa7b") + (str "#f1fa8c") + (type "#bd93f9") + (var "#f8f8f2") + (warning "#ffb86c") + (rainbow-1 "#f8f8f2") + (rainbow-2 "#8be9fd") + (rainbow-3 "#bd93f9") + (rainbow-4 "#ff79c6") + (rainbow-5 "#ffb86c") + (rainbow-6 "#50fa7b") + (rainbow-7 "#f1fa8c") + (rainbow-8 "#0189cc") + (rainbow-9 "#ff5555") + (rainbow-10 "#a0522d") + (eph-verbatim "#f1fa8c") + (eph-code "#ff79c6"))) + (faces '(;; default + (cursor :background ,fg3) + (default :background ,bg1 :foreground ,fg1) + (default-italic :italic t) + (ffap :foreground ,fg4) + (fringe :background ,bg1 :foreground ,fg4) + (highlight :foreground ,fg3 :background ,bg3) + (hl-line :background ,bg5) + (info-quoted-name :foreground ,builtin) + (info-string :foreground ,str) + (lazy-highlight :foreground ,fg2 :background ,bg3) + (link :foreground ,const :underline t) + (linum :slant italic :foreground ,bg4 :background ,bg1) + (line-number :slant italic :foreground ,bg4 :background ,bg1) + (minibuffer-prompt :bold t :foreground ,keyword) + (region :background ,str :foreground ,bg1) + (show-paren-match-face :background ,warning) + (trailing-whitespace :foreground nil :background ,warning) + (vertical-border :foreground ,bg2) + (warning :foreground ,warning) + (whitespace-trailing :inherit trailing-whitespace) + (header-line :background ,bg1) + ;; syntax + (font-lock-builtin-face :foreground ,builtin) + (font-lock-comment-face :foreground ,comment) + (font-lock-constant-face :foreground ,const) + (font-lock-doc-face :foreground ,comment) + (font-lock-function-name-face :foreground ,func :bold t) + (font-lock-keyword-face :bold t :foreground ,keyword) + (font-lock-negation-char-face :foreground ,const) + (font-lock-reference-face :foreground ,const) + (font-lock-string-face :foreground ,str) + (font-lock-type-face :foreground ,type ) + (font-lock-variable-name-face :foreground ,var) + (font-lock-warning-face :foreground ,warning :background ,bg2) + ;; auto-complete + (ac-completion-face :underline t :foreground ,keyword) + ;; company + (company-echo-common :foreground ,bg1 :background ,fg1) + (company-preview :background ,bg1 :foreground ,key2) + (company-preview-common :foreground ,bg2 :foreground ,fg3) + (company-preview-search :foreground ,type :background ,bg1) + (company-scrollbar-bg :background ,bg3) + (company-scrollbar-fg :foreground ,keyword) + (company-template-field :inherit region) + (company-tooltip :foreground ,fg2 :background ,bg1 :bold t) + (company-tooltip-annotation :foreground ,const) + (company-tooltip-common :foreground ,fg3) + (company-tooltip-common-selection :foreground ,str) + (company-tooltip-mouse :inherit highlight) + (company-tooltip-selection :background ,bg3 :foreground ,fg3) + ;; diff-hl + (diff-hl-change :foreground ,rainbow-5 :background ,rainbow-5) + (diff-hl-delete :foreground ,rainbow-9 :background ,rainbow-9) + (diff-hl-insert :foreground ,rainbow-6 :background ,rainbow-6) + ;; enh-ruby + (enh-ruby-heredoc-delimiter-face :foreground ,str) + (enh-ruby-op-face :foreground ,keyword) + (enh-ruby-regexp-delimiter-face :foreground ,str) + (enh-ruby-string-delimiter-face :foreground ,str) + ;; font-latex + (font-latex-bold-face :foreground ,type) + (font-latex-italic-face :foreground ,key3 :italic t) + (font-latex-match-reference-keywords :foreground ,const) + (font-latex-match-variable-keywords :foreground ,var) + (font-latex-string-face :foreground ,str) + ;; gnus-group + (gnus-group-mail-1 :foreground ,keyword :bold t) + (gnus-group-mail-1-empty :inherit gnus-group-mail-1 :bold nil) + (gnus-group-mail-2 :foreground ,const :bold t) + (gnus-group-mail-2-empty :inherit gnus-group-mail-2 :bold nil) + (gnus-group-mail-3 :foreground ,comment :bold t) + (gnus-group-mail-3-empty :inherit gnus-group-mail-3 :bold nil) + (gnus-group-mail-low :foreground ,bg5 :bold t) + (gnus-group-mail-low-empty :inherit gnus-group-mail-low :bold nil) + (gnus-group-news-1 :foreground ,keyword :bold t) + (gnus-group-news-1-empty :inherit gnus-group-news-1 :bold nil) + (gnus-group-news-2 :foreground ,const :bold t) + (gnus-group-news-2-empty :inherit gnus-group-news-2 :bold nil) + (gnus-group-news-3 :foreground ,comment :bold t) + (gnus-group-news-3-empty :inherit gnus-group-news-3 :bold nil) + (gnus-group-news-4 :inherit gnus-group-news-low) + (gnus-group-news-4-empty :inherit gnus-group-news-low-empty) + (gnus-group-news-5 :inherit gnus-group-news-low) + (gnus-group-news-5-empty :inherit gnus-group-news-low-empty) + (gnus-group-news-6 :inherit gnus-group-news-low) + (gnus-group-news-6-empty :inherit gnus-group-news-low-empty) + (gnus-group-news-low :foreground ,bg5 :bold t) + (gnus-group-news-low-empty :inherit gnus-group-news-low :bold nil) + (gnus-header-content :foreground ,keyword) + (gnus-header-from :foreground ,var) + (gnus-header-name :foreground ,type) + (gnus-header-subject :foreground ,func :bold t) + (gnus-summary-markup-face :foreground ,const) + (gnus-summary-high-unread :foreground ,keyword :weight bold) + (gnus-summary-high-read :inherit gnus-summary-high-unread :weight normal) + (gnus-summary-high-ancient :inherit gnus-summary-high-read) + (gnus-summary-high-ticked :inherit gnus-summary-high-read :underline t) + (gnus-summary-normal-unread :foreground ,key2 :weight bold) + (gnus-summary-normal-read :inherit gnus-summary-normal-unread :weight normal) + (gnus-summary-normal-ancient :inherit gnus-summary-normal-read) + (gnus-summary-normal-ticked :inherit gnus-summary-normal-read :underline t) + (gnus-summary-low-unread :foreground ,comment :weight bold) + (gnus-summary-low-read :inherit gnus-summary-low-unread :weight normal) + (gnus-summary-low-ancient :inherit gnus-summary-low-read) + (gnus-summary-low-ticked :inherit gnus-summary-low-read :underline t) + (gnus-summary-selected :inverse-video t) + ;; helm + (helm-bookmark-w3m :foreground ,type) + (helm-buffer-not-saved :foreground ,type :background ,bg1) + (helm-buffer-process :foreground ,builtin :background ,bg1) + (helm-buffer-saved-out :foreground ,fg1 :background ,bg1) + (helm-buffer-size :foreground ,fg1 :background ,bg1) + (helm-candidate-number :foreground ,bg1 :background ,fg1) + (helm-ff-directory :foreground ,func :background ,bg1 :weight bold) + (helm-ff-executable :foreground ,key2 :background ,bg1 :weight normal) + (helm-ff-file :foreground ,fg1 :background ,bg1 :weight normal) + (helm-ff-invalid-symlink :foreground ,key3 :background ,bg1 :weight bold) + (helm-ff-prefix :foreground ,bg1 :background ,keyword :weight normal) + (helm-ff-symlink :foreground ,keyword :background ,bg1 :weight bold) + (helm-grep-cmd-line :foreground ,fg1 :background ,bg1) + (helm-grep-file :foreground ,fg1 :background ,bg1) + (helm-grep-finish :foreground ,fg2 :background ,bg1) + (helm-grep-lineno :foreground ,fg1 :background ,bg1) + (helm-grep-match :foreground nil :background nil :inherit helm-match) + (helm-grep-running :foreground ,func :background ,bg1) + (helm-header :foreground ,fg2 :background ,bg1 :underline nil :box nil) + (helm-moccur-buffer :foreground ,func :background ,bg1) + (helm-selection :background ,bg2 :underline nil) + (helm-selection-line :background ,bg2) + (helm-separator :foreground ,type :background ,bg1) + (helm-source-go-package-godoc-description :foreground ,str) + (helm-source-header :foreground ,keyword :background ,bg1 :underline nil :weight bold) + (helm-time-zone-current :foreground ,builtin :background ,bg1) + (helm-time-zone-home :foreground ,type :background ,bg1) + (helm-visible-mark :foreground ,bg1 :background ,bg3) + ;; highlight-indentation minor mode + (highlight-indentation-face :background ,bg2) + ;; icomplete + (icompletep-determined :foreground ,builtin) + ;; ido + (ido-first-match :foreground ,keyword :bold t) + (ido-only-match :foreground ,warning) + (ido-subdir :foreground ,builtin) + ;; isearch + (isearch :bold t :foreground ,warning :background ,bg3) + (isearch-fail :foreground ,bg1 :background ,warning) + ;; jde-java + (jde-java-font-lock-constant-face :foreground ,const) + (jde-java-font-lock-modifier-face :foreground ,key3) + (jde-java-font-lock-number-face :foreground ,var) + (jde-java-font-lock-package-face :foreground ,var) + (jde-java-font-lock-private-face :foreground ,keyword) + (jde-java-font-lock-public-face :foreground ,keyword) + ;; js2-mode + (js2-external-variable :foreground ,type ) + (js2-function-param :foreground ,const) + (js2-jsdoc-html-tag-delimiter :foreground ,str) + (js2-jsdoc-html-tag-name :foreground ,key2) + (js2-jsdoc-value :foreground ,str) + (js2-private-function-call :foreground ,const) + (js2-private-member :foreground ,fg3) + ;; js3-mode + (js3-error-face :underline ,warning) + (js3-external-variable-face :foreground ,var) + (js3-function-param-face :foreground ,key3) + (js3-instance-member-face :foreground ,const) + (js3-jsdoc-tag-face :foreground ,keyword) + (js3-warning-face :underline ,keyword) + ;; magit + (magit-branch :foreground ,const :weight bold) + (magit-diff-context-highlight :background ,bg3 :foreground ,fg3) + (magit-diff-file-header :foreground ,fg2 :background ,bg3) + (magit-diffstat-added :foreground ,type) + (magit-diffstat-removed :foreground ,var) + (magit-hash :foreground ,fg2) + (magit-hunk-heading :background ,bg3) + (magit-hunk-heading-highlight :background ,bg3) + (magit-item-highlight :background ,bg3) + (magit-log-author :foreground ,fg3) + (magit-process-ng :foreground ,warning :weight bold) + (magit-process-ok :foreground ,func :weight bold) + (magit-section-heading :foreground ,keyword :weight bold) + (magit-section-highlight :background ,bg2) + ;; mode-line + (mode-line :foreground nil :background ,bg5 :box ,bg5) + (mode-line-inactive :foreground ,fg1 :background ,bg2 :box ,bg2) + ;; mu4e + (mu4e-cited-1-face :foreground ,fg2) + (mu4e-cited-7-face :foreground ,fg3) + (mu4e-header-marks-face :foreground ,type) + (mu4e-view-url-number-face :foreground ,type) + ;; org + (org-agenda-date :foreground ,rainbow-2 :underline nil) + (org-agenda-dimmed-todo-face :foreground ,comment) + (org-agenda-done :foreground ,rainbow-6) + (org-agenda-structure :foreground ,rainbow-3) + (org-block :foreground ,rainbow-5) + (org-code :foreground ,rainbow-7) + (org-column :background ,bg4) + (org-column-title :inherit org-column :weight bold :underline t) + (org-date :foreground ,rainbow-2 :underline t) + (org-document-info :foreground ,rainbow-8) + (org-document-info-keyword :foreground ,comment) + (org-document-title :weight bold :foreground ,rainbow-5 :height 1.44) + (org-done :foreground ,rainbow-6) + (org-ellipsis :foreground ,comment) + (org-footnote :foreground ,rainbow-8) + (org-formula :foreground ,rainbow-4) + (org-headline-done :foreground ,comment :bold nil :strike-through t) + (org-hide :foreground ,bg1 :background ,bg1) + (org-level-1 :inherit bold :foreground ,rainbow-4 :height 1.3) + (org-level-2 :inherit bold :foreground ,rainbow-3 :height 1.1) + (org-level-3 :bold nil :foreground ,rainbow-6 :height 1.0) + (org-level-4 :bold nil :foreground ,rainbow-7) + (org-level-5 :bold nil :foreground ,rainbow-2) + (org-level-6 :bold nil :foreground ,rainbow-5) + (org-level-7 :bold nil :foreground ,rainbow-8) + (org-level-8 :bold nil :foreground ,rainbow-1) + (org-link :foreground ,rainbow-2 :underline t) + (org-priority :foreground ,rainbow-2) + (org-scheduled :foreground ,rainbow-6) + (org-scheduled-previously :foreground ,rainbow-7) + (org-scheduled-today :foreground ,rainbow-6) + (org-sexp-date :foreground ,fg4) + (org-special-keyword :foreground ,rainbow-7) + (org-table :foreground ,rainbow-3) + (org-tag :foreground ,rainbow-4 :bold t :background ,bg2) + (org-todo :foreground ,rainbow-5 :bold t :background ,bg2) + (org-upcoming-deadline :foreground ,rainbow-7) + (org-warning :weight bold :foreground ,rainbow-4) + ;; outline + (outline-1 :foreground ,rainbow-6) + (outline-2 :foreground ,rainbow-3) + (outline-3 :foreground ,rainbow-2) + (outline-4 :foreground ,rainbow-5) + (outline-5 :foreground ,rainbow-5) + (outline-6 :foreground ,rainbow-8) + ;; powerline + (powerline-evil-base-face :foreground ,bg2) + (powerline-evil-emacs-face :inherit powerline-evil-base-face :background ,rainbow-7) + (powerline-evil-insert-face :inherit powerline-evil-base-face :background ,rainbow-2) + (powerline-evil-motion-face :inherit powerline-evil-base-face :background ,rainbow-3) + (powerline-evil-normal-face :inherit powerline-evil-base-face :background ,rainbow-6) + (powerline-evil-operator-face :inherit powerline-evil-base-face :background ,rainbow-4) + (powerline-evil-replace-face :inherit powerline-evil-base-face :background ,rainbow-9) + (powerline-evil-visual-face :inherit powerline-evil-base-face :background ,rainbow-5) + (powerline-active1 :background ,bg6 :foreground ,fg1) + (powerline-active2 :background ,bg6 :foreground ,fg1) + (powerline-inactive2 :background ,bg3 :foreground ,fg1) + (powerline-inactive2 :background ,bg3 :foreground ,fg1) + ;; rainbow-delimiters + (rainbow-delimiters-depth-1-face :foreground ,rainbow-1) + (rainbow-delimiters-depth-2-face :foreground ,rainbow-2) + (rainbow-delimiters-depth-3-face :foreground ,rainbow-3) + (rainbow-delimiters-depth-4-face :foreground ,rainbow-4) + (rainbow-delimiters-depth-5-face :foreground ,rainbow-5) + (rainbow-delimiters-depth-6-face :foreground ,rainbow-6) + (rainbow-delimiters-depth-7-face :foreground ,rainbow-7) + (rainbow-delimiters-depth-8-face :foreground ,rainbow-8) + (rainbow-delimiters-unmatched-face :foreground ,warning) + ;; rpm-spec + (rpm-spec-dir-face :foreground ,rainbow-6) + (rpm-spec-doc-face :foreground ,rainbow-4) + (rpm-spec-ghost-face :foreground ,rainbow-3) + (rpm-spec-macro-face :foreground ,rainbow-7) + (rpm-spec-obsolete-tag-face :inherit font-lock-warning-face) + (rpm-spec-package-face :foreground ,rainbow-3) + (rpm-spec-section-face :foreground ,rainbow-7) + (rpm-spec-tag-face :foreground ,rainbow-2) + (rpm-spec-var-face :foreground ,rainbow-10) + ;; slime + (slime-repl-inputed-output-face :foreground ,type) + ;; spam + (spam :inherit gnus-summary-normal-read :foreground ,warning :strike-through t :slant oblique) + ;; term + (term :foreground ,fg1 :background ,bg1) + (term-color-black :foreground ,bg3 :background ,bg3) + (term-color-blue :foreground ,type :background ,type) + (term-color-cyan :foreground ,const :background ,const) + (term-color-green :foreground ,func :background ,func) + (term-color-magenta :foreground ,keyword :background ,keyword) + (term-color-red :foreground ,rainbow-9 :background ,rainbow-9) + (term-color-white :foreground ,fg2 :background ,fg2) + (term-color-yellow :foreground ,str :background ,str) + ;; undo-tree + (undo-tree-visualizer-current-face :foreground ,builtin) + (undo-tree-visualizer-default-face :foreground ,fg2) + (undo-tree-visualizer-register-face :foreground ,type) + (undo-tree-visualizer-unmodified-face :foreground ,var) + ;; web-mode + (web-mode-builtin-face :inherit ,font-lock-builtin-face) + (web-mode-comment-face :inherit ,font-lock-comment-face) + (web-mode-constant-face :inherit ,font-lock-constant-face) + (web-mode-doctype-face :inherit ,font-lock-comment-face) + (web-mode-function-name-face :inherit ,font-lock-function-name-face) + (web-mode-html-attr-name-face :foreground ,type) + (web-mode-html-attr-value-face :foreground ,func) + (web-mode-html-tag-face :foreground ,keyword :bold t) + (web-mode-keyword-face :foreground ,keyword) + (web-mode-string-face :foreground ,str) + (web-mode-type-face :inherit ,font-lock-type-face) + (web-mode-warning-face :inherit ,font-lock-warning-face) + ;; which-func + (which-func :inherit ,font-lock-function-name-face) + (dired-directory :foreground ,func :weight normal) + (dired-flagged :foreground ,keyword) + (dired-header :foreground ,fg3 :background ,bg1) + (dired-ignored :inherit shadow) + (dired-mark :foreground ,var :weight bold) + (dired-marked :foreground ,builtin :weight bold) + (dired-perm-write :foreground ,fg3 :underline t) + (dired-symlink :foreground ,str :weight normal :slant italic) + (dired-warning :foreground ,warning :underline t) + (diredp-compressed-file-name :foreground ,fg3) + (diredp-compressed-file-suffix :foreground ,fg4) + (diredp-date-time :foreground ,var) + (diredp-deletion-file-name :foreground ,keyword :background ,bg5) + (diredp-deletion :foreground ,keyword :weight bold) + (diredp-dir-heading :foreground ,fg2 :background ,bg4) + (diredp-dir-name :inherit dired-directory) + (diredp-dir-priv :inherit dired-directory) + (diredp-executable-tag :foreground ,builtin) + (diredp-file-name :foreground ,fg1) + (diredp-file-suffix :foreground ,fg4) + (diredp-flag-mark-line :foreground ,fg2 :slant italic :background ,bg5) + (diredp-flag-mark :foreground ,fg2 :weight bold :background ,bg5) + (diredp-ignored-file-name :foreground ,fg1) + (diredp-mode-line-flagged :foreground ,warning) + (diredp-mode-line-marked :foreground ,warning) + (diredp-no-priv :foreground ,fg1) + (diredp-number :foreground ,const) + (diredp-other-priv :foreground ,builtin) + (diredp-rare-priv :foreground ,builtin) + (diredp-read-priv :foreground ,type) + (diredp-write-priv :foreground ,keyword) + (diredp-exec-priv :foreground ,str) + (diredp-symlink :foreground ,warning) + (diredp-link-priv :foreground ,warning) + (diredp-autofile-name :foreground ,str) + (diredp-tagged-autofile-name :foreground ,str) + (icicle-whitespace-highlight :background ,var) + (icicle-special-candidate :foreground ,fg2) + (icicle-extra-candidate :foreground ,fg2) + (icicle-search-main-regexp-others :foreground ,var) + (icicle-search-current-input :foreground ,keyword) + (icicle-search-context-level-8 :foreground ,warning) + (icicle-search-context-level-7 :foreground ,warning) + (icicle-search-context-level-6 :foreground ,warning) + (icicle-search-context-level-5 :foreground ,warning) + (icicle-search-context-level-4 :foreground ,warning) + (icicle-search-context-level-3 :foreground ,warning) + (icicle-search-context-level-2 :foreground ,warning) + (icicle-search-context-level-1 :foreground ,warning) + (icicle-search-main-regexp-current :foreground ,fg1) + (icicle-saved-candidate :foreground ,fg1) + (icicle-proxy-candidate :foreground ,fg1) + (icicle-mustmatch-completion :foreground ,type) + (icicle-multi-command-completion :foreground ,fg2 :background ,bg2) + (icicle-msg-emphasis :foreground ,func) + (icicle-mode-line-help :foreground ,fg4) + (icicle-match-highlight-minibuffer :foreground ,builtin) + (icicle-match-highlight-Completions :foreground ,func) + (icicle-key-complete-menu-local :foreground ,fg1) + (icicle-key-complete-menu :foreground ,fg1) + (icicle-input-completion-fail-lax :foreground ,keyword) + (icicle-input-completion-fail :foreground ,keyword) + (icicle-historical-candidate-other :foreground ,fg1) + (icicle-historical-candidate :foreground ,fg1) + (icicle-current-candidate-highlight :foreground ,warning :background ,bg3) + (icicle-Completions-instruction-2 :foreground ,fg4) + (icicle-Completions-instruction-1 :foreground ,fg4) + (icicle-completion :foreground ,var) + (icicle-complete-input :foreground ,builtin) + (icicle-common-match-highlight-Completions :foreground ,type) + (icicle-candidate-part :foreground ,var) + (icicle-annotation :foreground ,fg4)))) + + (apply #'custom-theme-set-faces + 'dracula + (let ((color-names (mapcar #'car colors)) + (graphic-colors (mapcar #'cadr colors)) + (tty-colors (mapcar #'car (mapcar #'last colors)))) + (cl-flet* ((expand-for-tty (spec) (cl-progv color-names tty-colors + (eval `(backquote ,spec)))) + (expand-for-graphic (spec) (cl-progv color-names graphic-colors + (eval `(backquote ,spec))))) + (cl-loop for (face . spec) in faces + collect `(,face + ((((min-colors 16777216)) + ,(expand-for-graphic spec)) + (t + ,(expand-for-tty spec))))))))) + +;;;###autoload +(when load-file-name + (add-to-list 'custom-theme-load-path + (file-name-as-directory (file-name-directory load-file-name)))) + +(provide-theme 'dracula) + +;; Local Variables: +;; no-byte-compile: t +;; End: + +;;; dracula-theme.el ends here