# HG changeset patch # User Luke Hoersten # Date 1332723792 18000 # Node ID c4e0668a2c871d3320397d33e5f987d02556104a # Parent 6590d340a568818b79348b01f35dfb706cc023a7 Updated zencoding mode. diff -r 6590d340a568 -r c4e0668a2c87 thirdparty/zencoding-mode.el --- a/thirdparty/zencoding-mode.el Thu Mar 01 17:25:13 2012 -0600 +++ b/thirdparty/zencoding-mode.el Sun Mar 25 20:03:12 2012 -0500 @@ -1,12 +1,13 @@ ;;; zencoding-mode.el --- Unfold CSS-selector-like expressions to markup -;; + ;; Copyright (C) 2009, Chris Done -;; + +;; Version: 0.5.1 ;; Author: Chris Done -(defconst zencoding-mode:version "0.5") -;; Last-Updated: 2009-11-20 Fri +;; URL: https://github.com/rooney/zencoding +;; Last-Updated: 2011-12-31 Sat ;; Keywords: convenience -;; + ;; This file is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 3, or (at your option) @@ -21,7 +22,7 @@ ;; along with GNU Emacs; see the file COPYING. If not, write to ;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, ;; Boston, MA 02110-1301, USA. -;; + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;;; Commentary: @@ -59,6 +60,13 @@ ;; ;;; Code: +(defconst zencoding-mode:version "0.5.1") + +;; Include the trie data structure for caching +;(require 'zencoding-trie) + +(require 'cl) + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Generic parsing macros and utilities @@ -111,7 +119,17 @@ ;; Zen coding parsers (defun zencoding-expr (input) - "Parse a zen coding expression. This pretty much defines precedence." + "Parse a zen coding expression with optional filters." + (zencoding-pif (zencoding-parse "\\(.*?\\)|" 2 "expr|filter" it) + (let ((input (elt it 1)) + (filters (elt it 2))) + (zencoding-pif (zencoding-extract-filters filters) + (zencoding-filter input it) + it)) + (zencoding-filter input (zencoding-default-filter)))) + +(defun zencoding-subexpr (input) + "Parse a zen coding expression with no filter. This pretty much defines precedence." (zencoding-run zencoding-siblings it (zencoding-run zencoding-parent-child @@ -124,6 +142,37 @@ it '(error "no match, expecting ( or a-zA-Z0-9"))))))) +(defun zencoding-extract-filters (input) + "Extract filters from expression." + (zencoding-pif (zencoding-parse "\\([^\\|]+?\\)|" 2 "" it) + (let ((filter-name (elt it 1)) + (more-filters (elt it 2))) + (zencoding-pif (zencoding-extract-filters more-filters) + (cons filter-name it) + it)) + (zencoding-parse "\\([^\\|]+\\)" 1 "filter name" `(,(elt it 1))))) + +(defun zencoding-filter (input filters) + "Construct AST with specified filters." + (zencoding-pif (zencoding-subexpr input) + (let ((result (car it)) + (rest (cdr it))) + `((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 ".*\\(\\..*\\)" (or (buffer-file-name) "") 1))) + (defaults '(".html" ("html") + ".htm" ("html") + ".haml" ("haml") + ".clj" ("hic"))) + (default-else '("html")) + (selected-default (member file-ext defaults))) + (if selected-default + (cadr selected-default) + default-else))) + (defun zencoding-multiplier (input) (zencoding-por zencoding-pexpr zencoding-tag (let ((multiplier expr)) @@ -135,26 +184,29 @@ (defun zencoding-tag (input) "Parse a tag." (zencoding-run zencoding-tagname - (let ((result it) - (tagname (cdr expr))) + (let ((tagname (cadr expr)) + (has-body? (cddr expr))) (zencoding-pif (zencoding-run zencoding-identifier (zencoding-tag-classes - `(tag ,tagname ((id ,(cddr expr)))) input) - (zencoding-tag-classes `(tag ,tagname ()) input)) - (let ((expr-and-input it) (expr (car it)) (input (cdr it))) - (zencoding-pif (zencoding-tag-props expr input) - it - expr-and-input)))) - '(error "expected tagname"))) + `(tag (,tagname ,has-body? ,(cddr expr))) input) + (zencoding-tag-classes + `(tag (,tagname ,has-body? nil)) input)) + (let ((expr (car it)) + (input (cdr it))) + (zencoding-tag-props expr input)))) + (zencoding-default-tag input))) + +(defun zencoding-default-tag (input) + "Parse a #id or .class" + (zencoding-parse "\\([#|\\.]\\)" 1 "tagname" + (zencoding-tag (concat "div" (elt it 0))))) (defun zencoding-tag-props (tag input) - (zencoding-run zencoding-props - (let ((tagname (cadr tag)) - (existing-props (caddr tag)) - (props (cdr expr))) - `((tag ,tagname - ,(append existing-props props)) - . ,input)))) + (let ((tag-data (cadr tag))) + (zencoding-run zencoding-props + (let ((props (cdr expr))) + `((tag ,(append tag-data (list props))) . ,input)) + `((tag ,(append tag-data '(nil))) . ,input)))) (defun zencoding-props (input) "Parse many props." @@ -169,33 +221,45 @@ (zencoding-run zencoding-name (let ((name (cdr expr))) - (zencoding-parse "=\\([^\\,\\+\\>\\ )]*\\)" 2 - "=property value" - (let ((value (elt it 1)) - (input (elt it 2))) - `((,(read name) ,value) . ,input))))))) + (zencoding-pif (zencoding-prop-value name input) + it + `((,(read name) "") . ,input)))))) + +(defun zencoding-prop-value (name input) + (zencoding-pif (zencoding-parse "=\"\\(.*?\\)\"" 2 + "=\"property value\"" + (let ((value (elt it 1)) + (input (elt it 2))) + `((,(read name) ,value) . ,input))) + it + (zencoding-parse "=\\([^\\,\\+\\>\\ )]*\\)" 2 + "=property value" + (let ((value (elt it 1)) + (input (elt it 2))) + `((,(read name) ,value) . ,input))))) (defun zencoding-tag-classes (tag input) - (zencoding-run zencoding-classes - (let ((tagname (cadr tag)) - (props (caddr tag)) - (classes `(class ,(mapconcat - (lambda (prop) - (cdadr prop)) - (cdr expr) - " ")))) - `((tag ,tagname ,(append props (list classes))) . ,input)) - `(,tag . ,input))) + (let ((tag-data (cadr tag))) + (zencoding-run zencoding-classes + (let ((classes (mapcar (lambda (cls) (cdadr cls)) + (cdr expr)))) + `((tag ,(append tag-data (list classes))) . ,input)) + `((tag ,(append tag-data '(nil))) . ,input)))) (defun zencoding-tagname (input) "Parse a tagname a-zA-Z0-9 tagname (e.g. html/head/xsl:if/br)." - (zencoding-parse "\\([a-zA-Z][a-zA-Z0-9:-]*\\)" 2 "tagname, a-zA-Z0-9" - `((tagname . ,(elt it 1)) . ,input))) + (zencoding-parse "\\([a-zA-Z][a-zA-Z0-9:-]*\/?\\)" 2 "tagname, a-zA-Z0-9" + (let* ((tag-spec (elt it 1)) + (empty-tag (zencoding-regex "\\([^\/]*\\)\/" tag-spec 1)) + (tag (if empty-tag + (car empty-tag) + tag-spec))) + `((tagname . (,tag . ,(not empty-tag))) . ,input)))) (defun zencoding-pexpr (input) "A zen coding expression with parentheses around it." (zencoding-parse "(" 1 "(" - (zencoding-run zencoding-expr + (zencoding-run zencoding-subexpr (zencoding-aif (zencoding-regex ")" input '(0 1)) `(,expr . ,(elt it 1)) '(error "expecting `)'"))))) @@ -222,13 +286,13 @@ (defun zencoding-child-sans (parent input) (zencoding-parse ">" 1 ">" - (zencoding-run zencoding-expr + (zencoding-run zencoding-subexpr it '(error "expected child")))) (defun zencoding-child (parent input) (zencoding-parse ">" 1 ">" - (zencoding-run zencoding-expr + (zencoding-run zencoding-subexpr (let ((child expr)) `((parent-child ,parent ,child) . ,input)) '(error "expected child")))) @@ -245,15 +309,33 @@ (zencoding-run zencoding-sibling (let ((parent expr)) (zencoding-parse "\\+" 1 "+" - (zencoding-run zencoding-expr + (zencoding-run zencoding-subexpr (let ((child expr)) - `((zencoding-siblings ,parent ,child) . ,input)) - '(error "expected second sibling")))) + `((sibling ,parent ,child) . ,input)) + (zencoding-expand parent input)))) '(error "expected first sibling"))) +(defvar zencoding-expandable-tags + '("dl" ">(dt+dd)" + "ol" ">li" + "ul" ">li" + "table" ">tr>td")) + +(defun zencoding-expand (parent input) + "Parse an e+ expression, where e is an expandable tag" + (let* ((parent-tag (car (elt parent 1))) + (expandable (member parent-tag zencoding-expandable-tags))) + (if expandable + (let ((expansion (zencoding-child parent (concat (cadr expandable))))) + (zencoding-pif (zencoding-parse "+\\(.*\\)" 1 "+expr" + (zencoding-subexpr (elt it 1))) + `((sibling ,(car expansion) ,(car it))) + expansion)) + '(error "expected second sibling")))) + (defun zencoding-name (input) "Parse a class or identifier name, e.g. news, footer, mainimage" - (zencoding-parse "\\([a-zA-Z][a-zA-Z0-9-_]*\\)" 2 "class or identifer name" + (zencoding-parse "\\([a-zA-Z][a-zA-Z0-9-_:]*\\)" 2 "class or identifer name" `((name . ,(elt it 1)) . ,input))) (defun zencoding-class (input) @@ -262,7 +344,6 @@ (zencoding-run zencoding-name `((class ,expr) . ,input) '(error "expected class name")))) - (defun zencoding-identifier (input) "Parse an identifier expression, e.g. #foo" (zencoding-parse "#" 1 "#" @@ -278,12 +359,7 @@ '(error "expected class"))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Zen coding transformer from AST to HTML - -;; Fix-me: make mode specific -(defvar zencoding-single-tags - '("br" - "img")) +;; Zen coding transformer from AST to string (defvar zencoding-inline-tags '("a" @@ -291,10 +367,13 @@ "acronym" "cite" "code" + "dd" "dfn" + "dt" "em" "h1" "h2" "h3" "h4" "h5" "h6" "kbd" + "li" "q" "span" "strong" @@ -303,56 +382,179 @@ (defvar zencoding-block-tags '("p")) -;; li -;; a -;; em -;; p +(defvar zencoding-self-closing-tags + '("br" + "img" + "input")) (defvar zencoding-leaf-function nil "Function to execute when expanding a leaf node in the Zencoding AST.") -(defun zencoding-make-tag (tag &optional content) - (let* ((name (car tag)) - (lf (if - (or - (member name zencoding-block-tags) - (and - (> (length name) 1) - (not (member name zencoding-inline-tags)) - )) - "\n" "")) - (single (member name zencoding-single-tags)) - (props (apply 'concat (mapcar - (lambda (prop) - (concat " " (symbol-name (car prop)) - "=\"" (cadr prop) "\"")) - (cadr tag))))) - (concat lf "<" name props ">" lf - (if single - "" - (concat - (if content content - (if zencoding-leaf-function - (funcall zencoding-leaf-function) - "")) - lf ""))))) +(defvar zencoding-filters + '("html" (zencoding-primary-filter zencoding-make-html-tag) + "c" (zencoding-primary-filter zencoding-make-commented-html-tag) + "haml" (zencoding-primary-filter zencoding-make-haml-tag) + "hic" (zencoding-primary-filter zencoding-make-hiccup-tag) + "e" (zencoding-escape-xml))) + +(defun zencoding-primary-filter (input proc) + "Process filter that needs to be executed first, ie. not given output from other filter." + (if (listp input) + (let ((tag-maker (cadr proc))) + (zencoding-transform-ast input tag-maker)) + nil)) + +(defun zencoding-process-filter (filters input) + "Process filters, chain one filter output as the input of the next filter." + (let ((filter-data (member (car filters) zencoding-filters)) + (more-filters (cdr filters))) + (if filter-data + (let* ((proc (cadr filter-data)) + (fun (car proc)) + (filter-output (funcall fun input proc))) + (if more-filters + (zencoding-process-filter more-filters filter-output) + filter-output)) + 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)) + (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 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-transform (ast) +(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")) + body))) + +(defun zencoding-make-haml-tag (tag-name tag-id tag-classes tag-props self-closing? content) + "Create HAML 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-make-hiccup-tag (tag-name tag-id tag-classes tag-props self-closing? content) + "Create Hiccup string" + (let* ((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) "\"")))) + (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)))))) + (concat "[:" tag-name id classes props + (if content + (if (or content-multiline? block-tag?) + (zencoding-indent content) + (concat " " 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))) + (concat prefix body suffix)) + "")) + +(defun zencoding-escape-xml (input proc) + "Escapes XML-unsafe characters: <, > and &." + (replace-regexp-in-string + "<" "<" + (replace-regexp-in-string + ">" ">" + (replace-regexp-in-string + "&" "&" + (if (stringp input) + input + (zencoding-process-filter (zencoding-default-filter) input)))))) + +(defun zencoding-transform (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) - (mapconcat 'zencoding-transform (cadr ast) "")) + (mapconcat (lexical-let ((make-tag-fun tag-maker)) + #'(lambda (sub-ast) + (zencoding-transform-ast sub-ast make-tag-fun))) + (cadr ast) + "\n")) ((eq type 'tag) - (zencoding-make-tag (cdr ast))) + (zencoding-make-tag tag-maker (cadr ast))) ((eq type 'parent-child) - (let ((parent (cdadr ast)) - (children (zencoding-transform (caddr ast)))) - (zencoding-make-tag parent children))) - ((eq type 'zencoding-siblings) - (let ((sib1 (zencoding-transform (cadr ast))) - (sib2 (zencoding-transform (caddr ast)))) - (concat sib1 sib2)))))) + (let ((parent (cadadr ast)) + (children (zencoding-transform-ast (caddr ast) tag-maker))) + (zencoding-make-tag tag-maker parent children))) + ((eq type 'sibling) + (let ((sib1 (zencoding-transform-ast (cadr ast) tag-maker)) + (sib2 (zencoding-transform-ast (caddr ast) tag-maker))) + (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 @@ -363,13 +565,63 @@ ("a.x" "") ("a#q.x" "") ("a#q.x.y.z" "") + ("#q" "
" + "
") + (".x" "
" + "
") + ("#q.x" "
" + "
") + ("#q.x.y.z" "
" + "
") + ;; Empty tags + ("a/" "") + ("a/.x" "") + ("a/#q.x" "") + ("a/#q.x.y.z" "") + ;; Self-closing tags + ("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+" "" + " " + " " + " " + "
" + "
") + ("dl+" "
" + "
" + "
" + "
") + ("ul+" "") + ("ul++ol+" "" + "
    " + "
  1. " + "
