From 450852d047bcc3214665c9345b60749b50858d76 Mon Sep 17 00:00:00 2001 From: Ron Panduwana Date: Sun, 20 Feb 2011 23:07:40 +0700 Subject: Added HAML filter (|haml), default for .haml files. --- zencoding-mode.el | 322 ++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 217 insertions(+), 105 deletions(-) (limited to 'zencoding-mode.el') diff --git a/zencoding-mode.el b/zencoding-mode.el index de61fbf..e014dc2 100644 --- a/zencoding-mode.el +++ b/zencoding-mode.el @@ -154,14 +154,15 @@ (zencoding-pif (zencoding-subexpr input) (let ((result (car it)) (rest (cdr it))) - `((,filters ,result) . ,rest)) + `((filter ,filters ,result) . ,rest)) it)) (defun zencoding-default-filter () "Default filter(s) to be used if none is specified." (let* ((file-ext (car (zencoding-regex ".*\\(\\..*\\)"(buffer-file-name) 1))) (defaults '(".html" ("html") - ".htm" ("html"))) + ".htm" ("html") + ".haml" ("haml"))) (default-else '("html")) (selected-default (member file-ext defaults))) (if selected-default @@ -362,10 +363,13 @@ "acronym" "cite" "code" + "dd" "dfn" + "dt" "em" "h1" "h2" "h3" "h4" "h5" "h6" "kbd" + "li" "q" "span" "strong" @@ -379,18 +383,14 @@ "img" "input")) -;; li -;; a -;; em -;; p - (defvar zencoding-leaf-function nil "Function to execute when expanding a leaf node in the Zencoding AST.") -(setq zencoding-filters +(defvar zencoding-filters '("html" (zencoding-primary-filter zencoding-make-html-tag) - "c" (zencoding-primary-filter zencoding-make-commented-html-tag))) + "c" (zencoding-primary-filter zencoding-make-commented-html-tag) + "haml" (zencoding-primary-filter zencoding-make-haml-tag))) (defun zencoding-primary-filter (input proc) "Process filter that needs to be executed first, ie. not given output from other filter." @@ -413,52 +413,74 @@ nil))) (defun zencoding-make-tag (tag-maker tag-info &optional content) + "Extract tag info and pass them to tag-maker." (let* ((name (pop tag-info)) (has-body? (pop tag-info)) (id (pop tag-info)) (classes (pop tag-info)) (props (pop tag-info)) - (has-body (or content - (and has-body? - (not (member name zencoding-self-closing-tags))))) - (lf (if (or (and content (string-match "\n" content)) - (member name zencoding-block-tags) - (and (> (length name) 1) - (not (member name zencoding-inline-tags)))) - "\n" ""))) - (funcall tag-maker name id classes props has-body lf + (self-closing? (not (or content + (and has-body? + (not (member name zencoding-self-closing-tags))))))) + (funcall tag-maker name id classes props self-closing? (if content content - (if zencoding-leaf-function (funcall zencoding-leaf-function) - ""))))) - -(defun zencoding-make-html-tag (tag-name tag-id tag-classes tag-props has-body lf content) - (let ((id (zencoding-concat-or-empty " id=\"" tag-id "\"")) - (classes (zencoding-mapconcat-or-empty " class=\"" tag-classes " " "\"")) - (props (zencoding-mapconcat-or-empty " " tag-props " " nil - (lambda (prop) - (concat (symbol-name (car prop)) "=\"" (cadr prop) "\""))))) - - (concat lf "<" tag-name id classes props - (if has-body - (concat ">" lf content lf "" lf) - "/>\n")))) - -(defun zencoding-make-commented-html-tag (tag-name tag-id tag-classes tag-props has-body lf content) - (let ((body (zencoding-make-html-tag tag-name tag-id tag-classes tag-props has-body lf content))) + (if zencoding-leaf-function (funcall zencoding-leaf-function)))))) + +(defun zencoding-make-html-tag (tag-name tag-id tag-classes tag-props self-closing? content) + "Create HTML markup string" + (let* ((id (zencoding-concat-or-empty " id=\"" tag-id "\"")) + (classes (zencoding-mapconcat-or-empty " class=\"" tag-classes " " "\"")) + (props (zencoding-mapconcat-or-empty " " tag-props " " nil + (lambda (prop) + (concat (symbol-name (car prop)) "=\"" (cadr prop) "\"")))) + (content-multiline? (and content (string-match "\n" content))) + (block-tag? (or (member tag-name zencoding-block-tags) + (and (> (length tag-name) 1) + (not (member tag-name zencoding-inline-tags))))) + (lf (if (or content-multiline? block-tag?) + "\n"))) + (concat "<" tag-name id classes props (if self-closing? + "/>" + (concat ">" (if content + (if (or content-multiline? block-tag?) + (zencoding-indent content) + content)) + lf + ""))))) + +(defun zencoding-make-commented-html-tag (tag-name tag-id tag-classes tag-props self-closing? content) + "Create HTML markup string with extra comments for elements with #id or .classes" + (let ((body (zencoding-make-html-tag tag-name tag-id tag-classes tag-props self-closing? content))) (if (or tag-id tag-classes) (let ((id (zencoding-concat-or-empty "#" tag-id)) (classes (zencoding-mapconcat-or-empty "." tag-classes "."))) (concat "\n" body - "\n\n")) + "\n")) body))) +(defun zencoding-make-haml-tag (tag-name tag-id tag-classes tag-props self-closing? content) + "Create HAML markup string" + (let ((name (if (and (equal tag-name "div") + (or tag-id tag-classes)) + "" + (concat "%" tag-name))) + (id (zencoding-concat-or-empty "#" tag-id)) + (classes (zencoding-mapconcat-or-empty "." tag-classes ".")) + (props (zencoding-mapconcat-or-empty "{" tag-props ", " "}" + (lambda (prop) + (concat ":" (symbol-name (car prop)) " => \"" (cadr prop) "\""))))) + (concat name id classes props (if content + (zencoding-indent content))))) + (defun zencoding-concat-or-empty (prefix body &optional suffix) + "Return prefixed suffixed text or empty string." (if body (concat prefix body suffix) "")) (defun zencoding-mapconcat-or-empty (prefix list-body delimiter &optional suffix map-fun) + "Return prefixed suffixed mapconcated text or empty string." (if list-body (let* ((mapper (if map-fun map-fun 'identity)) (body (mapconcat mapper list-body delimiter))) @@ -466,11 +488,13 @@ "")) (defun zencoding-transform (ast-with-filters) - (let ((filters (car ast-with-filters)) - (ast (cadr ast-with-filters))) + "Transform AST (containing filter data) into string." + (let ((filters (cadr ast-with-filters)) + (ast (caddr ast-with-filters))) (zencoding-process-filter filters ast))) (defun zencoding-transform-ast (ast tag-maker) + "Transform AST (without filter data) into string." (let ((type (car ast))) (cond ((eq type 'list) @@ -478,7 +502,7 @@ #'(lambda (sub-ast) (zencoding-transform-ast sub-ast make-tag-fun))) (cadr ast) - "")) + "\n")) ((eq type 'tag) (zencoding-make-tag tag-maker (cadr ast))) ((eq type 'parent-child) @@ -488,7 +512,13 @@ ((eq type 'sibling) (let ((sib1 (zencoding-transform-ast (cadr ast) tag-maker)) (sib2 (zencoding-transform-ast (caddr ast) tag-maker))) - (concat sib1 sib2)))))) + (concat sib1 "\n" sib2)))))) + +(defun zencoding-indent (text) + "Indent the text" + (if text + (replace-regexp-in-string "\n" "\n " (concat "\n" text)) + nil)) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Test-cases @@ -499,32 +529,63 @@ ("a.x" "") ("a#q.x" "") ("a#q.x.y.z" "") - ("#q" "\n
\n\n
\n") - (".x" "\n
\n\n
\n") - ("#q.x" "\n
\n\n
\n") - ("#q.x.y.z" "\n
\n\n
\n") + ("#q" "
" + "
") + (".x" "
" + "
") + ("#q.x" "
" + "
") + ("#q.x.y.z" "
" + "
") ;; Empty tags - ("a/" "\n") - ("a/.x" "\n") - ("a/#q.x" "\n") - ("a/#q.x.y.z" "\n") + ("a/" "") + ("a/.x" "") + ("a/#q.x" "") + ("a/#q.x.y.z" "") ;; Self-closing tags - ("input type=text" "\n\n") - ("img" "\n\n") - ("img>metadata/*2" "\n\n\n\n\n\n\n\n") + ("input type=text" "") + ("img" "") + ("img>metadata/*2" "" + " " + " " + "") ;; Siblings - ("a+b" "") - ("a+b+c" "") - ("a.x+b" "") - ("a#q.x+b" "") - ("a#q.x.y.z+b" "") - ("a#q.x.y.z+b#p.l.m.n" "") + ("a+b" "" + "") + ("a+b+c" "" + "" + "") + ("a.x+b" "" + "") + ("a#q.x+b" "" + "") + ("a#q.x.y.z+b" "" + "") + ("a#q.x.y.z+b#p.l.m.n" "" + "") ;; Tag expansion - ("table+" "\n\n\n\n\n\n\n\n\n
\n\n
\n") - ("dl+" "\n
\n\n
\n\n
\n\n
\n\n
\n\n
\n") - ("ul+" "\n\n") - ("ul++ol+" "\n\n\n
    \n\n
  1. \n\n
  2. \n\n
\n") - ("ul#q.x.y m=l+" "\n\n") + ("table+" "" + " " + " " + " " + "
" + "
") + ("dl+" "
" + "
" + "
" + "
") + ("ul+" "") + ("ul++ol+" "" + "
    " + "
  1. " + "
") + ("ul#q.x.y m=l+" "") ;; Parent > child ("a>b" "") ("a>b>c" "") @@ -532,18 +593,48 @@ ("a#q.x>b" "") ("a#q.x.y.z>b" "") ("a#q.x.y.z>b#p.l.m.n" "") - ("#q>.x" "\n
\n\n
\n\n
\n\n
\n") - ("a>b+c" "") - ("a>b+c>d" "") + ("#q>.x" "
" + "
" + "
" + "
") + ("a>b+c" "" + " " + " " + "") + ("a>b+c>d" "" + " " + " " + "") ;; Multiplication ("a*1" "") - ("a*2" "") - ("a/*2" "\n\n") - ("a*2+b*2" "") - ("a*2>b*2" "") - ("a>b*2" "") - ("a#q.x>b#q.x*2" "") - ("a#q.x>b/#q.x*2" "\n\n\n\n\n\n") + ("a*2" "" + "") + ("a/*2" "" + "") + ("a*2+b*2" "" + "" + "" + "") + ("a*2>b*2" "" + " " + " " + "" + "" + " " + " " + "") + ("a>b*2" "" + " " + " " + "") + ("a#q.x>b#q.x*2" "" + " " + " " + "") + ("a#q.x>b/#q.x*2" "" + " " + " " + "") ;; Properties ("a x" "") ("a x=" "") @@ -554,33 +645,62 @@ ("a x m" "") ("a x= m=\"\"" "") ("a x=y m=l" "") - ("a/ x=y m=l" "\n") + ("a/ x=y m=l" "") ("a#foo x=y m=l" "") ("a.foo x=y m=l" "") ("a#foo.bar.mu x=y m=l" "") - ("a/#foo.bar.mu x=y m=l" "\n") - ("a x=y+b" "") - ("a x=y+b x=y" "") + ("a/#foo.bar.mu x=y m=l" "") + ("a x=y+b" "" + "") + ("a x=y+b x=y" "" + "") ("a x=y>b" "") ("a x=y>b x=y" "") - ("a x=y>b x=y+c x=y" "") + ("a x=y>b x=y+c x=y" "" + " " + " " + "") ;; Parentheses ("(a)" "") - ("(a)+(b)" "") + ("(a)+(b)" "" + "") ("a>(b)" "") ("(a>b)>c" "") - ("(a>b)+c" "") - ("z+(a>b)+c+k" "") - ("(a)*2" "") - ("((a)*2)" "") - ("((a)*2)" "") - ("(a>b)*2" "") - ("(a+b)*2" "") + ("(a>b)+c" "" + "") + ("z+(a>b)+c+k" "" + "" + "" + "") + ("(a)*2" "" + "") + ("((a)*2)" "" + "") + ("((a))*2" "" + "") + ("(a>b)*2" "" + "") + ("(a+b)*2" "" + "" + "" + "") ;; Filters - ("#a.b|c" "\n\n
\n\n
\n\n\n") + ("#a.b|c" "" + "
" + "
" + "") + ("a|haml" "%a") + ("a#q.x.y.z|haml" "%a#q.x.y.z") + ("a#q.x x=y m=l|haml" "%a#q.x{:x => \"y\", :m => \"l\"}") + ("div|haml" "%div") + ("div.footer|haml" ".footer") + (".footer|haml" ".footer") + ("p>a href=#+br|haml" "%p" + " %a{:href => \"#\"}" + " %br") ))) (mapc (lambda (input) - (let ((expected (cadr input)) + (let ((expected (mapconcat 'identity (cdr input) "\n")) (actual (zencoding-transform (car (zencoding-expr (car input)))))) (if (not (equal expected actual)) (error (concat "Assertion " (car input) " failed:" @@ -590,8 +710,6 @@ tests) (concat (number-to-string (length tests)) " tests performed. All OK."))) -(zencoding-test-cases) - ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Zencoding minor mode @@ -609,20 +727,17 @@ (if (first expr) (list (first expr) start end)))) +(defcustom zencoding-indentation 4 + "Number of spaces used for indentation." + :type '(number :tag "Spaces") + :group 'zencoding) + (defun zencoding-prettify (markup indent) - (save-match-data - ;;(setq markup (replace-regexp-in-string "><" ">\n<" markup)) - (setq markup (replace-regexp-in-string "\n\n" "\n" markup)) - (setq markup (replace-regexp-in-string "^\n" "" markup))) - (with-temp-buffer - (indent-to indent) - (insert "") - (insert "\n") - (let ((here (point))) - (insert markup) - (sgml-mode) - (indent-region here (point-max)) - (buffer-substring-no-properties here (point-max))))) + (let ((first-col (format (format "%%%ds" indent) "")) + (tab (format (format "%%%ds" zencoding-indentation) ""))) + (concat first-col + (replace-regexp-in-string "\n" (concat "\n" first-col) + (replace-regexp-in-string " " tab markup))))) ;;;###autoload (defun zencoding-expand-line (arg) @@ -694,7 +809,6 @@ See also `zencoding-expand-line'." :lighter " Zen" :keymap zencoding-mode-keymap) - ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Zencoding yasnippet integration @@ -719,8 +833,6 @@ See also `zencoding-expand-line'." (buffer-substring (second expr) (point)) (second expr) (point)))))) - - ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Real-time preview ;; -- cgit v1.2.3