~ubuntu-branches/ubuntu/wily/ess/wily-proposed

« back to all changes in this revision

Viewing changes to lisp/ess-julia.el

  • Committer: Package Import Robot
  • Author(s): Dirk Eddelbuettel
  • Date: 2013-09-27 18:41:32 UTC
  • mto: This revision was merged to the branch mainline in revision 37.
  • Revision ID: package-import@ubuntu.com-20130927184132-dxa7ufsry9hjd9dc
Tags: upstream-13.09
ImportĀ upstreamĀ versionĀ 13.09

Show diffs side-by-side

added added

removed removed

Lines of Context:
15
15
;;
16
16
;; This program is free software; you can redistribute it and/or
17
17
;; modify it under the terms of the GNU General Public License as
18
 
;; published by the Free Software Foundation; either version 3, any later version.
19
 
;;
20
 
;; This program is distributed in the hope that it will be useful, but WITHOUT
21
 
;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
22
 
;; FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
23
 
;; details.
24
 
;;
25
 
;; You should have received a copy of the GNU General Public License along with
26
 
;; this program; see the file COPYING.  If not, write to the Free Software
27
 
;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
28
 
;; USA.
 
18
;; published by the Free Software Foundation; either version 3, or
 
19
;; (at your option) any later version.
 
20
;;
 
21
;; This file 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 GNU Emacs; see the file COPYING.  If not, write to
 
28
;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
29
29
;;
30
30
;;
31
31
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
32
32
;;
33
33
;;; Commentary:
34
 
;;  customise inferior-julia-program-name to point to your julia-release-basic
 
34
;;  customise inferior-julia-program-name to point to your julia-basic
35
35
;;  and start the inferior with M-x julia.
36
36
;;
37
37
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
38
38
;;
 
39
;;; Code:
 
40
 