") + ("ul#q.x.y m=l+" "") ;; Parent > child ("a>b" "") ("a>b>c" "") @@ -377,41 +629,138 @@ ("a#q.x>b" "") ("a#q.x.y.z>b" "") ("a#q.x.y.z>b#p.l.m.n" "") - ("a>b+c" "") - ("a>b+c>d" "") + ("#q>.x" "
" + "
" + "
" + "
") + ("a>b+c" "" + " " + " " + "") + ("a>b+c>d" "" + " " + " " + "") ;; Multiplication ("a*1" "") - ("a*2" "") - ("a*2+b*2" "") - ("a*2>b*2" "") - ("a>b*2" "") - ("a#q.x>b#q.x*2" "") + ("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=" "") + ("a x=\"\"" "") ("a x=y" "") + ("a x=\"y\"" "") + ("a x=\"()\"" "") + ("a x m" "") + ("a x= m=\"\"" "") ("a x=y m=l" "") + ("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 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" "" + "" + "" + "") + ;; Filter: comment + ("a.b|c" "" + "" + "") + ("#a>.b|c" "" + "
" + " " + "
" + "
" + " " + "
" + "") + ;; Filter: HAML + ("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") + ;; Filter: Hiccup + ("a|hic" "[:a]") + ("a#q.x.y.z|hic" "[:a#q.x.y.z]") + ("a#q.x x=y m=l|hic" "[:a#q.x {:x \"y\", :m \"l\"}]") + (".footer|hic" "[:div.footer]") + ("p>a href=#+br|hic" "[:p" + " [:a {:href \"#\"}]" + " [:br]]") + ("#q>(a*2>b)+p>b|hic" "[:div#q" + " [:a [:b]]" + " [:a [:b]]" + " [:p" + " [:b]]]") + ;; Filter: escape + ("script src="|e" "<script src=\"&quot;\">" + "</script>") ))) (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:" @@ -421,7 +770,6 @@ tests) (concat (number-to-string (length tests)) " tests performed. All OK."))) - ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Zencoding minor mode @@ -439,20 +787,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) @@ -497,6 +842,7 @@ nil (progn (setq zencoding-mode-keymap (make-sparse-keymap)) + (define-key zencoding-mode-keymap (kbd "C-j") 'zencoding-expand-line) (define-key zencoding-mode-keymap (kbd "") 'zencoding-expand-line))) ;;;###autoload @@ -523,7 +869,6 @@ :lighter " Zen" :keymap zencoding-mode-keymap) - ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Zencoding yasnippet integration @@ -576,6 +921,7 @@ (defvar zencoding-preview-keymap (let ((map (make-sparse-keymap))) + (define-key map (kbd "RET") 'zencoding-preview-accept) (define-key map (kbd "") 'zencoding-preview-accept) (define-key map [(control ?g)] 'zencoding-preview-abort) map)) @@ -701,8 +1047,9 @@ (overlay-end zencoding-preview-input))) (ast (car (zencoding-expr string)))) (when (not (eq ast 'error)) - (zencoding-prettify (zencoding-transform ast) - indent)))) + (let ((output (zencoding-transform ast))) + (when output + (zencoding-prettify output indent)))))) (defun zencoding-update-preview (indent) (let* ((pretty (zencoding-preview-transformed indent)) @@ -711,87 +1058,6 @@ (when show (overlay-put zencoding-preview-output 'after-string (concat show "\n"))))) -;; a+bc - -;;;;;;;;;; -;; Chris's version - -;; (defvar zencoding-realtime-preview-keymap -;; (let ((map (make-sparse-keymap))) -;; (define-key map "\C-c\C-c" 'zencoding-delete-overlay-pair) - -;; map) -;; "Keymap used in zencoding realtime preview overlays.") - -;; ;;;###autoload -;; (defun zencoding-realtime-preview-of-region (beg end) -;; "Construct a real-time preview for the region BEG to END." -;; (interactive "r") -;; (let ((beg2) -;; (end2)) -;; (save-excursion -;; (goto-char beg) -;; (forward-line) -;; (setq beg2 (point) -;; end2 (point)) -;; (insert "\n")) -;; (let ((input-and-output (zencoding-make-overlay-pair beg end beg2 end2))) -;; (zencoding-handle-overlay-change (car input-and-output) nil nil nil))) -;; ) - -;; (defun zencoding-make-overlay-pair (beg1 end1 beg2 end2) -;; "Construct an input and an output overlay for BEG1 END1 and BEG2 END2" -;; (let ((input (make-overlay beg1 end1 nil t t)) -;; (output (make-overlay beg2 end2))) -;; ;; Setup input overlay -;; (overlay-put input 'face '(:underline t)) -;; (overlay-put input 'modification-hooks -;; (list #'zencoding-handle-overlay-change)) -;; (overlay-put input 'output output) -;; (overlay-put input 'keymap zencoding-realtime-preview-keymap) -;; ;; Setup output overlay -;; (overlay-put output 'face '(:overline t)) -;; (overlay-put output 'intangible t) -;; (overlay-put output 'input input) -;; ;; Return the overlays. -;; (list input output)) -;; ) - -;; (defun zencoding-delete-overlay-pair (&optional one) -;; "Delete a pair of input and output overlays based on ONE." -;; (interactive) ;; Since called from keymap -;; (unless one -;; (let ((overlays (overlays-at (point)))) -;; (while (and overlays -;; (not (or (overlay-get (car overlays) 'input) -;; (overlay-get (car overlays) 'output)))) -;; (setq overlays (cdr overlays))) -;; (setq one (car overlays)))) -;; (when one -;; (let ((other (or (overlay-get one 'input) -;; (overlay-get one 'output)))) -;; (delete-overlay one) -;; (delete-overlay other))) -;; ) - -;; (defun zencoding-handle-overlay-change (input del beg end &optional old) -;; "Update preview after overlay change." -;; (let* ((output (overlay-get input 'output)) -;; (start (overlay-start output)) -;; (string (buffer-substring-no-properties -;; (overlay-start input) -;; (overlay-end input))) -;; (ast (car (zencoding-expr string))) -;; (markup (when (not (eq ast 'error)) -;; (zencoding-transform ast)))) -;; (save-excursion -;; (delete-region start (overlay-end output)) -;; (goto-char start) -;; (if markup -;; (insert markup) -;; (insert (propertize "error" 'face 'font-lock-error-face))) -;; (move-overlay output start (point)))) -;; ) (provide 'zencoding-mode)