├── demo.gif ├── README.md ├── wolfram-mode.elc └── wolfram-mode.el /demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kawabata/wolfram-mode/HEAD/demo.gif -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Wolfram-mode 2 | 3 | This provides basic editing features for Wolfram Language 4 | (http://reference.wolfram.com/language/), based on `math++.el' 5 | (http://chasen.org/~daiti-m/dist/math++.el). 6 | 7 | You should add the followings to `~/.emacs.d/init.el'. 8 | 9 | (autoload 'wolfram-mode "wolfram-mode" nil t) 10 | (autoload 'run-wolfram "wolfram-mode" nil t) 11 | (setq wolfram-program "/Applications/Mathematica.app/Contents/MacOS/MathKernel") 12 | (add-to-list 'auto-mode-alist '("\\.m$" . wolfram-mode)) 13 | (setq wolfram-path "direcotry-in-Mathematica-$Path") ;; e.g. on Linux "~/.Mathematica/Applications" 14 | 15 | 16 | ## wolfram-run-script 17 | 18 | You can call function `EPrint[expr]` in Mathematica code to get pretty printing of `expr` in Emacs 19 | 20 | ![wolfram-run-scrript-demo](./demo.gif) -------------------------------------------------------------------------------- /wolfram-mode.elc: -------------------------------------------------------------------------------- 1 | ;ELC 2 | ;;; Compiled 3 | ;;; in Emacs version 25.1.1 4 | ;;; with all optimizations. 5 | 6 | ;;; This file uses dynamic docstrings, first added in Emacs 19.29. 7 | 8 | ;;; This file does not contain utf-8 non-ASCII characters, 9 | ;;; and so can be loaded in Emacs versions earlier than 23. 10 | 11 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 12 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 13 | 14 | 15 | (byte-code "\300\301!\210\300\302!\210\303\304\305\306\307\310%\210\311\312\313\314\315DD\316\317\320\307\304&\210\311\321\313\314\322DD\323\317\324\307\304&\210\311\325\313\314\326DD\327\317\330\307\304&\210\311\331\313\314\332DD\333\317\334\307\304&\210\311\335\313\314\336DD\337\317\324\307\304&\207" [require comint smie custom-declare-group wolfram-mode nil "Editing Wolfram Language code" :group languages custom-declare-variable wolfram-mode-hook funcall function #[0 "\300\207" [nil] 1] "Normal hook run when entering `wolfram-mode'.\nSee `run-hooks'." :type hook wolfram-program #[0 "\300\207" [#1="math"] 1 #1#] "Command to invoke at `run-wolfram'." string wolfram-program-arguments #[0 "\300\207" [nil] 1] "Additional arguments to `wolfram-program'." (repeat string) wolfram-indent #[0 "\300\207" [8] 1] "Basic Indentation for newline." integer wolfram-path #[0 "\300\207" [nil] 1] "Directory in Mathematica $Path. Emacs has to be able to write in this directory."] 8) 16 | #@28 Keymap for `wolfram-mode'. 17 | (defvar wolfram-mode-map (byte-code "\300 \301\302\303#\210\301\304\305#\210\301\306\307#\210\301\310\311#\210\301\312\313#\210\301\314\315#\210\301\316\315#\210\211\207" [make-sparse-keymap define-key " " newline-and-indent "]" wolfram-electric-braket ")" wolfram-electric-paren "}" wolfram-electric-brace "" wolfram-send-region "" wolfram-send-last-mathexp ""] 5) (#$ . 1395)) 18 | #@38 Syntax table used in `wolfram-mode'. 19 | (defvar wolfram-mode-syntax-table (byte-code "\300 \301\302\303#\210\301\304\303#\210\301\305\303#\210\301\306\303#\210\301\307\303#\210\301\310\311#\210\301\312\313#\210\301\314\315#\210\301\316\317#\210\301\320\321#\210\301\322\323#\210\301\324\325#\210\301\326\327#\210\301\330\327#\210\301\331\327#\210\301\332\327#\210\301\333\327#\210\301\334\327#\210\301\335\327#\210\301\336\327#\210\301\337\327#\210\301\340\327#\210\301\341\327#\210\301\342\327#\210\301\343\327#\210\301\344\345#\210\301\346\347#\210\301\350\351#\210\301\352\351#\210\301\353\351#\210\301\354\351#\210\301\355\351#\210\301\356\351#\210\211\207" [make-syntax-table modify-syntax-entry 32 " " 9 12 10 13 40 "()1n" 41 ")(4n" 42 "_ 23n" 91 "(]" 93 ")[" 123 "(}" 125 "){" 61 "." 58 37 60 62 38 124 95 47 33 64 35 39 92 "\\" 34 "\"" 45 "_" 46 96 94 36 43] 5) (#$ . 1820)) 20 | (define-abbrev-table 'wolfram-mode-abbrev-table nil) 21 | (defvar wolfram-syntax-propertize-function #[514 "b\210`W\205\300\301\302#\205\303\304\224\304\225\305\306$\210\202\207" [re-search-forward "\\\\[[A-Z][A-Za-z]*]" t put-text-property 0 syntax-table (3)] 7 "\n\n(fn START END)"]) 22 | (defvar wolfram-font-lock-keywords '(("^In[[0-9]+]:=" . font-lock-keyword-face) ("^Out[[0-9]+]=" . font-lock-keyword-face) ("^Out[[0-9]+]//[A-Za-z][A-Za-z0-9]*=" . font-lock-keyword-face) ("\\([A-Za-z][A-Za-z0-9`]*\\)[ ]*[[][ ]*[[]" 1 "default") ("\\([A-Za-z][A-Za-z0-9`]*\\)[ ]*[[]" 1 font-lock-function-name-face) ("//[ \f\n]*\\([A-Za-z][A-Za-z0-9`]*\\)" 1 font-lock-function-name-face) ("\\([A-Za-z][A-Za-z0-9`]*\\)[ \f\n]*/@" 1 font-lock-function-name-face) ("\\([A-Za-z][A-Za-z0-9`]*\\)[ \f\n]*//@" 1 font-lock-function-name-face) ("\\([A-Za-z][A-Za-z0-9`]*\\)[ \f\n]*@@" 1 font-lock-function-name-face) ("~[ ]*\\([A-Za-z][A-Za-z0-9`]*\\)[ ]*~" 1 font-lock-function-name-face) ("_[) ]*\\?\\([A-Za-z][A-Za-z0-9`]*\\)" 1 font-lock-function-name-face) ("\\(&&\\)" 1 "default") ("&" . font-lock-function-name-face) ("\\\\[[A-Za-z][A-Za-z0-9]*]" . font-lock-constant-face) ("$[A-Za-z0-9]+" . font-lock-variable-name-face) ("\\([A-Za-z0-9]+\\)[ ]*\\->" 1 font-lock-type-face) ("<<[ \f\n]*[A-Za-z][A-Za-z0-9]*`[ \f\n]*[A-Za-z][A-Za-z0-9]*[ \f\n]*`" . font-lock-type-face) ("[A-Za-z][A-Za-z0-9]*::[A-Za-z][A-Za-z0-9]*" . font-lock-warning-face) ("\\[Calculating\\.\\.\\.\\]" . font-lock-warning-face) ("\\[Mathematica.*\\]" . font-lock-warning-face) ("^Interrupt>" . font-lock-warning-face) ("-Graphics-" . font-lock-type-face) ("-DensityGraphics-" . font-lock-type-face) ("-ContourGraphics-" . font-lock-type-face) ("-SurfaceGraphics-" . font-lock-type-face) ("-Graphics3D-" . font-lock-type-face) ("-GraphicsArray-" . font-lock-type-face) ("-Sound-" . font-lock-type-face) ("-CompiledCode-" . font-lock-type-face))) 23 | (defvar wolfram-outline-regexp "\\((\\*\\|.+?:=\\)") 24 | (defvar wolfram-smie-grammar '((:smie-closer-alist (#6="{" . #3="}") (#5="(" . #2=")") (#4="<|" . #1="|>")) (#1# 1 (160)) (#2# 2 (161)) (#3# 3 (162)) ("]]" 4 (163)) ("]" 5 (164)) ("," 16 27) ("//" 72 72) ("/;" 72 72) (":" 72 72) ("^" 138 138) ("/" 127 127) ("*" 127 127) ("-" 116 116) ("+" 116 116) ("&&" 105 105) ("||" 105 105) ("==" 94 94) ("@@" 94 94) ("~" 83 83) ("/=" 61 61) ("*=" 61 61) ("-=" 61 61) ("+=" 61 61) ("/:" 165 0) ("=" 61 61) (":=" 61 61) ("&" 49 (166)) (";" 38 38) ("::" 50 167) (#4# (168) 1) (#5# (169) 2) (#6# (170) 3) ("[[" 149 4) ("[" 171 5))) 25 | #@81 Wolfram Language SMIE indentation function for KIND and TOKEN. 26 | 27 | (fn KIND TOKEN) 28 | (defalias 'wolfram-smie-rules #[514 "B\211:\205\261\211@\211\301=\203;A\211\302\232\203#\212\303 \210\304i)B\2026\211\305\232\204/\211\306\232\2035\307!\2026\310\262\202\257\211\311=\203\210A\211\312\232\203O\304B\202\203\211\313\235\203Y\314\202\203\211\315\235\203p\212\316 \210\317\310w\210\304i\\)B\202\203\211\305\232\204|\211\306\232\203\202\307!\202\203\310\262\202\257A\211\305\232\203\226\307!\202\255\211\306\232\203\242\307!\202\255\320=\203\254\321\202\255\310\262\262\207" [wolfram-indent :before "[" smie-default-backward-token column ";" "," smie-rule-separator nil :after ":=" ("|>" ")" "}" "]") (column . 0) ("<|" "(" "{" "[") beginning-of-line " " :elem 0] 8 (#$ . 5278)]) 29 | (byte-code "\300\301\302\"\210\300\303\304\"\207" [defalias wolfram-smie-forward-token smie-default-forward-token wolfram-smie-backward-token smie-default-backward-token] 3) 30 | #@168 Hook run after entering Mathematica mode. 31 | No problems result if this variable is not bound. 32 | `add-hook' automatically binds it. (This is true for all hook variables.) 33 | (defvar wolfram-mode-hook nil (#$ . 6272)) 34 | (byte-code "\300\301!\204\f\302\301\303\304#\210\300\207" [boundp wolfram-mode-map put definition-name wolfram-mode] 4) 35 | (defvar wolfram-mode-map (make-sparse-keymap)) 36 | (byte-code "\300\301N\204\302\300\301\303\304!#\210\302\305\306\307#\207" [wolfram-mode-map variable-documentation put purecopy "Keymap for `wolfram-mode'." wolfram-mode derived-mode-parent prog-mode] 5) 37 | #@162 Major mode for editing Mathematica text files in Emacs. 38 | 39 | \{wolfram-mode-map} 40 | Entry to this mode calls the value of `wolfram-mode-hook' 41 | if that value is non-nil. 42 | (defalias 'wolfram-mode #[0 "\306\300!\210\307\310 \210\311\312\310\313N\203\314\311\313\310\313N#\210\315 !\204'\316 \317 \"\210\320 !\210\321\f!\210 \322\323\324\325\326\327&\210\330 \210)\331\332!\207" [delay-mode-hooks major-mode mode-name wolfram-mode-map wolfram-mode-syntax-table wolfram-mode-abbrev-table make-local-variable t prog-mode wolfram-mode "Mathematica" mode-class put keymap-parent set-keymap-parent current-local-map use-local-map set-syntax-table smie-setup wolfram-smie-rules :forward-token wolfram-smie-forward-token :backward-token wolfram-smie-backward-token wolfram-mode-variables run-mode-hooks wolfram-mode-hook local-abbrev-table wolfram-smie-grammar] 7 (#$ . 6863) nil]) 43 | #@51 Local variables for both Major and Inferior mode. 44 | (defalias 'wolfram-mode-variables #[0 "\306!\210\307\301!\210\310\307\302!\210\311\307\303!\210\312\307\305!\210\f\307\313!\210\314 \307\315!\210\211 \207" [wolfram-mode-syntax-table comment-start comment-end comment-start-skip wolfram-syntax-propertize-function syntax-propertize-function set-syntax-table make-local-variable "(*" "*)" "(\\*" font-lock-defaults (wolfram-font-lock-keywords nil nil) outline-regexp wolfram-outline-regexp] 2 (#$ . 7742)]) 45 | #@52 Indent on closing a CHAR ARG times. 46 | 47 | (fn CHAR ARG) 48 | (defalias 'wolfram-electric #[514 "\211\204\301\262\211\302\211W\203\211c\266\211T\262\202 \266 \210\303 \207" [indent-line-function 1 0 blink-matching-open] 6 (#$ . 8262)]) 49 | #@48 Indent on closing a paren ARG times. 50 | 51 | (fn ARG) 52 | (defalias 'wolfram-electric-paren #[257 "\300\301\"\207" [wolfram-electric ")"] 4 (#$ . 8505) "p"]) 53 | #@49 Indent on closing a braket ARG times. 54 | 55 | (fn ARG) 56 | (defalias 'wolfram-electric-braket #[257 "\300\301\"\207" [wolfram-electric "]"] 4 (#$ . 8659) "p"]) 57 | #@48 Indent on closing a brace ARG times. 58 | 59 | (fn ARG) 60 | (defalias 'wolfram-electric-brace #[257 "\300\301\"\207" [wolfram-electric "}"] 4 (#$ . 8815) "p"]) 61 | #@54 Indent on closing a association ARG times. 62 | 63 | (fn ARG) 64 | (defalias 'wolfram-electric-assoc #[257 "\300\301\"\207" [wolfram-electric "|>"] 4 (#$ . 8969) "p"]) 65 | (defalias 'wolfram-proc #[0 "\301\302=\203 p\202\f\303!\211\206\304\305!\207" [major-mode get-buffer-process inferior-wolfram-mode "*wolfram*" error "No current process. Do M-x `run-wolfram'"] 3]) 66 | #@78 Send the current region to the inferior Mathematica process. 67 | 68 | (fn START END) 69 | (defalias 'wolfram-send-region #[514 "\300\301 #\210\302\301 \303\"\207" [comint-send-region wolfram-proc comint-send-string "\n"] 6 (#$ . 9333) "r"]) 70 | #@177 Hook run after entering Inferior Mathematica mode. 71 | No problems result if this variable is not bound. 72 | `add-hook' automatically binds it. (This is true for all hook variables.) 73 | (defvar inferior-wolfram-mode-hook nil (#$ . 9570)) 74 | (byte-code "\300\301!\204\f\302\301\303\304#\210\300\207" [boundp inferior-wolfram-mode-map put definition-name inferior-wolfram-mode] 4) 75 | (defvar inferior-wolfram-mode-map (make-sparse-keymap)) 76 | (byte-code "\300\301N\204\302\300\301\303\304!#\210\305\306!\204\302\306\307\310#\210\300\207" [inferior-wolfram-mode-map variable-documentation put purecopy "Keymap for `inferior-wolfram-mode'." boundp inferior-wolfram-mode-syntax-table definition-name inferior-wolfram-mode] 5) 77 | (defvar inferior-wolfram-mode-syntax-table (make-syntax-table)) 78 | (byte-code "\300\301N\204\302\300\301\303\304!#\210\302\305\306\307#\207" [inferior-wolfram-mode-syntax-table variable-documentation put purecopy "Syntax table for `inferior-wolfram-mode'." inferior-wolfram-mode derived-mode-parent comint-mode] 5) 79 | #@262 Major mode for interacting with an inferior Mathematica process 80 | 81 | In addition to any hooks its parent mode `comint-mode' might have run, 82 | this mode runs the hook `inferior-wolfram-mode-hook', as the final step 83 | during initialization. 84 | 85 | \{inferior-wolfram-mode-map} 86 | (defalias 'inferior-wolfram-mode #[0 "\306\300!\210\307\310 \210\311\312\310\313N\203\314\311\313\310\313N#\210\315 !\204'\316 \317 \"\210\320\f!\211\2035\211\321 =\203;\322\f\323 \"\210\210\324 !\210\325\f!\210 \326\327 \210\330\307)\331\332!\207" [delay-mode-hooks major-mode mode-name inferior-wolfram-mode-map inferior-wolfram-mode-syntax-table wolfram-mode-abbrev-table make-local-variable t comint-mode inferior-wolfram-mode "Inferior Mathematica" mode-class put keymap-parent set-keymap-parent current-local-map char-table-parent standard-syntax-table set-char-table-parent syntax-table use-local-map set-syntax-table "^(In|Out)[[0-9]*]:?= *" wolfram-mode-variables (":%s") run-mode-hooks inferior-wolfram-mode-hook local-abbrev-table comint-prompt-regexp mode-line-process comint-process-echoes] 5 (#$ . 10598) nil]) 87 | #@91 Run an inferior Mathematica process CMD, input and output via buffer *wolfram*. 88 | 89 | (fn CMD) 90 | (defalias 'run-wolfram #[257 "\211\302\303! \"\304\305\306\307\310\311!@\312A&q!\266\313 \207" [wolfram-program wolfram-program-arguments append split-string-and-unquote pop-to-buffer-same-window apply make-comint-in-buffer "wolfram" get-buffer "*wolfram*" nil inferior-wolfram-mode] 10 (#$ . 11706) (byte-code "\203 \302\303 \"\202\f C\207" [current-prefix-arg wolfram-program read-string "Run Mathematica: "] 3)]) 91 | (defalias 'wolfram-here-is-space #[0 "\300f`Sf\205\211\205\301\302\303!\"\205\301\302\303!\"\207" [nil string-match "[ \n]" char-to-string] 6]) 92 | (defalias 'wolfram-moveto-last-content #[0 "\300 \205 \301u\210\202\207" [wolfram-here-is-space -1] 1]) 93 | (defalias 'wolfram-moveto-first-content #[0 "\300 \205 \301u\210\202\207" [wolfram-here-is-space 1] 1]) 94 | (defalias 'wolfram-beginning-of-cell #[0 "\300 \210\301\302\303\304#\203\305u\207eb\207" [wolfram-moveto-last-content re-search-backward "^$" nil t 1] 4]) 95 | (defalias 'wolfram-end-of-cell #[0 "\300 \210\301\302\303\304#\203\305u\207db\207" [wolfram-moveto-first-content re-search-forward "^$" nil t -1] 4]) 96 | #@68 Send the last math expression to the inferior Mathematica process. 97 | (defalias 'wolfram-send-last-mathexp #[0 "\212\300 \210`\301 \210`\302\303 #\210\304\303 \305\"\266\202)\207" [wolfram-beginning-of-cell wolfram-end-of-cell comint-send-region wolfram-proc comint-send-string "\n"] 6 (#$ . 12905) nil]) 98 | #@25 Execute and update file 99 | (defalias 'wolfram-run-script #[0 "\300 \210\301\302 !\303\302 !\304\302 !\305\306!\307\211rq\210ed|\210)\310 \210\311\312\313R\307#\210\314\315R\262\316\317\"\262\320!\210rq\210\321\322\323Q!\210\324\307\317\307#\210eb\210\325 \210\326 \210db)\207" [save-buffer file-name-base buffer-file-name file-name-nondirectory file-name-directory get-buffer-create "*MathematicaOutput*" nil wolfram-run-check-or-make-eprint-package call-process-shell-command "cd " "; MathKernel -script " ".pprint_" ".org" find-file-noselect t display-buffer rename-buffer "*MathematicaPrettyPrint_" "*" revert-buffer org-remove-latex-fragment-image-overlays org-toggle-latex-fragment] 11 (#$ . 13215) nil]) 100 | #@155 Checks if EPrint.m package exists in `wolfram-path'. The packed will be created it it is does not exists. 101 | 102 | Also returns an error if `wolfram-path' is nil 103 | (defalias 'wolfram-run-check-or-make-eprint-package #[0 "\204\301\302!\210\303\304P!?\205\305\306\307\304P#\207" [wolfram-path error "Please set `wolfram-path', so package EPrint.m can be created in that directory" file-exists-p "/EPrint.m" write-region "\nBeginPackage[ \"EPrint`\"]\n\nEPrint::usage =\n\"EPrint[ expr ] does pretty prints of expresion `expr` in emacs. You have to run *.m script in emacs via function `wolfram-run-script`.\"\n\nBegin[ \"Private`\"]\n\nn = 0;\n\nEPrint[ expr_ ] :=\n Module[ {file,dir},\n file = $InputFileName;\n dir = DirectoryName[file];\n name = FileBaseName[file];\n ppfile = FileNameJoin[{dir,\".pprint_\"<>name<>\".org\"}];\n WriteString[ ppfile, StringForm[\"#`1`:\\n\",n]];\n WriteString[ ppfile, \"\\\\begin{equation*}\\n\" ];\n WriteString[ ppfile, TeXForm[expr]];\n WriteString[ ppfile, \"\\n\\\\end{equation*}\"];\n WriteString[ ppfile, \"\\n\\n\"];\n n = n + 1\n ]\nEnd[]\n\nEndPackage[]\n" nil] 5 (#$ . 13944)]) 104 | (provide 'wolfram-mode) 105 | -------------------------------------------------------------------------------- /wolfram-mode.el: -------------------------------------------------------------------------------- 1 | ;;; wolfram-mode.el --- Mathematica editing and inferior mode. -*- lexical-binding: t -*- 2 | 3 | ;; Filename: wolfram-mode.el 4 | ;; Description: Wolfram Language (Mathematica) editing and inferior Mode 5 | ;; Package-Requires: ((emacs "24.3")) 6 | ;; Author: Daichi Mochihashi 7 | ;; Modified by: Taichi Kawabata 8 | ;; Modified by: Tomas Skrivan 9 | ;; Modified by: Ken Kang 10 | ;; Created: 2009-07-08 11 | ;; Modified: 2017-02-16 12 | ;; Keywords: languages, processes, tools 13 | ;; Namespace: wolfram- 14 | ;; URL: https://github.com/kawabata/wolfram-mode/ 15 | 16 | ;; This program is free software; you can redistribute it and/or 17 | ;; modify it under the terms of the GNU General Public License 18 | ;; as published by the Free Software Foundation; either version 2 19 | ;; of the License, or (at your option) any later version. 20 | 21 | ;; This program is distributed in the hope that it will be useful, 22 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of 23 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 24 | ;; GNU General Public License for more details. 25 | 26 | ;; You should have received a copy of the GNU General Public License 27 | ;; along with this program; if not, write to the Free Software 28 | ;; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 29 | 30 | ;;; Commentary: 31 | 32 | ;; This provides basic editing features for Wolfram Language 33 | ;; (http://reference.wolfram.com/language/), based on `math++.el' 34 | ;; (http://chasen.org/~daiti-m/dist/math++.el). 35 | 36 | ;; You should add the followings to `~/.emacs.d/init.el'. 37 | 38 | ;; (autoload 'wolfram-mode "wolfram-mode" nil t) 39 | ;; (autoload 'run-wolfram "wolfram-mode" nil t) 40 | ;; (setq wolfram-program "/Applications/Mathematica.app/Contents/MacOS/MathKernel") 41 | ;; (add-to-list 'auto-mode-alist '("\\.m$" . wolfram-mode)) 42 | ;; (setq wolfram-path "directory-in-Mathematica-$Path") ;; e.g. on Linux ~/.Mathematica/Applications 43 | 44 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 45 | ;; 46 | ;; Mathematica is (C) Copyright 1988-2013 Wolfram Research, Inc. 47 | ;; 48 | ;; Protected by copyright law and international treaties. 49 | ;; 50 | ;; Unauthorized reproduction or distribution subject to severe civil 51 | ;; and criminal penalties. 52 | ;; 53 | ;; Mathematica is a registered trademark of Wolfram Research. 54 | ;; 55 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 56 | 57 | ;; TODO 58 | ;; - wolfram-imenu-generic-expression 59 | ;; - sending useful commands to comint buffer. 60 | ;; - support for parsing string 61 | ;; - support for top level "\n" parsing 62 | 63 | ;;; Change Log: 64 | 65 | ;; 2013-10-01 Kawabata Taichi 66 | ;; * Modified to work with Emacs 24.3. 67 | ;; * Remove duplicate functions, undefined function calls and compiler warnings. 68 | ;; 2013-10-07 69 | ;; * Change `math-process-string' to `math-program' 70 | ;; * Change `scheme-args-to-list' to `split-string-and-unquote' 71 | ;; 2013-10-12 72 | ;; * Change `setq/make-local-variable' to `setq-local' 73 | ;; * Change `(* ... *)' comment to be nestable. 74 | ;; * `math-outline-regexp' : New variable. 75 | ;; * `math-electric' : New function. 76 | ;; * Change syntax of "`" to be word-constituent. 77 | ;; * Change indentation routines to use SMIE. 78 | ;; 2013-10-13 79 | ;; * `math-program-arguments' : New variable 80 | ;; * `run-math' : Cleanup 81 | ;; 2013-11-23 82 | ;; * Change `math-' prefix to `wolfram-' prefix. 83 | 84 | ;; * Code: 85 | 86 | (require 'comint) 87 | (require 'smie) 88 | 89 | ;; ** Customs Variables 90 | 91 | (defgroup wolfram-mode nil 92 | "Editing Wolfram Language code" 93 | :group 'languages) 94 | 95 | (defcustom wolfram-mode-hook nil 96 | "Normal hook run when entering `wolfram-mode'. 97 | See `run-hooks'." 98 | :type 'hook 99 | :group 'wolfram-mode) 100 | 101 | (defcustom wolfram-program "math" 102 | "Command to invoke at `run-wolfram'." 103 | :type 'string 104 | :group 'wolfram-mode) 105 | 106 | (defcustom wolfram-program-arguments '() 107 | "Additional arguments to `wolfram-program'." 108 | :type '(repeat string) 109 | :group 'wolfram-mode) 110 | 111 | (defcustom wolfram-indent 8 112 | "Basic Indentation for newline." 113 | :type 'integer 114 | :group 'wolfram-mode) 115 | 116 | (defcustom wolfram-path nil 117 | "Directory in Mathematica $Path. Emacs has to be able to write in this directory." 118 | :type 'string 119 | :group 'wolfram-mode) 120 | 121 | ;; ** wolfram-mode 122 | 123 | (defvar wolfram-mode-map 124 | (let ((map (make-sparse-keymap))) 125 | (define-key map "\C-m" 'newline-and-indent) 126 | (define-key map "]" 'wolfram-electric-braket) 127 | (define-key map ")" 'wolfram-electric-paren) 128 | (define-key map "}" 'wolfram-electric-brace) 129 | (define-key map "\C-c\C-r" 'wolfram-send-region) 130 | (define-key map "\C-c\C-e" 'wolfram-send-last-mathexp) 131 | (define-key map "\C-c\C-s" 'wolfram-send-last-mathexp) 132 | map) 133 | "Keymap for `wolfram-mode'.") 134 | 135 | (defvar wolfram-mode-syntax-table 136 | (let ((syntax-table (make-syntax-table))) 137 | ;; white space 138 | (modify-syntax-entry ? " " syntax-table) 139 | (modify-syntax-entry ?\t " " syntax-table) 140 | (modify-syntax-entry ?\f " " syntax-table) 141 | (modify-syntax-entry ?\n " " syntax-table) 142 | (modify-syntax-entry ?\^m " " syntax-table) 143 | 144 | ;; comments and parens 145 | (modify-syntax-entry ?( "()1n" syntax-table) 146 | (modify-syntax-entry ?) ")(4n" syntax-table) 147 | (modify-syntax-entry ?* "_ 23n" syntax-table) 148 | 149 | ;; pure parens 150 | (modify-syntax-entry ?[ "(]" syntax-table) 151 | (modify-syntax-entry ?] ")[" syntax-table) 152 | (modify-syntax-entry ?{ "(}" syntax-table) 153 | (modify-syntax-entry ?} "){" syntax-table) 154 | 155 | ;; punctuation 156 | (modify-syntax-entry ?= "." syntax-table) 157 | (modify-syntax-entry ?: "." syntax-table) 158 | (modify-syntax-entry ?% "." syntax-table) 159 | (modify-syntax-entry ?< "." syntax-table) 160 | (modify-syntax-entry ?> "." syntax-table) 161 | (modify-syntax-entry ?& "." syntax-table) 162 | (modify-syntax-entry ?| "." syntax-table) 163 | (modify-syntax-entry ?_ "." syntax-table) 164 | (modify-syntax-entry ?/ "." syntax-table) 165 | (modify-syntax-entry ?! "." syntax-table) 166 | (modify-syntax-entry ?@ "." syntax-table) 167 | (modify-syntax-entry ?# "." syntax-table) 168 | (modify-syntax-entry ?\' "." syntax-table) 169 | 170 | ;; quotes 171 | (modify-syntax-entry ?\\ "\\" syntax-table) 172 | (modify-syntax-entry ?\" "\"" syntax-table) 173 | 174 | ;; for Math numbers, the following would be better as 175 | ;; parts of symbols 176 | (modify-syntax-entry ?- "_" syntax-table) 177 | (modify-syntax-entry ?. "_" syntax-table) 178 | (modify-syntax-entry ?\` "_" syntax-table) 179 | (modify-syntax-entry ?^ "_" syntax-table) 180 | 181 | (modify-syntax-entry ?$ "_" syntax-table) 182 | (modify-syntax-entry ?+ "_" syntax-table) 183 | 184 | syntax-table) 185 | "Syntax table used in `wolfram-mode'.") 186 | 187 | (define-abbrev-table 'wolfram-mode-abbrev-table ()) 188 | 189 | (defvar wolfram-syntax-propertize-function 190 | (syntax-propertize-rules 191 | ("\\\\[[A-Z][A-Za-z]*]" (0 "_")))) 192 | 193 | (defvar wolfram-font-lock-keywords 194 | '( 195 | ("^In\[[0-9]+\]:=" . font-lock-keyword-face) 196 | ("^Out\[[0-9]+\]=" . font-lock-keyword-face) 197 | ("^Out\[[0-9]+\]//[A-Za-z][A-Za-z0-9]*=" . font-lock-keyword-face) 198 | ("\\([A-Za-z][A-Za-z0-9`]*\\)[ \t]*[\[][ \t]*[\[]" 1 "default") 199 | ("\\([A-Za-z][A-Za-z0-9`]*\\)[ \t]*[\[]" 1 font-lock-function-name-face) 200 | ("//[ \t\f\n]*\\([A-Za-z][A-Za-z0-9`]*\\)" 1 font-lock-function-name-face) 201 | ("\\([A-Za-z][A-Za-z0-9`]*\\)[ \t\f\n]*/@" 1 font-lock-function-name-face) 202 | ("\\([A-Za-z][A-Za-z0-9`]*\\)[ \t\f\n]*//@" 1 font-lock-function-name-face) 203 | ("\\([A-Za-z][A-Za-z0-9`]*\\)[ \t\f\n]*@@" 1 font-lock-function-name-face) 204 | ("~[ \t]*\\([A-Za-z][A-Za-z0-9`]*\\)[ \t]*~" 1 font-lock-function-name-face) 205 | ("_[) \t]*\\?\\([A-Za-z][A-Za-z0-9`]*\\)" 1 font-lock-function-name-face) 206 | ("\\(&&\\)" 1 "default") 207 | ("&" . font-lock-function-name-face) 208 | ("\\\\[[A-Za-z][A-Za-z0-9]*\]" . font-lock-constant-face ) 209 | ("$[A-Za-z0-9]+" . font-lock-variable-name-face ) 210 | ("\\([A-Za-z0-9]+\\)[ \t]*\\->" 1 font-lock-type-face ) 211 | ("<<[ \t\f\n]*[A-Za-z][A-Za-z0-9]*`[ \t\f\n]*[A-Za-z][A-Za-z0-9]*[ \t\f\n]*`" 212 | . font-lock-type-face ) 213 | ("[A-Za-z][A-Za-z0-9]*::[A-Za-z][A-Za-z0-9]*" . font-lock-warning-face) 214 | ("\\[Calculating\\.\\.\\.\\]" . font-lock-warning-face) 215 | ("\\[Mathematica.*\\]" . font-lock-warning-face) 216 | ("^Interrupt>" . font-lock-warning-face) 217 | ("-Graphics-" . font-lock-type-face) 218 | ("-DensityGraphics-" . font-lock-type-face) 219 | ("-ContourGraphics-" . font-lock-type-face) 220 | ("-SurfaceGraphics-" . font-lock-type-face) 221 | ("-Graphics3D-" . font-lock-type-face) 222 | ("-GraphicsArray-" . font-lock-type-face) 223 | ("-Sound-" . font-lock-type-face) 224 | ("-CompiledCode-" . font-lock-type-face))) 225 | 226 | (defvar wolfram-outline-regexp "\\((\\*\\|.+?:=\\)") 227 | 228 | (defvar wolfram-smie-grammar 229 | (smie-prec2->grammar 230 | (smie-bnf->prec2 231 | `((head) (epsilon) (string) 232 | (expr (head "[" exprs "]") 233 | (expr "[[" exprs "]]") 234 | ("{" exprs "}") 235 | ("(" expr ")") 236 | ("<|" exprs "|>") 237 | ;; message 238 | (expr "::" string) 239 | ;; statement separation 240 | (expr ";" expr) 241 | (expr "&") 242 | ;; delayed set 243 | (expr ":=" expr) 244 | (head "/:" expr ":=" expr) 245 | ;; set 246 | (expr "=" expr) 247 | (head "/:" expr "=" expr) 248 | (expr "+=" expr) 249 | (expr "-=" expr) 250 | (expr "*=" expr) 251 | (expr "/=" expr) 252 | ;; operation 253 | (expr "~" head "~" expr) 254 | (expr "@@" expr) 255 | (expr "==" expr) 256 | (expr "||" expr) 257 | (expr "&&" expr) 258 | (expr "+" expr) 259 | (expr "-" expr) 260 | (expr "*" expr) 261 | (expr "/" expr) 262 | (expr "^" expr) 263 | ;; application 264 | (expr ":" expr) 265 | (expr "/;" expr) 266 | (expr "//" expr)) 267 | (exprs (epsilon) 268 | (expr) 269 | (exprs "," expr))) 270 | '((assoc ";") 271 | (assoc "::") 272 | (assoc "&") 273 | (assoc "/:") 274 | (assoc ":=" "=" "+=" "-=" "*=" "/=") 275 | (assoc "/;" ":" "//") 276 | (assoc "~") 277 | (assoc "@@" "==") 278 | (assoc "||" "&&") 279 | (assoc "+" "-") 280 | (assoc "*" "/") 281 | (assoc "^") 282 | (assoc "[["))))) 283 | 284 | (defun wolfram-smie-rules (kind token) 285 | "Wolfram Language SMIE indentation function for KIND and TOKEN." 286 | (pcase (cons kind token) 287 | (`(:before . "[") 288 | (save-excursion 289 | (smie-default-backward-token) 290 | `(column . ,(current-column)))) 291 | (`(:after . ":=") `(column . ,wolfram-indent)) 292 | (`(:after . ,(or "]" "}" ")" "|>")) '(column . 0)) 293 | (`(:after . ,(or "[" "{" "(" "<|")) 294 | (save-excursion 295 | (beginning-of-line) 296 | (skip-chars-forward " \t") 297 | `(column . ,(+ wolfram-indent (current-column))))) 298 | (`(,_ . ";") (smie-rule-separator kind)) 299 | (`(,_ . ",") (smie-rule-separator kind)) 300 | (`(:elem . ,_) 0) 301 | (t nil))) 302 | 303 | (defalias 'wolfram-smie-forward-token 'smie-default-forward-token) 304 | (defalias 'wolfram-smie-backward-token 'smie-default-backward-token) 305 | 306 | ;;;###autoload 307 | (define-derived-mode wolfram-mode prog-mode "Mathematica" 308 | "Major mode for editing Mathematica text files in Emacs. 309 | 310 | \\{wolfram-mode-map} 311 | Entry to this mode calls the value of `wolfram-mode-hook' 312 | if that value is non-nil." 313 | :syntax-table wolfram-mode-syntax-table 314 | :abbrev-table wolfram-mode-abbrev-table 315 | (smie-setup wolfram-smie-grammar #'wolfram-smie-rules 316 | :forward-token 'wolfram-smie-forward-token 317 | :backward-token 'wolfram-smie-backward-token) 318 | (wolfram-mode-variables)) 319 | 320 | (defun wolfram-mode-variables () 321 | "Local variables for both Major and Inferior mode." 322 | (set-syntax-table wolfram-mode-syntax-table) 323 | ;; set local variables 324 | (setq-local comment-start "(*") 325 | (setq-local comment-end "*)") 326 | (setq-local comment-start-skip "(\\*") 327 | (set (make-local-variable 'syntax-propertize-function) 328 | wolfram-syntax-propertize-function) 329 | (setq-local font-lock-defaults '(wolfram-font-lock-keywords nil nil)) 330 | (setq-local outline-regexp wolfram-outline-regexp)) 331 | 332 | (defun wolfram-electric (char arg) 333 | "Indent on closing a CHAR ARG times." 334 | (if (not arg) (setq arg 1) nil) 335 | (dotimes (_i arg) (insert char)) 336 | (funcall indent-line-function) 337 | (blink-matching-open)) 338 | 339 | (defun wolfram-electric-paren (arg) 340 | "Indent on closing a paren ARG times." 341 | (interactive "p") 342 | (wolfram-electric ")" arg)) 343 | 344 | (defun wolfram-electric-braket (arg) 345 | "Indent on closing a braket ARG times." 346 | (interactive "p") 347 | (wolfram-electric "]" arg)) 348 | 349 | (defun wolfram-electric-brace (arg) 350 | "Indent on closing a brace ARG times." 351 | (interactive "p") 352 | (wolfram-electric "}" arg)) 353 | 354 | (defun wolfram-electric-assoc (arg) 355 | "Indent on closing a association ARG times." 356 | (interactive "p") 357 | (wolfram-electric "|>" arg)) 358 | 359 | ;; * inferior Mathematica mode. * 360 | 361 | (defun wolfram-proc () 362 | (let ((proc (get-buffer-process (if (eq major-mode 'inferior-wolfram-mode) 363 | (current-buffer) 364 | "*wolfram*")))) 365 | (or proc 366 | (error "No current process. Do M-x `run-wolfram'")))) 367 | 368 | (defun wolfram-send-region (start end) 369 | "Send the current region to the inferior Mathematica process." 370 | (interactive "r") 371 | (comint-send-region (wolfram-proc) start end) 372 | (comint-send-string (wolfram-proc) "\C-j")) 373 | 374 | (define-derived-mode inferior-wolfram-mode comint-mode "Inferior Mathematica" 375 | "Major mode for interacting with an inferior Mathematica process" 376 | :abbrev-table wolfram-mode-abbrev-table 377 | (setq comint-prompt-regexp "^(In|Out)\[[0-9]*\]:?= *") 378 | (wolfram-mode-variables) 379 | (setq mode-line-process '(":%s")) 380 | (setq comint-process-echoes t)) 381 | 382 | ;;;###autoload 383 | (defun run-wolfram (cmd) 384 | "Run an inferior Mathematica process CMD, input and output via buffer *wolfram*." 385 | (interactive (list (if current-prefix-arg 386 | (read-string "Run Mathematica: " wolfram-program) 387 | wolfram-program))) 388 | (setq wolfram-program cmd) 389 | (let ((cmdlist (append (split-string-and-unquote wolfram-program) 390 | wolfram-program-arguments))) 391 | (pop-to-buffer-same-window 392 | (set-buffer (apply 'make-comint-in-buffer "wolfram" (get-buffer "*wolfram*") 393 | (car cmdlist) nil (cdr cmdlist))))) 394 | (inferior-wolfram-mode)) 395 | 396 | (defun wolfram-here-is-space () 397 | (let ((ca (char-after)) 398 | (cb (char-before))) 399 | (and ca cb 400 | (string-match "[ \t\n]" (char-to-string ca)) 401 | (string-match "[ \t\n]" (char-to-string cb))))) 402 | 403 | (defun wolfram-moveto-last-content () 404 | (while (wolfram-here-is-space) 405 | (backward-char 1))) 406 | 407 | (defun wolfram-moveto-first-content () 408 | (while (wolfram-here-is-space) 409 | (forward-char 1))) 410 | 411 | (defun wolfram-beginning-of-cell () 412 | (wolfram-moveto-last-content) 413 | (if (re-search-backward "^$" nil t) (forward-char 1) 414 | (goto-char (point-min)))) 415 | 416 | (defun wolfram-end-of-cell () 417 | (wolfram-moveto-first-content) 418 | (if (re-search-forward "^$" nil t) (backward-char 1) 419 | (goto-char (point-max)))) 420 | 421 | (defun wolfram-send-last-mathexp () 422 | "Send the last math expression to the inferior Mathematica process." 423 | (interactive) 424 | (save-excursion 425 | (let ((wolfram-start (progn (wolfram-beginning-of-cell) (point))) 426 | (wolfram-end (progn (wolfram-end-of-cell) (point)))) 427 | (comint-send-region (wolfram-proc) wolfram-start wolfram-end) 428 | (comint-send-string (wolfram-proc) "\C-j")))) 429 | 430 | ;; * mathematica pretty print * 431 | 432 | (defun wolfram-run-script () 433 | "Execute and update file" 434 | (interactive) 435 | (save-buffer) 436 | (let ((cur-name (file-name-base (buffer-file-name))) 437 | (cur-file (file-name-nondirectory (buffer-file-name))) 438 | (cur-dir (file-name-directory (buffer-file-name))) 439 | (output-buffer (get-buffer-create "*MathematicaOutput*")) 440 | (pretty-buffer) 441 | (pretty-file)) 442 | 443 | ;; Prepare output buffer 444 | (with-current-buffer output-buffer 445 | (delete-region (point-min) (point-max))) 446 | 447 | ;; Ensure that package EPrint.m exists 448 | (wolfram-run-check-or-make-eprint-package) 449 | 450 | ;; Call Mathematica 451 | (call-process-shell-command (concat "cd " 452 | cur-dir 453 | "; MathKernel -script " 454 | cur-file) 455 | nil output-buffer) 456 | 457 | ;; Open buffer for pretty printing 458 | (setq pretty-file (concat cur-dir ".pprint_" cur-name ".org")) 459 | (setq pretty-buffer (find-file-noselect pretty-file t)) 460 | (display-buffer pretty-buffer) 461 | 462 | ;;(my-run-command-other-window "MathKernel -script test.m") 463 | (with-current-buffer pretty-buffer 464 | (rename-buffer (concat "*MathematicaPrettyPrint_" cur-name "*")) 465 | (revert-buffer nil t nil) 466 | (goto-char (point-min)) 467 | (org-remove-latex-fragment-image-overlays) 468 | (org-toggle-latex-fragment) 469 | (goto-char (point-max))))) 470 | 471 | (defun wolfram-run-check-or-make-eprint-package () 472 | "Checks if EPrint.m package exists in `wolfram-path'. \ 473 | The packed will be created it it is does not exists. 474 | 475 | Also returns an error if `wolfram-path' is nil" 476 | (unless wolfram-path 477 | (error "Please set `wolfram-path', so package EPrint.m can be created in that directory")) 478 | 479 | (unless (file-exists-p (concat wolfram-path "/EPrint.m")) 480 | (write-region 481 | " 482 | BeginPackage[ \"EPrint`\"] 483 | 484 | EPrint::usage = 485 | \"EPrint[ expr ] does pretty prints of expresion `expr` in emacs. You have to run *.m script in emacs via function `wolfram-run-script`.\" 486 | 487 | Begin[ \"Private`\"] 488 | 489 | n = 0; 490 | 491 | EPrint[ expr_ ] := 492 | Module[ {file,dir}, 493 | file = $InputFileName; 494 | dir = DirectoryName[file]; 495 | name = FileBaseName[file]; 496 | ppfile = FileNameJoin[{dir,\".pprint_\"<>name<>\".org\"}]; 497 | WriteString[ ppfile, StringForm[\"#`1`:\\n\",n]]; 498 | WriteString[ ppfile, \"\\\\begin{equation*}\\n\" ]; 499 | WriteString[ ppfile, TeXForm[expr]]; 500 | WriteString[ ppfile, \"\\n\\\\end{equation*}\"]; 501 | WriteString[ ppfile, \"\\n\\n\"]; 502 | n = n + 1 503 | ] 504 | End[] 505 | 506 | EndPackage[] 507 | " 508 | nil (concat wolfram-path "/EPrint.m")))) 509 | 510 | ;; * Provide * 511 | 512 | (provide 'wolfram-mode) 513 | 514 | ;; Local Variables: 515 | ;; coding: utf-8-unix 516 | ;; time-stamp-pattern: "10/Modified:\\\\?[ \t]+%:y-%02m-%02d\\\\?\n" 517 | ;; End: 518 | 519 | ;;; wolfram-mode.el ends here 520 | --------------------------------------------------------------------------------