Merge pull request #620 from fuxialexander/ob-ipython

lang/org: +ipython
This commit is contained in:
Henrik Lissner 2018-05-30 11:57:14 +02:00 committed by GitHub
commit 31d34ae5f0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 245 additions and 1 deletions

View file

@ -0,0 +1,47 @@
;;; lang/org/+ipython.el -*- lexical-binding: t; -*-
(defvar +org-ob-ipython-resources-dir ".ob-ipython-resrc")
(defvar +ob-ipython-local-runtime-dir
(substring (shell-command-to-string (concat "jupyter --runtime-dir")) 0 -1))
(def-package! ob-ipython
:when (featurep! +ipython)
:after (ob)
:config
(setq ob-ipython-resources-dir +org-ob-ipython-resources-dir)
;; popup
(when (featurep! +right-popup)
(set!
:popup "^\\*Org Src"
'((size . 100)
(side . right)
(slot . -1)
(window-height . 0.6))
'((quit)
(select . t)
(modeline)))
(set!
:popup "^\\*Python"
'((slot . 0)
(side . right)
(size . 100))
'((select) (quit) (transient)))
(set!
:popup "\\*ob-ipython.*"
'((slot . 2)
(side . right)
(size . 100)
(window-height . 0.2))
'((select) (quit) (transient)))
(set!
:popup "\\*Python:.*"
'((slot . 0)
(side . right)
(size . 100))
'((select) (quit) (transient))))
;; advices for remote kernel and org-src-edit
(advice-add 'org-babel-edit-prep:ipython :override #'+org*org-babel-edit-prep:ipython)
(advice-add 'org-babel-ipython-initiate-session :override #'+org*org-babel-ipython-initiate-session)
(advice-add 'ob-ipython--create-repl :override #'+org*ob-ipython--create-repl)
(advice-add 'org-babel-execute:ipython :override #'+org*org-babel-execute:ipython)
;; retina resolution image hack
(when (eq window-system 'ns)
(advice-add 'ob-ipython--write-base64-string :around #'+org*ob-ipython--write-base64-string)))

View file

