| Index: third_party/cython/src/Tools/cython-mode.el
|
| diff --git a/third_party/cython/src/Tools/cython-mode.el b/third_party/cython/src/Tools/cython-mode.el
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..5ff6d4a8236f4cbc8504e9bbe06b9d94c876cb7a
|
| --- /dev/null
|
| +++ b/third_party/cython/src/Tools/cython-mode.el
|
| @@ -0,0 +1,268 @@
|
| +;;; cython-mode.el --- Major mode for editing Cython files
|
| +
|
| +;;; 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
|
| + `(;; new keywords in Cython language
|
| + (,(regexp-opt '("by" "cdef" "cimport" "cpdef" "ctypedef" "enum" "except?"
|
| + "extern" "gil" "include" "nogil" "property" "public"
|
| + "readonly" "struct" "union" "DEF" "IF" "ELIF" "ELSE") 'words)
|
| + 1 font-lock-keyword-face)
|
| + ;; C and Python types (highlight as builtins)
|
| + (,(regexp-opt '("NULL" "bint" "char" "dict" "double" "float" "int" "list"
|
| + "long" "object" "Py_ssize_t" "short" "size_t" "void") 'words)
|
| + 1 font-lock-builtin-face)
|
| + ;; cdef is used for more than functions, so simply highlighting the next
|
| + ;; word is problematic. struct, enum and property work though.
|
| + ("\\<\\(?:struct\\|enum\\)[ \t]+\\([a-zA-Z_]+[a-zA-Z0-9_]*\\)"
|
| + 1 py-class-name-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 if
|
| +reached 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}"
|
| + (setcar font-lock-defaults
|
| + (append python-font-lock-keywords 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 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
|
|
|