unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
* patch to improve sh-script.el
@ 2006-03-06 14:29 Vivek Dasmohapatra
  0 siblings, 0 replies; only message in thread
From: Vivek Dasmohapatra @ 2006-03-06 14:29 UTC (permalink / raw)


[-- Attachment #1: Type: TEXT/PLAIN, Size: 971 bytes --]

Hi there: at the request of some users on #emacs, I've patched sh-script.el
to do the following:

   `command args...` is highlighted in a different face than normal strings

   $(command args...) has command highlighted in the same face as above

   "some text $(command "moose burgers")" is highlighted correctly, at least
   in that the "" inside the $() do not terminate the "" around it.
   this new support copes with nested $() and () and `` subshells within
   the "$()" construct.

   "`command "an argument"`" is similarly correctly handled (well... more
   correctly than before, anyway)

The changes are not invasive: there's a new item in sh-font-lock-keywords-var
for the bash shell, and the syntactic fontification variable likewise
has a new entry (with two support functions and a new face defined).

Hopefully this is of interest and can be included in the next version
of sh-script.el

[ The diff is against debian's emacs-snapshot package v 20060202 ]

[-- Attachment #2: Type: TEXT/plain, Size: 5524 bytes --]

--- /home/local/src/emacs-snapshot-20060202/lisp/progmodes/sh-script.el	2005-12-18 01:18:45.000000000 +0000
+++ /tmp/sh-script.el	2006-03-06 14:19:09.000000000 +0000
@@ -813,6 +813,18 @@
      (:weight bold)))
   "Face to show a here-document"
   :group 'sh-indentation)
+
+;; these colours are probably ick. whatever, it's just a placeholder.
+(defface sh-quoted-exec 
+  '( ( ((class color) (background dark))
+       (:foreground "salmon"))
+     ( ((class color) (background light))
+       (:foreground "magenta"))
+     (t
+      (:weight bold)) ) 
+  "Face to show quoted execs like ``"
+  :group 'sh-indentation)
+
 ;; backward-compatibility alias
 (put 'sh-heredoc-face 'face-alias 'sh-heredoc)
 (defvar sh-heredoc-face 'sh-heredoc)
@@ -832,7 +844,7 @@
          font-lock-variable-name-face))
 
     (rc sh-append es)