39
41
(require 'compile); for compilation-* below
40
 
 
41
 
;;; Code:
42
 
 
43
 
(defvar julia-mode-hook nil)
44
 
 
45
 
(add-to-list 'auto-mode-alist '("\\.jl\\'" . julia-mode))
 
42
(require 'ess-utils)
 
43
 
 
44
(autoload 'inferior-ess "ess-inf" "Run an ESS process.")
 
45
(autoload 'ess-mode     "ess-mode" "Edit an ESS process.")
46
46
 
47
47
(defvar julia-syntax-table
48
48
  (let ((table (make-syntax-table)))
73
73
    (modify-syntax-entry ?= "." table)
74
74
    (modify-syntax-entry ?% "." table)
75
75
    table)
76
 
  "Syntax table for julia-mode")
 
76
  "Syntax table for `julia-mode'.")
77
77
 
78
78
;; syntax table that holds within strings
79
79
(defvar julia-mode-string-syntax-table
80
80
  (let ((table (make-syntax-table)))
81
81
    table)
82
 
  "Syntax table for julia-mode")
 
82
  "Syntax table for `julia-mode'.")
83
83
 
84
84
;; disable " inside char quote
85
85
(defvar julia-mode-char-syntax-table
86
86
  (let ((table (make-syntax-table)))
87
87
    (modify-syntax-entry ?\" "." table)
88
88
    table)
89
 
  "Syntax table for julia-mode")
90
 
 
91
 
;; not used
92
 
;; (defconst julia-string-regex
93
 
;;   "\"[^\"]*?\\(\\(\\\\\\\\\\)*\\\\\"[^\"]*?\\)*\"")
 
89
  "Syntax table for `julia-mode'.")
94
90
 
95
91
(defconst julia-char-regex
96
92
  "\\(\\s(\\|\\s-\\|-\\|[,%=<>\\+*/?&|$!\\^~\\\\;:]\\|^\\)\\('\\(\\([^']*?[^\\\\]\\)\\|\\(\\\\\\\\\\)\\)'\\)")
101
97
(defconst julia-forloop-in-regex
102
98
  "for +[^      
 
 
b']+ +.*\\\\(in\\\\)\\\\(\\\\s-\\\\|$\\\\)+")'
103
99
 
104
 
(defconst ess-subset-regexp
105
 
      "\\[[0-9:, ]*\\]" )
106
 
 
107
 
(defconst julia-font-lock-defaults
108
 
  (list '("\\<\\(\\|Uint\\(8\\|16\\|32\\|64\\)\\|Int\\(8\\|16\\|32\\|64\\)\\|Integer\\|Float\\|Float32\\|Float64\\|Complex128\\|Complex64\\|ComplexNum\\|Bool\\|Char\\|Number\\|Scalar\\|Real\\|Int\\|Uint\\|Array\\|DArray\\|AbstractArray\\|AbstractVector\\|AbstractMatrix\\|SubArray\\|StridedArray\\|StridedVector\\|StridedMatrix\\|VecOrMat\\|StridedVecOrMat\\|Range\\|Range1\\|SparseMatrixCSC\\|Tuple\\|NTuple\\|Buffer\\|Size\\|Index\\|Symbol\\|Function\\|Vector\\|Matrix\\|Union\\|Type\\|Any\\|Complex\\|None\\|String\\|Ptr\\|Void\\|Exception\\|PtrInt\\|Long\\|Ulong\\)\\>" .
 
100
(defconst julia-font-lock-keywords
 
101
  (list '("\\<\\(\\|Uint\\(8\\|16\\|32\\|64\\|128\\)\\|Int\\(8\\|16\\|32\\|64\\|128\\)\\|BigInt\\|Integer\\|BigFloat\\|FloatingPoint\\|Float16\\|Float32\\|Float64\\|Complex128\\|Complex64\\|ComplexPair\\|Bool\\|Char\\|Number\\|Real\\|Int\\|Uint\\|Array\\|DArray\\|AbstractArray\\|AbstractVector\\|AbstractMatrix\\|AbstractSparseMatrix\\|SubArray\\|StridedArray\\|StridedVector\\|StridedMatrix\\|VecOrMat\\|StridedVecOrMat\\|Range\\|Range1\\|SparseMatrixCSC\\|Tuple\\|NTuple\\|Symbol\\|Function\\|Vector\\|Matrix\\|Union\\|Type\\|Any\\|Complex\\|None\\|String\\|Ptr\\|Void\\|Exception\\|Task\\|Signed\\|Unsigned\\|Associative\\|Dict\\|IO\\|IOStream\\|Ranges\\|Rational\\|Regex\\|RegexMatch\\|Set\\|IntSet\\|ASCIIString\\|UTF8String\\|ByteString\\|Expr\\|WeakRef\\|Nothing\\|ObjectIdDict\\|SubString\\)\\>" .
109
102
      font-lock-type-face)
110
103
    (cons
111
104
     (concat "\\<\\("
113
106
          'identity
114
107
          '("if" "else" "elseif" "while" "for" "begin" "end" "quote"
115
108
            "try" "catch" "return" "local" "abstract" "function" "macro" "ccall"
116
 
            "typealias" "break" "continue" "type" "global" "@\\w+"
117
 
            "module" "import" "export" "const" "let" "bitstype" "using")
 
109
            "finally" "typealias" "break" "continue" "type" "global" "@\\w+"
 
110
            "module" "using" "import" "export" "const" "let" "bitstype" "do"
 
111
            "baremodule" "importall" "immutable")
118
112
          "\\|") "\\)\\>")
119
113
     'font-lock-keyword-face)
120
 
    '("\\<\\(true\\|false\\|C_NULL\\|Inf\\|NaN\\|Inf32\\|NaN32\\)\\>" . font-lock-constant-face)
 
114
    '("\\<\\(true\\|false\\|C_NULL\\|Inf\\|NaN\\|Inf32\\|NaN32\\|nothing\\)\\>" . font-lock-constant-face)
121
115
    (list julia-unquote-regex 2 'font-lock-constant-face)
122
116
    (list julia-char-regex 2 'font-lock-string-face)
123
117
    (list julia-forloop-in-regex 1 'font-lock-keyword-face)
128
122
 
129
123
(defconst julia-block-start-keywords
130
124
  (list "if" "while" "for" "begin" "try" "function" "type" "let" "macro"
131
 
        "quote"))
 
125
        "quote" "do" "immutable"))
132
126
 
133
127
(defconst julia-block-other-keywords
134
128
  (list "else" "elseif"))
135
129
 
136
130
(defconst julia-block-end-keywords
137
 
  (list "end" "else" "elseif" "catch"))
138
 
 
139
 
(defun ess-inside-brackets-p (&optional pos)
140
 
  (save-excursion
141
 
    (let* ((pos (or pos (point)))
142
 
           (beg (re-search-backward "\\[" (max (point-min) (- pos 1000)) t))
143
 
           (end (re-search-forward "\\]" (min (point-max) (+ pos 1000)) t)))
144
 
    (and beg end (> pos beg) (> end pos)))))
 
131
  (list "end" "else" "elseif" "catch" "finally"))
145
132
 
146
133
(defun julia-at-keyword (kw-list)
147
 
  ; not a keyword if used as a field name, X.word, or quoted, :word
 
134
  "Return the word at point if it matches any keyword in KW-LIST.
 
135
KW-LIST is a list of strings.  The word at point is not considered
 
136
a keyword if used as a field name, X.word, or quoted, :word."
148
137
  (and (or (= (point) 1)
149
138
           (and (not (equal (char-before (point)) ?.))
150
139
                (not (equal (char-before (point)) ?:))))
152
141
       (not (ess-inside-brackets-p (point)))
153
142
       (member (current-word) kw-list)))
154
143
 
155
 
; get the position of the last open block
156
144
(defun julia-last-open-block-pos (min)
 
145
  "Move back and return the position of the last open block, if one found.
 
146
Do not move back beyond position MIN."
157
147
  (let ((count 0))
158
148
    (while (not (or (> count 0) (<= (point) min)))
159
149
      (backward-word 1)
161
151
            (cond ((julia-at-keyword julia-block-start-keywords)
162
152
                   (+ count 1))
163
153
                  ((and (equal (current-word) "end")
164
 
                        (not (ess-inside-comment-p)) (not (ess-inside-brackets-p)))
 
154
                        (not (ess-inside-comment-p))
 
155
                        (not (ess-inside-brackets-p)))
165
156
                   (- count 1))
166
157
                  (t count))))
167
158
    (if (> count 0)
168
159
        (point)
169
160
      nil)))
170
161
 
171
 
; get indent for last open block
172
162
(defun julia-last-open-block (min)
 
163
  "Move back and return indentation level for last open block.
 
164
Do not move back beyond MIN."
173
165
  (let ((pos (julia-last-open-block-pos min)))
174
166
    (and pos
175
167
         (progn
176
168
           (goto-char pos)
177
169
           (+ julia-basic-offset (current-indentation))))))
178
170
 
179
 
; return indent implied by a special form opening on the previous line, if any
180
171
(defun julia-form-indent ()
 
172
  "Return indent implied by a special form opening on the previous line."
181
173
  (forward-line -1)
182
174
  (end-of-line)
183
175
  (backward-sexp)
193
185
      nil)))
