From c58d16d12a5b50a13c569938de52288331696bb0 Mon Sep 17 00:00:00 2001 From: Takafumi Arakaki Date: Fri, 3 Aug 2012 22:21:17 +0200 Subject: [PATCH 01/12] Use destructuring-bind in ein:pytools-jump-to-source --- lisp/ein-pytools.el | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/lisp/ein-pytools.el b/lisp/ein-pytools.el index 7986a99..b62f2b5 100644 --- a/lisp/ein-pytools.el +++ b/lisp/ein-pytools.el @@ -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 (object other-window notebook-buffer) + packed (ein:case-equal msg-type (("stream") (ein:aif (plist-get content :data) From 51992efe5ba0e045dae270d574556ba70a733a18 Mon Sep 17 00:00:00 2001 From: Takafumi Arakaki Date: Fri, 3 Aug 2012 22:30:20 +0200 Subject: [PATCH 02/12] ein:pytools-jump-to-source works with tramp now ein:filename-translations is added. --- lisp/ein-pytools.el | 7 +++++-- lisp/ein-utils.el | 51 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+), 2 deletions(-) diff --git a/lisp/ein-pytools.el b/lisp/ein-pytools.el index b62f2b5..a855a18 100644 --- a/lisp/ein-pytools.el +++ b/lisp/ein-pytools.el @@ -109,7 +109,7 @@ If OTHER-WINDOW is non-`nil', open the file in the other window." :output (cons (lambda (packed msg-type content) - (destructuring-bind (object other-window notebook-buffer) + (destructuring-bind (kernel object other-window notebook-buffer) packed (ein:case-equal msg-type (("stream") @@ -121,6 +121,9 @@ 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:filename-from-python + filename + (ein:$kernel-url-or-port kernel))) (ein:goto-file filename lineno other-window) (when (and notebook-buffer (not ein:@connect)) (ein:connect-to-notebook-buffer notebook-buffer)) @@ -130,7 +133,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. diff --git a/lisp/ein-utils.el b/lisp/ein-utils.el index b08a187..8770e73 100644 --- a/lisp/ein-utils.el +++ b/lisp/ein-utils.el @@ -61,6 +61,41 @@ 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." + ;; 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 +423,22 @@ NOTE: This function creates new list." (ein:join-str " " (mapcar #'file-name-nondirectory it)))) (message "Compiled %s files" (length files)))) + +;;; File name translation + +(defun ein:filename-translations-get (url-or-port) + (ein:choose-setting 'ein:filename-translations url-or-port)) + +(defun ein:filename-to-python (filename url-or-port) + (ein:aif (car (ein:filename-translations-get url-or-port)) + (funcall it filename) + filename)) + +(defun ein:filename-from-python (filename url-or-port) + (ein:aif (cadr (ein:filename-translations-get url-or-port)) + (funcall it filename) + filename)) + ;;; utils.js compatible From 1be0c9924e8d5b5cc40403372dc563ba8ef565b2 Mon Sep 17 00:00:00 2001 From: Takafumi Arakaki Date: Fri, 3 Aug 2012 23:06:46 +0200 Subject: [PATCH 03/12] Add ein:make-tramp-filename-translation --- lisp/ein-utils.el | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/lisp/ein-utils.el b/lisp/ein-utils.el index 8770e73..ff36d96 100644 --- a/lisp/ein-utils.el +++ b/lisp/ein-utils.el @@ -83,7 +83,10 @@ TO-PYTHON `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." + Python process to the one Emacs understands. + +Use `ein:make-tramp-filename-translation' 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" @@ -439,6 +442,23 @@ NOTE: This function creates new list." (funcall it filename) filename)) +(defun ein:make-tramp-filename-translation (prefix) + "Generate a pair of TO-PYTHON and FROM-PYTHON for +`ein:filename-translations'. + +Usage:: + + (setq ein:filename-translations + `((8888 + . ,(ein:make-tramp-filename-translation \"/scpc: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." + (lexical-let ((prefix prefix)) + (list (lambda (filename) (substring filename (length prefix))) + (lambda (filename) (concat prefix filename))))) + ;;; utils.js compatible From 7a7e1bfa31e4b1d3d6289927a6855fbbceab2aad Mon Sep 17 00:00:00 2001 From: Takafumi Arakaki Date: Fri, 3 Aug 2012 23:24:27 +0200 Subject: [PATCH 04/12] Use filename translator in ein:kernelinfo-update-ccwd --- lisp/ein-kernel.el | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/lisp/ein-kernel.el b/lisp/ein-kernel.el index 0f73c30..c5b7abf 100644 --- a/lisp/ein-kernel.el +++ b/lisp/ein-kernel.el @@ -542,8 +542,11 @@ 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:filename-from-python + path + (ein:$kernel-url-or-port kernel))) (if (file-accessible-directory-p path) (progn (setq default-directory path) @@ -553,7 +556,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 +579,10 @@ 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:filename-from-python + cwd + (ein:$kernel-url-or-port kernel))) (setf (ein:$kernelinfo-ccwd kernelinfo) cwd) ;; sync buffer's `default-directory' with CWD (when (buffer-live-p buffer) @@ -584,7 +590,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 From 6113b47a76303e6a34740a572cefb432c39d3409 Mon Sep 17 00:00:00 2001 From: Takafumi Arakaki Date: Fri, 3 Aug 2012 23:52:34 +0200 Subject: [PATCH 05/12] Rename to ein:tramp-create-filename-translator And make it more robust by adapting code from slime-tramp.el. --- lisp/ein-utils.el | 37 +++++++++++++++++++++++++++++++------ 1 file changed, 31 insertions(+), 6 deletions(-) diff --git a/lisp/ein-utils.el b/lisp/ein-utils.el index ff36d96..297694f 100644 --- a/lisp/ein-utils.el +++ b/lisp/ein-utils.el @@ -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 @@ -442,7 +447,20 @@ NOTE: This function creates new list." (funcall it filename) filename)) -(defun ein:make-tramp-filename-translation (prefix) +(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'. @@ -450,14 +468,21 @@ Usage:: (setq ein:filename-translations `((8888 - . ,(ein:make-tramp-filename-translation \"/scpc:MY-HOSTNAME:\")))) + . ,(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." - (lexical-let ((prefix prefix)) - (list (lambda (filename) (substring filename (length prefix))) - (lambda (filename) (concat prefix filename))))) +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 From 959102e70ee471dc1efaffce2c58c506095d6659 Mon Sep 17 00:00:00 2001 From: Takafumi Arakaki Date: Fri, 3 Aug 2012 23:58:08 +0200 Subject: [PATCH 06/12] Document ein:tramp-create-filename-translator more --- lisp/ein-utils.el | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lisp/ein-utils.el b/lisp/ein-utils.el index 297694f..ce4173c 100644 --- a/lisp/ein-utils.el +++ b/lisp/ein-utils.el @@ -469,6 +469,11 @@ 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 From d2c8c5eee6cdd33744a2f99920e27d429246accd Mon Sep 17 00:00:00 2001 From: Takafumi Arakaki Date: Sat, 4 Aug 2012 00:04:16 +0200 Subject: [PATCH 07/12] Document ein:kernel-request-stream --- lisp/ein-kernel.el | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lisp/ein-kernel.el b/lisp/ein-kernel.el index c5b7abf..7ee0c7a 100644 --- a/lisp/ein-kernel.el +++ b/lisp/ein-kernel.el @@ -524,6 +524,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 From c4924efdbdd999cdb04446a310d373963bc4e02f Mon Sep 17 00:00:00 2001 From: Takafumi Arakaki Date: Sat, 4 Aug 2012 00:26:30 +0200 Subject: [PATCH 08/12] Refactor ein:filename-to/from-python functions --- lisp/ein-kernel.el | 16 ++++++++++------ lisp/ein-pytools.el | 5 ++--- lisp/ein-utils.el | 8 ++++++-- 3 files changed, 18 insertions(+), 11 deletions(-) diff --git a/lisp/ein-kernel.el b/lisp/ein-kernel.el index 7ee0c7a..1d1b70a 100644 --- a/lisp/ein-kernel.el +++ b/lisp/ein-kernel.el @@ -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." @@ -548,9 +556,7 @@ When no such directory exists, `default-directory' will not be changed." "__import__('sys').stdout.write(__import__('os').getcwd())" (lambda (path kernel buffer) (with-current-buffer buffer - (setq path (ein:filename-from-python - path - (ein:$kernel-url-or-port kernel))) + (setq path (ein:kernel-filename-from-python kernel path)) (if (file-accessible-directory-p path) (progn (setq default-directory path) @@ -584,9 +590,7 @@ When no such directory exists, `default-directory' will not be changed." kernel "__import__('sys').stdout.write(__import__('os').getcwd())" (lambda (cwd kernel kernelinfo buffer) - (setq cwd (ein:filename-from-python - cwd - (ein:$kernel-url-or-port kernel))) + (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) diff --git a/lisp/ein-pytools.el b/lisp/ein-pytools.el index a855a18..d696d8a 100644 --- a/lisp/ein-pytools.el +++ b/lisp/ein-pytools.el @@ -121,9 +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:filename-from-python - filename - (ein:$kernel-url-or-port kernel))) + (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)) diff --git a/lisp/ein-utils.el b/lisp/ein-utils.el index ce4173c..4f33be6 100644 --- a/lisp/ein-utils.el +++ b/lisp/ein-utils.el @@ -434,15 +434,19 @@ NOTE: This function creates new list." ;;; 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 (filename 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 (filename url-or-port) +(defun ein:filename-from-python (url-or-port filename) (ein:aif (cadr (ein:filename-translations-get url-or-port)) (funcall it filename) filename)) From e49811db5c0942a2748ff7e88d415d697ff7e3d8 Mon Sep 17 00:00:00 2001 From: Takafumi Arakaki Date: Sat, 4 Aug 2012 04:01:27 +0200 Subject: [PATCH 09/12] Add tests for filename translator --- tests/test-ein-utils.el | 47 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/tests/test-ein-utils.el b/tests/test-ein-utils.el index 1f575dc..142a107 100644 --- a/tests/test-ein-utils.el +++ b/tests/test-ein-utils.el @@ -85,3 +85,50 @@ 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 + +(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)))) From dedef7e0323d403e038dc5de3d4a69a7836d913d Mon Sep 17 00:00:00 2001 From: Takafumi Arakaki Date: Sat, 4 Aug 2012 04:10:58 +0200 Subject: [PATCH 10/12] Workaround error in tests from MuMaMo Without this workaround, I had three failed tests: 3 unexpected results: FAILED ein:notebook-ask-before-kill-emacs-simple FAILED ein:notebook-from-json-simple FAILED ein:notebook-yank-cell-command-two-buffers These tests failed because of the following same error: (error "fun-var-sym=mumamo-eval-in-ein:notebook-bg-mode, use-major-entry=(ein:notebook-bg-mode (mumamo-eval-in-ein:notebook-bg-mode mumamo-def-eval-in-ein:notebook-bg-mode mumamo-kw-eval-in-ein:notebook-bg-mode))") --- tests/test-ein-utils.el | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/test-ein-utils.el b/tests/test-ein-utils.el index 142a107..ded0db6 100644 --- a/tests/test-ein-utils.el +++ b/tests/test-ein-utils.el @@ -89,6 +89,11 @@ def func(): ;;; 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"))) From 588858231035e0f56565e196dd080eac36d90c68 Mon Sep 17 00:00:00 2001 From: Takafumi Arakaki Date: Sat, 4 Aug 2012 04:16:05 +0200 Subject: [PATCH 11/12] Fix ein:filename-translations docstring --- lisp/ein-utils.el | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lisp/ein-utils.el b/lisp/ein-utils.el index 4f33be6..8e5d0fc 100644 --- a/lisp/ein-utils.el +++ b/lisp/ein-utils.el @@ -90,7 +90,7 @@ FROM-PYTHON A function which converts a file path returned by Python process to the one Emacs understands. -Use `ein:make-tramp-filename-translation' to easily generate the +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 From c00bfd231d2b563854f0c4c37065fe645e2891ea Mon Sep 17 00:00:00 2001 From: Takafumi Arakaki Date: Sat, 4 Aug 2012 04:18:44 +0200 Subject: [PATCH 12/12] Update change log --- doc/source/index.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/doc/source/index.rst b/doc/source/index.rst index fed240f..75cdba2 100644 --- a/doc/source/index.rst +++ b/doc/source/index.rst @@ -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