;; ess-julia.el --- ESS julia mode and inferior interaction -*- lexical-binding: t; -*- ;; ;; Copyright (C) 2012-2015 Vitalie Spinu and the ESS Core team. ;; ;; Author: Vitalie Spinu ;; Maintainer: Vitalie Spinu ;; Created: 02-04-2012 (ESS 12.03) ;; Keywords: ESS, julia ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;; This file is *NOT* part of GNU Emacs. ;; This file is part of ESS ;; ;; 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 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. ;; ;; A copy of the GNU General Public License is available at ;; https://www.r-project.org/Licenses/ ;; ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;;; Commentary: ;; ;; Customize inferior-julia-program to point to your julia binary ;; and start the inferior with M-x julia. ;; ;; As of Sept 2015, this file depends heavily on julia-mode.el from the Julia ;; sources. If you install ESS using `make', this will work fine, otherwise ;; ensure that julia-mode.el is on your path before loading this file. ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;;; Code: (require 'ess-help) (require 'ess-inf) (require 'ess-r-mode) (require 'ess-utils) (require 'julia-mode) (defvar ac-prefix) (declare-function company-in-string-or-comment "company") (declare-function company-doc-buffer "company") (defcustom inferior-julia-args "" "String of arguments (see `julia --help') used when starting julia." :group 'ess-julia :type 'string) (eval-when-compile (require 'cl-lib)) (defun ess-julia-send-string-function (process string _visibly) "Send the Julia STRING to the PROCESS. VISIBLY is not currently used." (let ((file (concat temporary-file-directory "julia_eval_region.jl"))) (with-temp-file file (insert string)) (process-send-string process (format ess-load-command file)))) ;;; HELP (cl-defmethod ess-help-get-topics (proc &context (ess-dialect "julia")) (append (with-current-buffer (ess-command "ESS.all_help_topics()\n") (split-string (buffer-string) "\n")) (ess-julia--get-objects proc))) (defun ess-julia--retrive-topics (url) (with-current-buffer (url-retrieve-synchronously url) (require 'url) (goto-char (point-min)) (let (out) (while (re-search-forward "toctext[ \"]+href=\"\\([^>]+\\)\">\\([^<]+\\) ") (inferior-ess-secondary-prompt . nil) (inferior-ess-prompt . "\\w*> ") (ess-local-customize-alist . 'ess-julia-customize-alist) (inferior-ess-program . inferior-julia-program) (ess-load-command . "include(expanduser(\"%s\"))\n") (ess-funargs-command . "ESS.fun_args(\"%s\")\n") (ess-dump-error-re . "in \\w* at \\(.*\\):[0-9]+") (ess-error-regexp . "\\(^\\s-*at\\s-*\\(?3:.*\\):\\(?2:[0-9]+\\)\\)") (ess-error-regexp-alist . ess-julia-error-regexp-alist) (ess-mode-completion-syntax-table . ess-julia-completion-syntax-table) ;; (inferior-ess-objects-command . inferior-ess-r-objects-command) ;; (inferior-ess-search-list-command . "search()\n") (inferior-ess-help-command . "ESS.help(\"%s\")\n") ;; (inferior-ess-help-command . "help(\"%s\")\n") (ess-language . "julia") (ess-dialect . "julia") (ess-suffix . "jl") (ess-dump-filename-template . (replace-regexp-in-string "S$" ess-suffix ; in the one from custom: ess-dump-filename-template-proto)) (ess-mode-editing-alist . nil) (ess-change-sp-regexp . nil );ess-r-change-sp-regexp) (ess-help-sec-regex . ess-help-r-sec-regex) (ess-help-sec-keys-alist . ess-help-r-sec-keys-alist) (ess-function-pattern . ess-r-function-pattern) (ess-object-name-db-file . "ess-jl-namedb.el" ) (ess-smart-operators . ess-r-smart-operators) (inferior-ess-exit-command . "exit()\n") ;;harmful for shell-mode's C-a: -- but "necessary" for ESS-help? (inferior-ess-language-start . nil) (ess-STERM . "iESS") (ess-editor . ess-r-editor) (ess-pager . ess-r-pager) (ess-getwd-command . "pwd()\n") (ess-setwd-command . "cd(expanduser(\"%s\"))\n")) "Variables to customize for Julia.") (cl-defmethod ess--help-web-search-override (cmd &context (ess-dialect "julia")) "Offer to search the web for a Julia command." (browse-url (format "https://docs.julialang.org/en/latest/search/?q=%s" cmd))) (defvar ess-julia-completion-syntax-table (let ((table (copy-syntax-table ess-r-mode-syntax-table))) (modify-syntax-entry ?. "_" table) ;; (modify-syntax-entry ?: "_" table) ;; (modify-syntax-entry ?$ "_" table) (modify-syntax-entry ?@ "_" table) table) "Syntax table used for completion and help symbol lookup. It makes underscores and dots word constituent chars.") (cl-defmethod ess-help-commands (&context (ess-dialect "julia")) '((packages . "_ess_list_categories()\n") (package-index . "_ess_print_index(\"%s\")\n") (index-keyword-reg . "^\\(.*+\\):$*") (index-start-reg . ":"))) (defvar ess-julia-mode-syntax-table (copy-syntax-table julia-mode-syntax-table)) (defvar ess-julia-mode-map (let ((map (make-sparse-keymap))) (set-keymap-parent map ess-mode-map) map) "Keymap for `ess-julia-mode'.") ;;;###autoload (define-derived-mode ess-julia-mode julia-mode "ESS[julia]" "Major mode for julia files." :group 'ess-Julia (setq-local ess-local-customize-alist ess-julia-customize-alist) (setq ess-dialect "julia") (ess-setq-vars-local ess-julia-customize-alist) ;; eldoc (add-function :before-until (local 'eldoc-documentation-function) #'ess-julia-eldoc-function) (when ess-use-eldoc (eldoc-mode)) ;; auto-complete (ess--setup-auto-complete '(ac-source-ess-julia-objects)) ;; company (ess--setup-company '(company-ess-julia-objects)) ;; for emacs >= 24 (remove-hook 'completion-at-point-functions 'ess-filename-completion 'local) ;; should be first (add-hook 'completion-at-point-functions 'ess-julia-object-completion nil 'local) (add-hook 'completion-at-point-functions 'ess-filename-completion nil 'local) (add-hook 'completion-at-point-functions 'ess-julia-latexsub-completion nil 'local) (if (fboundp 'ess-add-toolbar) (ess-add-toolbar))) ;; Inferior mode (defvar inferior-ess-julia-mode-syntax-table (copy-syntax-table ess-julia-mode-syntax-table) "Syntax table for `inferior-ess-julia-mode'.") (define-derived-mode inferior-ess-julia-mode inferior-ess-mode "iESS[julia]" "Major mode for inferior julia processes." :group 'ess-Julia (ess-setq-vars-local ess-julia-customize-alist) (setq-local comint-use-prompt-regexp t) (setq comint-prompt-regexp (concat "^" inferior-ess-prompt)) (setq ess-dialect "julia") ;; eldoc (add-function :before-until (local 'eldoc-documentation-function) #'ess-julia-eldoc-function) (when ess-use-eldoc (eldoc-mode)) ;; auto-complete (ess--setup-auto-complete '(ac-source-ess-julia-objects) t) ;; company (ess--setup-company '(company-ess-julia-objects) t) (remove-hook 'completion-at-point-functions 'ess-filename-completion 'local) ;; should be first (add-hook 'completion-at-point-functions 'ess-julia-object-completion nil 'local) (add-hook 'completion-at-point-functions 'ess-filename-completion nil 'local) (add-hook 'completion-at-point-functions 'ess-julia-latexsub-completion nil 'local) (setq comint-input-sender #'ess-julia-input-sender)) (defvar ess-julia-mode-hook nil) (defvar ess-julia-post-run-hook nil "Functions run in process buffer after starting julia process.") ;;;###autoload (defun run-ess-julia (&optional start-args) "Start an inferior julia process. Optional prefix START-ARGS (\\[universal-argument]) allows to set command line arguments, such as --load=. This should be OS agnostic. If you have certain command line arguments that should always be passed to julia, put them in the variable `inferior-julia-args'." (interactive "P") ;; get settings, notably inferior-julia-program : (if (null inferior-julia-program) (error "'inferior-julia-program' does not point to 'julia' or 'julia-basic' executable") (ess-write-to-dribble-buffer ;; for debugging only (format "\n(julia): ess-dialect=%s, buf=%s, start-arg=%s\n current-prefix-arg=%s\n" ess-dialect (current-buffer) start-args current-prefix-arg)) (let* ((jl-start-args (concat inferior-julia-args " " ; add space just in case (if start-args (read-string (concat "Starting Args" (if inferior-julia-args (concat " [other than '" inferior-julia-args "']")) " ? ")) nil)))) (let ((inf-buf (inferior-ess jl-start-args ess-julia-customize-alist))) (with-current-buffer inf-buf (ess--tb-start) ;; Remove ` from julia's logo (goto-char (point-min)) (while (re-search-forward "`" nil t) (replace-match "'")) ;; Remove an offending unmatched parenthesis (goto-char (point-min)) (forward-line 4) (when (re-search-forward "(" nil t) (replace-match "|")) (goto-char (point-max)) ;; --> julia helpers from ../etc/ess-julia.jl : (ess--inject-code-from-file (format "%sess-julia.jl" ess-etc-directory)) (run-mode-hooks 'ess-julia-post-run-hook)) inf-buf)))) ;;;###autoload (defalias 'julia #'run-ess-julia) (cl-defmethod ess--help-major-mode (&context (ess-dialect "julia")) (ess-julia-help-mode)) (define-derived-mode ess-julia-help-mode ess-help-mode "ESS[Julia] Help" "Major mode for Julia documentation." :group 'ess-help (let ((inhibit-read-only t)) ;; Julia help buffers can contain color if julia starts with ;; --color=yes (ansi-color-apply-on-region (point-min) (point-max)))) (add-to-list 'auto-mode-alist '("\\.jl\\'" . ess-julia-mode)) (provide 'ess-julia) ;;; ess-julia.el ends here