diff .elisp/python-mode.el @ 175:4741c022c7ae

python-mode: apply patch from the python-mode list to fix triplequotes. This patch is originally by Andreas Roehler <andreas.roehler at online.de>. It was not applied because it works only in GNU Emacs based on list archives.
author Augie Fackler <durin42@gmail.com>
date Wed, 16 Dec 2009 22:59:38 -0600
parents 014e745b2d04
children
line wrap: on
line diff
--- 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))))