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.
|
|
;;; cython-mode.el --- Major mode for editing Cython files;; Package-Version: 0.29.23;; Package-Commit: 17670781083e3ccfedb1af4adcec614d4599eef9
;; License: Apache-2.0
;;; Commentary:
;; This should work with python-mode.el as well as either the new;; python.el or the old.
;;; Code:
;; Load python-mode if available, otherwise use builtin emacs python package(when (not (require 'python-mode nil t)) (require 'python))(eval-when-compile (require 'rx))
;;;###autoload(add-to-list 'auto-mode-alist '("\\.pyx\\'" . cython-mode));;;###autoload(add-to-list 'auto-mode-alist '("\\.pxd\\'" . cython-mode));;;###autoload(add-to-list 'auto-mode-alist '("\\.pxi\\'" . cython-mode))
(defvar cython-buffer nil "Variable pointing to the cython buffer which was compiled.")
(defun cython-compile () "Compile the file via Cython." (interactive) (let ((cy-buffer (current-buffer))) (with-current-buffer (compile compile-command) (set (make-local-variable 'cython-buffer) cy-buffer) (add-to-list (make-local-variable 'compilation-finish-functions) 'cython-compilation-finish))))
(defun cython-compilation-finish (buffer how) "Called when Cython compilation finishes." ;; XXX could annotate source here )
(defvar cython-mode-map (let ((map (make-sparse-keymap))) ;; Will inherit from `python-mode-map' thanks to define-derived-mode. (define-key map "\C-c\C-c" 'cython-compile) map) "Keymap used in `cython-mode'.")
(defvar cython-font-lock-keywords `(;; ctypedef statement: "ctypedef (...type... alias)?" (,(rx ;; keyword itself symbol-start (group "ctypedef") ;; type specifier: at least 1 non-identifier symbol + 1 identifier ;; symbol and anything but a comment-starter after that. (opt (regexp "[^a-zA-Z0-9_\n]+[a-zA-Z0-9_][^#\n]*") ;; type alias: an identifier symbol-start (group (regexp "[a-zA-Z_]+[a-zA-Z0-9_]*")) ;; space-or-comments till the end of the line (* space) (opt "#" (* nonl)) line-end)) (1 font-lock-keyword-face) (2 font-lock-type-face nil 'noerror)) ;; new keywords in Cython language (,(rx symbol-start (or "by" "cdef" "cimport" "cpdef" "extern" "gil" "include" "nogil" "property" "public" "readonly" "DEF" "IF" "ELIF" "ELSE" "new" "del" "cppclass" "namespace" "const" "__stdcall" "__cdecl" "__fastcall" "inline" "api") symbol-end) . font-lock-keyword-face) ;; Question mark won't match at a symbol-end, so 'except?' must be ;; special-cased. It's simpler to handle it separately than weaving it ;; into the lengthy list of other keywords. (,(rx symbol-start "except?") . font-lock-keyword-face) ;; C and Python types (highlight as builtins) (,(rx symbol-start (or "object" "dict" "list" ;; basic c type names "void" "char" "int" "float" "double" "bint" ;; longness/signed/constness "signed" "unsigned" "long" "short" ;; special basic c types "size_t" "Py_ssize_t" "Py_UNICODE" "Py_UCS4" "ssize_t" "ptrdiff_t") symbol-end) . font-lock-builtin-face) (,(rx symbol-start "NULL" symbol-end) . font-lock-constant-face) ;; cdef is used for more than functions, so simply highlighting the next ;; word is problematic. struct, enum and property work though. (,(rx symbol-start (group (or "struct" "enum" "union" (seq "ctypedef" (+ space "fused")))) (+ space) (group (regexp "[a-zA-Z_]+[a-zA-Z0-9_]*"))) (1 font-lock-keyword-face prepend) (2 font-lock-type-face)) ("\\_<property[ \t]+\\([a-zA-Z_]+[a-zA-Z0-9_]*\\)" 1 font-lock-function-name-face)) "Additional font lock keywords for Cython mode.")
;;;###autoload(defgroup cython nil "Major mode for editing and compiling Cython files" :group 'languages :prefix "cython-" :link '(url-link :tag "Homepage" "http://cython.org"))
;;;###autoload(defcustom cython-default-compile-format "cython -a %s" "Format for the default command to compile a Cython file.
It will be passed to `format' with `buffer-file-name' as the only other argument."
:group 'cython :type 'string)
;; Some functions defined differently in the different python modes(defun cython-comment-line-p () "Return non-nil if current line is a comment." (save-excursion (back-to-indentation) (eq ?# (char-after (point)))))
(defun cython-in-string/comment () "Return non-nil if point is in a comment or string." (nth 8 (syntax-ppss)))
(defalias 'cython-beginning-of-statement (cond ;; python-mode.el ((fboundp 'py-beginning-of-statement) 'py-beginning-of-statement) ;; old python.el ((fboundp 'python-beginning-of-statement) 'python-beginning-of-statement) ;; new python.el ((fboundp 'python-nav-beginning-of-statement) 'python-nav-beginning-of-statement) (t (error "Couldn't find implementation for `cython-beginning-of-statement'"))))
(defalias 'cython-beginning-of-block (cond ;; python-mode.el ((fboundp 'py-beginning-of-block) 'py-beginning-of-block) ;; old python.el ((fboundp 'python-beginning-of-block) 'python-beginning-of-block) ;; new python.el ((fboundp 'python-nav-beginning-of-block) 'python-nav-beginning-of-block) (t (error "Couldn't find implementation for `cython-beginning-of-block'"))))
(defalias 'cython-end-of-statement (cond ;; python-mode.el ((fboundp 'py-end-of-statement) 'py-end-of-statement) ;; old python.el ((fboundp 'python-end-of-statement) 'python-end-of-statement) ;; new python.el ((fboundp 'python-nav-end-of-statement) 'python-nav-end-of-statement) (t (error "Couldn't find implementation for `cython-end-of-statement'"))))
(defun cython-open-block-statement-p (&optional bos) "Return non-nil if statement at point opens a Cython block.
BOS non-nil means point is known to be at beginning of statement."
(save-excursion (unless bos (cython-beginning-of-statement)) (looking-at (rx (and (or "if" "else" "elif" "while" "for" "def" "cdef" "cpdef" "class" "try" "except" "finally" "with" "EXAMPLES:" "TESTS:" "INPUT:" "OUTPUT:") symbol-end)))))
(defun cython-beginning-of-defun () "`beginning-of-defun-function' for Cython.
Finds beginning of innermost nested class or method definition.Returns the name of the definition found at the end, or nil ifreached start of buffer."
(let ((ci (current-indentation)) (def-re (rx line-start (0+ space) (or "def" "cdef" "cpdef" "class") (1+ space) (group (1+ (or word (syntax symbol)))))) found lep) ;; def-line (if (cython-comment-line-p) (setq ci most-positive-fixnum)) (while (and (not (bobp)) (not found)) ;; Treat bol at beginning of function as outside function so ;; that successive C-M-a makes progress backwards. ;;(setq def-line (looking-at def-re)) (unless (bolp) (end-of-line)) (setq lep (line-end-position)) (if (and (re-search-backward def-re nil 'move) ;; Must be less indented or matching top level, or ;; equally indented if we started on a definition line. (let ((in (current-indentation))) (or (and (zerop ci) (zerop in)) (= lep (line-end-position)) ; on initial line ;; Not sure why it was like this -- fails in case of ;; last internal function followed by first ;; non-def statement of the main body. ;;(and def-line (= in ci)) (= in ci) (< in ci))) (not (cython-in-string/comment))) (setq found t)))))
(defun cython-end-of-defun () "`end-of-defun-function' for Cython.
Finds end of innermost nested class or method definition."
(let ((orig (point)) (pattern (rx line-start (0+ space) (or "def" "cdef" "cpdef" "class") space))) ;; Go to start of current block and check whether it's at top ;; level. If it is, and not a block start, look forward for ;; definition statement. (when (cython-comment-line-p) (end-of-line) (forward-comment most-positive-fixnum)) (when (not (cython-open-block-statement-p)) (cython-beginning-of-block)) (if (zerop (current-indentation)) (unless (cython-open-block-statement-p) (while (and (re-search-forward pattern nil 'move) (cython-in-string/comment))) ; just loop (unless (eobp) (beginning-of-line))) ;; Don't move before top-level statement that would end defun. (end-of-line) (beginning-of-defun)) ;; If we got to the start of buffer, look forward for ;; definition statement. (when (and (bobp) (not (looking-at (rx (or "def" "cdef" "cpdef" "class"))))) (while (and (not (eobp)) (re-search-forward pattern nil 'move) (cython-in-string/comment)))) ; just loop ;; We're at a definition statement (or end-of-buffer). ;; This is where we should have started when called from end-of-defun (unless (eobp) (let ((block-indentation (current-indentation))) (python-nav-end-of-statement) (while (and (forward-line 1) (not (eobp)) (or (and (> (current-indentation) block-indentation) (or (cython-end-of-statement) t)) ;; comment or empty line (looking-at (rx (0+ space) (or eol "#")))))) (forward-comment -1)) ;; Count trailing space in defun (but not trailing comments). (skip-syntax-forward " >") (unless (eobp) ; e.g. missing final newline (beginning-of-line))) ;; Catch pathological cases like this, where the beginning-of-defun ;; skips to a definition we're not in: ;; if ...: ;; ... ;; else: ;; ... # point here ;; ... ;; def ... (if (< (point) orig) (goto-char (point-max)))))
(defun cython-current-defun () "`add-log-current-defun-function' for Cython." (save-excursion ;; Move up the tree of nested `class' and `def' blocks until we ;; get to zero indentation, accumulating the defined names. (let ((start t) accum) (while (or start (> (current-indentation) 0)) (setq start nil) (cython-beginning-of-block) (end-of-line) (beginning-of-defun) (if (looking-at (rx (0+ space) (or "def" "cdef" "cpdef" "class") (1+ space) (group (1+ (or word (syntax symbol)))))) (push (match-string 1) accum))) (if accum (mapconcat 'identity accum ".")))))
;;;###autoload(define-derived-mode cython-mode python-mode "Cython" "Major mode for Cython development, derived from Python mode.
\\{cython-mode-map}"
(font-lock-add-keywords nil cython-font-lock-keywords) (set (make-local-variable 'outline-regexp) (rx (* space) (or "class" "def" "cdef" "cpdef" "elif" "else" "except" "finally" "for" "if" "try" "while" "with") symbol-end)) (set (make-local-variable 'beginning-of-defun-function) #'cython-beginning-of-defun) (set (make-local-variable 'end-of-defun-function) #'cython-end-of-defun) (set (make-local-variable 'compile-command) (format cython-default-compile-format (shell-quote-argument (or buffer-file-name "")))) (set (make-local-variable 'add-log-current-defun-function) #'cython-current-defun) (add-hook 'which-func-functions #'cython-current-defun nil t) (add-to-list (make-local-variable 'compilation-finish-functions) 'cython-compilation-finish))
(provide 'cython-mode)
;;; cython-mode.el ends here
|