mirror of
https://github.com/vale981/emacs-ipython-notebook
synced 2025-03-06 17:41:40 -05:00
Merge branch 'tramp'
This commit is contained in:
commit
5f10dcccb4
5 changed files with 183 additions and 8 deletions
|
@ -332,6 +332,8 @@ MuMaMo
|
|||
Misc
|
||||
^^^^
|
||||
|
||||
.. el:variable:: ein:filename-translations
|
||||
.. el:function:: ein:tramp-create-filename-translator
|
||||
.. el:variable:: ein:query-timeout
|
||||
|
||||
|
||||
|
@ -485,6 +487,7 @@ v0.1.1
|
|||
:el:symbol:`ein:notebook-turn-on-autoexec`).
|
||||
* Start completion when "." is inserted.
|
||||
Use :el:symbol:`ein:complete-on-dot` to disable this feature.
|
||||
* Support tramp. See :el:symbol:`ein:filename-translations`.
|
||||
|
||||
|
||||
v0.1
|
||||
|
|
|
@ -495,6 +495,14 @@ http://ipython.org/ipython-doc/dev/development/messaging.html#complete
|
|||
|
||||
;;; Utility functions
|
||||
|
||||
(defun ein:kernel-filename-to-python (kernel filename)
|
||||
"See: `ein:filename-to-python'."
|
||||
(ein:filename-to-python (ein:$kernel-url-or-port kernel) filename))
|
||||
|
||||
(defun ein:kernel-filename-from-python (kernel filename)
|
||||
"See: `ein:filename-from-python'."
|
||||
(ein:filename-from-python (ein:$kernel-url-or-port kernel) filename))
|
||||
|
||||
(defun ein:kernel-construct-defstring (content)
|
||||
"Construct call signature from CONTENT of ``:object_info_reply``.
|
||||
Used in `ein:cell-finish-tooltip', etc."
|
||||
|
@ -524,6 +532,10 @@ Used in `ein:cell-finish-tooltip', etc."
|
|||
help))
|
||||
|
||||
(defun ein:kernel-request-stream (kernel code func &optional args)
|
||||
"Run lisp callback FUNC with the output stream returned by Python CODE.
|
||||
|
||||
The first argument to the lisp function FUNC is the stream output
|
||||
as a string and the rest of the argument is the optional ARGS."
|
||||
(ein:kernel-execute
|
||||
kernel
|
||||
code
|
||||
|
@ -542,8 +554,9 @@ When no such directory exists, `default-directory' will not be changed."
|
|||
(ein:kernel-request-stream
|
||||
kernel
|
||||
"__import__('sys').stdout.write(__import__('os').getcwd())"
|
||||
(lambda (path buffer)
|
||||
(lambda (path kernel buffer)
|
||||
(with-current-buffer buffer
|
||||
(setq path (ein:kernel-filename-from-python kernel path))
|
||||
(if (file-accessible-directory-p path)
|
||||
(progn
|
||||
(setq default-directory path)
|
||||
|
@ -553,7 +566,7 @@ When no such directory exists, `default-directory' will not be changed."
|
|||
(ein:log 'info
|
||||
"Syncing directory of %s with kernel...FAILED (no dir: %s)"
|
||||
buffer path))))
|
||||
(list buffer)))
|
||||
(list kernel buffer)))
|
||||
|
||||
(defun ein:kernelinfo-init (kernelinfo buffer)
|
||||
(setf (ein:$kernelinfo-buffer kernelinfo) buffer))
|
||||
|
@ -576,7 +589,8 @@ When no such directory exists, `default-directory' will not be changed."
|
|||
(ein:kernel-request-stream
|
||||
kernel
|
||||
"__import__('sys').stdout.write(__import__('os').getcwd())"
|
||||
(lambda (cwd kernelinfo buffer)
|
||||
(lambda (cwd kernel kernelinfo buffer)
|
||||
(setq cwd (ein:kernel-filename-from-python kernel cwd))
|
||||
(setf (ein:$kernelinfo-ccwd kernelinfo) cwd)
|
||||
;; sync buffer's `default-directory' with CWD
|
||||
(when (buffer-live-p buffer)
|
||||
|
@ -584,7 +598,7 @@ When no such directory exists, `default-directory' will not be changed."
|
|||
(when (file-accessible-directory-p cwd)
|
||||
(setq default-directory (file-name-as-directory cwd))))))
|
||||
(let ((kernelinfo (ein:$kernel-kernelinfo kernel)))
|
||||
(list kernelinfo (ein:$kernelinfo-buffer kernelinfo)))))
|
||||
(list kernel kernelinfo (ein:$kernelinfo-buffer kernelinfo)))))
|
||||
|
||||
(defun ein:kernelinfo-update-hostname (kernel)
|
||||
(ein:kernel-request-stream
|
||||
|
|
|
@ -109,9 +109,8 @@ If OTHER-WINDOW is non-`nil', open the file in the other window."
|
|||
:output
|
||||
(cons
|
||||
(lambda (packed msg-type content)
|
||||
(let ((object (nth 0 packed))
|
||||
(other-window (nth 1 packed))
|
||||
(notebook-buffer (nth 2 packed)))
|
||||
(destructuring-bind (kernel object other-window notebook-buffer)
|
||||
packed
|
||||
(ein:case-equal msg-type
|
||||
(("stream")
|
||||
(ein:aif (plist-get content :data)
|
||||
|
@ -122,6 +121,8 @@ If OTHER-WINDOW is non-`nil', open the file in the other window."
|
|||
(destructuring-bind (filename &optional lineno &rest ignore)
|
||||
(split-string it "\n")
|
||||
(setq lineno (string-to-number lineno))
|
||||
(setq filename
|
||||
(ein:kernel-filename-from-python kernel filename))
|
||||
(ein:goto-file filename lineno other-window)
|
||||
(when (and notebook-buffer (not ein:@connect))
|
||||
(ein:connect-to-notebook-buffer notebook-buffer))
|
||||
|
@ -131,7 +132,7 @@ If OTHER-WINDOW is non-`nil', open the file in the other window."
|
|||
(("pyerr")
|
||||
(ein:log 'info
|
||||
"Jumping to the source of %s...Not found" object)))))
|
||||
(list object other-window notebook-buffer)))))
|
||||
(list kernel object other-window notebook-buffer)))))
|
||||
|
||||
(defun ein:pytools-jump-to-source-command (&optional other-window)
|
||||
"Jump to the source code of the object at point.
|
||||
|
|
|
@ -28,6 +28,11 @@
|
|||
(eval-when-compile (require 'cl))
|
||||
(require 'json)
|
||||
|
||||
;; Optional dependency on tramp:
|
||||
(declare-function tramp-make-tramp-file-name "tramp")
|
||||
(declare-function tramp-file-name-localname "tramp")
|
||||
(declare-function tramp-dissect-file-name "tramp")
|
||||
|
||||
(defgroup ein nil
|
||||
"IPython notebook client in Emacs"
|
||||
:group 'applications
|
||||
|
@ -61,6 +66,44 @@ format string which can be passed to `format-time-string'."
|
|||
:type '(string :tag "Format string")
|
||||
:group 'ein)
|
||||
|
||||
(defcustom ein:filename-translations nil
|
||||
"Convert file paths between Emacs and Python process.
|
||||
|
||||
This value can take these form:
|
||||
|
||||
alist
|
||||
Its key specifies URL-OR-PORT and value must be a list of two
|
||||
functions: (TO-PYTHON FROM-PYTHON). Key (URL-OR-PORT) can be
|
||||
string (URL), integer (port), or `default' (symbol). The
|
||||
value of `default' is used when other key does not much.
|
||||
function
|
||||
Called with an argument URL-OR-PORT (integer or string).
|
||||
This function must return a list of two functions:
|
||||
(TO-PYTHON FROM-PYTHON).
|
||||
|
||||
Here, the functions TO-PYTHON and FROM-PYTHON are defined as:
|
||||
|
||||
TO-PYTHON
|
||||
A function which converts a file name (returned by
|
||||
`buffer-file-name') to the one Python understands.
|
||||
FROM-PYTHON
|
||||
A function which converts a file path returned by
|
||||
Python process to the one Emacs understands.
|
||||
|
||||
Use `ein:tramp-create-filename-translator' to easily generate the
|
||||
pair of TO-PYTHON and FROM-PYTHON."
|
||||
;; I've got the idea from `slime-filename-translations'.
|
||||
:type '(choice
|
||||
(alist :tag "Translations mapping"
|
||||
:key-type (choice :tag "URL or PORT"
|
||||
(string :tag "URL" "http://127.0.0.1:8888")
|
||||
(integer :tag "PORT" 8888)
|
||||
(const default))
|
||||
:value-type (list (function :tag "TO-PYTHON")
|
||||
(function :tag "FROM-PYTHON")))
|
||||
(function :tag "Translations getter"))
|
||||
:group 'ein)
|
||||
|
||||
|
||||
;;; Macros and core functions/variables
|
||||
|
||||
|
@ -388,6 +431,68 @@ NOTE: This function creates new list."
|
|||
(ein:join-str " " (mapcar #'file-name-nondirectory it))))
|
||||
(message "Compiled %s files" (length files))))
|
||||
|
||||
|
||||
;;; File name translation
|
||||
|
||||
;; Probably it's better to define `ein:filename-translations-get' as
|
||||
;; an EIEIO method so that I don't have to re-define functions such as
|
||||
;; `ein:kernel-filename-to-python' and `ein:kernel-filename-from-python'.
|
||||
|
||||
(defun ein:filename-translations-get (url-or-port)
|
||||
(ein:choose-setting 'ein:filename-translations url-or-port))
|
||||
|
||||
(defun ein:filename-to-python (url-or-port filename)
|
||||
(ein:aif (car (ein:filename-translations-get url-or-port))
|
||||
(funcall it filename)
|
||||
filename))
|
||||
|
||||
(defun ein:filename-from-python (url-or-port filename)
|
||||
(ein:aif (cadr (ein:filename-translations-get url-or-port))
|
||||
(funcall it filename)
|
||||
filename))
|
||||
|
||||
(defun ein:make-tramp-file-name (username remote-host python-filename)
|
||||
"Old (with multi-hops) tramp compatability function.
|
||||
Adapted from `slime-make-tramp-file-name'."
|
||||
(if (boundp 'tramp-multi-methods)
|
||||
(tramp-make-tramp-file-name nil nil
|
||||
username
|
||||
remote-host
|
||||
python-filename)
|
||||
(tramp-make-tramp-file-name nil
|
||||
username
|
||||
remote-host
|
||||
python-filename)))
|
||||
|
||||
(defun ein:tramp-create-filename-translator (remote-host &optional username)
|
||||
"Generate a pair of TO-PYTHON and FROM-PYTHON for
|
||||
`ein:filename-translations'.
|
||||
|
||||
Usage::
|
||||
|
||||
(setq ein:filename-translations
|
||||
`((8888
|
||||
. ,(ein:tramp-create-filename-translator \"MY-HOSTNAME\"))))
|
||||
;; Equivalently:
|
||||
(setq ein:filename-translations
|
||||
(lambda (url-or-port)
|
||||
(when (equal url-or-port 8888)
|
||||
(ein:tramp-create-filename-translator \"MY-HOSTNAME\"))))
|
||||
|
||||
This setting assumes that the IPython server which can be
|
||||
connected using the port 8888 in localhost is actually running in
|
||||
the host named MY-HOSTNAME.
|
||||
|
||||
Adapted from `slime-create-filename-translator'."
|
||||
(require 'tramp)
|
||||
(lexical-let ((remote-host remote-host)
|
||||
(username (or username (user-login-name))))
|
||||
(list (lambda (emacs-filename)
|
||||
(tramp-file-name-localname
|
||||
(tramp-dissect-file-name emacs-filename)))
|
||||
(lambda (python-filename)
|
||||
(ein:make-tramp-file-name username remote-host python-filename)))))
|
||||
|
||||
|
||||
;;; utils.js compatible
|
||||
|
||||
|
|
|
@ -85,3 +85,55 @@ def func():
|
|||
(ert-deftest ein:version ()
|
||||
"Check if `ein:version' can be parsed by `version-to-list'."
|
||||
(version-to-list ein:version))
|
||||
|
||||
|
||||
;;; File name translation
|
||||
|
||||
;; Requiring `tramp' during (inside of) tests yields error from
|
||||
;; MuMaMo. Although I don't understand the reason, requiring it
|
||||
;; before running tests workarounds this problem.
|
||||
(require 'tramp)
|
||||
|
||||
(ert-deftest ein:filename-translations-from-to-tramp ()
|
||||
(loop with ein:filename-translations =
|
||||
`((8888 . ,(ein:tramp-create-filename-translator "HOST" "USER")))
|
||||
with filename = "/file/name"
|
||||
for port in '(7777 8888) ; check for the one w/o translation
|
||||
for emacs-filename = (ein:filename-from-python port filename)
|
||||
do (message "emacs-filename = %s" emacs-filename)
|
||||
do (should
|
||||
(equal (ein:filename-to-python port emacs-filename)
|
||||
filename))))
|
||||
|
||||
(ert-deftest ein:filename-translations-to-from-tramp ()
|
||||
(loop with ein:filename-translations =
|
||||
`((8888 . ,(ein:tramp-create-filename-translator "HOST" "USER")))
|
||||
with filename = "/USER@HOST:/filename"
|
||||
for port in '(8888)
|
||||
do (should
|
||||
(equal (ein:filename-from-python
|
||||
port (ein:filename-to-python port filename))
|
||||
filename))))
|
||||
|
||||
(ert-deftest ein:filename-to-python-tramp ()
|
||||
(let* ((port 8888)
|
||||
(ein:filename-translations
|
||||
`((,port . ,(ein:tramp-create-filename-translator "DUMMY")))))
|
||||
(loop with python-filename = "/file/name"
|
||||
for emacs-filename in '("/scpc:HOST:/file/name"
|
||||
"/USER@HOST:/file/name")
|
||||
do (should
|
||||
(equal (ein:filename-to-python port emacs-filename)
|
||||
python-filename)))
|
||||
;; Error: Not a Tramp file name: /file/name
|
||||
(should-error (ein:filename-to-python port "/file/name"))))
|
||||
|
||||
(ert-deftest ein:filename-from-python-tramp ()
|
||||
(loop with ein:filename-translations =
|
||||
`((8888 . ,(ein:tramp-create-filename-translator "HOST" "USER")))
|
||||
with python-filename = "/file/name"
|
||||
for emacs-filename in '("/USER@HOST:/file/name" "/file/name")
|
||||
for port in '(8888 7777)
|
||||
do (should
|
||||
(equal (ein:filename-from-python port python-filename)
|
||||
emacs-filename))))
|
||||
|
|
Loading…
Add table
Reference in a new issue