-
+    (bash sh-append shell ("\\$(\\(\\sw+\\)" (1 'sh-quoted-exec t) ))
     (sh sh-append shell
 	;; Variable names.
 	("\\$\\({#?\\)?\\([A-Za-z_][A-Za-z0-9_]*\\|[-#?@!]\\)" 2
@@ -966,6 +978,49 @@
   ;; This looks silly, but it's because `sh-here-doc-re' keeps changing.
   (re-search-forward sh-here-doc-re limit t))
 
+(defun sh-quoted-subshell (limit)
+  "Search for a subshell embedded in a string. FInd all the unescaped 
+\" characters within said subshell, remembering that subshells can nest."
+  (if (re-search-forward "\"\\(?:.\\|\n\\)*?\\(\\$(\\|`\\)" limit t)
+      ;; bingo we have a $( or a ` inside a ""
+      (let ((char (char-after (point))) 
+            (continue t)
+            (pos (point))
+            (data nil)    ;; value to put into match-data (and return)
+            (last nil)    ;; last char seen
+            (bq  (equal (match-string 1) "`")) ;; ` state flip-flop
+            (seen nil)    ;; list of important positions
+            (nest 1))     ;; subshell nesting level
+        (while (and continue char (<= pos limit))
+          ;; unescaped " inside a $( ... ) construct.
+          ;; state machine time...
+          ;; \ => ignore next char; 
+          ;; ` => increase or decrease nesting level based on bq flag
+          ;; ) [where nesting > 0] => decrease nesting
+          ;; ( [where nesting > 0] => increase nesting
+          ;; ( [preceeded by $ ]   => increase nesting
+          ;; " [nesting <= 0 ]     => terminate, we're done.
+          ;; " [nesting >  0 ]     => remember this, it's not a proper "
+          (if (eq ?\\ last) nil
+            (if (eq ?\` char) (setq nest (+ nest (if bq -1 1)) bq (not bq))
+              (if (and (> nest 0) (eq ?\) char))  (setq nest (1- nest))
+                (if (and (eq ?$ last) (eq ?\( char)) (setq nest (1+ nest))
+                  (if (and (> nest 0) (eq ?\( char)) (setq nest (1+ nest))
+                    (if (eq char ?\")
+                        (if (>= 0 nest) (setq continue nil)
+                          (setq seen (cons pos seen)) ) ))))))
+          ;;(message "POS: %d [%d]" pos nest)
+          (setq last char
+                pos  (1+ pos) 
+                char (char-after pos)) )
+        (when seen 
+          ;;(message "SEEN: %S" seen)
+          (setq data (list (current-buffer)))
+          (mapc (lambda (P) 
+                  (setq data (cons P (cons (1+ P) data)) ) ) seen)
+          (store-match-data data))
+        data) ))
+
 (defun sh-is-quoted-p (pos)
   (and (eq (char-before pos) ?\\)
        (not (sh-is-quoted-p (1- pos)))))
@@ -996,6 +1051,17 @@
     (when (save-excursion (backward-char 2) (looking-at ";;\\|in"))
       sh-st-punc)))
 
+(defun sh-apply-quoted-subshell () 
+  "Apply the `sh-st-punc' syntax to all the matches in `match-data'.
+This is used to flag quote characters in subshell constructs inside strings
+\(which should therefore not be treated as normal quote characters\)"
+  (let ((m (match-data)) a b)
+    (while m
+      (setq a (car  m)
+            b (cadr m)
+            m (cddr m))
+      (put-text-property a b 'syntax-table sh-st-punc))) sh-st-punc)
+
 (defconst sh-font-lock-syntactic-keywords
   ;; A `#' begins a comment when it is unquoted and at the beginning of a
   ;; word.  In the shell, words are separated by metacharacters.
@@ -1006,6 +1072,8 @@
     ("\\(\\\\\\)'" 1 ,sh-st-punc)
     ;; Make sure $@ and @? are correctly recognized as sexps.
     ("\\$\\([?@]\\)" 1 ,sh-st-symbol)
+    (sh-quoted-subshell 
+     (1 (sh-apply-quoted-subshell) t t))
     ;; Find HEREDOC starters and add a corresponding rule for the ender.
     (sh-font-lock-here-doc
      (2 (sh-font-lock-open-heredoc
@@ -1018,11 +1086,12 @@
     (")" 0 (sh-font-lock-paren (match-beginning 0)))))
 
 (defun sh-font-lock-syntactic-face-function (state)
-  (if (nth 3 state)
-      (if (char-valid-p (nth 3 state))
-	  font-lock-string-face
+  (let ((q (nth 3 state)))
+    (if q
+        (if (char-valid-p q)
+            (if (eq q ?\`) 'sh-quoted-exec font-lock-string-face)
 	sh-heredoc-face)
-    font-lock-comment-face))
+      font-lock-comment-face)))
 
 (defgroup sh-indentation nil
   "Variables controlling indentation in shell scripts.
@@ -1336,7 +1405,7 @@
 The default style of this mode is that of Rosenblatt's Korn shell book.
 The syntax of the statements varies with the shell being used.  The
 following commands are available, based on the current shell's syntax:
-\\<sh-mode-map>
+
 \\[sh-case]	 case statement
 \\[sh-for]	 for loop
 \\[sh-function]	 function definition

[-- Attachment #3: Type: text/plain, Size: 142 bytes --]

_______________________________________________
Emacs-devel mailing list
Emacs-devel@gnu.org
http://lists.gnu.org/mailman/listinfo/emacs-devel

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2006-03-06 14:29 UTC | newest]

Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2006-03-06 14:29 patch to improve sh-script.el Vivek Dasmohapatra

Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).