Below 2 files represent the same structure. With compare 2 files, SEML is short and easy to understand for Lisp hacker.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8"/>
<title>sample page</title>
<link rel="stylesheet" href="sample1.css"/>
</head>
<body>
<h1>sample</h1>
<p>
text sample
</p>
</body>
</html>
(html ((lang . "en"))
(head nil
(meta ((charset . "utf-8")))
(title nil "sample page")
(link ((rel . "stylesheet") (href . "sample1.css"))))
(body nil
(h1 nil "sample")
(p nil "text sample")))
Since SEML can use Elisp freely in SEML file, I think that it has the same power as PHP. You can open files, use information that is only visible to Emacs, and use the results of Emacs hitting an external API.
seml-mode.el
provides major mode for editing SEML (S-Expression Markup Language) files
and utilities for you.
SEML syntax is very easy.
(TAG ATTRS VALUE...)
TAG
is symbol of html tag name.ATTRS
is list ofattribute
.attribute
is dotted pair such as(ATTR . VALUE)
.attribute
is also allowed jade/pug like syntax sugar such as#id.class1.class2
You do not need to specify
id
, but you need to put it at the beginning. Andclass
must be separated by.
.
VALUE
is string.VALUE
is also allowed another SEML.
(cort-deftest seml-mode:/simple-jade
(:string= (seml-decode-seml-from-sexp '(h1 ("#header.class1.class2") "sample"))
"<h1 id=\"header\" class=\"class1 class2\">sample</h1>"))
(cort-deftest seml-mode:/simple-jade2
(:string= (seml-decode-seml-from-sexp '(h1 ("#header.class1") "sample"))
"<h1 id=\"header\" class=\"class1\">sample</h1>"))
(cort-deftest seml-mode:/simple-jade3
(:string= (seml-decode-seml-from-sexp '(h1 ("class1") "sample"))
"<h1 class=\"class1\">sample</h1>"))
(cort-deftest seml-mode:/simple-ul
(:string= (seml-decode-seml-from-sexp
`(ul nil
,@(mapcar (lambda (x)
`(li nil ,(format "item-%s" x)))
(number-sequence 1 5))))
"<ul>
<li>item-1</li>
<li>item-2</li>
<li>item-3</li>
<li>item-4</li>
<li>item-5</li>
</ul>"))
You only need to think about passing SEML list to SEML decoder. So you can use any function returning list.
seml-mode.el
can install with package.el from MELPA,
so sample instration code is below using leaf.el.
(prog1 "Load leaf.el"
(add-to-list 'load-path (locate-user-emacs-file "site-lisp/leaf.el"))
(require 'leaf)
(leaf leaf
:doc "Symplify your init.el configuration"
:doc "Initialize leaf dependent packages"
:url "https://github.com/conao3/leaf.el"
:custom ((leaf-backend-ensure . 'package))
:config
(leaf package
:custom ((package-archives . '(("org" . "https://orgmode.org/elpa/")
("melpa" . "https://melpa.org/packages/")
("gnu" . "https://elpa.gnu.org/packages/"))))
:config
(package-initialize))))
(leaf seml-mode
:when (version<= "25.1" emacs-version)
:ensure t)
Put this package in your load-path
, require it.
(add-to-list 'load-path
(locate-user-emacs-file (format "site-lisp/seml-mode.el")))
(require 'seml-mode)
It is already set to automatically enable seml-mode for typical seml file extensions as follows, but if you want to enable seml-mode for special extensions or for other reasons, you need to set it to an optional setting.
;;;###autoload
(add-to-list 'auto-mode-alist '("\\.seml\\'" . seml-mode))
;;;###autoload
(add-to-list 'interpreter-mode-alist '("seml" . seml-mode))
- seml-mode-hook
- seml-import-dir
- seml-live-refresh-interval
- seml-live-refresh-url-variable
- seml-live-refresh-url-quety
- seml-mode-keywords
Support HTML5 tags.
(defconst seml-mode-keywords '(html head title base link meta style script noscript body section nav article aside hgroup header footer address h1 h2 h3 h4 h5 h6 p hr pre backquote ol ul li dl dt dd figure figcaption div main a em strong small s cite q dfn addr time code var samp kbd sub sup i b mark ruby rt rpbdo span br wbr ins del img iframe embed object param video audio source canvas map area table caption colgroup col tbody thead tfoot tr td th form fieldset legend label input button select datalist optgroup option textarea keygen output progress meter details summary command menu ;; libxml-parse keywords comment top))
- seml-html-single-tags
Define single tag (without closing tag)
(defconst seml-html-single-tags '(base link meta img br area param hr col option input wbr))
- with-seml-elisp
Provide environment to eval Elisp. Use
,@(with-seml-elisp (sexp) (sexp) ...)
(seml-mode misunderstands Elisp’s return value as a component of SEML. If you want to freely execute Elisp that does not need a return value, you need to use this macro to remove the return value from seml.)
- (seml-encode-region-from-html pointmin pointmax)
- (seml-encode-string-from-html str)
- (seml-encode-buffer-from-html &optional buf)
- (seml-encode-file-from-html filepath)
- (seml-encode-region-from-seml start end &optional doctype)
- (seml-encode-sexp-from-seml sexp &optional doctype)
- (seml-encode-string-from-seml str &optional doctype)
- (seml-encode-buffer-from-seml &optional buf doctype)
- (seml-encode-file-from-seml filepath &optional doctype)
- (seml-replace-region-from-html)
- (seml-replace-region-from-seml)
- (seml-impatient-mode)
- (seml-indent-function indent-point state)
- (seml-to-string sexp)
- (seml-pp sexp &optional stream return-p)
- (seml-xpath xpath sexp &optional without-top)
(cort-deftest seml-test:simple-xpath (:equal (seml-xpath '(html head link) '(html ((lang . "en")) (head nil (meta ((charset . "utf-8"))) (title nil "sample page") (link ((rel . "stylesheet") (href . "sample1.css"))) (link ((rel . "stylesheet") (href . "sample2.css")))) (body nil (h1 nil "sample") (p nil "sample" "text sample")))) '((link ((rel . "stylesheet") (href . "sample1.css"))) (link ((rel . "stylesheet") (href . "sample2.css"))))))
- (seml-xpath-single xpath sexp &optional without-top)
(cort-deftest seml-test:/simple-xpath-single (:equal (seml-xpath-single '(html body) '(html ((lang . "en")) (head nil (meta ((charset . "utf-8"))) (title nil "sample page") (link ((rel . "stylesheet") (href . "sample1.css"))) (link ((rel . "stylesheet") (href . "sample2.css")))) (body nil (h2 nil "sample-1") (h2 nil "sample-2") (h2 nil "sample-3") (p nil "sample" "text sample")))) '(body nil (h2 nil "sample-1") (h2 nil "sample-2") (h2 nil "sample-3") (p nil "sample" "text sample"))))
- (seml-xpath-without-top xpath sexp)
(cort-deftest seml-test:/simple-xpath-without-top (:equal (seml-xpath '(html body h2) '(html ((lang . "en")) (head nil (meta ((charset . "utf-8"))) (title nil "sample page") (link ((rel . "stylesheet") (href . "sample1.css"))) (link ((rel . "stylesheet") (href . "sample2.css")))) (body nil (h2 nil "sample-1") (h2 nil "sample-2") (h2 nil "sample-3") (p nil "sample" "text sample"))) t) '(("sample-1") ("sample-2") ("sample-3"))))
- (seml-xpath-single-without-top xpath sexp)
- (seml-htmlize majormode codestr &optional noindentp formatfn)
Get SEML expression of any code in syntax highlight as specify major-mode.
(cort-deftest seml-mode:/simple-htmlize (:equal (seml-htmlize 'emacs-lisp-mode "(leaf real-auto-save :ensure t :custom ((real-auto-save-interval . 0.3)) :commands real-auto-save-mode :hook (find-file-hook . real-auto-save-mode))") '(pre nil " (" (span ((class . "keyword")) "leaf") " real-auto-save " (span ((class . "builtin")) ":ensure") " t " (span ((class . "builtin")) ":custom") " ((real-auto-save-interval . 0.3)) " (span ((class . "builtin")) ":commands") " real-auto-save-mode " (span ((class . "builtin")) ":hook") " (find-file-hook . real-auto-save-mode))")))
- (seml-import path)
- (seml-expand-url path baseurl)
- (seml-mode)
Packages build on seml-mode.
- leaf-browser.el - Web browser frontend of Emacs customize-mode for leaf.el.
I love OSS and I am dreaming of working on it as full-time job.
With your support, I will be able to spend more time at OSS!
All feedback and suggestions are welcome!
You can use github issues, but you can also use Slack if you want a more casual conversation.
Feel free to send PR!
Affero General Public License Version 3 (AGPLv3) Copyright (c) Naoya Yamashita - https://seml-mode.el https://github.com/conao3/seml-mode.el/blob/master/LICENSE
- Naoya Yamashita (conao3)
- Not yet… Now send PR and add your name!!