Personal emacs config
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

266 lines
9.8 KiB

  1. ;; -*- lexical-binding: t -*-
  2. ;;; ein-shared-output.el --- Output buffer for ein-connect.el
  3. ;; Copyright (C) 2012- Takafumi Arakaki
  4. ;; Author: Takafumi Arakaki <aka.tkf at gmail.com>
  5. ;; This file is NOT part of GNU Emacs.
  6. ;; ein-shared-output.el is free software: you can redistribute it and/or modify
  7. ;; it under the terms of the GNU General Public License as published by
  8. ;; the Free Software Foundation, either version 3 of the License, or
  9. ;; (at your option) any later version.
  10. ;; ein-shared-output.el is distributed in the hope that it will be useful,
  11. ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ;; GNU General Public License for more details.
  14. ;; You should have received a copy of the GNU General Public License
  15. ;; along with ein-shared-output.el. If not, see <http://www.gnu.org/licenses/>.
  16. ;;; Commentary:
  17. ;; When executing code from outside of notebook, some place for output
  18. ;; is needed. This module buffer containing one special cell for that
  19. ;; purpose.
  20. ;; TODO - Undo accounting is almost certainly broken by this module
  21. ;;; Code:
  22. (require 'eieio)
  23. (require 'ein-cell)
  24. ;;; Classes and variables
  25. (defclass ein:shared-output-cell (ein:codecell)
  26. ((cell-type :initarg :cell-type :initform "shared-output")
  27. ;; (element-names :initform (:prompt :output :footer))
  28. (popup :initarg :popup :initform nil :type boolean)
  29. (callback :initarg :callback :initform #'ignore :type function)
  30. (callback-called :initarg :callback-called :initform nil :type boolean))
  31. "A singleton cell to show output from non-notebook buffers.")
  32. (defclass ein:shared-output ()
  33. ((cell :initarg :cell :type ein:shared-output-cell)
  34. (events :initarg :events :type ein:events)
  35. (ewoc :initarg :ewoc :type ewoc)))
  36. (defvar *ein:shared-output* nil
  37. "Hold an instance of `ein:shared-output'.")
  38. (defconst ein:shared-output-buffer-name "*ein:shared-output*")
  39. ;;; Cell related
  40. (cl-defmethod ein:cell-insert-prompt ((cell ein:shared-output-cell))
  41. "Insert prompt of the CELL in the buffer.
  42. Called from ewoc pretty printer via `ein:cell-pp'."
  43. ;; Newline is inserted in `ein:cell-insert-input'.
  44. (ein:insert-read-only
  45. (concat
  46. (format "In [%s]" (or (ein:oref-safe cell 'input-prompt-number) " "))
  47. (when (slot-value cell 'autoexec) " %s" ein:cell-autoexec-prompt))
  48. 'font-lock-face 'ein:cell-input-prompt))
  49. (cl-defmethod ein:cell-execute ((cell ein:shared-output-cell) kernel code popup
  50. &rest args)
  51. (unless (plist-get args :silent)
  52. (setq args (plist-put args :silent nil)))
  53. (setf (slot-value cell 'popup) popup)
  54. (setf (slot-value cell 'kernel) kernel)
  55. (apply #'ein:cell-execute-internal cell kernel code args))
  56. (cl-defmethod ein:cell--handle-output ((cell ein:shared-output-cell)
  57. msg-type _content _metadata)
  58. (ein:log 'debug
  59. "ein:cell--handle-output (cell ein:shared-output-cell): %s" msg-type)
  60. (when (slot-value cell 'popup)
  61. (pop-to-buffer (ein:shared-output-create-buffer)))
  62. (cl-call-next-method)
  63. (ein:aif (ein:oref-safe cell 'callback)
  64. (progn
  65. (funcall it cell)
  66. (setf (slot-value cell 'callback-called) t))))
  67. (cl-defmethod ein:cell--handle-execute-reply ((cell ein:shared-output-cell)
  68. content _metadata)
  69. (ein:log 'debug
  70. "ein:cell--handle-execute-reply (cell ein:shared-output-cell): %s"
  71. content)
  72. (cl-call-next-method)
  73. (ein:aif (ein:oref-safe cell 'callback)
  74. ;; clear the way for waiting block in `ob-ein--execute-async'
  75. ;; but only after 2 seconds to allow for handle-output stragglers
  76. ;; TODO avoid this hack
  77. (progn
  78. (unless (ein:oref-safe cell 'callback-called)
  79. (funcall it cell)
  80. (setf (slot-value cell 'callback-called) t))
  81. (run-at-time 2 nil (lambda ()
  82. (ein:log 'debug "Clearing callback shared output cell")
  83. (setf (slot-value cell 'callback) #'ignore)
  84. (setf (slot-value cell 'callback-called) nil))))))
  85. ;;; Main
  86. (defun ein:shared-output-create-buffer ()
  87. "Get or create the shared output buffer."
  88. (get-buffer-create ein:shared-output-buffer-name))
  89. (defun ein:shared-output-buffer ()
  90. "Get the buffer associated with `*ein:shared-output*'."
  91. (ewoc-buffer (slot-value *ein:shared-output* 'ewoc)))
  92. (defun ein:shared-output-buffer-p (&optional buffer)
  93. "Return non-`nil' when BUFFER (or current buffer) is shared-output buffer."
  94. (eq (or buffer (current-buffer)) (ein:shared-output-buffer)))
  95. (defun ein:shared-output-healthy-p ()
  96. (and (ein:shared-output-p *ein:shared-output*)
  97. (buffer-live-p (ein:shared-output-buffer))))
  98. (defun ein:shared-output-get-or-create ()
  99. (if (ein:shared-output-healthy-p)
  100. *ein:shared-output*
  101. (with-current-buffer (ein:shared-output-create-buffer)
  102. ;; FIXME: This is a duplication of `ein:worksheet-render'.
  103. (let* ((inhibit-read-only t)
  104. ;; Apply read-only text property to newlines by
  105. ;; setting nonsep flag to `ein:ewoc-create'
  106. (ewoc (let ((buffer-undo-list t))
  107. (ein:ewoc-create 'ein:worksheet-pp
  108. (ein:propertize-read-only "\n")
  109. nil t)))
  110. (events (ein:events-new))
  111. (cell (ein:shared-output-cell :ewoc ewoc
  112. :events events)))
  113. (erase-buffer)
  114. (ein:shared-output-bind-events events)
  115. (setq *ein:shared-output*
  116. (ein:shared-output :ewoc ewoc :cell cell
  117. :events events))
  118. (ein:cell-enter-last cell))
  119. (setq buffer-read-only t)
  120. (ein:shared-output-mode)
  121. *ein:shared-output*)))
  122. (defun ein:shared-output-bind-events (events)
  123. "Add dummy event handlers."
  124. (ein:events-on events 'set_dirty.Worksheet #'ignore)
  125. (ein:events-on events 'maybe_reset_undo.Worksheet #'ignore))
  126. (defun ein:shared-output-get-cell ()
  127. "Get the singleton shared output cell.
  128. Create a cell if the buffer has none."
  129. (slot-value (ein:shared-output-get-or-create) 'cell))
  130. ;;;###autoload
  131. (defun ein:shared-output-pop-to-buffer ()
  132. "Open shared output buffer."
  133. (interactive)
  134. (ein:shared-output-get-or-create)
  135. (pop-to-buffer (ein:shared-output-create-buffer)))
  136. (cl-defmethod ein:shared-output-show-code-cell ((cell ein:codecell))
  137. "Show code CELL in shared-output buffer."
  138. (let ((new (ein:cell-convert cell "shared-output")))
  139. ;; Make sure `*ein:shared-output*' is initialized:
  140. (ein:shared-output-get-or-create)
  141. (with-current-buffer (ein:shared-output-create-buffer)
  142. (let ((inhibit-read-only t)
  143. (ein:cell-max-num-outputs nil))
  144. (setf (slot-value new 'ewoc) (slot-value *ein:shared-output* 'ewoc))
  145. (setf (slot-value new 'events) (slot-value *ein:shared-output* 'events))
  146. (erase-buffer) ; because there are only one cell anyway
  147. (setf (slot-value *ein:shared-output* 'cell) new)
  148. (ein:cell-enter-last new)
  149. (pop-to-buffer (current-buffer))))))
  150. ;;;###autoload
  151. (defun ein:shared-output-show-code-cell-at-point ()
  152. "Show code cell at point in shared-output buffer.
  153. It is useful when the output of the cell at point is truncated.
  154. See also `ein:cell-max-num-outputs'."
  155. (interactive)
  156. (let ((cell (ein:get-cell-at-point)))
  157. (if (ein:codecell-p cell)
  158. (ein:shared-output-show-code-cell cell)
  159. (error "No code cell at point."))))
  160. (defvar ein:shared-output-eval-string-history nil
  161. "History of the `ein:shared-output-eval-string' prompt.")
  162. ;;;###autoload
  163. (defun ein:shared-output-eval-string (kernel code popup &rest args)
  164. "Evaluate a piece of code. Prompt will appear asking the code to run.
  165. This is handy when you want to execute something quickly without
  166. making a cell. If the code outputs something, it will go to the
  167. shared output buffer. You can open the buffer by the command
  168. `ein:shared-output-pop-to-buffer'.
  169. .. ARGS is passed to `ein:kernel-execute'. Unlike `ein:kernel-execute',
  170. `:silent' is `nil' by default."
  171. (interactive
  172. (list nil
  173. (read-string
  174. "IP[y]: "
  175. (when (region-active-p)
  176. (buffer-substring (region-beginning) (region-end)))
  177. 'ein:shared-output-eval-string-history)
  178. nil))
  179. (unless kernel (setq kernel (ein:get-kernel-or-error)))
  180. (let ((cell (ein:shared-output-get-cell)))
  181. (ein:kernel-when-ready
  182. kernel
  183. (lambda (ready-kernel)
  184. (apply #'ein:cell-execute cell ready-kernel (ein:trim-indent code) popup args)))))
  185. ;;; Generic getter
  186. (defun ein:get-url-or-port--shared-output ()
  187. (ein:aand (ein:get-kernel--shared-output) (ein:kernel-url-or-port it)))
  188. ;; (defun ein:get-notebook--shared-output ())
  189. (defun ein:get-kernel--shared-output ()
  190. (let ((cell (ein:get-cell-at-point--shared-output)))
  191. (when (and (eieio-object-p cell) (slot-boundp cell :kernel))
  192. (slot-value cell 'kernel))))
  193. (defun ein:get-cell-at-point--shared-output ()
  194. (when (and (ein:shared-output-p *ein:shared-output*)
  195. (ein:shared-output-buffer-p))
  196. (slot-value *ein:shared-output* 'cell)))
  197. (defun ein:get-traceback-data--shared-output ()
  198. (ein:aand (ein:get-cell-at-point--shared-output) (ein:cell-get-tb-data it)))
  199. ;;; ein:shared-output-mode
  200. (defvar ein:shared-output-mode-map
  201. (let ((map (make-sparse-keymap)))
  202. (define-key map "\C-c\C-x" 'ein:tb-show)
  203. (define-key map "\M-." 'ein:pytools-jump-to-source-command)
  204. (define-key map (kbd "C-c C-.") 'ein:pytools-jump-to-source-command)
  205. map)
  206. "The map for ein:shared-output-mode-map.")
  207. (define-derived-mode ein:shared-output-mode special-mode "ein:so"
  208. "Shared output mode."
  209. (font-lock-mode))
  210. (add-hook 'ein:shared-output-mode-hook 'ein:truncate-lines-on)
  211. (provide 'ein-shared-output)
  212. ;;; ein-shared-output.el ends here