自 [分享] 使用elisp很方便地打印html 继续讨论:
基于之前的代码,增加了类似Django的模版标签,组织成了package放在了github上。第一次写package,可能有些不成熟的地方,欢迎指正。(顺手给个star呗 )
目前支持 include, if, each, extend(继承) and block 这些逻辑标签。基本的思路是:当列表的第一个元素为标签对象时,正常解析标签(之前的帖子解释的很详细);当第一个元素为逻辑标签时,按照特定的逻辑解析。
这里给一个简单的例子,其余的README里面写的很详细。
(setq comment nil)
(setq comment-div1 '((a :class "if-test" "if-test-content")))
(setq comment-div2 '((a :class "else-test" "else-test-content")))
(setq front ‘((span :class "test" "test-content")))
(pp-html
`(div :class "post-info"
(p "「"
(:include front)
(:if ,comment
(:include comment-div1)
(:include comment-div2))
(ul
(:for fruit
("apple" "peach" "orange" "grape")
(li :class "fruit" fruit)))
(span "分类")
(span "字数")
(span :id "id" :class "class"
(span :class "post-meta-item-text" "阅读 ")
(span :class "leancloud-visitors-count" "...")
" 次")
"」")))
结果:
<div class="post-info">
<p>
「
<span class="test">test-content</span>
<a class="if-test">if-test-content</a>
<ul>
<li class="fruit">apple</li>
<li class="fruit">peach</li>
<li class="fruit">orange</li>
<li class="fruit">grape</li>
</ul>
<span>分类</span>
<span>字数</span>
<span id="id" class="class">
<span class="post-meta-item-text">阅读 </span>
<span class="leancloud-visitors-count">...</span>
次
</span>
」
</p>
</div>
另外,pp-html-test 可以在view-buffer里预览生成的html code。
后续计划:
融合bootstrap等css框架,更加方便控制html布局。
2 个赞
其它生成 XML 的包:
由于 XML、HTML 跟 Sexp 的结构相似,scheme、racket、clojure、common lisp 好像有不少现有用 sexp 表示 xml/html 的方法,或者用来模版,或许值得参考。不过大家也不会用 Emacs 来开发 Web 应用,估计没什么机会用上。另外,能生成专门的 HTML5 应该是个加分项,比如:
;; HTML5
<img>
;; XML
<img />
1 个赞
yfzhe
3
其实 HTML 5 也是建议用 <img />
这种形式的啊。
说 HTML5 和 XML 差别也有,比如 boolean attribute,不知道帖主的包支不支持
是吗?我其实也不了解,只是直觉上没必要加的就不加。
yfzhe
6
在 LISP 中用纯 list 结构(或者叫 s-exp)来表达 XML / HTML 有点好处是可以直接使用 LISP 里的各种方法,尤其指 quasiquote, unquote, unquote-splice。利用这些完全可以实现插入、条件插入等功能,比如你上面的例子就可以写成:
(pp-html
`(div :class "post-info"
(p "「"
,@front
,@(if comment
comment-div1
comment-div2)
(ul
,@(mapcar (lambda (item) `(li :class "fruit" ,item))
'("apple" "peach" "orange" "grape")))
...
"」")))
这样就不需要 :include
, :if
, :each
这种东西了,同样很简单。
2 个赞
谢谢回复,看了下那两个package,第二个竟然和我的实现效果一模一样😅,,,,
不过它的代码好像比我简单,可以学习一下。
谢谢回复,我知道S表达式中可以写些复杂的逻辑(但不知道怎么写😅),用:include :each … 这样的关键字封装主要为了写法尽可能统一,也便于看出html的结构。不过用各种quote封装,我的实现就可以更简单了,而且可以有更复杂的逻辑。
还有个继承的例子,不知道用quote的方式怎么实现?
(setq base-html
'(body
(h1 :id "logo" "戈楷旎")
(p :id "description" "happy hacking emacs")
(div :id "content"
(:block main (p "this is default content")))
(div :id "postamble"
(:block end (p "this is default postamble")))))
(pp-html
`(:extend ,base-html
;; (:block main (p "this is the extend content"))
(:block end (p "this is the extend postamble"))))
结果:
<body>
<h1 id="logo">戈楷旎</h1>
<p id="description">happy hacking emacs</p>
<div id="content">
<p>this is default content</p>
</div>
<div id="postamble">
<p>this is the extend postamble</p>
</div>
</body>
yfzhe
10
不太好找常见的例子,boolean attribute 就是指这个属性的值只能为 boolean,于是就省写它的值,通过这个属性存不存在来表示 true 和 false,比如 <Button disabled />
这样,写了就表示 “disabled”,不写就是 “enabled”。
似乎不太合适用 quasiquote 来实现,但是直接对 list 操作还是很容易的:
(pp-html
(append base-html
'((:block end (p "this is the extend postamble")))))
当然写 quasiquote 也不是不可以:
(pp-html
`(body ;; 甚至可以用 ,(car base-html)
,@(cdr base-html)
(:block end (p "this is the extend postamble"))))
1 个赞
Kinney
11
这个不对吧,继承的意思是在extend中替换base中相同block的内容,没有则使用base中的默认内容。
这需要匹配名称相同的block,然后修改block内容,继承其余默认内容。
append不是用来连接的吗?
Kinney
12
现在也支持这种boolean attribute了,将属性的值设为nil就可以。
例子:
(pp-html '(button :class "btn" :disable nil))
结果:
<button class="btn" disable></button>