# HG changeset patch # User Augie Fackler # Date 1261025978 21600 # Node ID 4741c022c7aefec38e171ebae9ec404485a007d3 # Parent 014e745b2d04ccbea2b7109980b2d62a188d9240 python-mode: apply patch from the python-mode list to fix triplequotes. This patch is originally by Andreas Roehler . It was not applied because it works only in GNU Emacs based on list archives. diff --git a/.elisp/python-mode.el b/.elisp/python-mode.el --- a/.elisp/python-mode.el +++ b/.elisp/python-mode.el @@ -9,6 +9,7 @@ ;; Created: Feb 1992 ;; Keywords: python languages oop + (defconst py-version "5.1.0+" "`python-mode' version number.") @@ -385,6 +386,105 @@ subsequent py-up-exception needs the lin started, in order to jump to the correct file line. This variable is set in py-execute-region and used in py-jump-to-exception.") +;; 2009-09-10 a.roehler@web.de changed section start +;; from python.el, version "22.1" + +(defconst python-font-lock-syntactic-keywords + ;; Make outer chars of matching triple-quote sequences into generic + ;; string delimiters. Fixme: Is there a better way? + ;; First avoid a sequence preceded by an odd number of backslashes. + `((,(rx (not (any ?\\)) + ?\\ (* (and ?\\ ?\\)) + (group (syntax string-quote)) + (backref 1) + (group (backref 1))) + (2 ,(string-to-syntax "\""))) ; dummy + (,(rx (group (optional (any "uUrR"))) ; prefix gets syntax property + (optional (any "rR")) ; possible second prefix + (group (syntax string-quote)) ; maybe gets property + (backref 2) ; per first quote + (group (backref 2))) ; maybe gets property + (1 (python-quote-syntax 1)) + (2 (python-quote-syntax 2)) + (3 (python-quote-syntax 3))) + ;; This doesn't really help. +;;; (,(rx (and ?\\ (group ?\n))) (1 " ")) + )) + +(defun python-quote-syntax (n) + "Put `syntax-table' property correctly on triple quote. +Used for syntactic keywords. N is the match number (1, 2 or 3)." + ;; Given a triple quote, we have to check the context to know + ;; whether this is an opening or closing triple or whether it's + ;; quoted anyhow, and should be ignored. (For that we need to do + ;; the same job as `syntax-ppss' to be correct and it seems to be OK + ;; to use it here despite initial worries.) We also have to sort + ;; out a possible prefix -- well, we don't _have_ to, but I think it + ;; should be treated as part of the string. + + ;; Test cases: + ;; ur"""ar""" x='"' # """ + ;; x = ''' """ ' a + ;; ''' + ;; x '"""' x """ \"""" x + (save-excursion + (goto-char (match-beginning 0)) + (cond + ;; Consider property for the last char if in a fenced string. + ((= n 3) + (let* ((font-lock-syntactic-keywords nil) + (syntax (syntax-ppss))) + (when (eq t (nth 3 syntax)) ; after unclosed fence + (goto-char (nth 8 syntax)) ; fence position + (skip-chars-forward "uUrR") ; skip any prefix + ;; Is it a matching sequence? + (if (eq (char-after) (char-after (match-beginning 2))) + (eval-when-compile (string-to-syntax "|")))))) + ;; Consider property for initial char, accounting for prefixes. + ((or (and (= n 2) ; leading quote (not prefix) + (= (match-beginning 1) (match-end 1))) ; prefix is null + (and (= n 1) ; prefix + (/= (match-beginning 1) (match-end 1)))) ; non-empty + (let ((font-lock-syntactic-keywords nil)) + (unless (eq 'string (syntax-ppss-context (syntax-ppss))) + (eval-when-compile (string-to-syntax "|"))))) + ;; Otherwise (we're in a non-matching string) the property is + ;; nil, which is OK. + ))) + + +(defvar py-mode-syntax-table + (let ((table (make-syntax-table))) + ;; Give punctuation syntax to ASCII that normally has symbol + ;; syntax or has word syntax and isn't a letter. + (let ((symbol (string-to-syntax "_")) + (sst (standard-syntax-table))) + (dotimes (i 128) + (unless (= i ?_) + (if (equal symbol (aref sst i)) + (modify-syntax-entry i "." table))))) + (modify-syntax-entry ?$ "." table) + (modify-syntax-entry ?% "." table) + ;; exceptions + (modify-syntax-entry ?# "<" table) + (modify-syntax-entry ?\n ">" table) + (modify-syntax-entry ?' "\"" table) + (modify-syntax-entry ?` "$" table) + table)) + +(defsubst python-in-string/comment () + "Return non-nil if point is in a Python literal (a comment or string)." + ;; We don't need to save the match data. + (nth 8 (syntax-ppss))) + +(defconst python-space-backslash-table + (let ((table (copy-syntax-table py-mode-syntax-table))) + (modify-syntax-entry ?\\ " " table) + table) + "`python-mode-syntax-table' with backslash given whitespace syntax.") + +;; 2009-09-10 a.roehler@web.de changed section end + (defconst py-emacs-features (let (features) features) @@ -505,7 +605,6 @@ support for features needed by `python-m '("XXX\\|TODO\\|FIXME" 0 py-XXX-tag-face t) )) "Additional expressions to highlight in Python mode.") -(put 'python-mode 'font-lock-defaults '(python-font-lock-keywords)) ;; have to bind py-file-queue before installing the kill-emacs-hook (defvar py-file-queue nil @@ -727,48 +826,53 @@ Currently-active file is at the head of (define-key py-shell-map "\C-c=" 'py-down-exception) ) -(defvar py-mode-syntax-table nil - "Syntax table used in `python-mode' buffers.") -(when (not py-mode-syntax-table) - (setq py-mode-syntax-table (make-syntax-table)) - (modify-syntax-entry ?\( "()" py-mode-syntax-table) - (modify-syntax-entry ?\) ")(" py-mode-syntax-table) - (modify-syntax-entry ?\[ "(]" py-mode-syntax-table) - (modify-syntax-entry ?\] ")[" py-mode-syntax-table) - (modify-syntax-entry ?\{ "(}" py-mode-syntax-table) - (modify-syntax-entry ?\} "){" py-mode-syntax-table) - ;; Add operator symbols misassigned in the std table - (modify-syntax-entry ?\$ "." py-mode-syntax-table) - (modify-syntax-entry ?\% "." py-mode-syntax-table) - (modify-syntax-entry ?\& "." py-mode-syntax-table) - (modify-syntax-entry ?\* "." py-mode-syntax-table) - (modify-syntax-entry ?\+ "." py-mode-syntax-table) - (modify-syntax-entry ?\- "." py-mode-syntax-table) - (modify-syntax-entry ?\/ "." py-mode-syntax-table) - (modify-syntax-entry ?\< "." py-mode-syntax-table) - (modify-syntax-entry ?\= "." py-mode-syntax-table) - (modify-syntax-entry ?\> "." py-mode-syntax-table) - (modify-syntax-entry ?\| "." py-mode-syntax-table) - ;; For historical reasons, underscore is word class instead of - ;; symbol class. GNU conventions say it should be symbol class, but - ;; there's a natural conflict between what major mode authors want - ;; and what users expect from `forward-word' and `backward-word'. - ;; Guido and I have hashed this out and have decided to keep - ;; underscore in word class. If you're tempted to change it, try - ;; binding M-f and M-b to py-forward-into-nomenclature and - ;; py-backward-into-nomenclature instead. This doesn't help in all - ;; situations where you'd want the different behavior - ;; (e.g. backward-kill-word). - (modify-syntax-entry ?\_ "w" py-mode-syntax-table) - ;; Both single quote and double quote are string delimiters - (modify-syntax-entry ?\' "\"" py-mode-syntax-table) - (modify-syntax-entry ?\" "\"" py-mode-syntax-table) - ;; backquote is open and close paren - (modify-syntax-entry ?\` "$" py-mode-syntax-table) - ;; comment delimiters - (modify-syntax-entry ?\# "<" py-mode-syntax-table) - (modify-syntax-entry ?\n ">" py-mode-syntax-table) - ) +;; 2009-09-09 a.roehler@web.de changed section start +;; from python.el, version "22.1" + +;; (defvar py-mode-syntax-table nil + ;; "Syntax table used in `python-mode' buffers.") +;; (when (not py-mode-syntax-table) +;; (setq py-mode-syntax-table (make-syntax-table)) +;; (modify-syntax-entry ?\( "()" py-mode-syntax-table) +;; (modify-syntax-entry ?\) ")(" py-mode-syntax-table) +;; (modify-syntax-entry ?\[ "(]" py-mode-syntax-table) +;; (modify-syntax-entry ?\] ")[" py-mode-syntax-table) +;; (modify-syntax-entry ?\{ "(}" py-mode-syntax-table) +;; (modify-syntax-entry ?\} "){" py-mode-syntax-table) +;; ;; Add operator symbols misassigned in the std table +;; (modify-syntax-entry ?\$ "." py-mode-syntax-table) +;; (modify-syntax-entry ?\% "." py-mode-syntax-table) +;; (modify-syntax-entry ?\& "." py-mode-syntax-table) +;; (modify-syntax-entry ?\* "." py-mode-syntax-table) +;; (modify-syntax-entry ?\+ "." py-mode-syntax-table) +;; (modify-syntax-entry ?\- "." py-mode-syntax-table) +;; (modify-syntax-entry ?\/ "." py-mode-syntax-table) +;; (modify-syntax-entry ?\< "." py-mode-syntax-table) +;; (modify-syntax-entry ?\= "." py-mode-syntax-table) +;; (modify-syntax-entry ?\> "." py-mode-syntax-table) +;; (modify-syntax-entry ?\| "." py-mode-syntax-table) +;; ;; For historical reasons, underscore is word class instead of +;; ;; symbol class. GNU conventions say it should be symbol class, but +;; ;; there's a natural conflict between what major mode authors want +;; ;; and what users expect from `forward-word' and `backward-word'. +;; ;; Guido and I have hashed this out and have decided to keep +;; ;; underscore in word class. If you're tempted to change it, try +;; ;; binding M-f and M-b to py-forward-into-nomenclature and +;; ;; py-backward-into-nomenclature instead. This doesn't help in all +;; ;; situations where you'd want the different behavior +;; ;; (e.g. backward-kill-word). +;; (modify-syntax-entry ?\_ "w" py-mode-syntax-table) +;; ;; Both single quote and double quote are string delimiters +;; (modify-syntax-entry ?\' "\"" py-mode-syntax-table) +;; (modify-syntax-entry ?\" "\"" py-mode-syntax-table) +;; ;; backquote is open and close paren +;; (modify-syntax-entry ?\` "$" py-mode-syntax-table) +;; ;; comment delimiters +;; (modify-syntax-entry ?\# "<" py-mode-syntax-table) +;; (modify-syntax-entry ?\n ">" py-mode-syntax-table) +;; +;; ) +;; 2009-09-09 a.roehler@web.de changed section end ;; An auxiliary syntax table which places underscore and dot in the ;; symbol class for simplicity @@ -1161,14 +1265,11 @@ To submit a problem report, enter `\\[py `python-mode' buffer. Do `\\[py-describe-mode]' for detailed documentation. To see what version of `python-mode' you are running, enter `\\[py-version]'. - This mode knows about Python indentation, tokens, comments and continuation lines. Paragraphs are separated by blank lines only. - COMMANDS \\{py-mode-map} VARIABLES - py-indent-offset\t\tindentation increment py-block-comment-prefix\t\tcomment string used by `comment-region' py-python-command\t\tshell command to invoke Python interpreter @@ -1177,7 +1278,7 @@ py-beep-if-tab-change\t\tring the bell i (interactive) ;; set up local variables (kill-all-local-variables) - (make-local-variable 'font-lock-defaults) + ;; (make-local-variable 'font-lock-defaults) (make-local-variable 'paragraph-separate) (make-local-variable 'paragraph-start) (make-local-variable 'require-final-newline) @@ -1192,25 +1293,32 @@ py-beep-if-tab-change\t\tring the bell i (make-local-variable 'fill-paragraph-function) ;; (set-syntax-table py-mode-syntax-table) - (setq major-mode 'python-mode - mode-name "Python" - local-abbrev-table python-mode-abbrev-table - font-lock-defaults '(python-font-lock-keywords) - paragraph-separate "^[ \t]*$" - paragraph-start "^[ \t]*$" - require-final-newline t - comment-start "# " - comment-end "" - comment-start-skip "# *" - comment-column 40 + ;; 2009-09-10 a.roehler@web.de changed section start + ;; from python.el, version "22.1" + (set (make-local-variable 'font-lock-defaults) + '(python-font-lock-keywords nil nil nil nil + (font-lock-syntactic-keywords + . python-font-lock-syntactic-keywords))) + ;; 2009-09-10 a.roehler@web.de changed section end + (setq major-mode 'python-mode + mode-name "Python" + local-abbrev-table python-mode-abbrev-table + ;; 2009-09-10 a.roehler@web.de changed section start + ;; font-lock-defaults ... + ;; 2009-09-10 a.roehler@web.de changed section end + paragraph-separate "^[ \t]*$" + paragraph-start "^[ \t]*$" + require-final-newline t + comment-start "# " + comment-end "" + comment-start-skip "# *" + comment-column 40 comment-indent-function 'py-comment-indent-function - indent-region-function 'py-indent-region - indent-line-function 'py-indent-line + indent-region-function 'py-indent-region + indent-line-function 'py-indent-line ;; tell add-log.el how to find the current function/method/variable add-log-current-defun-function 'py-current-defun - - fill-paragraph-function 'py-fill-paragraph - ) + fill-paragraph-function 'py-fill-paragraph) (use-local-map py-mode-map) ;; add the menu (if py-menu @@ -1223,27 +1331,25 @@ py-beep-if-tab-change\t\tring the bell i (setq imenu-create-index-function #'py-imenu-create-index-function) (setq imenu-generic-expression py-imenu-generic-expression) (if (fboundp 'imenu-add-to-menubar) - (imenu-add-to-menubar (format "%s-%s" "IM" mode-name))) - ) + (imenu-add-to-menubar (format "%s-%s" "IM" mode-name)))) ;; Run the mode hook. Note that py-mode-hook is deprecated. (if python-mode-hook (run-hooks 'python-mode-hook) (run-hooks 'py-mode-hook)) ;; Now do the automagical guessing (if py-smart-indentation - (let ((offset py-indent-offset)) - ;; It's okay if this fails to guess a good value - (if (and (py-safe (py-guess-indent-offset)) - (<= py-indent-offset 8) - (>= py-indent-offset 2)) - (setq offset py-indent-offset)) - (setq py-indent-offset offset) - ;; Only turn indent-tabs-mode off if tab-width != - ;; py-indent-offset. Never turn it on, because the user must - ;; have explicitly turned it off. - (if (/= tab-width py-indent-offset) - (setq indent-tabs-mode nil)) - )) + (let ((offset py-indent-offset)) + ;; It's okay if this fails to guess a good value + (if (and (py-safe (py-guess-indent-offset)) + (<= py-indent-offset 8) + (>= py-indent-offset 2)) + (setq offset py-indent-offset)) + (setq py-indent-offset offset) + ;; Only turn indent-tabs-mode off if tab-width != + ;; py-indent-offset. Never turn it on, because the user must + ;; have explicitly turned it off. + (if (/= tab-width py-indent-offset) + (setq indent-tabs-mode nil)))) ;; Set the default shell if not already set (when (null py-which-shell) (py-toggle-shells (py-choose-shell))))