diff options
Diffstat (limited to 'lisp/progmodes')
| -rw-r--r-- | lisp/progmodes/asm-mode.el | 2 | ||||
| -rw-r--r-- | lisp/progmodes/cc-guess.el | 3 | ||||
| -rw-r--r-- | lisp/progmodes/hideif.el | 630 | ||||
| -rw-r--r-- | lisp/progmodes/idlw-shell.el | 41 | ||||
| -rw-r--r-- | lisp/progmodes/python.el | 16 | ||||
| -rw-r--r-- | lisp/progmodes/ruby-mode.el | 2 | ||||
| -rw-r--r-- | lisp/progmodes/sh-script.el | 87 | 
7 files changed, 681 insertions, 100 deletions
| diff --git a/lisp/progmodes/asm-mode.el b/lisp/progmodes/asm-mode.el index ab7612082d5..3532b4a03f1 100644 --- a/lisp/progmodes/asm-mode.el +++ b/lisp/progmodes/asm-mode.el @@ -172,7 +172,7 @@ Special commands:     ;; Simple `;' comments go to the comment-column.     (and (looking-at "\\s<\\(\\S<\\|\\'\\)") comment-column)     ;; The rest goes at the first tab stop. -   (or (car tab-stop-list) tab-width))) +   (or (indent-next-tab-stop 0))))  (defun asm-colon ()    "Insert a colon; if it follows a label, delete the label's indentation." diff --git a/lisp/progmodes/cc-guess.el b/lisp/progmodes/cc-guess.el index abde007cd04..5424e8d4a61 100644 --- a/lisp/progmodes/cc-guess.el +++ b/lisp/progmodes/cc-guess.el @@ -504,8 +504,7 @@ is called with one argument, the guessed style."  		      (cond  		       ((or (and a-guessed? b-guessed?)  			    (not (or a-guessed? b-guessed?))) -			(string-lessp (symbol-name (car a)) -				      (symbol-name (car b)))) +			(string-lessp (car a) (car b)))  		       (a-guessed? t)  		       (b-guessed? nil)))))))    style) diff --git a/lisp/progmodes/hideif.el b/lisp/progmodes/hideif.el index bcb46592465..4b78c08690a 100644 --- a/lisp/progmodes/hideif.el +++ b/lisp/progmodes/hideif.el @@ -36,6 +36,8 @@  ;;  ;; Hide-ifdef suppresses the display of code that the preprocessor wouldn't  ;; pass through.  Support complete C/C++ expression and precedence. +;; It will automatically scan for new #define symbols and macros on the way +;; parsing.  ;;  ;; The hidden code is marked by ellipses (...).  Be  ;; cautious when editing near ellipses, since the hidden text is @@ -97,11 +99,12 @@  ;; Extensively modified by Daniel LaLiberte (while at Gould).  ;;  ;; Extensively modified by Luke Lee in 2013 to support complete C expression -;; evaluation. +;; evaluation and argumented macro expansion.  ;;; Code:  (require 'cc-mode) +(require 'cl-lib)  (defgroup hide-ifdef nil    "Hide selected code within `ifdef'." @@ -133,6 +136,9 @@    :group 'hide-ifdef    :version "23.1") +(defcustom hide-ifdef-exclude-define-regexp nil +  "Ignore #define names if those names match this exclusion pattern." +  :type 'string)  (defvar hide-ifdef-mode-submap    ;; Set up the submap that goes after the prefix key. @@ -198,7 +204,7 @@            (cons '(hide-ifdef-hiding " Hiding")                  minor-mode-alist))) -;; fix c-mode syntax table so we can recognize whole symbols. +;; Fix c-mode syntax table so we can recognize whole symbols.  (defvar hide-ifdef-syntax-table    (let ((st (copy-syntax-table c-mode-syntax-table)))      (modify-syntax-entry ?_ "w" st) @@ -327,7 +333,7 @@ that form should be displayed.")  (defun hif-set-var (var value) -  "Prepend (var value) pair to `hide-ifdef-env'." +  "Prepend (VAR VALUE) pair to `hide-ifdef-env'."    (setq hide-ifdef-env (cons (cons var value) hide-ifdef-env)))  (declare-function semantic-c-hideif-lookup  "semantic/bovine/c" (var)) @@ -356,15 +362,35 @@ that form should be displayed.")  ;;;  The code that understands what ifs and ifdef in files look like.  (defconst hif-cpp-prefix "\\(^\\|\r\\)[ \t]*#[ \t]*") +(defconst hif-ifxdef-regexp (concat hif-cpp-prefix "if\\(n\\)?def"))  (defconst hif-ifndef-regexp (concat hif-cpp-prefix "ifndef"))  (defconst hif-ifx-regexp (concat hif-cpp-prefix "if\\(n?def\\)?[ \t]+")) +(defconst hif-elif-regexp   (concat hif-cpp-prefix "elif"))  (defconst hif-else-regexp (concat hif-cpp-prefix "else"))  (defconst hif-endif-regexp (concat hif-cpp-prefix "endif"))  (defconst hif-ifx-else-endif-regexp -  (concat hif-ifx-regexp "\\|" hif-else-regexp "\\|" hif-endif-regexp)) - -;; Used to store the current token and the whole token list during parsing. -;; Only bound dynamically. +  (concat hif-ifx-regexp "\\|" hif-elif-regexp "\\|" hif-else-regexp "\\|" +          hif-endif-regexp)) +(defconst hif-macro-expr-prefix-regexp +  (concat hif-cpp-prefix "\\(if\\(n?def\\)?\\|elif\\|define\\)[ \t]+")) + +(defconst hif-white-regexp         "[ \t]*") +(defconst hif-define-regexp +  (concat hif-cpp-prefix "\\(define\\|undef\\)")) +(defconst hif-id-regexp +  (concat "[[:alpha:]_][[:alnum:]_]*")) +(defconst hif-macroref-regexp +  (concat hif-white-regexp "\\(" hif-id-regexp "\\)" hif-white-regexp +          "\\(" +          "(" hif-white-regexp +          "\\(" hif-id-regexp "\\)?" hif-white-regexp +          "\\(" "," hif-white-regexp hif-id-regexp hif-white-regexp "\\)*" +          "\\(\\.\\.\\.\\)?" hif-white-regexp +          ")" +          "\\)?" )) + +;; Store the current token and the whole token list during parsing. +;; Bound dynamically.  (defvar hif-token)  (defvar hif-token-list) @@ -397,7 +423,12 @@ that form should be displayed.")      ("/"   . hif-divide)      ("%"   . hif-modulo)      ("?"  . hif-conditional) -    (":"  . hif-colon))) +    (":"   . hif-colon) +    (","   . hif-comma) +    ("#"   . hif-stringify) +    ("..." . hif-etc))) + +(defconst hif-valid-token-list (mapcar 'cdr hif-token-alist))  (defconst hif-token-regexp    (concat (regexp-opt (mapcar 'car hif-token-alist)) @@ -412,13 +443,25 @@ that form should be displayed.")    (if (or (not base) (= base 10))        (string-to-number string base)      (let* ((parts (split-string string "\\." t "[ \t]+")) -	   (frac (cadr parts)) -	   (quot (expt (* base 1.0) (length frac)))) +           (frac (cadr parts)) +           (fraclen (length frac)) +           (quot (expt (if (zerop fraclen) +                           base +                           (* base 1.0)) fraclen)))        (/ (string-to-number (concat (car parts) frac) base) quot)))) +;; The dynamic binding variable `hif-simple-token-only' is shared only by +;; `hif-tokenize' and `hif-find-define'. The purpose is to prevent `hif-tokenize' +;; from returning one more value to indicate a simple token is scanned. This help +;; speeding up macro evaluation on those very simple cases like integers or +;; literals. +;; Check the long comments before `hif-find-define' for more details. [lukelee] +(defvar hif-simple-token-only) +  (defun hif-tokenize (start end)    "Separate string between START and END into a list of tokens."    (let ((token-list nil)) +    (setq hif-simple-token-only t)      (with-syntax-table hide-ifdef-syntax-table        (save-excursion  	(goto-char start) @@ -431,8 +474,10 @@ that form should be displayed.")             ((looking-at hif-string-literal-regexp)              (push (substring-no-properties (match-string 1)) token-list)              (goto-char (match-end 0))) +  	   ((looking-at hif-token-regexp) -	    (let ((token (buffer-substring (point) (match-end 0)))) +            (let ((token (buffer-substring-no-properties +                          (point) (match-end 0))))  	      (goto-char (match-end 0))  	      ;; (message "token: %s" token) (sit-for 1)  	      (push @@ -440,7 +485,7 @@ that form should be displayed.")                     (if (string-equal token "defined") 'hif-defined)                     ;; TODO:                     ;; 1. postfix 'l', 'll', 'ul' and 'ull' -                   ;; 2. floating number formats +                   ;; 2. floating number formats (like 1.23e4)                     ;; 3. 098 is interpreted as octal conversion error                     (if (string-match "0x\\([0-9a-fA-F]+\\.?[0-9a-fA-F]*\\)"                                       token) @@ -450,9 +495,12 @@ that form should be displayed.")                     (if (string-match "\\`[1-9][0-9]*\\(\\.[0-9]+\\)?\\'"                                       token)                         (string-to-number token)) ;; decimal -                   (intern token)) +                   (prog1 (intern token) +                     (setq hif-simple-token-only nil)))                 token-list))) +  	   (t (error "Bad #if expression: %s" (buffer-string))))))) +      (nreverse token-list)))  ;;------------------------------------------------------------------------ @@ -487,9 +535,117 @@ that form should be displayed.")    "Pop the next token from token-list into the let variable `hif-token'."    (setq hif-token (pop hif-token-list))) -(defun hif-parse-if-exp (token-list) -  "Parse the TOKEN-LIST.  Return translated list in prefix form." -  (let ((hif-token-list token-list)) +(defsubst hif-if-valid-identifier-p (id) +  (not (or (numberp id) +           (stringp id)))) + +(defun hif-define-operator (tokens) +  "`Upgrade' hif-define xxx to '(hif-define xxx)' so it won't be subsitituted." +  (let ((result nil) +        (tok nil)) +    (while (setq tok (pop tokens)) +      (push +       (if (eq tok 'hif-defined) +           (progn +             (setq tok (cadr tokens)) +             (if (eq (car tokens) 'hif-lparen) +                 (if (and (hif-if-valid-identifier-p tok) +                          (eq (caddr tokens) 'hif-rparen)) +                     (setq tokens (cdddr tokens)) +                   (error "#define followed by non-identifier: %S" tok)) +               (setq tok (car tokens) +                     tokens (cdr tokens)) +               (unless (hif-if-valid-identifier-p tok) +                 (error "#define followed by non-identifier: %S" tok))) +             (list 'hif-defined 'hif-lparen tok 'hif-rparen)) +         tok) +       result)) +    (nreverse result))) + +(defun hif-flatten (l) +  "Flatten a tree." +  (apply #'nconc +         (mapcar (lambda (x) (if (listp x) +                                 (hif-flatten x) +                               (list x))) l))) + +(defun hif-expand-token-list (tokens &optional macroname expand_list) +  "Perform expansion on TOKENS till everything expanded. +Self-reference (directly or indirectly) tokens are not expanded. +EXPAND_LIST is the list of macro names currently being expanded, use for +detecting self-reference." +  (catch 'self-referencing +    (let ((expanded nil) +          (remains (hif-define-operator +                    (hif-token-concatenation +                     (hif-token-stringification tokens)))) +          tok rep) +      (if macroname +          (setq expand_list (cons macroname expand_list))) +      ;; Expanding all tokens till list exhausted +      (while (setq tok (pop remains)) +        (if (memq tok expand_list) +            ;; For self-referencing tokens, don't expand it +            (throw 'self-referencing tokens)) +        (push +         (cond +          ((or (memq tok hif-valid-token-list) +               (numberp tok) +               (stringp tok)) +           tok) + +          ((setq rep (hif-lookup tok)) +           (if (and (listp rep) +                    (eq (car rep) 'hif-define-macro)) ; A defined macro +               ;; Recursively expand it +               (if (cadr rep) ; Argument list is not nil +                   (if (not (eq (car remains) 'hif-lparen)) +                       ;; No argument, no invocation +                       tok +                     ;; Argumented macro, get arguments and invoke it. +                     ;; Dynamically bind hif-token-list and hif-token +                     ;; for hif-macro-supply-arguments +                     (let* ((hif-token-list (cdr remains)) +                            (hif-token nil) +                            (parmlist (mapcar 'hif-expand-token-list +                                              (hif-get-argument-list +                                               tok))) +                            (result +                             (hif-expand-token-list +                              (hif-macro-supply-arguments tok parmlist) +                              tok expand_list))) +                       (setq remains (cons hif-token hif-token-list)) +                       result)) +                 ;; Argument list is nil, direct expansion +                 (setq rep (hif-expand-token-list +                            (caddr rep) ; Macro's token list +                            tok expand_list)) +                 ;; Replace all remaining references immediately +                 (setq remains (substitute tok rep remains)) +                 rep) +             ;; Lookup tok returns an atom +             rep)) + +          ;;[2013-10-22 16:06:12 +0800] Must keep the token, removing +          ;; this token might results in an incomplete expression that +          ;; cannot be parsed further. +          ;;((= 1 (hif-defined tok)) ; defined (hif-defined tok)=1, +          ;;  ;;but empty (hif-lookup tok)=nil, thus remove this token +          ;; (setq remains (delete tok remains)) +          ;; nil) + +          (t ; Usual IDs +           tok)) + +         expanded)) + +      (hif-flatten (nreverse expanded))))) + +(defun hif-parse-exp (token-list &optional macroname) +  "Parse the TOKEN-LIST. +Return translated list in prefix form.  MACRONAME is applied when invoking +macros to prevent self-reference." +  (let ((hif-token-list (hif-expand-token-list token-list macroname)))      (hif-nexttoken)      (prog1          (and hif-token @@ -498,7 +654,7 @@ that form should be displayed.")            (error "Error: unexpected token: %s" hif-token)))))  (defun hif-exprlist () -  "Parse an exprlist: expr { ',' expr}" +  "Parse an exprlist: expr { ',' expr}."    (let ((result (hif-expr)))      (if (eq hif-token 'hif-comma)  	(let ((temp (list result))) @@ -579,7 +735,8 @@ that form should be displayed.")    "Parse a comp-expr : logshift | comp-expr `<'|`>'|`>='|`<=' logshift."    (let ((result (hif-logshift-expr))          (comp-token nil)) -    (while (memq hif-token '(hif-greater hif-less hif-greater-equal hif-less-equal)) +    (while (memq hif-token '(hif-greater hif-less hif-greater-equal +                                         hif-less-equal))        (setq comp-token hif-token)        (hif-nexttoken)        (setq result (list comp-token result (hif-logshift-expr)))) @@ -618,7 +775,9 @@ that form should be displayed.")    result))  (defun hif-factor () -  "Parse a factor: '!' factor | '~' factor | '(' expr ')' | 'defined(' id ')' | 'id(parmlist)' | strings | id." +  "Parse a factor. +factor : '!' factor | '~' factor | '(' expr ')' | 'defined(' id ')' | +         'id(parmlist)' | strings | id."    (cond     ((eq hif-token 'hif-not)      (hif-nexttoken) @@ -651,6 +810,8 @@ that form should be displayed.")     ((numberp hif-token)      (prog1 hif-token (hif-nexttoken))) +   ((stringp hif-token) +    (hif-string-concatenation))     ;; Unary plus/minus.     ((memq hif-token '(hif-minus hif-plus)) @@ -658,10 +819,91 @@ that form should be displayed.")     (t					; identifier      (let ((ident hif-token)) -      (if (memq ident '(or and)) -	  (error "Error: missing identifier"))        (hif-nexttoken) -      `(hif-lookup (quote ,ident)))))) +      (if (eq hif-token 'hif-lparen) +          (hif-place-macro-invocation ident) +        `(hif-lookup (quote ,ident))))))) + +(defun hif-get-argument-list (ident) +  (let ((nest 0) +        (parmlist nil) ; A "token" list of parameters, will later be parsed +        (parm nil)) + +    (while (or (not (eq (hif-nexttoken) 'hif-rparen)) +               (/= nest 0)) +      (if (eq (car (last parm)) 'hif-comma) +          (setq parm nil)) +      (cond +       ((eq hif-token 'hif-lparen) +        (setq nest (1+ nest))) +       ((eq hif-token 'hif-rparen) +        (setq nest (1- nest))) +       ((and (eq hif-token 'hif-comma) +             (= nest 0)) +        (push (nreverse parm) parmlist) +        (setq parm nil))) +      (push hif-token parm)) + +    (push (nreverse parm) parmlist) ; Okay even if PARM is nil +    (hif-nexttoken) ; Drop the `hif-rparen', get next token +    (nreverse parmlist))) + +(defun hif-place-macro-invocation (ident) +  (let ((parmlist (hif-get-argument-list ident))) +    `(hif-invoke (quote ,ident) (quote ,parmlist)))) + +(defun hif-string-concatenation () +  "Parse concatenated strings: string | strings string." +  (let ((result (substring-no-properties hif-token))) +    (while (stringp (hif-nexttoken)) +      (setq result (concat +                    (substring result 0 -1)    ; remove trailing '"' +                    (substring hif-token 1)))) ; remove leading  '"' +    result)) + +(defun hif-define-macro (parmlist token-body) +  "A marker for defined macro with arguments. +This macro cannot be evaluated alone without parameters inputed." +  ;;TODO: input arguments at run time, use minibuffer to query all arguments +  (error +   "Argumented macro cannot be evaluated without passing any parameter")) + +(defun hif-stringify (a) +  "Stringify a number, string or symbol." +  (cond +   ((numberp a) +    (number-to-string a)) +   ((atom a) +    (symbol-name a)) +   ((stringp a) +    (concat "\"" a "\"")) +   (t +    (error "Invalid token to stringify")))) + +(defun intern-safe (str) +  (if (stringp str) +      (intern str))) + +(defun hif-token-concat (a b) +  "Concatenate two tokens into a longer token. +Currently support only simple token concatenation.  Also support weird (but +valid) token concatenation like '>' ## '>' becomes '>>'.  Here we take care only +those that can be evaluated during preprocessing time and ignore all those that +can only be evaluated at C(++) runtime (like '++', '--' and '+='...)." +  (if (or (memq a hif-valid-token-list) +          (memq b hif-valid-token-list)) +      (let* ((ra (car (rassq a hif-token-alist))) +             (rb (car (rassq b hif-token-alist))) +             (result (and ra rb +                          (cdr (assoc (concat ra rb) hif-token-alist))))) +        (or result +            ;;(error "Invalid token to concatenate") +            (error "Concatenating \"%s\" and \"%s\" does not give a valid \ +preprocessing token" +                   (or ra (symbol-name a)) +                   (or rb (symbol-name b))))) +    (intern-safe (concat (hif-stringify a) +                         (hif-stringify b)))))  (defun hif-mathify (val)    "Treat VAL as a number: if it's t or nil, use 1 or 0." @@ -717,30 +959,160 @@ that form should be displayed.")  (defun hif-comma (&rest expr) -  "Evaluate a list of expr, return the result of the last item." +  "Evaluate a list of EXPR, return the result of the last item."    (let ((result nil))      (dolist (e expr)        (ignore-errors          (setq result (funcall hide-ifdef-evaluator e))))      result)) +(defun hif-token-stringification (l) +  "Scan token list for `hif-stringify' ('#') token and stringify the next token." +  (let (result) +    (while l +      (push (if (eq (car l) 'hif-stringify) +                (prog1 +                    (if (cadr l) +                        (hif-stringify (cadr l)) +                      (error "No token to stringify")) +                  (setq l (cdr l))) +              (car l)) +            result) +      (setq l (cdr l))) +    (nreverse result))) + +(defun hif-token-concatenation (l) +  "Scan token list for `hif-token-concat' ('##') token and concatenate two tokens." +  (let ((prev nil) +        result) +    (while l +      (while (eq (car l) 'hif-token-concat) +        (unless prev +          (error "No token before ## to concatenate")) +        (unless (cdr l) +          (error "No token after ## to concatenate")) +        (setq prev (hif-token-concat prev (cadr l))) +        (setq l (cddr l))) +      (if prev +        (setq result (append result (list prev)))) +      (setq prev (car l) +            l (cdr l))) +    (if prev +        (append result (list prev)) +      result))) + +(defun hif-delimit (lis atom) +  (nconc (mapcan (lambda (l) (list l atom)) +                 (butlast lis)) +         (last lis))) + +;; Perform token replacement: +(defun hif-macro-supply-arguments (macro-name actual-parms) +  "Expand a macro call, replace ACTUAL-PARMS in the macro body." +  (let* ((SA                   (assoc macro-name hide-ifdef-env)) +         (macro                (and SA +                                    (cdr SA) +                                    (eq (cadr SA) 'hif-define-macro) +                                    (cddr SA))) +         (formal-parms         (and macro (car macro))) +         (macro-body           (and macro (cadr macro))) +         actual-count +         formal-count +         actual +         formal +         etc) + +    (when (and actual-parms formal-parms macro-body) +      ;; For each actual parameter, evaluate each one and associate it +      ;; with an actual parameter, put it into local table and finally +      ;; evaluate the macro body. +      (if (setq etc (eq (car formal-parms) 'hif-etc)) +          ;; Take care of `hif-etc' first. Prefix `hif-comma' back if needed. +          (setq formal-parms (cdr formal-parms))) +      (setq formal-count (length formal-parms) +            actual-count (length actual-parms)) + +      (if (> formal-count actual-count) +          (error "Too few parmameter for macro %S" macro-name) +        (if (< formal-count actual-count) +            (or etc +                (error "Too many parameters for macro %S" macro-name)))) + +      ;; Perform token replacement on the MACRO-BODY with the parameters +      (while (setq formal (pop formal-parms)) +        ;; Prevent repetitive substitutation, thus cannot use `subst' +        ;; for example: +        ;; #define mac(a,b) (a+b) +        ;; #define testmac mac(b,y) +        ;; testmac should expand to (b+y): replace of argument a and b +        ;; occurs simultaneously, not sequentially. If sequentially, +        ;; according to the argument order, it will become: +        ;; 1. formal parm #1 'a' replaced by actual parm 'b', thus (a+b) +        ;;    becomes (b+b) +        ;; 2. formal parm #2 'b' replaced by actual parm 'y', thus (b+b) +        ;;    becomes (y+y). +        (setq macro-body +              ;; Unlike `subst', `substitute' replace only the top level +              ;; instead of the whole tree; more importantly, it's not +              ;; destructive. +              (substitute (if (and etc (null formal-parms)) +                              (hif-delimit actual-parms 'hif-comma) +                            (car actual-parms)) +                          formal macro-body)) +        (setq actual-parms (cdr actual-parms))) + +      ;; Replacement completed, flatten the whole token list +      (setq macro-body (hif-flatten macro-body)) + +      ;; Stringification and token concatenation happens here +      (hif-token-concatenation (hif-token-stringification macro-body))))) + +(defun hif-invoke (macro-name actual-parms) +  "Invoke a macro by expanding it, reparse macro-body and finally invoke it." +    ;; Reparse the macro body and evaluate it +    (funcall hide-ifdef-evaluator +             (hif-parse-exp +              (hif-macro-supply-arguments macro-name actual-parms) +              macro-name)))  ;;;----------- end of parser ----------------------- -(defun hif-canonicalize () -  "When at beginning of #ifX, return a Lisp expression for its condition." +(defun hif-canonicalize-tokens (regexp) ; For debugging +  "Return the expanded result of the scanned tokens."    (save-excursion -    (let ((negate (looking-at hif-ifndef-regexp))) -      (re-search-forward hif-ifx-regexp) -      (let* ((tokens (hif-tokenize (point) -				   (progn (hif-end-of-line) (point)))) -	     (expr (hif-parse-if-exp tokens))) -	;; (message "hif-canonicalized: %s" expr) -	(if negate -	    (list 'hif-not expr) -	  expr))))) - +    (re-search-forward regexp) +    (let* ((curr-regexp (match-string 0)) +           (defined (string-match hif-ifxdef-regexp curr-regexp)) +           (negate (and defined +                        (string= (match-string 2 curr-regexp) "n"))) +           (hif-simple-token-only nil) ;; Dynamic binding var for `hif-tokenize' +           (tokens (hif-tokenize (point) +                                 (progn (hif-end-of-line) (point))))) +      (if defined +          (setq tokens (list 'hif-defined tokens))) +      (if negate +          (setq tokens (list 'hif-not tokens))) +      tokens))) + +(defun hif-canonicalize (regexp) +  "Return a Lisp expression for its condition by scanning current buffer. +Do this when cursor is at the beginning of `regexp' (i.e. #ifX)." +  (let ((case-fold-search nil)) +    (save-excursion +      (re-search-forward regexp) +      (let* ((curr-regexp (match-string 0)) +             (defined (string-match hif-ifxdef-regexp curr-regexp)) +             (negate (and defined +                          (string= (match-string 2 curr-regexp) "n"))) +             (hif-simple-token-only nil) ; Dynamic binding for `hif-tokenize' +             (tokens (hif-tokenize (point) +                                   (progn (hif-end-of-line) (point))))) +        (if defined +            (setq tokens (list 'hif-defined tokens))) +        (if negate +            (setq tokens (list 'hif-not tokens))) +        (hif-parse-exp tokens)))))  (defun hif-find-any-ifX ()    "Move to next #if..., or #ifndef, at point or after." @@ -751,10 +1123,10 @@ that form should be displayed.")  (defun hif-find-next-relevant () -  "Move to next #if..., #else, or #endif, after the current line." +  "Move to next #if..., #elif..., #else, or #endif, after the current line."    ;; (message "hif-find-next-relevant at %d" (point))    (end-of-line) -  ;; avoid infinite recursion by only going to beginning of line if match found +  ;; Avoid infinite recursion by only going to line-beginning if match found    (if (re-search-forward hif-ifx-else-endif-regexp (point-max) t)        (beginning-of-line))) @@ -762,29 +1134,33 @@ that form should be displayed.")    "Move to previous #if..., #else, or #endif, before the current line."    ;; (message "hif-find-previous-relevant at %d" (point))    (beginning-of-line) -  ;; avoid infinite recursion by only going to beginning of line if match found +  ;; Avoid infinite recursion by only going to line-beginning if match found    (if (re-search-backward hif-ifx-else-endif-regexp (point-min) t)       (beginning-of-line))) -(defun hif-looking-at-ifX ()		;; Should eventually see #if -  (looking-at hif-ifx-regexp)) +(defun hif-looking-at-ifX () +  (looking-at hif-ifx-regexp))   ; Should eventually see #if  (defun hif-looking-at-endif ()    (looking-at hif-endif-regexp))  (defun hif-looking-at-else ()    (looking-at hif-else-regexp)) +(defun hif-looking-at-elif () +  (looking-at hif-elif-regexp))  (defun hif-ifdef-to-endif () -  "If positioned at #ifX or #else form, skip to corresponding #endif." +  "If positioned at #ifX, #elif, or #else form, skip to corresponding #endif."    ;; (message "hif-ifdef-to-endif at %d" (point)) (sit-for 1)    (hif-find-next-relevant)    (cond ((hif-looking-at-ifX) -	 (hif-ifdef-to-endif) ; find endif of nested if -	 (hif-ifdef-to-endif)) ; find outer endif or else +         (hif-ifdef-to-endif) ; Find endif of nested if +         (hif-ifdef-to-endif)) ; Find outer endif or else +        ((hif-looking-at-elif) +         (hif-ifdef-to-endif))  	((hif-looking-at-else) -	 (hif-ifdef-to-endif)) ; find endif following else +         (hif-ifdef-to-endif)) ; Find endif following else  	((hif-looking-at-endif)  	 'done)  	(t @@ -952,10 +1328,11 @@ Point is left unchanged."        (hif-make-range start end else)))) -;;; A bit slimy. +;; A bit slimy.  (defun hif-hide-line (point) -  "Hide the line containing point.  Does nothing if `hide-ifdef-lines' is nil." +  "Hide the line containing point. +Does nothing if `hide-ifdef-lines' is nil."    (when hide-ifdef-lines      (save-excursion        (goto-char point) @@ -999,7 +1376,7 @@ Point is left unchanged."    "Called at #ifX expression, this hides those parts that should be hidden.  It uses the judgment of `hide-ifdef-evaluator'."    ;; (message "hif-possibly-hide") (sit-for 1) -  (let ((test (hif-canonicalize)) +  (let ((test (hif-canonicalize hif-ifx-regexp))  	(range (hif-find-range)))      ;; (message "test = %s" test) (sit-for 1) @@ -1027,16 +1404,145 @@ It uses the judgment of `hide-ifdef-evaluator'."      (goto-char (hif-range-end range))      (end-of-line))) +(defun hif-parse-macro-arglist (str) +  "Parse argument list formatted as '( arg1 [ , argn] [...] )'. +The '...' is also included.  Return a list of the arguments, if '...' exists the +first arg will be `hif-etc'." +  (let* ((hif-simple-token-only nil) ; Dynamic binding var for `hif-tokenize' +         (tokenlist +          (cdr (hif-tokenize +               (- (point) (length str)) (point)))) ; Remove `hif-lparen' +         etc result token) +    (while (not (eq (setq token (pop tokenlist)) 'hif-rparen)) +      (cond +       ((eq token 'hif-etc) +        (setq etc t)) +       ((eq token 'hif-comma) +        t) +       (t +        (push token result)))) +    (if etc +        (cons 'hif-etc (nreverse result)) +      (nreverse result)))) + +;; The original version of hideif evaluates the macro early and store the +;; final values for the defined macro into the symbol database (aka +;; `hide-ifdef-env'). The evaluation process is "strings -> tokens -> parsed +;; tree -> [value]". (The square bracket refers to what's stored in in our +;; `hide-ifdef-env'.) +;; +;; This forbids the evaluation of an argumented macro since the parameters +;; are applied at run time. In order to support argumented macro I then +;; postponed the evaluation process one stage and store the "parsed tree" +;; into symbol database. The evaluation process was then "strings -> tokens +;; -> [parsed tree] -> value". Hideif therefore run slower since it need to +;; evaluate the parsed tree everytime when trying to expand the symbol. These +;; temporarily code changes are obsolete and not in Emacs source repository. +;; +;; Furthermore, CPP did allow partial expression to be defined in several +;; macros and later got concatenated into a complete expression and then +;; evaluate it. In order to match this behavior I had to postpone one stage +;; further, otherwise those partial expression will be fail on parsing and +;; we'll miss all macros that reference it. The evaluation process thus +;; became "strings -> [tokens] -> parsed tree -> value." This degraded the +;; performance since we need to parse tokens and evaluate them everytime +;; when that symbol is referenced. +;; +;; In real cases I found a lot portion of macros are "simple macros" that +;; expand to literals like integers or other symbols. In order to enhance +;; the performance I use this `hif-simple-token-only' to notify my code and +;; save the final [value] into symbol database. [lukelee] +(defun hif-find-define (&optional min max) +  "Parse texts and retrieve all defines within the region MIN and MAX." +  (interactive) +  (and min (goto-char min)) +  (and (re-search-forward hif-define-regexp max t) +       (or +        (let* ((defining (string= "define" (match-string 2))) +               (name (and (re-search-forward hif-macroref-regexp max t) +                          (match-string 1))) +               (parsed nil) +               (parmlist (and (match-string 3) ; First arg id found +                              (hif-parse-macro-arglist (match-string 2))))) +          (if defining +              ;; Ignore name (still need to return 't), or define the name +              (or (and hide-ifdef-exclude-define-regexp +                       (string-match hide-ifdef-exclude-define-regexp +                                     name)) + +                  (let* ((start (point)) +                         (end   (progn (hif-end-of-line) (point))) +                         (hif-simple-token-only nil) ; Dynamic binding +                         (tokens +                          (and name +                               ;; `hif-simple-token-only' is set/clear +                               ;; only in this block +                               (condition-case nil +                                   ;; Prevent C statements like +                                   ;; 'do { ... } while (0)' +                                   (hif-tokenize start end) +                                 (error +                                  ;; We can't just return nil here since +                                  ;; this will stop hideif from searching +                                  ;; for more #defines. +                                  (setq hif-simple-token-only t) +                                  (buffer-substring-no-properties +                                   start end))))) +                         ;; For simple tokens we save only the parsed result; +                         ;; otherwise we save the tokens and parse it after +                         ;; parameter replacement +                         (expr (and tokens +                                    ;; `hif-simple-token-only' is checked only +                                    ;; here. +                                    (or (and hif-simple-token-only +                                             (listp tokens) +                                             (= (length tokens) 1) +                                             (hif-parse-exp tokens)) +                                        `(hif-define-macro ,parmlist +                                                           ,tokens)))) +                         (SA (and name +                                  (assoc (intern name) hide-ifdef-env)))) +                    (and name +                         (if SA +                             (or (setcdr SA expr) t) +                           ;; Lazy evaluation, eval only if hif-lookup find it. +                           ;; Define it anyway, even if nil it's still in list +                           ;; and therefore considerred defined +                           (push (cons (intern name) expr) hide-ifdef-env))))) +            ;; #undef +            (and name +                 (hif-undefine-symbol (intern name)))))) +       t)) + + +(defun hif-add-new-defines (&optional min max) +  "Scan and add all #define macros between MIN and MAX." +  (interactive) +  (save-excursion +    (save-restriction +      ;; (mark-region min max) ;; for debugging +      (while (hif-find-define min max) +        (setf min (point))) +      (if max (goto-char max) +        (goto-char (point-max))))))  (defun hide-ifdef-guts ()    "Does most of the work of `hide-ifdefs'.  It does not do the work that's pointless to redo on a recursive entry."    ;; (message "hide-ifdef-guts")    (save-excursion +    (let ((case-fold-search nil) +          min max)      (goto-char (point-min)) -    (while (hif-find-any-ifX) -      (hif-possibly-hide)))) +      (setf min (point)) +      (loop do +            (setf max (hif-find-any-ifX)) +            (hif-add-new-defines min max) +            (if max +                (hif-possibly-hide)) +            (setf min (point)) +            while max))))  ;;===%%SF%% hide-ifdef-hiding (End)  === @@ -1050,7 +1556,8 @@ It does not do the work that's pointless to redo on a recursive entry."    (message "Hide-Read-Only %s"  	   (if hide-ifdef-read-only "ON" "OFF"))    (if hide-ifdef-hiding -      (setq buffer-read-only (or hide-ifdef-read-only hif-outside-read-only))) +      (setq buffer-read-only (or hide-ifdef-read-only +                                 hif-outside-read-only)))    (force-mode-line-update))  (defun hide-ifdef-toggle-outside-read-only () @@ -1086,12 +1593,25 @@ It does not do the work that's pointless to redo on a recursive entry."    (hif-set-var var 1)    (if hide-ifdef-hiding (hide-ifdefs))) -(defun hide-ifdef-undef (var) -  "Undefine a VAR so that #ifdef VAR would not be included." -  (interactive "SUndefine what? ") -  (hif-set-var var nil) -  (if hide-ifdef-hiding (hide-ifdefs))) +(defun hif-undefine-symbol (var) +  (setq hide-ifdef-env +        (delete (assoc var hide-ifdef-env) hide-ifdef-env))) + +(defun hide-ifdef-undef (start end) +  "Undefine a VAR so that #ifdef VAR would not be included." +  (interactive "r") +  (let* ((symstr +          (or (and mark-active +                   (buffer-substring-no-properties start end)) +              (read-string "Undefine what? " (current-word)))) +         (sym (and symstr +                   (intern symstr)))) +    (if (zerop (hif-defined sym)) +        (message "`%s' not defined, no need to undefine it" symstr) +      (hif-undefine-symbol sym) +      (if hide-ifdef-hiding (hide-ifdefs)) +      (message "`%S' undefined" sym))))  (defun hide-ifdefs (&optional nomsg)    "Hide the contents of some #ifdefs. diff --git a/lisp/progmodes/idlw-shell.el b/lisp/progmodes/idlw-shell.el index e7bf3792e5f..a0683d1c409 100644 --- a/lisp/progmodes/idlw-shell.el +++ b/lisp/progmodes/idlw-shell.el @@ -590,27 +590,28 @@ TYPE is either 'pro' or 'rinfo', and `idlwave-shell-temp-pro-file' or  (defun idlwave-shell-make-temp-file (prefix)    "Create a temporary file." -  ; Hard coded make-temp-file for Emacs<21 -  (if (fboundp 'make-temp-file) +  (if (featurep 'emacs)        (make-temp-file prefix) -    (let (file -	  (temp-file-dir (if (boundp 'temporary-file-directory) -			     temporary-file-directory -			   "/tmp"))) -      (while (condition-case () -		 (progn -		   (setq file -			 (make-temp-name -			  (expand-file-name prefix temp-file-dir))) -                   (if (featurep 'xemacs) -		       (write-region "" nil file nil 'silent nil) -		     (write-region "" nil file nil 'silent nil 'excl)) -		   nil) -	       (file-already-exists t)) -	;; the file was somehow created by someone else between -	;; `make-temp-name' and `write-region', let's try again. -	nil) -      file))) +    (if (fboundp 'make-temp-file) +	(make-temp-file prefix) +      (let (file +	    (temp-file-dir (if (boundp 'temporary-file-directory) +			       temporary-file-directory +			     "/tmp"))) +	(while (condition-case () +		   (progn +		     (setq file +			   (make-temp-name +			    (expand-file-name prefix temp-file-dir))) +		     (if (featurep 'xemacs) +			 (write-region "" nil file nil 'silent nil) +		       (write-region "" nil file nil 'silent nil 'excl)) +		     nil) +		 (file-already-exists t)) +	  ;; the file was somehow created by someone else between +	  ;; `make-temp-name' and `write-region', let's try again. +	  nil) +	file))))  (defvar idlwave-shell-dirstack-query "cd,current=___cur & print,___cur" diff --git a/lisp/progmodes/python.el b/lisp/progmodes/python.el index 91a85526420..743981b3714 100644 --- a/lisp/progmodes/python.el +++ b/lisp/progmodes/python.el @@ -2461,8 +2461,10 @@ LINE is used to detect the context on how to complete given INPUT."      (and completion-code           (> (length input) 0)           (with-current-buffer (process-buffer process) -           (let ((completions (python-shell-send-string-no-output -                               (format completion-code input) process))) +           (let ((completions +                  (python-util-strip-string +                   (python-shell-send-string-no-output +                    (format completion-code input) process))))               (and (> (length completions) 2)                    (split-string completions                                  "^'\\|^\"\\|;\\|'$\\|\"$" t))))))) @@ -3648,6 +3650,14 @@ returned as is."                n (1- n)))        (reverse acc)))) +(defun python-util-strip-string (string) +  "Strip STRING whitespace and newlines from end and beginning." +  (replace-regexp-in-string +   (rx (or (: string-start (* (any whitespace ?\r ?\n))) +           (: (* (any whitespace ?\r ?\n)) string-end))) +   "" +   string)) +  (defun python-electric-pair-string-delimiter ()    (when (and electric-pair-mode @@ -3736,7 +3746,7 @@ returned as is."    (set (make-local-variable 'outline-regexp)         (python-rx (* space) block-start)) -  (set (make-local-variable 'outline-heading-end-regexp) ":\\s-*\n") +  (set (make-local-variable 'outline-heading-end-regexp) ":[^\n]*\n")    (set (make-local-variable 'outline-level)         #'(lambda ()             "`outline-level' function for Python mode." diff --git a/lisp/progmodes/ruby-mode.el b/lisp/progmodes/ruby-mode.el index 74edf7a680f..3c20279600e 100644 --- a/lisp/progmodes/ruby-mode.el +++ b/lisp/progmodes/ruby-mode.el @@ -2152,7 +2152,7 @@ See `font-lock-syntax-table'.")      (ruby-match-expression-expansion       2 font-lock-variable-name-face t)      ;; Negation char. -    ("\\(?:^\\|[^[:alnum:]_]\\)\\(!+\\)[^=]" +    ("\\(?:^\\|[^[:alnum:]_]\\)\\(!+\\)[^=~]"       1 font-lock-negation-char-face)      ;; Character literals.      ;; FIXME: Support longer escape sequences. diff --git a/lisp/progmodes/sh-script.el b/lisp/progmodes/sh-script.el index b4148ef5621..eb6a55689c1 100644 --- a/lisp/progmodes/sh-script.el +++ b/lisp/progmodes/sh-script.el @@ -481,6 +481,9 @@ name symbol."  	?~ "_"  	?, "_"  	?= "." +	?\; "." +	?| "." +	?& "."  	?< "."  	?> ".")    "The syntax table to use for Shell-Script mode. @@ -1860,6 +1863,40 @@ Does not preserve point."     ((equal tok "in") (sh-smie--sh-keyword-in-p))     (t (sh-smie--keyword-p)))) +(defun sh-smie--default-forward-token () +  (forward-comment (point-max)) +  (buffer-substring-no-properties +   (point) +   (progn (if (zerop (skip-syntax-forward ".")) +              (while (progn (skip-syntax-forward "w_'") +                            (looking-at "\\\\")) +                (forward-char 2))) +          (point)))) + +(defun sh-smie--default-backward-token () +  (forward-comment (- (point))) +  (let ((pos (point)) +        (n (skip-syntax-backward "."))) +    (if (or (zerop n) +            (and (eq n -1) +                 (let ((p (point))) +                   (if (eq -1 (% (skip-syntax-backward "\\") 2)) +                       t +                     (goto-char p) +                     nil)))) +        (while +            (progn (skip-syntax-backward "w_'") +                   (or (not (zerop (skip-syntax-backward "\\"))) +                       (when (eq ?\\ (char-before (1- (point)))) +                         (let ((p (point))) +                           (forward-char -1) +                           (if (eq -1 (% (skip-syntax-backward "\\") 2)) +                               t +                             (goto-char p) +                             nil)))))) +      (goto-char (- (point) (% (skip-syntax-backward "\\") 2)))) +    (buffer-substring-no-properties (point) pos))) +  (defun sh-smie-sh-forward-token ()    (if (and (looking-at "[ \t]*\\(?:#\\|\\(\\s|\\)\\|$\\)")             (save-excursion @@ -1888,7 +1925,7 @@ Does not preserve point."          tok))       (t        (let* ((pos (point)) -             (tok (smie-default-forward-token))) +             (tok (sh-smie--default-forward-token)))          (cond           ((equal tok ")") "case-)")           ((equal tok "(") "case-(") @@ -1932,7 +1969,7 @@ Does not preserve point."        (goto-char (match-beginning 1))        (match-string-no-properties 1))       (t -      (let ((tok (smie-default-backward-token))) +      (let ((tok (sh-smie--default-backward-token)))          (cond           ((equal tok ")") "case-)")           ((equal tok "(") "case-(") @@ -1962,20 +1999,24 @@ May return nil if the line should not be treated as continued."      (`(:after . "case-)") (- (sh-var-value 'sh-indent-for-case-alt)                               (sh-var-value 'sh-indent-for-case-label)))      ((and `(:before . ,_) -          (guard (when sh-indent-after-continuation -                   (save-excursion -                     (ignore-errors -                       (skip-chars-backward " \t") -                       (sh-smie--looking-back-at-continuation-p)))))) -     ;; After a line-continuation, make sure the rest is indented. -     (let* ((sh-indent-after-continuation nil) -            (indent (smie-indent-calculate)) -            (initial (sh-smie--continuation-start-indent))) -       (when (and (numberp indent) (numberp initial) -                  (<= indent initial)) -         `(column . ,(+ initial sh-indentation))))) +          ;; After a line-continuation, make sure the rest is indented. +          (guard sh-indent-after-continuation) +          (guard (save-excursion +                   (ignore-errors +                     (skip-chars-backward " \t") +                     (sh-smie--looking-back-at-continuation-p)))) +          (let initial (sh-smie--continuation-start-indent)) +          (guard (let* ((sh-indent-after-continuation nil) +                        (indent (smie-indent-calculate))) +                   (and (numberp indent) (numberp initial) +                        (<= indent initial))))) +     `(column . ,(+ initial sh-indentation)))      (`(:before . ,(or `"(" `"{" `"[")) -     (if (smie-rule-hanging-p) (smie-rule-parent))) +     (when (smie-rule-hanging-p) +       (if (not (smie-rule-prev-p "&&" "||" "|")) +	   (smie-rule-parent) +	 (smie-backward-sexp 'halfexp) +	 `(column . ,(smie-indent-virtual)))))      ;; FIXME: Maybe this handling of ;; should be made into      ;; a smie-rule-terminator function that takes the substitute ";" as arg.      (`(:before . ,(or `";;" `";&" `";;&")) @@ -1993,7 +2034,12 @@ May return nil if the line should not be treated as continued."                              (smie-rule-bolp))))                   (current-column)                 (smie-indent-calculate))))) -    (`(:after . "|") (if (smie-rule-parent-p "|") nil 4)) +    (`(:before . ,(or `"|" `"&&" `"||")) +     (unless (smie-rule-parent-p token) +       (smie-backward-sexp token) +       `(column . ,(+ (funcall smie-rules-function :elem 'basic) +                      (smie-indent-virtual))))) +      ;; Attempt at backward compatibility with the old config variables.      (`(:before . "fi") (sh-var-value 'sh-indent-for-fi))      (`(:before . "done") (sh-var-value 'sh-indent-for-done)) @@ -2114,7 +2160,7 @@ Point should be before the newline."       ;;    tok))       (t        (let* ((pos (point)) -             (tok (smie-default-forward-token))) +             (tok (sh-smie--default-forward-token)))          (cond           ;; ((equal tok ")") "case-)")           ((and tok (string-match "\\`[a-z]" tok) @@ -2155,7 +2201,7 @@ Point should be before the newline."       ;;  (goto-char (match-beginning 1))       ;;  (match-string-no-properties 1))       (t -      (let ((tok (smie-default-backward-token))) +      (let ((tok (sh-smie--default-backward-token)))          (cond           ;; ((equal tok ")") "case-)")           ((and tok (string-match "\\`[a-z]" tok) @@ -2300,6 +2346,11 @@ Calls the value of `sh-set-shell-hook' if set."          (let ((mksym (lambda (name)                         (intern (format "sh-smie-%s-%s"                                         sh-indent-supported-here name))))) +	  (add-function :around (local 'smie--hanging-eolp-function) +			(lambda (orig) +			  (if (looking-at "[ \t]*\\\\\n") +			      (goto-char (match-end 0)) +			    (funcall orig))))            (smie-setup (symbol-value (funcall mksym "grammar"))                        (funcall mksym "rules")                        :forward-token  (funcall mksym "forward-token") | 
