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.

404 lines
13 KiB

  1. ;;; ein-classes.el --- Classes and structures.
  2. ;; Copyright (C) 2017 John M. Miller
  3. ;; Author: John M Miller <millejoh at mac dot com>
  4. ;; This file is NOT part of GNU Emacs.
  5. ;; ein-classes.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-classes.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-worksheet.el. If not, see <http://www.gnu.org/licenses/>.
  15. ;;; Commentary:
  16. ;;; Content
  17. (require 'eieio)
  18. (require 'ein-utils)
  19. (cl-defstruct ein:$content
  20. "Content returned from the Jupyter notebook server:
  21. `ein:$content-url-or-port'
  22. URL or port of Jupyter server.
  23. `ein:$content-name'
  24. The name/filename of the content. Always equivalent to the last
  25. part of the path field
  26. `ein:$content-path'
  27. The full file path. It will not start with /, and it will be /-delimited.
  28. `ein:$content-type'
  29. One of three values: :directory, :file, :notebook.
  30. `ein:$content-writable'
  31. Indicates if requester has permission to modified the requested content.
  32. `ein:$content-created'
  33. `ein:$content-last-modified'
  34. `ein:$content-mimetype'
  35. Specify the mime-type of :file content, null otherwise.
  36. `ein:$content-raw-content'
  37. Contents of resource as returned by Jupyter. Depending on content-type will hold:
  38. :directory : JSON list of models for each item in the directory.
  39. :file : Text of file as a string or base64 encoded string if mimetype
  40. is other than 'text/plain'.
  41. :notebook : JSON structure of the file.
  42. `ein:$content-format'
  43. Value will depend on content-type:
  44. :directory : :json.
  45. :file : Either :text or :base64
  46. :notebook : :json.
  47. `ein:$content-checkpoints'
  48. Names auto-saved checkpoints for content. Stored as a list
  49. of (<id> . <last_modified>) pairs.
  50. "
  51. url-or-port
  52. notebook-version
  53. name
  54. path
  55. type
  56. writable
  57. created
  58. last-modified
  59. mimetype
  60. raw-content
  61. format
  62. session-p
  63. checkpoints)
  64. ;;; Websockets
  65. (cl-defstruct ein:$websocket
  66. "A wrapper object of `websocket'.
  67. `ein:$websocket-ws' : an instance returned by `websocket-open'
  68. `ein:$websocket-kernel' : kernel at the time of instantiation
  69. `ein:$websocket-closed-by-client' : t/nil'
  70. "
  71. ws
  72. kernel
  73. closed-by-client)
  74. ;;; Notebook
  75. (cl-defstruct ein:$notebook
  76. "Hold notebook variables.
  77. `ein:$notebook-url-or-port'
  78. URL or port of IPython server.
  79. `ein:$notebook-notebook-id' : string
  80. uuid string (as of ipython 2.0 this is the same is notebook-name).
  81. `ein:$notebook-notebook-path' : string
  82. Path to notebook.
  83. `ein:$notebook-kernel' : `ein:$kernel'
  84. `ein:$kernel' instance.
  85. `ein:$notebook-kernelspec' : `ein:$kernelspec'
  86. Jupyter kernel specification for the notebook.
  87. `ein:$notebook-kernelinfo' : `ein:kernelinfo'
  88. `ein:kernelinfo' instance.
  89. `ein:$notebook-pager'
  90. Variable for `ein:pager-*' functions. See ein-pager.el.
  91. `ein:$notebook-dirty' : boolean
  92. Set to `t' if notebook has unsaved changes. Otherwise `nil'.
  93. `ein:$notebook-metadata' : plist
  94. Notebook meta data (e.g., notebook name).
  95. `ein:$notebook-name' : string
  96. Notebook name.
  97. `ein:$notebook-nbformat' : integer
  98. Notebook file format version.
  99. `ein:$notebook-nbformat-minor' : integer
  100. Notebook file format version.
  101. `ein:$notebook-events' : `ein:$events'
  102. Event handler instance.
  103. `ein:$notebook-worksheets' : list of `ein:worksheet'
  104. List of worksheets.
  105. `ein:$notebook-scratchsheets' : list of `ein:worksheet'
  106. List of scratch worksheets.
  107. `ein:$notebook-api-version' : integer
  108. Major version of the IPython notebook server we are talking to.
  109. `ein:$notebook-checkpoints'
  110. Names auto-saved checkpoints for content. Stored as a list
  111. of (<id> . <last_modified>) pairs.
  112. `ein:$notebook-q-checkpoints'
  113. Whether to checkpoint on save. Overrides ein:notebook-create-checkpoint-on-save
  114. "
  115. url-or-port
  116. notebook-id ;; In IPython-2.0 this is "[:path]/[:name].ipynb"
  117. notebook-path
  118. kernel
  119. kernelinfo
  120. kernelspec
  121. pager
  122. dirty
  123. metadata
  124. notebook-name
  125. nbformat
  126. nbformat-minor
  127. events
  128. worksheets
  129. scratchsheets
  130. api-version
  131. autosave-timer
  132. checkpoints
  133. q-checkpoints)
  134. ;;; Worksheet
  135. (defclass ein:worksheet ()
  136. ((nbformat :initarg :nbformat :type integer)
  137. (get-notebook-name :initarg :get-notebook-name :type cons
  138. :accessor ein:worksheet--notebook-name)
  139. ;; This slot introduces too much complexity so therefore must be
  140. ;; removed later. This is here only for backward compatible
  141. ;; reason.
  142. (discard-output-p :initarg :discard-output-p :accessor ein:worksheet--discard-output-p)
  143. (saved-cells :initarg :saved-cells :initform nil
  144. :accessor ein:worksheet--saved-cells
  145. :documentation
  146. "Slot to cache cells for worksheet without buffer")
  147. (dont-save-cells :initarg :dont-save-cells :initform nil :type boolean
  148. :accessor ein:worksheet--dont-save-cells-p
  149. :documentation "Don't cache cells when this flag is on.")
  150. (ewoc :initarg :ewoc :type ewoc :accessor ein:worksheet--ewoc)
  151. (kernel :initarg :kernel :type ein:$kernel :accessor ein:worksheet--kernel)
  152. (dirty :initarg :dirty :type boolean :initform nil :accessor ein:worksheet--dirty-p)
  153. (metadata :initarg :metadata :initform nil :accessor ein:worksheet--metadata)
  154. (events :initarg :events :accessor ein:worksheet--events)))
  155. ;;; Kernel
  156. (cl-defstruct ein:$kernelspec
  157. "Kernel specification as return by the Jupyter notebook server.
  158. `ein:$kernelspec-name' : string
  159. Name used to identify the kernel (like python2, or python3).
  160. `ein:$kernelspec-display-name' : string
  161. Name used to display kernel to user.
  162. `ein:$kernelspec-language' : string
  163. Programming language supported by kernel, like 'python'.
  164. `ein:$kernelspec-resources' : plist
  165. Resources, if any, used by the kernel.
  166. `ein:$kernelspec-spec' : plist
  167. How the outside world defines kernelspec:
  168. https://ipython.org/ipython-doc/dev/development/kernels.html#kernelspecs
  169. "
  170. name
  171. display-name
  172. resources
  173. spec
  174. language)
  175. ;; FIXME: Rewrite `ein:$kernel' using `defclass'. It should ease
  176. ;; testing since I can mock I/O using method overriding.
  177. (cl-defstruct ein:$kernel
  178. "Should perhaps be named ein:$session. We glom session and kernel as defined by the server as just ein:$kernel in the client.
  179. "
  180. url-or-port
  181. path
  182. kernelspec
  183. events
  184. api-version
  185. session-id
  186. kernel-id
  187. shell-channel
  188. iopub-channel
  189. websocket ; For IPython 3.x+
  190. base-url ; /api/kernels/
  191. kernel-url ; /api/kernels/<KERNEL-ID>
  192. ws-url ; ws://<URL>[:<PORT>]
  193. stdin-activep
  194. username
  195. msg-callbacks
  196. oinfo-cache
  197. ;; FIXME: Use event instead of hook.
  198. after-start-hook
  199. after-execute-hook)
  200. ;;; Cells
  201. (defclass ein:basecell ()
  202. ((cell-type :initarg :cell-type :type string :accessor ein:cell-type)
  203. (read-only :initarg :read-only :initform nil :type boolean)
  204. (ewoc :initarg :ewoc :type ewoc :accessor ein:basecell--ewoc)
  205. (element :initarg :element :initform nil :type list
  206. :documentation "ewoc nodes")
  207. (element-names :initarg :element-names)
  208. (input :initarg :input :type string
  209. :documentation "Place to hold data until it is rendered via `ewoc'.")
  210. (outputs :initarg :outputs :initform nil :type list)
  211. (metadata :initarg :metadata :initform nil :type list :accessor ein:cell-metadata) ;; For nbformat >= 4
  212. (events :initarg :events :type ein:events)
  213. (slidetype :initarg :slidetype :initform "-" :type string)
  214. (cell-id :initarg :cell-id :initform (ein:utils-uuid) :type string
  215. :accessor ein:cell-id))
  216. "Notebook cell base class")
  217. (defclass ein:codecell (ein:basecell)
  218. ((traceback :initform nil :initarg :traceback :type list)
  219. (cell-type :initarg :cell-type :initform "code")
  220. (kernel :initarg :kernel :type ein:$kernel :accessor ein:cell-kernel)
  221. (element-names :initform (:prompt :input :output :footer :slidetype))
  222. (input-prompt-number :initarg :input-prompt-number
  223. :documentation "\
  224. Integer or \"*\" (running state).
  225. Implementation note:
  226. Typed `:input-prompt-number' becomes a problem when reading a
  227. notebook that saved "*". So don't add `:type'!")
  228. (collapsed :initarg :collapsed :initform nil :type boolean)
  229. (running :initarg :running :initform nil :type boolean)
  230. (dynamic :initarg :dynamic :initform nil :type boolean
  231. :documentation "\
  232. Whether cell output is evaluated dynamically or not.
  233. Only Emacs lisp type output data will be affected by this
  234. slot (Javascript will not be evaluated). This value must be set
  235. to `t' when executing cell. See `ein:notebook-execute-cell'.
  236. In the implantation of IPython web client it is passed around via
  237. argument, but since it is difficult to pass argument to EWOC
  238. pretty printer, `ein:codecell' instance holds this setting in a
  239. slot.")
  240. (autoexec :initarg :autoexec :initform nil :type boolean
  241. :documentation "Auto-execution flag.
  242. This cell is executed when the connected buffer is saved,
  243. provided that (1) this flag is `t' and (2) corresponding
  244. auto-execution mode flag in the connected buffer is `t'.")))
  245. ;; Use this cell to execute hy code in notebook running a Python kernel.
  246. (defclass ein:hy-codecell (ein:codecell)
  247. ((cell-type :initarg :cell-type :initform "hy-code"))
  248. "Codecell that supports executing hy code from within a Python kernel.")
  249. (defclass ein:textcell (ein:basecell)
  250. ((cell-type :initarg :cell-type :initform "text")
  251. (element-names :initform (:prompt :input :footer :slidetype))))
  252. (defclass ein:htmlcell (ein:textcell)
  253. ((cell-type :initarg :cell-type :initform "html")))
  254. (defclass ein:markdowncell (ein:textcell)
  255. ((cell-type :initarg :cell-type :initform "markdown")))
  256. (defclass ein:rawcell (ein:textcell)
  257. ((cell-type :initarg :cell-type :initform "raw")))
  258. (defclass ein:headingcell (ein:textcell)
  259. ((cell-type :initarg :cell-type :initform "heading")
  260. (level :initarg :level :initform 1)))
  261. ;;; Notifications
  262. (defclass ein:notification-status ()
  263. ((status :initarg :status :initform nil)
  264. (message :initarg :message :initform nil)
  265. (s2m :initarg :s2m))
  266. "Hold status and its string representation (message).")
  267. (defclass ein:notification-tab ()
  268. ((get-list :initarg :get-list :type function)
  269. (get-current :initarg :get-current :type function)
  270. (get-name :initarg :get-name :type function)
  271. (get-buffer :initarg :get-buffer :type function)
  272. (delete :initarg :delete :type function)
  273. (insert-prev :initarg :insert-prev :type function)
  274. (insert-next :initarg :insert-next :type function)
  275. (move-prev :initarg :move-prev :type function)
  276. (move-next :initarg :move-next :type function)
  277. )
  278. ;; These "methods" are for not depending on what the TABs for.
  279. ;; Probably I'd want change this to be a separated Emacs lisp
  280. ;; library at some point.
  281. "See `ein:notification-setup' for explanation.")
  282. (defclass ein:notification ()
  283. ((buffer :initarg :buffer :type buffer :document "Notebook buffer")
  284. (tab :initarg :tab :type ein:notification-tab)
  285. (execution-count
  286. :initform "y" :initarg :execution-count
  287. :documentation "Last `execution_count' sent by `execute_reply'.")
  288. (notebook
  289. :initarg :notebook
  290. :initform
  291. (ein:notification-status
  292. "NotebookStatus"
  293. :s2m
  294. '((notebook_saving.Notebook . "Saving Notebook...")
  295. (notebook_create_checkpoint.Notebook . "Creating Checkpoint...")
  296. (notebook_saved.Notebook . "Notebook is saved")
  297. (notebook_checkpoint_created.Notebook . "Checkpoint created.")
  298. (notebook_save_failed.Notebook . "Failed to save Notebook!")))
  299. :type ein:notification-status)
  300. (kernel
  301. :initarg :kernel
  302. :initform
  303. (ein:notification-status
  304. "KernelStatus"
  305. :s2m
  306. '((status_idle.Kernel . nil)
  307. (status_busy.Kernel . "Kernel is busy...")
  308. (status_restarting.Kernel . "Kernel restarting...")
  309. (status_restarted.Kernel . "Kernel restarted")
  310. (status_dead.Kernel . "Kernel requires restart \\<ein:notebook-mode-map>\\[ein:notebook-restart-session-command]")
  311. (status_reconnecting.Kernel . "Kernel reconnecting...")
  312. (status_reconnected.Kernel . "Kernel reconnected")
  313. (status_disconnected.Kernel . "Kernel requires reconnect \\<ein:notebook-mode-map>\\[ein:notebook-reconnect-session-command]")))
  314. :type ein:notification-status))
  315. "Notification widget for Notebook.")
  316. ;;; Events
  317. (defclass ein:events ()
  318. ((callbacks :initarg :callbacks :type hash-table
  319. :initform (make-hash-table :test 'eq)))
  320. "Event handler class.")
  321. (provide 'ein-classes)
  322. ;;; ein-classes.el ends here