ein-shared-output.el 9.1 KB

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