@ -0,0 +1,194 @@
;;; lang/org/autoload/ipython.el -*- lexical-binding: t; -*-
;; * remote
;;;###autoload
(defun +org*org-babel-ipython-initiate-session (&optional session params)
"Create a session named SESSION according to PARAMS."
(if (string= session "none")
(error
"ob-ipython currently only supports evaluation using a session.
Make sure your src block has a :session param.")
(when (not (s-ends-with-p ".json" session))
(ob-ipython--create-kernel
(ob-ipython--normalize-session
session)
(cdr (assoc :kernel params))))
(ob-ipython--create-repl
(ob-ipython--normalize-session
session)
params)))
;;;###autoload
(defun +org*ob-ipython--create-repl (name &optional params)
"Create repl based on NAME and PARAMS.
If PARAMS specifies remote kernel, copy the kernel config from remote server and
create a repl connecting to remote session."
(let ((cmd (s-join
" "
(ob-ipython--kernel-repl-cmd
name))))
(if (string= "default" name)
(progn
(run-python cmd nil nil)
(format
"*%s*"
python-shell-buffer-name))
(if (string-match
"^remote-.*ssh.json"
name)
(when (not (ignore-errors
(process-live-p
(get-process
(format
"Python:ob-ipython-%s"
name)))))
(let* ((remote (s-split "-" name))
(remote-host (nth 1 remote))
(remote-session (nth 3 remote)))
(+org/ob-ipython-generate-local-path-from-remote
remote-session
remote-host
params)))
(let* ((process-name (format
"Python:ob-ipython-%s"
name))
(python-shell-prompt-detect-enabled nil)
(python-shell-completion-native-enable nil)
(buf (python-shell-make-comint
cmd
process-name
t))
(dir (cdr (assoc :pydir params))))
(if dir
(with-current-buffer
buf
(setq-local
default-directory
dir)))
(sleep-for 1)
(format "*%s*" process-name))))))
;;;###autoload
(defun +org*org-babel-execute:ipython (body params)
"Execute a BODY of IPython code with PARAMS in org-babel.
This function is called by `org-babel-execute-src-block'."
(message default-directory)
(let ((session (cdr (assoc :session params))))
(org-babel-ipython-initiate-session
session
params))
(ob-ipython--clear-output-buffer)
(if (cdr (assoc :async params))
(ob-ipython--execute-async
body
params)
(ob-ipython--execute-sync
body
params)))
;;;###autoload
(defun +org/ob-ipython-generate-local-path-from-remote (session host params)
"Given a remote SESSION with PARAMS and corresponding HOST, copy remote config to local, start a jupyter console to generate a new one."
(let* ((runtime-dir
(substring (shell-command-to-string (concat "ssh " host " jupyter --runtime-dir")) 0 -1))
(runtime-file (concat runtime-dir "/" "kernel-" session ".json"))
(tramp-path (concat "/ssh:" host ":" runtime-file))
(tramp-copy (concat +ob-ipython-local-runtime-dir "/remote-" host "-kernel-" session ".json"))
(local-path
(concat
"Python:ob-ipython-"
(file-name-sans-extension (file-name-nondirectory tramp-copy))
"-ssh.json")))
;; scp remote file to local
(copy-file tramp-path tramp-copy t)
;; connect to remote use new config
(let* ((python-shell-interpreter-interactive-arg " console --simple-prompt")
(python-shell-prompt-detect-enabled nil)
(python-shell-completion-native-enable nil)
(buf (python-shell-make-comint
(concat
ob-ipython-command
" console --simple-prompt --existing "
tramp-copy
" --ssh "
host)
(concat "" local-path)
t))
(proc (get-buffer-process buf))
(dir (cdr (assoc :pydir params))))
(sleep-for 3)
(if dir
(with-current-buffer
buf
(setq-local default-directory dir)))
(format "*%s*" proc))))
;; * org-src-edit
;;;###autoload
(defun +org*org-babel-edit-prep:ipython (info)
(let* ((params (nth 2 info))
(session (cdr (assoc :session params))))
(org-babel-ipython-initiate-session
session
params))
;; Support for python.el's "send-code" commands within edit buffers.
(setq-local
python-shell-buffer-name
(format
"Python:ob-ipython-%s"
(->>
info
(nth 2)
(assoc :session)
cdr ob-ipython--normalize-session)))
(setq-local
default-directory
(format
"%s"
(->>
info
(nth 2)
(assoc :pydir)
cdr ob-ipython--normalize-session)))
(ob-ipython-mode 1)
;; hack on company mode to use company-capf rather than company-anaconda
(when (featurep! :completion company)
(setq-local
company-backends
'(company-capf
company-dabbrev
company-files
company-yasnippet))
(setq-local
company-idle-delay
nil))
(when (featurep 'lpy)
(setq lispy-python-proc
(format
"Python:ob-ipython-%s"
(->>
info
(nth 2)
(assoc :session)
cdr ob-ipython--normalize-session)))
(setq lispy--python-middleware-loaded-p
nil)
(lispy--python-middleware-load)))
;; * retina
;;;###autoload
(defun +org/ob-ipython-mac-2x-image-file-name (filename &optional scale)
"Return the name of high-resolution image file for FILENAME.
The optional arg SCALE is scale factor, and defaults to 2."
(let ((pos (or (string-match "\\.[^./]*\\'" filename) (length filename))))
(format
"%s@%dx%s"
(substring filename 0 pos)
(or scale 2)
(substring filename pos))))
;;;###autoload
(defun +org*ob-ipython--write-base64-string (oldfunc &rest args)
(let ((file (car args))
(b64-string (cdr args)))
(let ((file2x (+org/ob-ipython-mac-2x-image-file-name file)))
(apply oldfunc file2x b64-string)
(shell-command (concat "convert " file2x " -resize 50% " file)))))

View file

@ -8,6 +8,7 @@
(if (featurep! +babel) (load! "+babel"))
(if (featurep! +capture) (load! "+capture"))
(if (featurep! +export) (load! "+export"))
(if (featurep! +ipython) (load! "+ipython"))
(if (featurep! +present) (load! "+present"))
;; TODO (if (featurep! +publish) (load! "+publish"))

View file

@ -29,7 +29,9 @@
(when (featurep! :lang restclient)
(package! ob-restclient))
(when (featurep! :lang crystal)
(package! ob-crystal)))
(package! ob-crystal))
(when (featurep! +ipython)
(package! ob-ipython :recipe (:fetcher github :repo "fuxialexander/ob-ipython" :files ("*")))))
(when (featurep! +export)
(package! ox-pandoc)