Fix "Kernel is busy..." bug

One line change to fix header not updating after cell execution
(keeps saying "Kernel is busy").

The bug does not manifest when running with `ein:debug` true since
EMACS's display loop updates more frequently with debug messages.

In tracking this bug, noticed eldoc support isn't quite there.
`__import__('ein').print_object_info_for(%s)` appears in
`ein-completer` and `ein-pytools`, and is invalid python syntax
afaict.  Took a few steps to make it whole, but incomplete.
This commit is contained in:
dickmao 2018-10-27 17:52:17 -04:00
parent e1b26550b2
commit b950bd3a4c
9 changed files with 71 additions and 69 deletions

View file

@ -1,4 +1,3 @@
EMACS ?= $(shell which emacs)
SRC=$(shell cask files)
ELCFILES = $(SRC:.el=.elc)
@ -23,7 +22,7 @@ env-ipy.%:
.PHONY: test-compile
test-compile: clean autoloads
! ( cask build 2>&1 | awk '{if (/^ /) { gsub(/^ +/, " ", $$0); printf "%s", $$0 } else { printf "\n%s", $$0 }}' | egrep "not known|Error|free variable|error for|Use of gv-ref" )
! ( cask build 2>&1 | awk '{if (/^ /) { gsub(/^ +/, " ", $$0); printf "%s", $$0 } else { printf "\n%s", $$0 }}' | egrep -a "not known|Error|free variable|error for|Use of gv-ref" )
cask clean-elc
.PHONY: quick

View file

@ -173,7 +173,6 @@ Scenario: Undo needs to at least work for reopened notebooks
Given I start the server configured "\n"
Given I enable "ein:worksheet-enable-undo"
Given old notebook "undo.ipynb"
When I press "C-<down>"
And I type "howdy"
And I press "RET"
And I press "C-<down>"

View file