194
186
 
195
187
(defun julia-paren-indent ()
196
 
  (let* ((p (parse-partial-sexp (save-excursion
197
 
                                  ;; only indent by paren if the last open
198
 
                                  ;; paren is closer than the last open
199
 
                                  ;; block
200
 
                                  (or (julia-last-open-block-pos (point-min))
201
 
                                      (point-min)))
202
 
                                (progn (beginning-of-line)
203
 
                                       (point))))
 
188
  "Return indent by last opening paren."
 
189
  (let* ((p (parse-partial-sexp
 
190
             (save-excursion
 
191
               ;; only indent by paren if the last open
 
192
               ;; paren is closer than the last open
 
193
               ;; block
 
194
               (or (julia-last-open-block-pos (point-min))
 
195
                   (point-min)))
 
196
             (progn (beginning-of-line)
 
197
                    (point))))
204
198
         (pos (cadr p)))
205
199
    (if (or (= 0 (car p)) (null pos))
206
200
        nil
207
201
      (progn (goto-char pos) (+ 1 (current-column))))))
208
 
                                        ;  (forward-line -1)
209
 
                                        ;  (end-of-line)
210
 
                                        ;  (let ((pos (condition-case nil
211
 
                                        ;                (scan-lists (point) -1 1)
212
 
                                        ;              (error nil))))
213
 
                                        ;   (if pos
214
 
                                        ;       (progn (goto-char pos) (+ 1 (current-column)))
215
 
                                        ;     nil)))
216
202
 
217
203
(defun julia-indent-line ()
218
 
  "Indent current line of julia code"
 
204
  "Indent current line of julia code."
219
205
  (interactive)
220
 
                                        ;  (save-excursion
221
 
    (end-of-line)
222
 
    (indent-line-to
223
 
     (or (and (ess-inside-string-p (point-at-bol)) 0)
224
 
         (save-excursion (ignore-errors (julia-form-indent)))
225
 
         (save-excursion (ignore-errors (julia-paren-indent)))
226
 
         ;; previous line ends in =
227
 
         (save-excursion
228
 
           (beginning-of-line)
229
 
           (skip-chars-backward " \t\n")
230
 
           (when (eql (char-before) ?=)
231
 
             (+ julia-basic-offset (current-indentation))))
232
 
         (save-excursion
233
 
           (let ((endtok (progn
234
 
                           (beginning-of-line)
235
 
                           (forward-to-indentation 0)
236
 
                           (julia-at-keyword julia-block-end-keywords))))
237
 
             (ignore-errors (+ (julia-last-open-block (point-min))
238
 
                               (if endtok (- julia-basic-offset) 0)))))
239
 
         ;; take same indentation as previous line
240
 
         (save-excursion (forward-line -1)
241
 
                         (current-indentation))
242
 
         0))
243
 
    (when (julia-at-keyword julia-block-end-keywords)
244
 
      (forward-word 1)))
 
206
  (end-of-line)
 
207
  (indent-line-to
 
208
   (or (and (ess-inside-string-p (point-at-bol)) 0)
 
209
       (save-excursion (ignore-errors (julia-form-indent)))
 
210
       (save-excursion (ignore-errors (julia-paren-indent)))
 
211
       ;; previous line ends in =
 
212
       (save-excursion
 
213
         (beginning-of-line)
 
214
         (skip-chars-backward " \t\n")
 
215
         (when (eql (char-before) ?=)
 
216
           (+ julia-basic-offset (current-indentation))))
 
217
       (save-excursion
 
218
         (let ((endtok (progn
 
219
                         (beginning-of-line)
 
220
                         (forward-to-indentation 0)
 
221
                         (julia-at-keyword julia-block-end-keywords))))
 
222
           (ignore-errors (+ (julia-last-open-block (point-min))
 
223
                             (if endtok (- julia-basic-offset) 0)))))
 
224
       ;; take same indentation as previous line
 
225
       (save-excursion (forward-line -1)
 
226
                       (current-indentation))
 
227
       0))
 
228
  (when (julia-at-keyword julia-block-end-keywords)
 
229
    (forward-word 1)))
245
230
 
246
231
(defvar julia-editing-alist
247
232
  '((paragraph-start              . (concat "\\s-*$\\|" page-delimiter))
252
237
    (comment-add                  . 1)
253
238
    (comment-start-skip           . "#+\\s-*")
254
239
    (comment-column               . 40)
255
 
    ;;(comment-indent-function  . 'S-comment-indent)
256
 
    ;;(ess-comment-indent           . 'S-comment-indent)
257
 
    ;; (ess-indent-line                     . 'S-indent-line)
258
 
    ;;(ess-calculate-indent           . 'ess-calculate-indent)
259
240
    (ess-indent-line-function     . 'julia-indent-line)
260
241
    (indent-line-function         . 'julia-indent-line)
261
242
    (parse-sexp-ignore-comments   . t)
262
243
    (ess-style                    . ess-default-style) ;; ignored
263
244
    (ess-local-process-name       . nil)
264
 
    ;;(ess-keep-dump-files          . 'ask)
265
245
    (ess-mode-syntax-table        . julia-syntax-table)
266
 
    ;; For Changelog add, require ' ' before <- : "attr<-" is a function name :
267
 
    ;; (add-log-current-defun-header-regexp . "^\\(.+\\)\\s-+=[ \t\n]*function")
268
246
    (add-log-current-defun-header-regexp . "^.*function[ \t]*\\([^ \t(]*\\)[ \t]*(")
269
 
    (font-lock-defaults           . '(julia-font-lock-defaults
270
 
                                      nil nil ((?\_ . "w"))))
 
247
    (font-lock-defaults           . '(julia-font-lock-keywords nil nil ((?\_ . "w"))))
271
248
    )
272
249
  "General options for julia source files.")
273
250
 
274
 
(autoload 'inferior-ess "ess-inf" "Run an ESS process.")
275
 
(autoload 'ess-mode     "ess-mode" "Edit an ESS process.")
276
 
 
277
251
(defun julia-send-string-function (process string visibly)
 
252
  "Send the Julia STRING to the PROCESS.
 
253
VISIBLY is not currently used."
278
254
  (let ((file (concat temporary-file-directory "julia_eval_region.jl")))
279
255
    (with-temp-file file
280
256
      (insert string))
281
 
    (process-send-string process (format inferior-ess-load-command file))))
 
257
    (process-send-string process (format ess-load-command file))))
282
258
 
 
259
 
 
260
;;; HELP
283
261
(defun julia-get-help-topics (&optional proc)
284
 
  (ess-get-words-from-vector "ESS.all_help_topics()\n"))
 
262
  (append (ess-get-words-from-vector "ESS.all_help_topics()\n")
 
263
          (julia--get-objects)))
285
264
    ;; (ess-command com)))
286
265
 
287
 
(defvar julia-help-command "help(\"%s\")\n")
288
 
 
289
 
(defvar ess-julia-error-regexp-alist '(julia-in julia-at)
 
266
(defun julia--retrive-topics (url)
 
267
  (with-current-buffer (url-retrieve-synchronously url)
 
268
    (require 'url)
 
269
    (goto-char (point-min))
 
270
    (let (out)
 
271
      (while (re-search-forward "toctree.*href=\"\\(.+\\)\">\\(.+\\)</a" nil t)
 
272
        (push (propertize (match-string 2)
 
273
                          :manual (concat url (match-string 1)))
 
274
              out))
 
275
      (kill-buffer)
 
276
      (nreverse out))))
 
277
 
 
278
(defvar julia--manual-topics nil)
 
279
(defun julia-manual-lookup-function (&rest args) ; args are not used
 
280
  (interactive)
 
281
  "Look up topics at http://docs.julialang.org/en/latest/manual/"
 
282
  ;; <li class="toctree-l1"><a class="reference internal" href="introduction/">Introduction</a></li>
 
283
  (let* ((pages (or julia--manual-topics
 
284
                    (setq julia--manual-topics
 
285
                          (julia--retrive-topics "http://docs.julialang.org/en/latest/manual/"))))
 
286
         (page (ess-completing-read "Lookup:" pages nil t)))
 
287
    (browse-url (get-text-property 1 :manual page))))
 
288
 
 
289
(defvar julia--reference-topics nil)
 
290
(defun julia-reference-lookup-function (&rest args) ; args are not used
 
291
  (interactive)
 
292
  "Look up reference topics"
 
293
  ;; <li class="toctree-l1"><a class="reference internal" href="introduction/">Introduction</a></li>
 
294
  (let* ((pages (ess-get-words-from-vector "ESS.help_categories()\n")))
 
295
    (ess-display-help-on-object
 
296
     (ess-completing-read "Category" pages nil t))))
 
297
 
 
298
 
 
299
 
 
300
;;; COMPLETION
 
301
(defun julia-object-completion ()
 
302
  "Return completions at point in a format required by `completion-at-point-functions'. "
 
303
  (let ((proc (ess-get-next-available-process ess-dialect t))
 
304
        (beg (ess-symbol-start)))
 
305
    (if proc
 
306
        (when beg
 
307
          (let* ((prefix (buffer-substring-no-properties beg (point)))
 
308
                 (obj (and (string-match "\\(.*\\)\\..*$" prefix)
 
309
                           (match-string 1 prefix)))
 
310
                 (beg (if obj
 
311
                          (+ beg 1 (length obj))
 
312
                        beg)))
 
313
            (list beg (point)
 
314
                  (nreverse (mapcar 'car (julia--get-objects proc obj)))
 
315
                  :exclusive 'no)))
 
316
      (when (string-match "complet" (symbol-name last-command))
 
317
        (message "No ESS process of dialect %s started" ess-dialect)
 
318
        nil))))
 
319
 
 
320
(defun julia--get-objects (&optional proc obj)
 
321
  "Return all available objects.
 
322
Local caching might be used. If MODULE is givven, return only
 
323
objects from that MODULE."
 
324
  (setq proc (or proc
 
325
                 (get-process ess-local-process-name)))
 
326
  (when (process-live-p proc)
 
327
    (let ((objects (process-get proc 'objects)))
 
328
     (if (process-get proc 'busy)
 
329
         (if obj
 
330
             (assoc obj objects)
 
331
           (process-get proc 'objects))
 
332
       (if obj
 
333
           (or (cdr (assoc obj objects))
 
334
               ;; don't cache composite objects and datatypes
 
335
               (julia--get-components proc obj))
 
336
         ;; this segment is entered when user completon at top level is
 
337
         ;; requested, either Tab or AC. Hence Main is always updated.
 
338
         (let ((modules (ess-get-words-from-vector
 
339
                         "ESS.main_modules()\n" nil nil proc))
 
340
               (loc (process-get proc 'last-objects-cache))
 
341
               (lev (process-get proc 'last-eval)))
 
342
           (prog1
 
343
               (mapcan (lambda (mod)
 
344
                         ;; we are caching all modules, and reinit Main every
 
345
                         ;; time user enters commands
 
346
                         (copy-sequence
 
347
                          (or (and (or (not (equal mod "Main"))
 
348
                                       (ignore-errors (time-less-p lev loc)))
 
349
                                   (cdr (assoc mod objects)))
 
350
                              (julia--get-components proc mod t))))
 
351
                       modules)
 
352
             (process-put proc 'last-objects-cache (current-time)))))))))
 
353
 
 
354
(defun julia--get-components (proc obj &optional cache?)
 
355
  (with-current-buffer (ess-command (format "ESS.components(%s)\n" obj)
 
356
                                    nil nil nil nil proc)
 
357
    (goto-char (point-min))
 
358
    (let (list)
 
359
      (while (re-search-forward
 
360
              "^\\([^ \t\n]+\\) +\\([^ \t\n]+\\)$" nil t)
 
361
        (push (cons (match-string 1) (match-string 2)) list))
 
362
      (when cache?
 
363
        (let ((objects (process-get proc 'objects)))
 
364
         (push (cons obj list) objects)
 
365
         (process-put proc 'objects objects)))
 
366
      list)))
 
367
 
 
368
 
 
369
;;; AC
 
370
(defvar  ac-source-julia-objects
 
371
  '((prefix     . ess-symbol-start)
 
372
    (requires   . 2)
 
373
    (candidates . ess-ac-julia-objects)
 
374
    (document   . ess-ac-help-object)
 
375
    )
 
376
  "Auto-completion source for julia objects")
 
377
 
 
378
(defun ess-ac-julia-objects ()
 
379
  "Get all cached objects"
 
380
  (let ((aprf ac-prefix))
 
381
    (let ((proc (ess-get-next-available-process nil t)))
 
382
      (when aprf
 
383
        (if (string-match "\\(.*\\)\\..*$" aprf)
 
384
            (let ((module (match-string 1 aprf)))
 
385
              (mapcar (lambda (el) (concat module "." (car el)))
 
386
                      (julia--get-objects proc module)))
 
387
          (julia--get-objects proc))))))
 
388
 
 
389
 
 
390
 
 
391
;;; ERRORS
 
392
(defvar julia-error-regexp-alist '(julia-in julia-at)
290
393
  "List of symbols which are looked up in `compilation-error-regexp-alist-alist'.")
291
394
 
292
395
(add-to-list 'compilation-error-regexp-alist-alist
294
397
(add-to-list 'compilation-error-regexp-alist-alist
295
398
             '(julia-at "^\\S-+\\s-+\\(at \\(.*\\):\\([0-9]+\\)\\)"  2 3 nil 2 1))
296
399
 
 
400
 
 
401
 
 
402
;;; ELDOC
 
403
(defun julia-eldoc-function ()
 
404
  "Return the doc string, or nil.
 
405
If an ESS process is not associated with the buffer, do not try
 
406
to look up any doc strings."
 
407
  (interactive)
 
408
  (when (and (ess-process-live-p)
 
409
             (not (ess-process-get 'busy)))
 
410
    (let ((funname (or (and ess-eldoc-show-on-symbol ;; aggressive completion
 
411
                            (symbol-at-point))
 
412
                       (car (ess--funname.start)))))
 
413
      (when funname
 
414
        (let* ((args (copy-sequence (nth 2 (ess-function-arguments funname))))
 
415
               (W (- (window-width (minibuffer-window)) (+ 4 (length funname))))
 
416
               (doc (concat (propertize funname 'face font-lock-function-name-face) ": ")))
 
417
          (when args
 
418
            (setq args (sort args (lambda (s1 s2)
 
419
                                    (< (length s1) (length s2)))))
 
420
            (setq doc (concat doc (pop args)))
 
421
            (while (and args (< (+ (length doc) (length (car args))) W))
 
422
              (setq doc (concat doc "  "
 
423
                                (pop args))))
 
424
            (when (and args (< (length doc) W))
 
425
              (setq doc (concat doc " {--}"))))
 
426
          doc)))))
 
427
 
 
428
 
 
429
;;; IMENU
 
430
(defvar julia-imenu-generic-expression
 
431
  ;; don't use syntax classes, screws egrep
 
432
  '(("Function (_)" "[ \t]*function[ \t]+\\(_[^ \t\n]*\\)" 1)
 
433
    ("Function" "^[ \t]*function[ \t]+\\([^_][^\t\n]*\\)" 1)
 
434
    ("Const" "[ \t]*const \\([^ \t\n]*\\)" 1)
 
435
    ("Type"  "^[ \t]*[a-zA-Z0-9_]*type[a-zA-Z0-9_]* \\([^ \t\n]*\\)" 1)
 
436
    ("Require"      " *\\(\\brequire\\)(\\([^ \t\n)]*\\)" 2)
 
437
    ("Include"      " *\\(\\binclude\\)(\\([^ \t\n)]*\\)" 2)
 
438
    ))
 
439
 
 
440
 
 
441
;;; CORE
297
442
(defvar julia-customize-alist
298
443
  '((comint-use-prompt-regexp           . t)
299
 
    (ess-eldoc-function           . 'ess-julia-eldoc-function)
 
444
    (ess-eldoc-function                 . 'julia-eldoc-function)
300
445
    (inferior-ess-primary-prompt        . "a> ") ;; from julia>
301
446
    (inferior-ess-secondary-prompt      . nil)
302
447
    (inferior-ess-prompt                . "\\w*> ")
303
448
    (ess-local-customize-alist          . 'julia-customize-alist)
304
449
    (inferior-ess-program               . inferior-julia-program-name)
305
 
    (inferior-ess-font-lock-defaults    . julia-font-lock-defaults)
 
450
    (inferior-ess-font-lock-defaults    . julia-font-lock-keywords)
306
451
    (ess-get-help-topics-function       . 'julia-get-help-topics)
307
452
    (ess-help-web-search-command        . "http://docs.julialang.org/en/latest/search/?q=%s")
308
 
    (inferior-ess-load-command          . "include(\"%s\")\n")
 
453
    (ess-manual-lookup-command          . 'julia-manual-lookup-function)
 
454
    (ess-reference-lookup-command       . 'julia-reference-lookup-function)
 
455
    (ess-load-command                   . "include(\"%s\")\n")
309
456
    (ess-funargs-command                . "ESS.fun_args(\"%s\")\n")
310
457
    (ess-dump-error-re                  . "in \\w* at \\(.*\\):[0-9]+")
311
458
    (ess-error-regexp                   . "\\(^\\s-*at\\s-*\\(?3:.*\\):\\(?2:[0-9]+\\)\\)")
312
 
    (ess-error-regexp-alist             . ess-julia-error-regexp-alist)
 
459
    (ess-error-regexp-alist             . julia-error-regexp-alist)
313
460
    (ess-send-string-function           . nil);'julia-send-string-function)
314
461
    (ess-imenu-generic-expression       . julia-imenu-generic-expression)
315
462
    ;; (inferior-ess-objects-command    . inferior-R-objects-command)
316
463
    ;; (inferior-ess-search-list-command        . "search()\n")
317
 
    (inferior-ess-help-command          . julia-help-command)
 
464
    (inferior-ess-help-command          . "ESS.help(\"%s\")\n")
318
465
    ;; (inferior-ess-help-command       . "help(\"%s\")\n")
319
466
    (ess-language                       . "julia")
320
467
    (ess-dialect                        . "julia")
321
468
    (ess-suffix                         . "jl")
 
469
    (ess-ac-sources                     . '(ac-source-julia-objects))
322
470
    (ess-dump-filename-template         . (ess-replace-regexp-in-string
323
471
                                           "S$" ess-suffix ; in the one from custom:
324
472
                                           ess-dump-filename-template-proto))
330
478
    (ess-loop-timeout                   . ess-S-loop-timeout);fixme: dialect spec.
331
479
    (ess-cmd-delay                      . ess-R-cmd-delay)
332
480
    (ess-function-pattern               . ess-R-function-pattern)
333
 
    (ess-object-name-db-file            . "ess-r-namedb.el" )
 
481
    (ess-object-name-db-file            . "ess-jl-namedb.el" )
334
482
    (ess-smart-operators                . ess-R-smart-operators)
335
483
    (inferior-ess-help-filetype        . nil)
336
484
    (inferior-ess-exit-command          . "exit()\n")
344
492
    )
345
493
  "Variables to customize for Julia -- set up later than emacs initialization.")
346
494
 
347
 
 
348
 
(defvar ess-julia-versions '("julia")
 
495
(defvar julia-versions '("julia")
349
496
  "List of partial strings for versions of Julia to access within ESS.
350
497
Each string specifies the start of a filename.  If a filename
351
498
beginning with one of these strings is found on `exec-path', a M-x
352
 
command for that version of Julia is made available.  ")
 
499
command for that version of Julia is made available.")
353
500
 
354
501
(defcustom inferior-julia-args ""
355
502
  "String of arguments (see 'julia --help') used when starting julia."
356
 
;; These arguments are currently not passed to other versions of julia that have
357
 
;; been created using the variable `ess-r-versions'."
 
503
  ;; These arguments are currently not passed to other versions of julia that have
 
504
  ;; been created using the variable `ess-r-versions'."
358
505
  :group 'ess-julia
359
506
  :type 'string)
360
507
 
364
511
  (interactive "P")
365
512
  ;; (setq ess-customize-alist julia-customize-alist)
366
513
  (ess-mode julia-customize-alist proc-name)
367
 
  ;; for emacs < 24
368
 
  ;; (add-hook 'comint-dynamic-complete-functions 'ess-complete-object-name nil 'local)
369
514
  ;; for emacs >= 24
370
 
  ;; (remove-hook 'completion-at-point-functions 'ess-filename-completion 'local) ;; should be first
371
 
  ;; (add-hook 'completion-at-point-functions 'ess-object-completion nil 'local)
372
 
  ;; (add-hook 'completion-at-point-functions 'ess-filename-completion nil 'local)
 
515
  (remove-hook 'completion-at-point-functions 'ess-filename-completion 'local) ;; should be first
 
516
  (add-hook 'completion-at-point-functions 'julia-object-completion nil 'local)
 
517
  (add-hook 'completion-at-point-functions 'ess-filename-completion nil 'local)
373
518
  (if (fboundp 'ess-add-toolbar) (ess-add-toolbar))
374
519
  (set (make-local-variable 'end-of-defun-function) 'ess-end-of-function)
375
520
  ;; (local-set-key  "\t" 'julia-indent-line) ;; temp workaround
379
524
  (imenu-add-to-menubar "Imenu-jl")
380
525
  (run-hooks 'julia-mode-hook))
381
526
 
382
 
 
383
 
(defvar ess-julia-post-run-hook nil
384
 
  "Functions run in process buffer after the initialization of
385
 
  julia process.")
 
527
(defvar julia-mode-hook nil)
 
528
(defvar julia-post-run-hook nil
 
529
  "Functions run in process buffer after starting julia process.")
386
530
 
387
531
;;;###autoload
388
532
(defun julia (&optional start-args)
389
 
  "Call 'julia',
 
533
  "Call 'julia'.
390
534
Optional prefix (C-u) allows to set command line arguments, such as
391
535
--load=<file>.  This should be OS agnostic.
392
536
If you have certain command line arguments that should always be passed
394
538
  (interactive "P")
395
539
  ;; get settings, notably inferior-julia-program-name :
396
540
  (if (null inferior-julia-program-name)
397
 
      (error "'inferior-julia-program-name' does not point to 'julia-release-basic' executable")
 
541
      (error "'inferior-julia-program-name' does not point to 'julia-basic' executable")
398
542
    (setq ess-customize-alist julia-customize-alist)
399
543
    (ess-write-to-dribble-buffer   ;; for debugging only
400
544
     (format
409
553
                                     (concat " [other than '" inferior-julia-args "']"))
410
554
                                 " ? "))
411
555
                      nil))))
412
 
      (inferior-ess jl-start-args) ;; -> .. (ess-multi ...) -> .. (inferior-ess-mode) ..
 
556
      (inferior-ess jl-start-args)
 
557
 
 
558
      (remove-hook 'completion-at-point-functions 'ess-filename-completion 'local) ;; should be first
 
559
      (add-hook 'completion-at-point-functions 'julia-object-completion nil 'local)
 
560
      (add-hook 'completion-at-point-functions 'ess-filename-completion nil 'local)
 
561
 
413
562
      (ess--tb-start)
414
563
      (set (make-local-variable 'julia-basic-offset) 4)
415
564
      ;; remove ` from julia's logo
419
568
      (goto-char (point-max))
420
569
      (ess--inject-code-from-file (format "%sess-julia.jl" ess-etc-directory))
421
570
      (with-ess-process-buffer nil
422
 
        (run-mode-hooks 'ess-julia-post-run-hook))
 
571
        (run-mode-hooks 'julia-post-run-hook))
423
572
      )))
424
573
 
425
 
;;; ELDOC
426
 
 
427
 
(defun ess-julia-eldoc-function ()
428
 
  "Return the doc string, or nil.
429
 
If an ESS process is not associated with the buffer, do not try
430
 
to look up any doc strings."
431
 
  (interactive)
432
 
  (when (and (ess-process-live-p)
433
 
             (not (ess-process-get 'busy)))
434
 
    (let ((funname (or (and ess-eldoc-show-on-symbol ;; aggressive completion
435
 
                            (symbol-at-point))
436
 
                       (car (ess--funname.start)))))
437
 
      (when funname
438
 
        (let* ((args (copy-sequence (nth 2 (ess-function-arguments funname))))
439
 
               (W (- (window-width (minibuffer-window)) (+ 4 (length funname))))
440
 
               (doc (concat (propertize funname 'face font-lock-function-name-face) ": ")))
441
 
          (when args
442
 
            (setq args (sort args (lambda (s1 s2)
443
 
                                    (< (length s1) (length s2)))))
444
 
            (setq doc (concat doc (pop args)))
445
 
            (while (and args (< (length doc) W))
446
 
              (setq doc (concat doc "  "
447
 
                                (pop args))))
448
 
            (when (and args (< (length doc) W))
449
 
              (setq doc (concat doc " {--}"))))
450
 
          doc)))))
451
 
 
452
 
 
453
 
;;; IMENU
454
 
(defvar julia-imenu-generic-expression
455
 
  ;; don't use syntax classes, screws egrep
456
 
  '(("Function (_)" "[ \t]*function[ \t]+\\(_[^ \t\n]*\\)" 1)
457
 
    ("Function" "[ \t]*function[ \t]+\\([^_][^\t\n]*\\)" 1)
458
 
    ("Const" "[ \t]*const \\([^ \t\n]*\\)" 1)
459
 
    ("Type"  "^[ \t]*[a-zA-Z0-9_]*type[a-zA-Z0-9_]* \\([^ \t\n]*\\)" 1)
460
 
    ("Require"      " *\\(\\brequire\\)(\\([^ \t\n)]*\\)" 2)
461
 
    ("Include"      " *\\(\\binclude\\)(\\([^ \t\n)]*\\)" 2)
462
 
    ;; ("Classes" "^.*setClass(\\(.*\\)," 1)
463
 
    ;; ("Coercions" "^.*setAs(\\([^,]+,[^,]*\\)," 1) ; show from and to
464
 
    ;; ("Generics" "^.*setGeneric(\\([^,]*\\)," 1)
465
 
    ;; ("Methods" "^.*set\\(Group\\|Replace\\)?Method(\"\\(.+\\)\"," 2)
466
 
    ;; ;;[ ]*\\(signature=\\)?(\\(.*,?\\)*\\)," 1)
467
 
    ;; ;;
468
 
    ;; ;;("Other" "^\\(.+\\)\\s-*<-[ \t\n]*[^\\(function\\|read\\|.*data\.frame\\)]" 1)
469
 
    ;; ("Package" "^.*\\(library\\|require\\)(\\(.*\\)," 2)
470
 
    ;; ("Data" "^\\(.+\\)\\s-*<-[ \t\n]*\\(read\\|.*data\.frame\\).*(" 1)))
471
 
    ))
 
574
(add-to-list 'auto-mode-alist '("\\.jl\\'" . julia-mode))
472
575
 
473
576
(provide 'ess-julia)
 
577
 
 
578
;;; ess-julia.el ends here