diff --git a/skewer-html.el b/skewer-html.el index e8fecbe..c960058 100644 --- a/skewer-html.el +++ b/skewer-html.el @@ -22,9 +22,9 @@ ;; Selector computation -(defun skewer-html--cleanup (name) - "Cleanup tag names provided by sgml-mode." - (replace-regexp-in-string "/$" "" name)) +(defun skewer-html--cleanup (tag) + "Cleanup TAG name from sgml-mode." + (replace-regexp-in-string "/$" "" (sgml-tag-name tag))) (defun skewer-html--tag-after-point () "Return the tag struct for the tag immediately following point." @@ -32,34 +32,46 @@ (forward-char 1) (sgml-parse-tag-backward))) -(defun skewer-html-compute-tag-nth () +(defun skewer-html--get-context () + "Like `sgml-get-context' but to the root, skipping close tags." + (save-excursion + (cl-loop for context = (sgml-get-context) + while context + nconc (nreverse context) into tags + finally return (cl-delete 'close tags :key #'sgml-tag-type)))) + +(cl-defun skewer-html-compute-tag-nth (&optional (point (point))) "Compute the position of this tag within its parent." (save-excursion - (let ((tag (car (last (sgml-get-context))))) - (if (null tag) - 1 - (cl-loop with start = (sgml-tag-name tag) - with stop = (save-excursion (sgml-get-context) (point)) - with n = 1 - do (sgml-skip-tag-backward 1) - while (> (point) stop) - when (equal start (sgml-tag-name - (skewer-html--tag-after-point))) - do (cl-incf n) - finally (return n)))))) + (setf (point) point) + (let ((context (skewer-html--get-context))) + (when context + (let ((tag-name (skewer-html--cleanup (car context))) + (target-depth (1- (length context)))) + (cl-loop with n = 0 + ;; If point doesn't move, we're at the root. + for point-start = (point) + do (sgml-skip-tag-backward 1) + until (= (point) point-start) + ;; If depth changed, we're done. + for current-depth = (length (skewer-html--get-context)) + until (< current-depth target-depth) + ;; Examine the sibling tag. + for current-name = (save-excursion + (forward-char) + (sgml-parse-tag-name)) + when (equal current-name tag-name) + do (cl-incf n) + finally return n)))))) (defun skewer-html-compute-tag-ancestry () "Compute the ancestry chain at point." - (save-excursion - (nreverse - (cl-loop for nth = (skewer-html-compute-tag-nth) - for tag = (car (last (sgml-get-context))) - while tag - for name = (skewer-html--cleanup (sgml-tag-name tag)) - for type = (sgml-tag-type tag) - when (not (or (string= name "html") - (eq type 'close))) - collect (list name nth))))) + (nreverse + (cl-loop for tag in (skewer-html--get-context) + for nth = (skewer-html-compute-tag-nth (1+ (sgml-tag-start tag))) + for name = (skewer-html--cleanup tag) + unless (equal name "html") + collect (list name nth)))) (defun skewer-html-compute-selector () "Compute the selector for exactly the tag around point." @@ -96,10 +108,8 @@ (let ((ancestry (skewer-html-compute-tag-ancestry))) (save-excursion ;; Move to beginning of opening tag - (cl-loop for tag = (car (last (sgml-get-context))) - while (and tag (eq 'close (sgml-tag-type tag)))) - (let* ((beg (progn (point))) - (end (progn (sgml-skip-tag-forward 1) (point))) + (let* ((beg (progn (sgml-skip-tag-forward 1) (point))) + (end (progn (sgml-skip-tag-backward 1) (point))) (region (buffer-substring-no-properties beg end))) (skewer-flash-region beg end) (if (= (length ancestry) 1)