X-Git-Url: https://code.delx.au/gnu-emacs-elpa/blobdiff_plain/d78bc26f8a2fec19df8f7ba9084cd59d4e4e8bc5..6331624abc9af9779bbf2560f21d1678336f5729:/sml-proc.el?ds=inline diff --git a/sml-proc.el b/sml-proc.el index 5fad90c63..110ba4228 100644 --- a/sml-proc.el +++ b/sml-proc.el @@ -1,4 +1,4 @@ -;;; sml-proc.el. Comint based interaction mode for Standard ML. +;;; sml-proc.el --- Comint based interaction mode for Standard ML. ;; Copyright (C) 1989, Lars Bo Nielsen, 1994,1997 Matthew J. Morley @@ -31,19 +31,19 @@ ;; under 18.59 (or anywhere without comint, if there are such places). ;; See sml-mode.el for further information. -;;; DESCRIPTION +;;; 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 sml which starts a sub-process under emacs. You may +;; 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 'sml "sml-proc" "Run an inferior ML process." t) +;; (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 -;; sml) you will be prompted for a different program to execute from +;; 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 @@ -64,136 +64,102 @@ ;; 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-c ` (sml-next-error) will step through +;; 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 (see file sml-{mosml,poly-ml}.el). Look at -;; the documentation for sml-error-parser and sml-next-error -- you -;; may only need to modify the former to recover this feature for some -;; other ML systems, along with sml-error-regexp. +;; Moscow ML, and Poly/ML. For other compilers, add the relevant +;; regexp to sml-error-regexp-alist and send it to me. -;; While small pieces of text can be fed quite happily into the ML -;; process directly, lager pieces should (probably) be sent via a -;; temporary file making use of the compiler's "use" command. +;; 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. -;; CURRENT RATIONALE: you get sense out of the error messages if -;; there's a real file associated with a block of code, and XEmacs is -;; less likely to hang. These are likely to change. +;; Bugs: -;; For more information see the variable sml-temp-threshold. You -;; should set the variable sml-use-command appropriately for your ML -;; compiler. By default things are set up to work for the SML/NJ -;; compiler. +;; Todo: -;;; FOR YOUR .EMACS +;; - Keep improving `sml-compile'. +;; - ignore warnings (if requested) for next-error -;; Here are some ideas for inferior-sml-*-hooks: - -;; (setq inferior-sml-load-hook -;; '(lambda() "Set global defaults for inferior-sml-mode" -;; (define-key inferior-sml-mode-map "\C-cd" 'sml-cd) -;; (define-key sml-mode-map "\C-cd" 'sml-cd) -;; (define-key sml-mode-map "\C-c\C-f" 'sml-send-function) -;; (setq sml-temp-threshold 0))) ; safe: always use tmp file - -;; (setq inferior-sml-mode-hook -;; '(lambda() "Inferior SML mode defaults" -;; (setq comint-scroll-show-maximum-output t -;; comint-scroll-to-bottom-on-output t -;; comint-input-autoexpand nil))) - -;; =================================================================== - -;;; INFERIOR ML MODE VARIABLES +;;; Code: (require 'sml-mode) +(require 'sml-util) (require 'comint) -(provide 'sml-proc) - -(defvar sml-program-name "sml" - "*Program to run as ML.") - -(defvar sml-default-arg "" - "*Default command line option to pass, if any.") - -(defvar sml-display-frame-alist - '((height . 24) (width . 80) (menu-bar-lines . 0)) - "*Alist of frame parameters used in creating dedicated ML interaction frames. -These supersede the values given in `default-frame-alist'. -You might like a larger screen - - \(setcdr \(assoc 'height sml-display-frame-alist\) 40\) - -or you might like a small font - - \(setq sml-display-frame-alist - \(cons '\(font . \"7x14\"\) sml-display-frame-alist\)\) - -in your `inferior-sml-load-hook', say. The parameters - - '\(\(unsplittable . t\) \(icon-name . \"*sml*\"\)\) - -are always added to sml-display-frame-alist by default, though the value of -icon-name is actually culled from `sml-program-name'. - -See also the documentation for `modify-frame-parameters'.") - -(defvar sml-dedicated-frame (if window-system t nil) - "*If non-nil, interaction buffers display in their own frame. -Default is equivalent to variable `window-system'. -If you reset this variable after starting the compiler, you might have -to reset the window-dedicated property of the window displaying the -interaction buffer. See `set-window-dedicated-p'.") - -;;(defvar sml-raise-on-error nil -;; "*When non-nil, `sml-next-error' will raise the ML process's frame.") - -(defvar sml-temp-threshold 0 - "*Controls when emacs uses temporary files to communicate with ML. -If not a number (e.g., NIL), then emacs always sends text directly to -the subprocess. If an integer N, then emacs uses a temporary file -whenever the text is longer than N chars. `sml-temp-file' contains the -name of the temporary file for communicating. See variable -`sml-use-command' and function `sml-send-region'. - -Sending regions directly through the pty (not using temp files) -doesn't work very well -- e.g., SML/NJ nor Poly/ML incorrectly report -the line # of errors occurring in std_in.") - -(defvar sml-temp-file (make-temp-name "/tmp/ml") - "*Temp file that emacs uses to communicate with the ML process. -See `sml-temp-threshold'. Defaults to \(make-temp-name \"/tmp/ml\"\)") +(require 'compile) + +(defgroup sml-proc () + "Interacting with an SML process." + :group 'sml) + +(defcustom sml-program-name "sml" + "*Program to run as ML." + :group 'sml-proc + :type '(string)) + +(defcustom sml-default-arg "" + "*Default command line option to pass, if any." + :group 'sml-proc + :type '(string)) + +(defcustom sml-host-name "" + "*Host on which to run ML." + :group 'sml-proc + :type '(string)) + +(defcustom sml-config-file "~/.smlproc.sml" + "*File that should be fed to the ML process when started." + :group 'sml-proc + :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 inferior-sml-load-hook nil - "*Hook run when inferior-sml-mode (sml-proc.el) is loaded into Emacs. -This is a good place to put your preferred key bindings.") +(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 +`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 +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 +`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 # @@ -208,12 +174,12 @@ what process do 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 +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 +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.") @@ -225,202 +191,114 @@ use the command \\[sml-buffer] in the interaction buffer of choice.") Set to \"use \\\"%s\\\"\" for SML/NJ or Edinburgh ML; set to \"PolyML.use \\\"%s\\\"\" for Poly/ML, etc.") -(defvar sml-cd-command "System.Directory.cd \"%s\"" +(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].") -(defvar sml-prompt-regexp "^[\-=] *" - "*Regexp used to recognise prompts in the inferior ML process.") - -(defvar sml-error-parser 'sml-smlnj-error-parser - "*This function parses an error message into a 3-5 element list: - - \(file start-line start-col end-line-col err-msg\). - -The first three components are required by `sml-next-error', but the other -two are optional. If the file associated with the input is the standard -input stream, this function should probably return - - \(\"std_in\" start-line start-col\). - -This function will be called in a context in which the match data \(see -`match-data'\) are current for `sml-error-regexp'. The mode sets the -default value to the function `sml-smlnj-error-parser'. - -In a step towards greater sml-mode modularity END-LINE-COL can be either - - - the symbol nil \(in which case it is ignored\) - -or - - - an Emacs Lisp expression that when `eval'd at \(start-line,start-col\) - will move point to the end of the errorful text in the file. - -Note that the compiler should return the full path name of the errorful -file, and that this might require you to fiddle with the compiler's -prettyprinting switches.") - -;; std_in:2.1-4.3 Error: operator and operand don't agree (tycon mismatch) -;; std_in:2.1 Error: operator and operand don't agree (tycon mismatch) - -(defconst sml-smlnj-error-regexp - (concat - "^[-= ]*\\(.+\\):" ;file name - "\\([0-9]+\\)\\.\\([0-9]+\\)" ;start line.column - "\\(-\\([0-9]+\\)\\.\\([0-9]+\\)\\)?" ;end line.colum - ".+\\(\\(Error\\|Warning\\): .*\\)") ;the message - - "Default regexp matching SML/NJ error and warning messages. - -There should be no need to customise this, though you might decide -that you aren't interested in Warnings -- my advice would be to modify -`sml-error-regexp' explicitly to do that though. - -If you do customise `sml-smlnj-error-regexp' you may need to modify -the function `sml-smlnj-error-parser' (qv).") - -(defvar sml-error-regexp sml-smlnj-error-regexp - "*Regexp for matching \(the start of\) an error message.") - -(defun sml-smlnj-error-parser (pt) - "This parses the SML/NJ error message at PT into a 5 element list - - \(file start-line start-col end-of-err msg\) - -where FILE is the file in which the error occurs\; START-LINE is the line -number in the file where the error occurs\; START-COL is the character -position on that line where the error occurs. - -If present, the fourth return value is a simple Emacs Lisp expression that -will move point to the end of the errorful text, assuming that point is at -\(start-line,start-col\) to begin with\; and MSG is the text of the error -message given by the compiler." - - ;; This function uses `sml-smlnj-error-regexp' to do the parsing, and - ;; assumes that regexp groups 1, 2, and 3 correspond to the first three - ;; elements of the list returned\; and groups 5, 6 and 7 correspond to the - ;; optional elements in that order. - - (save-excursion - (goto-char pt) - (if (not (looking-at sml-smlnj-error-regexp)) - ;; the user loses big time. - (list nil nil nil) - (let ((file (match-string 1)) ; the file - (slin (string-to-int (match-string 2))) ; the start line - (scol (string-to-int (match-string 3))) ; the start col - (msg (if (match-beginning 7) (match-string 7)))) - ;; another loss: buggy sml/nj's produce nonsense like file:0.0 Error - (if (zerop slin) (list file nil scol) - ;; ok, was a range of characters mentioned? - (if (match-beginning 4) - ;; assume m-b 4 implies m-b 5 and m-b 6 (sml-smlnj-error-regexp) - (let* ((elin (string-to-int (match-string 5))) ; end line - (ecol (string-to-int (match-string 6))) ; end col - (jump (if (= elin slin) - ;; move forward on the same line - `(forward-char ,(1+ (- ecol scol))) - ;; otherwise move down, and over to ecol - `(progn - (forward-line ,(- elin slin)) - (forward-char ,ecol))))) - ;; nconc glues lists together. jump & msg aren't lists - (nconc (list file slin scol) (list jump) (list msg))) - (nconc (list file slin scol) (list nil) (list msg)))))))) - -(defun sml-smlnj (pfx) - "Set up and run Standard ML of New Jersey. -Prefix argument means accept the defaults below. - -Note: defaults set here will be clobbered if you setq them in the -inferior-sml-mode-hook. - - sml-program-name