[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: html, css, and js modes working together
From: |
Stefan Monnier |
Subject: |
Re: html, css, and js modes working together |
Date: |
Thu, 02 Feb 2017 09:19:08 -0500 |
User-agent: |
Gnus/5.13 (Gnus v5.13) Emacs/26.0.50 (gnu/linux) |
> * I didn't read SMIE deeply enough to see if the indentation parts
> relied heavily on the forward/backward-a-token rules. If so then the
> new macro will need some additional work.
In most major modes, the tokenizer needs to be adjusted (IOW, the
default values of smie-*ward-token-functions only exists so it's easier
to get a new major mode half-working): a quick "grep '(smie-setup'
**/*.el" indicates that only ps-mode relies on the default tokenizer.
So yes, it's important for smie-with-rules to set the
for/backward-token-function.
> - (if (bobp) 0)))
> + (if (bobp) (prog-first-column))))
Hmm.. if we want to obey prog-indentation-context,
don't we want something like
(if (and prog-indentation-context
(<= (point) (caadr prog-indentation-context)))
(car prog-indentation-context)
0)
> +(defmacro with-smie-rules (spec &rest body)
> + "Temporarily set up SMIE indentation and evaluate BODY.
> +SPEC is of the form (GRAMMAR RULES-FUNCTION); see `smie-setup'.
> +BODY is evaluated with the relevant SMIE variables temporarily bound."
> + (declare (indent 1))
> + `(let ((smie-grammar ,(car spec))
> + (smie-rules-function ,(cadr spec))
> + (indent-line-function #'smie-indent-line))
> + ,@body))
I think it's likely that the implementation of this macro will change
over time, even if it's external appearance doesn't. So I think we
should make it expand to a code that calls an smie function that does
the actual work. E.g.
(defmacro smie-with-rules (spec &rest body)
(smie-funcall-with-rules (list ,@spec) (lambda () . ,body)))
(defun smie-funcall-with-rules (spec fun)
(let ((smie-grammar (car spec))
(smie-rules-function (cadr spec))
(indent-line-function #'smie-indent-line))
(funcall fun)))
Then again, maybe we want something even more generic that's not
specific to SMIE (see below).
> + (t (prog-first-column)))))
I suspect here as well, we should obey (caadr prog-indentation-context).
> +(defconst html-syntax-propertize-function
> + (syntax-propertize-rules
> + ("<style.*?>\\(\\(\n\\|.\\)*?\\)</style>"
> + (1
> + (prog1 css-mode-syntax-table
> + (let ((start (nth 2 (match-data)))
> + (end (nth 3 (match-data))))
> + (funcall css-syntax-propertize-function start end)
> + (add-text-properties start end '(syntax-multiline t))))))
> + ("<script.*?>\\(\\(\n\\|.\\)*?\\)</script>"
> + (1
> + (prog1 js-mode-syntax-table
> + (let ((start (nth 2 (match-data)))
> + (end (nth 3 (match-data))))
> + (js-syntax-propertize start end)
> + (add-text-properties start end '(syntax-multiline t))))))
> + sgml-syntax-propertize-rules)
> + "Syntactic keywords for `html-mode'.")
As pointed out by Clément, these regexps are a bad idea.
Better do something like:
(defun html-syntax-propertize (start end)
(goto-char start)
(when (get-text-property (point) 'html-submode)
(html--syntax-propertize-submode
(get-text-property (point) 'html-submode)
end))
(funcall
(syntax-propertize-rules
("<style.*?>"
(0 (ignore (goto-char (match-end 0))
(html--syntax-propertize-submode 'css-mode end))))
("<script.*?>"
(0 (ignore (goto-char (match-end 0))
(html--syntax-propertize-submode 'js-mode end)))))
(point) end))
> + (cond
> + ((equal tag "style")
> + ;; CSS.
> + (save-restriction
> + (let ((base-indent (save-excursion
> + (goto-char (sgml-tag-end context))
> + (sgml-calculate-indent))))
> + (narrow-to-region (sgml-tag-end context) (point-max))
> + (let ((prog-indentation-context (list base-indent
> + (cons (point-min) nil)
> + nil)))
> + (with-smie-rules (css-smie-grammar #'css-smie-rules)
> + (smie-indent-line))))))
> + ((equal tag "script")
> + ;; Javascript.
> + (save-restriction
> + (let ((base-indent (save-excursion
> + (goto-char (sgml-tag-end context))
> + (sgml-calculate-indent))))
> + (narrow-to-region (sgml-tag-end context) (point-max))
> + (let ((prog-indentation-context (list base-indent
> + (cons (point-min) nil)
> + nil)))
> + (js-indent-line)))))
> + (t
> + ;; HTML.
> + (sgml-indent-line)))))
How 'bout instead doing something like:
(defun html--get-mode-vars (mode)
(with-temp-buffer
(funcall mode)
(buffer-local-variables)))
(defconst html--css-vars (html--get-mode-vars 'css-mode))
(defconst html--js-vars (html--get-mode-vars js-mode))
(defun html--funcall-with-mode-var (vars fun)
(cl-progv (mapcar #'car vars) (mapcar #'cdr vars) (funcall fun)))
and then do
((member tag '("style" "script"))
(let* ((start (sgml-tag-end context))
(base-indent (save-excursion
(goto-char start)
(sgml-calculate-indent)))
(prog-indentation-context (list base-indent
(cons start nil)
nil))
(vars (if (equal tag "style") html--css-vars html--js-vars)))
(cl-progv (mapcar #'car vars) (mapcar #'cdr vars)
(indent-according-to-mode))))
I'm sure the above will break miserably, because you'll need to tweak
the list of vars that really matter (most likely some of the
buffer-local-variables should not be in html--*-vars), but such an
approach should also help break the cyclic dependencies.
Stefan
- Re: html, css, and js modes working together, Clément Pit-Claudel, 2017/02/01
- Re: html, css, and js modes working together,
Stefan Monnier <=
- Re: html, css, and js modes working together, Dmitry Gutov, 2017/02/05
- Re: html, css, and js modes working together, Tom Tromey, 2017/02/05
- Re: html, css, and js modes working together, Dmitry Gutov, 2017/02/05
- Re: html, css, and js modes working together, Clément Pit-Claudel, 2017/02/06
- Re: html, css, and js modes working together, Stefan Monnier, 2017/02/06
- Re: html, css, and js modes working together, Tom Tromey, 2017/02/06
- Re: html, css, and js modes working together, Dmitry Gutov, 2017/02/06
- Re: html, css, and js modes working together, Stefan Monnier, 2017/02/06
- Re: html, css, and js modes working together, Lennart Borgman, 2017/02/06