diff --git a/python.el b/python.el index b1d5292..8f52a6f 100644 --- a/python.el +++ b/python.el @@ -253,6 +253,9 @@ ;; Shell interaction (define-key map "\C-c\C-s" 'python-shell-send-string) (define-key map "\C-c\C-r" 'python-shell-send-region) + (define-key map (kbd "C-") 'python-backward-cell) + (define-key map (kbd "C-") 'python-forward-cell) + (define-key map (kbd "") 'python-shell-send-cell) (define-key map "\C-\M-x" 'python-shell-send-defun) (define-key map "\C-c\C-c" 'python-shell-send-buffer) (define-key map "\C-c\C-l" 'python-shell-send-file) @@ -346,6 +349,30 @@ This variant of `rx' supports common python named REGEXPS." (rx-to-string (car regexps) t))))) + +(defvar python-cellbreak-face 'python-cellbreak-face + "Self reference for cellbreaks.") + +(defface python-cellbreak-face + (list + (list t + (list :background (face-background font-lock-comment-face) + :foreground (face-foreground font-lock-comment-face) + :overline t + :bold t))) + "*Face to use for cellbreak lines." + :group 'python) + +;; Now make some cellbreak variable faces +(cond ((facep 'font-comment-face) + (copy-face 'font-lock-comment-face 'python-cellbreak-face)) + (t + (make-face 'python-cellbreak-face))) +(set-face-bold-p 'python-cellbreak-face t) +(condition-case nil + (set-face-attribute 'python-cellbreak-face nil :overline t) + (error nil)) + ;;; Font-lock and syntax (defvar python-font-lock-keywords ;; Keywords @@ -426,6 +453,11 @@ This variant of `rx' supports common python named REGEXPS." ;; Extra: "__all__" "__doc__" "__name__" "__package__") symbol-end) . font-lock-builtin-face) + ;; Cell Break + (,(rx line-start (* space) (group (and "#" (or (and "#" (* (not (any "\n")))) + (and " <" (or "codecell" "markdowncell") ">")) + line-end))) + (1 python-cellbreak-face append)) ;; asignations ;; support for a = b = c = 5 (,(lambda (limit) @@ -1166,6 +1198,60 @@ when defun is completed, else nil." (goto-char (marker-position def-marker)) (back-to-indentation)))) +(defcustom python-cell-delimiter-regexp "^##" + "Delimiter used for detecting the cell boundaries of code cells/blocks." + :type 'string + :group 'python + :safe 'stringp) + +(defun python-forward-cell (&optional arg) + (interactive "p") + ;; TODO: prefix support + + (if (re-search-forward python-cell-delimiter-regexp nil t) + (progn (end-of-line) + (forward-char 1)) + (goto-char (point-max)))) + +(defun python-backward-cell (&optional arg) + (interactive "p") + ;; TODO: prefix support + + ;; check if it finds a line matched by the delimiter regexp before + ;; the actual point + (and (save-excursion (re-search-backward python-cell-delimiter-regexp + nil t)) + (= (match-beginning 0) (save-excursion + (forward-char -1) (beginning-of-line) (point))) + (goto-char (match-beginning 0))) + + (if (> (point) (point-min)) + (forward-char -1)) + (if (re-search-backward python-cell-delimiter-regexp nil t) + (progn (goto-char (match-end 0)) + (end-of-line) + (forward-char 1)) + (goto-char (point-min)))) + +(defun python-beginning-of-cell (&optional arg) + (interactive "p") + ;; TODO: prefix support + + (if (re-search-backward python-cell-delimiter-regexp nil t) + (progn (goto-char (match-end 0)) + (end-of-line) + (forward-char 1)) + (goto-char (point-min)))) + +(defun python-end-of-cell (&optional arg) + (interactive "p") + ;; TODO: prefix support + + (if (re-search-forward python-cell-delimiter-regexp nil t) + (progn (goto-char (match-beginning 0)) + (forward-char -1)) + (goto-char (point-max)))) + ;;; Shell integration @@ -1594,6 +1680,21 @@ Returns the output. See `python-shell-send-string-no-output'." (let ((deactivate-mark nil)) (python-shell-send-string (buffer-substring start end) nil t))) + +(defun python-shell-send-cell () + "Send the cell the cursor is in to the inferior Python process." + (interactive) + (let ( + (start (save-excursion (python-beginning-of-cell) + (point))) + (end (save-excursion (python-end-of-cell) + (point)))) + ;; (goto-char end) + ;; (push-mark start) + ;; (activate-mark))) + (python-shell-send-region start end))) + + (defun python-shell-send-buffer () "Send the entire buffer to inferior Python process." (interactive) @@ -2781,8 +2882,14 @@ if that value is non-nil." (python-skeleton-add-menu-items) (when python-indent-guess-indent-offset - (python-indent-guess-indent-offset))) - + (python-indent-guess-indent-offset)) + + ;; cell-support for *.py files created with the IPython notebook + (when (save-excursion + (save-match-data + (goto-char (point-min)) + (re-search-forward "^# " nil t))) + (set (make-local-variable 'python-cell-delimiter-regexp) "^# <\\(codecell\\|markdowncell\\)>"))) (provide 'python) ;;; python.el ends here