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.

354 lines
13 KiB

  1. ;;; ein-dev.el --- Development tools -*- lexical-binding: t -*-
  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-dev.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-dev.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-dev.el. If not, see <http://www.gnu.org/licenses/>.
  15. ;;; Commentary:
  16. ;;
  17. ;;; Code:
  18. (declare-function rst-shift-region "rst")
  19. (require 'ein-notebook)
  20. (require 'ein-subpackages)
  21. ;;;###autoload
  22. (defun ein:dev-insert-mode-map (map-string)
  23. "Insert mode-map into rst document. For README.rst."
  24. (save-excursion
  25. (insert "\n\n::\n\n")
  26. (let ((beg (point)))
  27. (search-forward ".. // KEYS END //")
  28. (move-beginning-of-line nil)
  29. (delete-region beg (point))
  30. (insert "\n")
  31. (goto-char beg)
  32. (insert (substitute-command-keys map-string))
  33. (rst-shift-region beg (point) 1))))
  34. (defun ein:load-files (&optional regex dir ignore-compiled)
  35. (let* ((dir (or dir ein:source-dir))
  36. (regex (or regex ".+"))
  37. (files (-remove #'(lambda (x)
  38. (or (string-match-p "ein-pkg\\.el" x)
  39. (string-match-p "ein-smartrep\\.el" x)))
  40. (and
  41. (file-accessible-directory-p dir)
  42. (directory-files dir 'full regex)))))
  43. (unless ignore-compiled
  44. (setq files (mapcar #'file-name-sans-extension files)))
  45. (mapc #'load files)))
  46. (defun ein:dev-reload ()
  47. "Reload ein-*.el modules."
  48. (interactive)
  49. (makunbound 'ein:notebook-mode-map) ; so defvar works.
  50. (load "ein-notebook") ; ... but make sure it will be defined first.
  51. (ein:load-files "^ein-.*\\.el$"))
  52. (cl-defun ein:dev-require-all (&key (ignore-p #'ignore))
  53. (cl-loop for f in (directory-files ein:source-dir nil "^ein-.*\\.el$")
  54. unless (or (equal f "ein-pkg.el")
  55. (equal f "ein-autoloads.el")
  56. (equal f "ein-smartrep.el")
  57. (funcall ignore-p f))
  58. do (require (intern (file-name-sans-extension f)) nil t))
  59. ;; For `widget-button-press':
  60. (require 'wid-edit nil t))
  61. (defadvice backtrace (around ein:dev-short-backtrace)
  62. "A hack to shorten backtrace.
  63. As code cells hold base64-encoded image data, backtrace tends to
  64. be VERY long. So I am setting `print-level' to *1*. Note that
  65. setting it globally via `setq' does not work because the value
  66. for debugger is hard-coded. See `debugger-setup-buffer'."
  67. (let ((print-level 1)
  68. (print-length 1)
  69. (print-circle t))
  70. ad-do-it))
  71. (defun ein:dev-patch-backtrace ()
  72. "Monkey patch `backtrace' function to make it shorter."
  73. (interactive)
  74. (ad-enable-advice 'backtrace 'around 'ein:dev-short-backtrace)
  75. (ad-activate 'backtrace))
  76. (defun ein:dev-depatch-backtrace ()
  77. "Undo `ein:dev-patch-backtrace'."
  78. (interactive)
  79. (ad-deactivate 'backtrace)
  80. (ad-disable-advice 'backtrace 'around 'ein:dev-short-backtrace)
  81. ;; In case it has other advices.
  82. (ad-activate 'backtrace))
  83. (defun ein:dev-show-debug-setting ()
  84. "Show variables related to EIN debugging."
  85. (interactive)
  86. (message (concat "debug-on-error=%s websocket-debug=%s "
  87. "websocket-callback-debug-on-error=%s "
  88. "ein:debug=%s ein:log-level=%s ein:log-message-level=%s")
  89. debug-on-error websocket-debug websocket-callback-debug-on-error
  90. ein:debug
  91. (ein:log-level-int-to-name ein:log-level)
  92. (ein:log-level-int-to-name ein:log-message-level)))
  93. ;;;###autoload
  94. (defun ein:dev-start-debug ()
  95. "Enable EIN debugging support.
  96. When the prefix argument is given, debugging support for websocket
  97. callback (`websocket-callback-debug-on-error') is enabled."
  98. (interactive)
  99. (setq debug-on-error t)
  100. ;; only use these with deferred:sync! they cause strange failures otherwise!
  101. ;; (setq deferred:debug-on-signal t)
  102. ;; (setq deferred:debug t)
  103. (setq request-log-level (quote debug))
  104. (let ((curl-trace (concat temporary-file-directory "curl-trace")))
  105. (nconc request-curl-options `("--trace-ascii" ,curl-trace))
  106. (add-function :after
  107. (symbol-function 'request--curl-callback)
  108. (lambda (&rest _args)
  109. (if (file-readable-p curl-trace)
  110. (with-temp-buffer
  111. (insert-file-contents curl-trace)
  112. (request-log 'debug (buffer-string)))
  113. (request-log 'debug "%s unreadable" curl-trace)))))
  114. (setq request-message-level (quote verbose))
  115. (setq websocket-debug t)
  116. (setq websocket-callback-debug-on-error t)
  117. (setq ein:debug t)
  118. (ein:log-set-level 'debug)
  119. (ein:log-set-message-level 'verbose)
  120. (ein:dev-patch-backtrace)
  121. (ein:dev-show-debug-setting))
  122. ;;;###autoload
  123. (defun ein:dev-stop-debug ()
  124. "Inverse of `ein:dev-start-debug'. Hard to maintain because it needs to match start"
  125. (interactive)
  126. (setq debug-on-error nil)
  127. (setq websocket-debug nil)
  128. (setq deferred:debug-on-signal nil)
  129. (setq deferred:debug nil)
  130. (setq request-log-level -1)
  131. (setq request-message-level 'warn)
  132. (setq websocket-callback-debug-on-error nil)
  133. (setq ein:debug nil)
  134. (ein:log-set-level 'verbose)
  135. (ein:log-set-message-level 'info)
  136. (ein:dev-depatch-backtrace)
  137. (ein:dev-show-debug-setting))
  138. (defun ein:dev-pop-to-debug-channels ()
  139. "Open notebook communication channels websocket log buffer."
  140. (interactive)
  141. (-when-let* ((kernel (ein:get-kernel--notebook))
  142. (websocket (ein:$kernel-websocket kernel)))
  143. (pop-to-buffer
  144. (websocket-get-debug-buffer-create
  145. (ein:$websocket-ws websocket)))))
  146. (defun ein:dev-pop-to-debug-shell ()
  147. "Legacy diagnostic for shell channel that got folded into ein:$kernel-websocket."
  148. (interactive)
  149. (-when-let* ((kernel (ein:get-kernel--notebook))
  150. (channel (ein:$kernel-shell-channel kernel)))
  151. (pop-to-buffer
  152. (websocket-get-debug-buffer-create
  153. (ein:$websocket-ws channel)))))
  154. (defun ein:dev-pop-to-debug-iopub ()
  155. "Legacy diagnostic for iopub channel that got folded into ein:$kernel-websocket."
  156. (interactive)
  157. (-when-let* ((kernel (ein:get-kernel--notebook))
  158. (channel (ein:$kernel-shell-channel kernel)))
  159. (pop-to-buffer
  160. (websocket-get-debug-buffer-create
  161. (ein:$websocket-ws channel)))))
  162. (defun ein:dev-notebook-plain-mode ()
  163. "Use `ein:notebook-plain-mode'."
  164. (interactive)
  165. (setq ein:notebook-modes '(ein:notebook-plain-mode)))
  166. (defun ein:dev-notebook-python-mode ()
  167. "Use `ein:notebook-python-mode'."
  168. (interactive)
  169. (setq ein:notebook-modes '(ein:notebook-python-mode)))
  170. (defun ein:dev-notebook-mumamo-mode ()
  171. "Use `ein:notebook-mumamo-mode'."
  172. (interactive)
  173. (setq ein:notebook-modes '(ein:notebook-mumamo-mode)))
  174. (defun ein:dev-notebook-multilang-mode ()
  175. "Use `ein:notebook-multilang-mode'."
  176. (interactive)
  177. (setq ein:notebook-modes '(ein:notebook-multilang-mode)))
  178. (defun ein:dev-sys-info--lib (name)
  179. (let* ((libsym (intern-soft name))
  180. (version-var (cl-loop for fmt in '("%s-version" "%s:version")
  181. if (intern-soft (format fmt name))
  182. return it))
  183. (version (symbol-value version-var)))
  184. (list :name name
  185. :path (ein:aand (locate-library name) (abbreviate-file-name it))
  186. :featurep (featurep libsym)
  187. :version-var version-var
  188. :version version)))
  189. (defun ein:dev-dump-vars (names)
  190. (cl-loop for var in names
  191. collect (intern (format ":%s" var))
  192. collect (symbol-value (intern (format "ein:%s" var)))))
  193. (defun ein:dev-stdout-program (command args)
  194. "Safely call COMMAND with ARGS and return its stdout."
  195. (ein:aand (executable-find command)
  196. (with-temp-buffer
  197. (erase-buffer)
  198. (apply #'call-process it nil t nil args)
  199. (buffer-string))))
  200. (defsubst ein:dev-packages ()
  201. (let (result)
  202. (cl-letf (((symbol-function 'define-package)
  203. (lambda (&rest args)
  204. (setq result (mapcar (lambda (x) (symbol-name (car x))) (nth 3 args))))))
  205. (load "ein-pkg")
  206. result)))
  207. (defun ein:dev-sys-info ()
  208. (list
  209. "EIN system info"
  210. :emacs-version (emacs-version)
  211. :emacs-bzr-version (ein:eval-if-bound 'emacs-bzr-version)
  212. :window-system window-system
  213. ;; Emacs variant detection
  214. ;; http://coderepos.org/share/browser/lang/elisp/init-loader/init-loader.el
  215. :emacs-variant
  216. (cond ((featurep 'meadow) 'meadow)
  217. ((featurep 'core-spacemacs) 'spacemacs)
  218. ((featurep 'carbon-emacs-package) 'carbon))
  219. :os (list
  220. :uname (ein:dev-stdout-program "uname" '("-a"))
  221. :lsb-release (ein:dev-stdout-program "lsb_release" '("-a")))
  222. :notebook (ein:dev-stdout-program "pip" '("show" "notebook"))
  223. :ipython (ein:dev-stdout-program "ipython" '("--version"))
  224. :image-types (ein:eval-if-bound 'image-types)
  225. :image-types-available (seq-filter #'image-type-available-p
  226. (ein:eval-if-bound 'image-types))
  227. :request (list :backend request-backend)
  228. :ein (append (list :version (ein:version))
  229. (ein:dev-dump-vars '("source-dir")))
  230. :lib (seq-filter (lambda (info) (plist-get info :path))
  231. (mapcar #'ein:dev-sys-info--lib
  232. (ein:dev-packages)))))
  233. (defun ein:dev-show-sys-info (&optional show-in-buffer)
  234. "Show Emacs and library information."
  235. (interactive (list t))
  236. (let ((info (ein:dev-sys-info)))
  237. (if show-in-buffer
  238. (let ((buffer (get-buffer-create "*ein:sys-info*")))
  239. (with-current-buffer buffer
  240. (erase-buffer)
  241. (pp info buffer)
  242. (pop-to-buffer buffer)))
  243. (message "EIN INFO:\n%s" (pp-to-string info)))))
  244. ;;;###autoload
  245. (defun ein:dev-bug-report-template ()
  246. "Open a buffer with bug report template."
  247. (interactive)
  248. (let ((buffer (generate-new-buffer "*ein:bug-report*")))
  249. (with-current-buffer buffer
  250. (erase-buffer)
  251. (insert "## Problem description\n\n## Steps to reproduce the problem\n\n")
  252. (insert "<!-- Ensure no information sensitive to your institution is included!!! -->\n")
  253. (insert "## System info:\n\n```cl\n")
  254. (condition-case err
  255. (ein:dev-print-sys-info buffer)
  256. (error (insert (format "`ein:dev-sys-info' produce: %S" err))))
  257. (insert "```\n")
  258. (goto-char (point-min))
  259. (markdown-mode)
  260. (pop-to-buffer buffer))))
  261. (defun ein:dev-print-sys-info (&optional stream)
  262. (princ (ein:dev--pp-to-string (ein:dev-sys-info))
  263. (or stream standard-output)))
  264. (defun ein:dev--pp-to-string (object)
  265. "`pp-to-string' with additional prettifier."
  266. (with-temp-buffer
  267. (erase-buffer)
  268. (let ((pp-escape-newlines nil))
  269. (pp object (current-buffer)))
  270. (goto-char (point-min))
  271. (let ((emacs-lisp-mode-hook nil))
  272. (emacs-lisp-mode))
  273. (ein:dev--prettify-sexp)
  274. (buffer-string)))
  275. (defun ein:dev--prettify-sexp ()
  276. "Prettify s-exp at point recursively.
  277. Use this function in addition to `pp' (see `ein:dev--pp-to-string')."
  278. (down-list)
  279. (condition-case nil
  280. (while t
  281. (forward-sexp)
  282. ;; Prettify nested s-exp.
  283. (when (looking-back ")" (1- (point)))
  284. (save-excursion
  285. (backward-sexp)
  286. (ein:dev--prettify-sexp)))
  287. ;; Add newline before keyword symbol.
  288. (when (looking-at-p " :")
  289. (newline-and-indent))
  290. ;; Add newline before long string literal.
  291. (when (and (looking-at-p " \"")
  292. (let ((end (save-excursion
  293. (forward-sexp)
  294. (point))))
  295. (> (- end (point)) 80)))
  296. (newline-and-indent)))
  297. (scan-error)))
  298. (defun ein:debug-notebook-to-json-buffer ()
  299. "Create a new buffer with the json representation of the current notebook."
  300. (interactive)
  301. (when-let ((notebook (ein:get-notebook)))
  302. (let ((content-data (ein:notebook-to-json notebook))
  303. (bufname (format "*notebook-json:%s" (ein:$notebook-notebook-name notebook))))
  304. (with-current-buffer (get-buffer-create bufname)
  305. (barf-if-buffer-read-only)
  306. (erase-buffer)
  307. (save-excursion
  308. (insert (json-encode content-data))
  309. (json-pretty-print (point-min) (point-max))))
  310. (pop-to-buffer bufname))))
  311. (provide 'ein-dev)
  312. ;;; ein-dev.el ends here