@ -25,9 +25,6 @@
;;; Code:
(require 'ein-cell)
(require 'ess-r-mode nil t)
(require 'org-src nil t)
(require 'markdown-mode nil t)
(autoload 'markdown-mode "markdown-mode")
(autoload 'R-mode "ess-r-mode")

View file

@ -348,7 +348,7 @@ auto-execution mode flag in the connected buffer is `t'.")))
((status :initarg :status :initform nil)
(message :initarg :message :initform nil)
(s2m :initarg :s2m))
"Hold status and it's string representation (message).")
"Hold status and its string representation (message).")
(defclass ein:notification-tab ()
((get-list :initarg :get-list :type function)

View file

@ -34,6 +34,7 @@
(require 'ein-log)
(require 'ein-subpackages)
(require 'ein-kernel)
(require 'dash)
(defun ein:completer-choose ()
(require 'ein-ac)
@ -130,23 +131,19 @@ notebook buffers and connected buffers."
(defvar *ein:oinfo-cache* (make-hash-table :test #'equal))
(defun ein:completions--get-oinfo (obj)
(let ((d (deferred:new #'identity))
(kernel (ein:get-kernel)))
(lexical-let ((d (deferred:new #'identity))
(kernel (ein:get-kernel)))
(if (ein:kernel-live-p kernel)
(ein:kernel-execute
kernel
(format "__import__('ein').print_object_info_for(%s)" obj)
(list
:output (cons (lambda (d &rest args) (deferred:callback-post d args))
d)))
:output `(,(lambda (d &rest args) (deferred:callback-post d args)) . ,d)))
(deferred:callback-post d (list nil nil)))
d))
(defun ein:clear-oinfo-cache ()
(clrhash *ein:oinfo-cache*))
(defun ein:completions--build-oinfo-cache (objs)
(dolist (o objs)
(dolist (o (-non-nil objs))
(deferred:$
(deferred:next
(lambda ()
@ -156,26 +153,23 @@ notebook buffers and connected buffers."
(ein:completions--prepare-oinfo output o))))))
(defun ein:completions--prepare-oinfo (output obj)
(condition-case _
(condition-case err
(destructuring-bind (msg-type content _) output
(ein:case-equal msg-type
(("stream" "display_data")
(let* ((oinfo (ein:json-read-from-string (plist-get content :text))))
(setf (gethash obj *ein:oinfo-cache*) oinfo)))))
(error (setf (gethash obj *ein:oinfo-cache*) ""))))
(("stream" "display_data" "pyout" "execute_result")
(setf (gethash obj *ein:oinfo-cache*) (plist-get content :text)))
(("error" "pyerr")
(ein:log 'error "ein:completions--prepare-oinfo: %S" (plist-get content :traceback)))))
(error (ein:log 'error "ein:completions--prepare-oinfo: [%s] %s" err obj)
(setf (gethash obj *ein:oinfo-cache*) :json-false))))
;;; Support for Eldoc
(defun ein:completer--get-eldoc-signature ()
(let* ((func (ein:function-at-point))
(oinfo (gethash func *ein:oinfo-cache* nil)))
(if (not oinfo)
(ein:completions--build-oinfo-cache (list func))
(plist-get oinfo :definition))))
(defun ein:notebook--enable-eldoc ()
(set (make-local-variable 'eldoc-documentation-function)
#'ein:completer--get-eldoc-signature))
(let ((func (ein:function-at-point)))
(ein:aif (gethash func *ein:oinfo-cache*)
(ein:kernel-construct-defstring it)
(ein:completions--build-oinfo-cache (list func)))))
(provide 'ein-completer)

View file

@ -368,7 +368,7 @@ notebook."
(define-key map "\C-c\C-l" 'ein:connect-reload-buffer)
(define-key map "\C-c\C-r" 'ein:connect-eval-region)
(define-key map (kbd "C-:") 'ein:shared-output-eval-string)
(define-key map "\C-c\C-f" 'ein:pytools-request-tooltip-or-help)
(define-key map "\C-c\C-h" 'ein:pytools-request-tooltip-or-help)
(define-key map "\C-c\C-i" 'ein:completer-complete)
(define-key map "\C-c\C-z" 'ein:connect-pop-to-notebook)
(define-key map "\C-c\C-a" 'ein:connect-toggle-autoexec)

View file

@ -464,7 +464,7 @@ When calling this method pass a CALLBACKS structure of the form:
:clear_output CLEAR-OUTPUT-CALLBACK
:set_next_input SET-NEXT-INPUT)
Objects end with -CALLBACK above must pack a FUNCTION and its
Right hand sides ending -CALLBACK above must pack a FUNCTION and its
first ARGUMENT in a `cons'::
(FUNCTION . ARGUMENT)
@ -515,27 +515,23 @@ Sample implementations
;; (funcall FUNCTION [ARG ...] CONTENT METADATA)
(assert (ein:kernel-live-p kernel) nil "execute_reply: Kernel is not active.")
(if (not (ein:$kernel-stdin-activep kernel))
(let* ((content (list
:code code
:silent (or silent json-false)
:store_history (or store-history json-false)
:user_expressions user-expressions
:allow_stdin allow-stdin
:stop_on_error (or stop-on-error json-false)))
(msg (ein:kernel--get-msg kernel "execute_request" content))
(msg-id (plist-get (plist-get msg :header) :msg_id)))
(run-hook-with-args 'ein:pre-kernel-execute-functions msg)
(ein:websocket-send-shell-channel kernel msg)
(unless (plist-get callbacks :execute_reply)
(ein:log 'debug "code: %s" code))
(ein:kernel-set-callbacks-for-msg kernel msg-id callbacks)
(unless silent
(mapc #'ein:funcall-packed
(ein:$kernel-after-execute-hook kernel)))
msg-id)
(message "[ein]: stdin active, cannot communicate with kernel.")))
(let* ((content (list
:code code
:silent (or silent json-false)
:store_history (or store-history json-false)
:user_expressions user-expressions
:allow_stdin allow-stdin
:stop_on_error (or stop-on-error json-false)))
(msg (ein:kernel--get-msg kernel "execute_request" content))
(msg-id (plist-get (plist-get msg :header) :msg_id)))
(ein:log 'debug "KERNEL-EXECUTE: code=%s msg_id=%s" code msg-id)
(run-hook-with-args 'ein:pre-kernel-execute-functions msg)
(ein:websocket-send-shell-channel kernel msg)
(ein:kernel-set-callbacks-for-msg kernel msg-id callbacks)
(unless silent
(mapc #'ein:funcall-packed
(ein:$kernel-after-execute-hook kernel)))
msg-id))
(defun ein:kernel-complete (kernel line cursor-pos callbacks)
"Complete code at CURSOR-POS in a string LINE on KERNEL.
@ -736,6 +732,8 @@ Example::
(let ((msg-type (plist-get header :msg_type))
(msg-id (plist-get header :msg_id))
(password (plist-get content :password)))
(ein:log 'debug "KERNEL--HANDLE-STDIN-REPLY: msg_type=%s msg_id=%s"
msg-type msg-id)
(cond ((string-equal msg-type "input_request")
(if (not (eql password :json-false))
(let* ((passwd (read-passwd (plist-get content :prompt)))
@ -760,12 +758,10 @@ Example::
(msg-id (plist-get parent_header :msg_id))
(callbacks (ein:kernel-get-callbacks-for-msg kernel msg-id))
(cb (plist-get callbacks (intern (format ":%s" msg-type)))))
(ein:log 'debug "KERNEL--HANDLE-SHELL-REPLY: msg_type=%s msg_id=%s"
msg-type msg-id)
(run-hook-with-args 'ein:on-shell-reply-functions msg-type header content metadata)
(ein:log 'debug "KERNEL--HANDLE-SHELL-REPLY: msg_type = %s" msg-type)
(if cb
(ein:funcall-packed cb content metadata)
(ein:log 'debug "no callback for: msg_type=%s msg_id=%s"
msg-type msg-id))
(ein:aif cb (ein:funcall-packed it content metadata))
(ein:aif (plist-get content :payload)
(ein:kernel--handle-payload kernel callbacks it))
(let ((events (ein:$kernel-events kernel)))
@ -806,10 +802,11 @@ Example::
(&key content metadata parent_header header &allow-other-keys)
(ein:json-read-from-string packet)
(let* ((msg-type (plist-get header :msg_type))
(callbacks (ein:kernel-get-callbacks-for-msg
kernel (plist-get parent_header :msg_id)))
(msg-id (plist-get parent_header :msg_id))
(callbacks (ein:kernel-get-callbacks-for-msg kernel msg-id))
(events (ein:$kernel-events kernel)))
(ein:log 'debug "KERNEL--HANDLE-IOPUB-REPLY: msg_type = %s" msg-type)
(ein:log 'debug "KERNEL--HANDLE-IOPUB-REPLY: msg_type=%s msg_id=%s"
msg-type msg-id)
(if (and (not (equal msg-type "status")) (null callbacks))
(ein:log 'verbose "Got message not from this notebook.")
(ein:case-equal msg-type
@ -829,8 +826,8 @@ Example::
(ein:log 'verbose (format "Received data_pub message w/content %s" packet)))
(("clear_output")
(ein:aif (plist-get callbacks :clear_output)
(ein:funcall-packed it content metadata))))))))
(ein:log 'debug "KERNEL--HANDLE-IOPUB-REPLY: finished"))
(ein:funcall-packed it content metadata)))))))))
(ein:log 'debug "KERNEL--HANDLE-IOPUB-REPLY: finished")
;;; Utility functions

View file

@ -188,6 +188,7 @@ Current buffer for these functions is set to the notebook buffer.")
(ein:deflocal ein:%notebook% nil
"Buffer local variable to store an instance of `ein:$notebook'.")
(define-obsolete-variable-alias 'ein:notebook 'ein:%notebook% "0.1.2")
@ -299,6 +300,8 @@ will be updated with kernel's cwd."
(defun ein:notebook-open--decorate-callback (notebook existing callback)
"In addition to CALLBACK, also pop-to-buffer the new notebook, and save to disk the kernelspec metadata."
(apply-partially (lambda (notebook* created callback*)
(with-current-buffer (ein:notebook-buffer notebook*)
(ein:worksheet-focus-cell))
(pop-to-buffer (ein:notebook-buffer notebook*))
(ein:aif (ein:$notebook-kernelspec notebook*)
(progn
@ -604,7 +607,6 @@ This is equivalent to do ``C-c`` in the console program."
;; Now that major-mode is set, set buffer local variables:
(ein:notebook--notification-setup notebook)
(ein:notebook-setup-kill-buffer-hook)
(ein:notebook--enable-eldoc)
(setq ein:%notebook% notebook)))
(defun ein:notebook--notification-setup (notebook)
@ -1286,10 +1288,11 @@ Use simple `python-mode' based notebook mode when MuMaMo is not installed::
(const :tag "Plain" ein:notebook-plain-mode)))
:group 'ein)
(defcustom ein:notebook-mode-hook nil
(defcustom ein:notebook-mode-hook
'(ein:worksheet-imenu-setup ein:worksheet-reinstall-which-cell-hook)
"Hook for `ein:notebook-mode'.
This hook is run regardless the actual major mode used."
:type 'hook
:type '(repeat function)
:group 'ein)
(defun ein:notebook-choose-mode ()
@ -1497,6 +1500,20 @@ This hook is run regardless the actual major mode used."
))
map)
(defun ein:notebook-configure-eldoc ()
"eldoc comments say: Major modes for other languages may use ElDoc by defining an
appropriate function as the buffer-local value of `eldoc-documentation-function'."
;; TODO
(when nil
(require 'eldoc nil t)
(if (boundp 'eldoc-documentation-function)
(setq-local eldoc-documentation-function
(apply-partially (lambda (oldfun &rest args)
(or (apply #'ein:completer--get-eldoc-signature args)
(apply oldfun args)))
eldoc-documentation-function))
(setq-local eldoc-documentation-function #'ein:completer--get-eldoc-signature))))
(defun ein:notebook-mode ()
(funcall (ein:notebook-choose-mode))
(case ein:completion-backend
@ -1519,11 +1536,9 @@ This hook is run regardless the actual major mode used."
(define-key ein:notebook-mode-map it 'anything-ein-kernel-history))
(ein:notebook-minor-mode +1)
(setq indent-tabs-mode nil) ;; Being T causes problems with Python code.
(ein:notebook-configure-eldoc)
(run-hooks 'ein:notebook-mode-hook))
(add-hook 'ein:notebook-mode-hook 'ein:worksheet-imenu-setup)
(add-hook 'ein:notebook-mode-hook 'ein:worksheet-reinstall-which-cell-hook)
(define-minor-mode ein:notebook-minor-mode
"Minor mode to install `ein:notebook-mode-map' for `ein:notebook-mode'."
:keymap ein:notebook-mode-map

View file

@ -57,7 +57,8 @@ S-mouse-1/3 (Shift + left/right click): move this tab to left/right"
(defmethod ein:notification-status-set ((ns ein:notification-status) status)
(let* ((message (cdr (assoc status (slot-value ns 's2m)))))
(setf (slot-value ns 'status) status)
(setf (slot-value ns 'message) message)))
(setf (slot-value ns 'message) message)
(force-mode-line-update)))
(defmethod ein:notification-bind-events ((notification ein:notification)
events)