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.

199 lines
7.3 KiB

  1. ;;; ein-traceback.el --- Traceback module
  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-traceback.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-traceback.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-traceback.el. If not, see <http://www.gnu.org/licenses/>.
  15. ;;; Commentary:
  16. ;;
  17. ;;; Code:
  18. (require 'eieio)
  19. (require 'ewoc)
  20. (require 'ansi-color)
  21. (require 'ein-core)
  22. (require 'ein-shared-output)
  23. (declare-function ein:notebook-buffer "ein-notebook" (notebook))
  24. (defclass ein:traceback ()
  25. ((tb-data :initarg :tb-data :type list)
  26. (notebook :initarg :source-notebook ;; :type ein:$notebook
  27. :accessor ein:traceback-notebook)
  28. (buffer-name :initarg :buffer-name :type string)
  29. (buffer :initarg :buffer :type buffer)
  30. (ewoc :initarg :ewoc :type ewoc)))
  31. (ein:deflocal ein:%traceback% nil
  32. "Buffer local variable to store an instance of `ein:traceback'.")
  33. (defvar ein:tb-buffer-name-template "*ein:tb %s/%s*")
  34. (defun ein:tb-new (buffer-name notebook)
  35. (make-instance 'ein:traceback
  36. :buffer-name buffer-name
  37. :source-notebook notebook))
  38. (cl-defmethod ein:tb-get-buffer ((traceback ein:traceback))
  39. (unless (and (slot-boundp traceback :buffer)
  40. (buffer-live-p (slot-value traceback 'buffer)))
  41. (let ((buf (get-buffer-create (slot-value traceback 'buffer-name))))
  42. (setf (slot-value traceback 'buffer) buf)))
  43. (slot-value traceback 'buffer))
  44. (defun ein:tb-pp (ewoc-data)
  45. (insert (ansi-color-apply ewoc-data)))
  46. (cl-defmethod ein:tb-render ((traceback ein:traceback) tb-data)
  47. (with-current-buffer (ein:tb-get-buffer traceback)
  48. (setq ein:%traceback% traceback)
  49. (setq buffer-read-only t)
  50. (let ((inhibit-read-only t)
  51. (ewoc (ein:ewoc-create #'ein:tb-pp)))
  52. (erase-buffer)
  53. (setf (slot-value traceback 'ewoc) ewoc)
  54. (setf (slot-value traceback 'tb-data) tb-data)
  55. (mapc (lambda (data) (ewoc-enter-last ewoc data)) tb-data))
  56. (ein:traceback-mode)))
  57. (cl-defmethod ein:tb-popup ((traceback ein:traceback) tb-data)
  58. (ein:tb-render traceback tb-data)
  59. (pop-to-buffer (ein:tb-get-buffer traceback)))
  60. ;;;###autoload
  61. (defun ein:tb-show ()
  62. "Show full traceback in traceback viewer."
  63. (interactive)
  64. (unless
  65. (ein:and-let* ((tb-data (ein:get-traceback-data))
  66. (url-or-port (or (ein:get-url-or-port)
  67. (ein:get-url-or-port--shared-output)))
  68. (kernel (or (ein:get-kernel)
  69. (ein:get-kernel--shared-output)))
  70. (kr-id (ein:kernel-id kernel))
  71. (tb-name (format ein:tb-buffer-name-template
  72. url-or-port kr-id)))
  73. (ein:tb-popup (ein:tb-new tb-name (ein:get-notebook)) tb-data)
  74. t)
  75. (error "No traceback is available.")))
  76. (cl-defmethod ein:tb-range-of-node-at-point ((traceback ein:traceback))
  77. (let* ((ewoc (slot-value traceback 'ewoc))
  78. (ewoc-node (ewoc-locate ewoc))
  79. (beg (ewoc-location ewoc-node))
  80. (end (ein:aand (ewoc-next ewoc ewoc-node) (ewoc-location it))))
  81. (list beg end)))
  82. (cl-defmethod ein:tb-file-path-at-point ((traceback ein:traceback))
  83. (cl-destructuring-bind (beg end)
  84. (ein:tb-range-of-node-at-point traceback)
  85. (let* ((file-tail
  86. (if (>= emacs-major-version 24)
  87. (next-single-property-change beg 'font-lock-face nil end)
  88. ;; For Emacs 23.x:
  89. (next-single-property-change beg 'face nil end)))
  90. (file (when file-tail
  91. (buffer-substring-no-properties beg file-tail))))
  92. (if (string-match "\\.pyc$" file)
  93. (concat (file-name-sans-extension file) ".py")
  94. file))))
  95. (cl-defmethod ein:tb-file-lineno-at-point ((traceback ein:traceback))
  96. (cl-destructuring-bind (beg end)
  97. (ein:tb-range-of-node-at-point traceback)
  98. (when (save-excursion
  99. (goto-char beg)
  100. (search-forward-regexp "^[-]+> \\([0-9]+\\)" end t))
  101. (string-to-number (match-string 1)))))
  102. (cl-defmethod ein:tb-jump-to-source-at-point ((traceback ein:traceback)
  103. &optional select)
  104. (let ((file (ein:tb-file-path-at-point traceback))
  105. (lineno (ein:tb-file-lineno-at-point traceback)))
  106. (if (string-match "<ipython-input-\\([0-9]+\\)-.*" file)
  107. (let* ((cellnum (string-to-number (match-string 1 file)))
  108. (nb (slot-value traceback 'notebook))
  109. (ws (car (ein:$notebook-worksheets nb)))
  110. (cells (ein:worksheet-get-cells ws))
  111. (it (cl-find cellnum cells :key #'(lambda (x)
  112. (if (same-class-p x 'ein:codecell)
  113. (slot-value x 'input-prompt-number))))))
  114. (if it
  115. (progn
  116. (pop-to-buffer (ein:notebook-buffer nb))
  117. (ein:cell-goto-line it lineno))))
  118. (let ((url-or-port (ein:$notebook-url-or-port (ein:traceback-notebook traceback))))
  119. (cond
  120. ((numberp url-or-port) (ein:tb-jtsap--local file lineno select))
  121. ((string-match "localhost" url-or-port) (ein:tb-jtsap--local file lineno select))
  122. ((string-match "127.0.0.1" url-or-port) (ein:tb-jtsap--local file lineno select))
  123. (t (ein:tb-jtsap--remote url-or-port file lineno select)))))))
  124. (defun ein:tb-jtsap--local (file lineno select)
  125. (cl-assert (file-exists-p file) nil "File %s does not exist." file)
  126. (let ((buf (find-file-noselect file))
  127. (scroll (lambda ()
  128. (goto-char (point-min))
  129. (forward-line (1- lineno)))))
  130. (if select
  131. (progn (pop-to-buffer buf)
  132. (funcall scroll))
  133. (with-selected-window (display-buffer buf)
  134. (funcall scroll)))))
  135. (defun ein:tb-jtsap--remote (uri path lineno select)
  136. (let* ((uri (url-generic-parse-url uri))
  137. (host-path (concat "/" (url-host uri)
  138. ":" path)))
  139. (ein:tb-jtsap--local host-path lineno select)))
  140. (defun ein:tb-jump-to-source-at-point-command (&optional select)
  141. (interactive "P")
  142. (ein:tb-jump-to-source-at-point ein:%traceback% select))
  143. ;;; ein:traceback-mode
  144. (defun ein:tb-prev-item ()
  145. (interactive)
  146. (ewoc-goto-prev (slot-value ein:%traceback% 'ewoc) 1))
  147. (defun ein:tb-next-item ()
  148. (interactive)
  149. (ewoc-goto-next (slot-value ein:%traceback% 'ewoc) 1))
  150. (defvar ein:traceback-mode-map
  151. (let ((map (make-sparse-keymap)))
  152. (define-key map (kbd "RET") 'ein:tb-jump-to-source-at-point-command)
  153. (define-key map "p" 'ein:tb-prev-item)
  154. (define-key map "n" 'ein:tb-next-item)
  155. map)
  156. "Keymap for ein:traceback-mode.")
  157. (define-derived-mode ein:traceback-mode special-mode "ein:tb"
  158. (font-lock-mode))
  159. (add-hook 'ein:traceback-mode-hook 'ein:truncate-lines-on)
  160. (provide 'ein-traceback)
  161. ;;; ein-traceback.el ends here