emacs-elpa-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[elpa] master 8ab7041 297/433: Adjust indentation in primary mode for ER


From: Dmitry Gutov
Subject: [elpa] master 8ab7041 297/433: Adjust indentation in primary mode for ERB blocks
Date: Thu, 15 Mar 2018 19:44:23 -0400 (EDT)

branch: master
commit 8ab704156fd3808a7061a2e2cbb3190c4612333f
Author: Dmitry Gutov <address@hidden>
Commit: Dmitry Gutov <address@hidden>

    Adjust indentation in primary mode for ERB blocks
---
 mmm-erb.el | 157 +++++++++++++++++++++++++++++++++++++++++++------------------
 1 file changed, 110 insertions(+), 47 deletions(-)

diff --git a/mmm-erb.el b/mmm-erb.el
index 53f472e..1e51507 100644
--- a/mmm-erb.el
+++ b/mmm-erb.el
@@ -46,14 +46,14 @@
 
 (pushnew '(indent-line-function buffer) mmm-save-local-variables)
 
-(dolist (mode (list 'html-erb-mode 'nxml-mode))
-  (mmm-add-mode-ext-class mode "\\.html\\(\\.erb\\)?\\'" 'html-js)
-  (mmm-add-mode-ext-class mode "\\.html\\(\\.erb\\)?\\'" 'html-css)
-  (mmm-add-mode-ext-class mode "\\.html\\.erb\\'" 'erb)
-  (mmm-add-mode-ext-class mode "\\.jst\\.ejs\\'" 'ejs))
+(mmm-add-mode-ext-class 'html-erb-mode "\\.html\\(\\.erb\\)?\\'" 'html-js)
+(mmm-add-mode-ext-class 'html-erb-mode "\\.html\\(\\.erb\\)?\\'" 'html-css)
+(mmm-add-mode-ext-class 'html-erb-mode "\\.html\\.erb\\'" 'erb)
+(mmm-add-mode-ext-class 'html-erb-mode "\\.jst\\.ejs\\'" 'ejs)
 
 ;;;###autoload
 (define-derived-mode html-erb-mode html-mode "ERB-HTML"
+  (setq sgml-unclosed-tags nil) ; Simplifies indentation logic.
   (add-hook 'mmm-html-erb-mode-hook 'mmm-erb-process-submode nil t)
   (add-hook 'mmm-ruby-mode-submode-hook 'mmm-erb-process-submode nil t)
   (add-hook 'mmm-css-mode-submode-hook 'mmm-erb-process-submode nil t)
@@ -65,49 +65,39 @@
 (defun mmm-erb-indent-line ()
   (interactive)
   (mmm-update-submode-region)
-  (destructuring-bind (primary-indent-function submode-indent-function)
-      (mapcar (lambda (mode) (cadr (assoc 'indent-line-function
-                                     (get mode 'mmm-local-variables))))
-              (list mmm-primary-mode mmm-current-submode))
-    (let (added-whitespace)
-      (if (and mmm-current-overlay mmm-current-submode
-               ;; Region starts before the current line.
-               (< (overlay-start mmm-current-overlay)
-                  (point-at-bol)))
-          (if (<= (overlay-end mmm-current-overlay)
-                  (save-excursion (back-to-indentation) (point)))
-              ;; We're at a closing tag.
-              (mmm-erb-indent-to-region-start)
-            (save-restriction
-              (save-excursion
-                (goto-char (overlay-start mmm-current-overlay))
-                (when (not (looking-at "^\\|\\s-*$"))
-                  ;; Submode region has text on the same line as the opening 
tag,
-                  ;; pad it with whitespace to make the following lines line 
up.
-                  (setq added-whitespace (current-column))
-                  (insert-char ?\s added-whitespace)))
-              (narrow-to-region (overlay-start mmm-current-overlay)
-                                (overlay-end mmm-current-overlay))
-              (funcall submode-indent-function)
-              (when added-whitespace
-                ;; Remove the padding.
-                (save-excursion
-                  (goto-char (overlay-start mmm-current-overlay))
-                  (delete-char added-whitespace))))
-            ;; If submode indent function moved us to bol,
-            ;; we're on the top level, indent according to the primary mode.
-            (when (zerop (current-indentation))
-              (mmm-erb-indent-to-region-start
-               (mmm-erb-indent-offset mmm-primary-mode))))
-        (funcall primary-indent-function)))))
+  (if (and mmm-current-overlay mmm-current-submode
+           (< (overlay-start mmm-current-overlay) (point-at-bol)))
+      ;; Region starts before the current line (hence, contains indentation).
+      (mmm-erb-indent-line-submode)
+    (mmm-erb-indent-line-primary)))
 
-(defvar mmm-erb-offset-var-alist
-  '((html-erb-mode . sgml-basic-offset)
-    (nxml-mode . nxml-child-indent)))
-
-(defun mmm-erb-indent-offset (mode)
-  (let ((name (cdr (assoc mode mmm-erb-offset-var-alist))))
-    (when name (symbol-value name))))
+(defun mmm-erb-indent-line-submode ()
+  (let (added-whitespace)
+    (if (<= (overlay-end mmm-current-overlay)
+            (save-excursion (back-to-indentation) (point)))
+        ;; We're at a closing tag.
+        (mmm-erb-indent-to-region-start)
+      (save-restriction
+        (save-excursion
+          (goto-char (overlay-start mmm-current-overlay))
+          (when (not (looking-at "^\\|\\s-*$"))
+            ;; Submode region has text on the same line as the opening tag,
+            ;; pad it with whitespace to make the following lines line up.
+            (setq added-whitespace (current-column))
+            (insert-char ?\s added-whitespace)))
+        (narrow-to-region (overlay-start mmm-current-overlay)
+                          (overlay-end mmm-current-overlay))
+        (funcall (mmm-erb-orig-indent-function mmm-current-submode))
+        (when added-whitespace
+          ;; Remove the padding.
+          (save-excursion
+            (goto-char (overlay-start mmm-current-overlay))
+            (delete-char added-whitespace))))
+      ;; If submode indent function moved us to bol,
+      ;; we're on the top level, indent according to the primary mode.
+      (when (zerop (current-indentation))
+        (mmm-erb-indent-to-region-start
+         (mmm-erb-indent-offset mmm-primary-mode))))))
 
 (defun mmm-erb-indent-to-region-start (&optional additional-offset)
   (let* ((indent (current-indentation))
@@ -119,4 +109,77 @@
           (or additional-offset 0))))
     (when (> offset 0) (forward-char offset))))
 
+(defun mmm-erb-indent-line-primary ()
+  (save-excursion
+    (let* ((here (point))
+           ;; Before previous line's tag.
+           (start (progn (forward-line -1)
+                         (back-to-indentation)
+                         (let ((lcon (sgml-lexical-context)))
+                           (when (eq (car lcon) 'tag)
+                             ;; Tag spreads several lines.
+                             (goto-char (cdr lcon))
+                             (back-to-indentation)))
+                         (point)))
+           (regions (mmm-regions-in start here))
+           (offset (- (current-column) (current-indentation)))
+           (n 0))
+      ;; Collect indent modifier depending on type of tags.
+      (loop for region in regions
+            for type = (mmm-erb-scan-region region)
+            when type do
+            (if (eq type 'close)
+                (when (plusp n) (decf n))
+              (incf n (if (eq type 'close) 0 1))))
+      (let ((eol (progn (goto-char here) (end-of-line 1) (point))))
+        ;; There can be primary mode regions in the list, so we loop.
+        ;; Look for "else" and "end" instructions.
+        ;; If a block start instruction comes first, don't adjust modifier.
+        (loop for region in (mmm-regions-in here eol)
+              for type = (mmm-erb-scan-region region)
+              until (eq type 'open)
+              when (memq type '(middle close)) do (decf n)))
+      (goto-char here)
+      (funcall (mmm-erb-orig-indent-function mmm-primary-mode))
+      (let* ((indent (current-indentation))
+             (indent-step (mmm-erb-indent-offset mmm-primary-mode)))
+        (indent-line-to (+ indent (if n (* indent-step n) 0)))
+        (when (> offset 0) (forward-char offset))))))
+
+(defun mmm-erb-scan-region (region)
+  (when region ; Can be nil if a line is empty, for example.
+    (destructuring-bind (submode beg end) region
+      (let ((scan-fn (plist-get '(ruby-mode mmm-erb-scan-erb
+                                  js-mode   mmm-erb-scan-ejs)
+                                submode)))
+        (when scan-fn
+          (save-excursion
+            (goto-char beg)
+            (skip-syntax-forward "-")
+            (funcall scan-fn end)))))))
+
+(defun mmm-erb-scan-erb (limit)
+  (cond ((looking-at "\\(?:if\\|unless\\|for\\|while\\)\\b") 'open)
+        ((looking-at "\\(?:else\\|elsif\\)\\b") 'middle)
+        ((looking-at "end\\b\\|}") 'close)
+        ((re-search-forward (concat "\\(?: +do +\\| *{ *\\)"
+                                    "\\(?:|[A-Za-z0-9_, ]*|\\)? *") limit t)
+         'open)))
+
+(defun mmm-erb-scan-ejs (limit)
+  (cond ((looking-at "\\(?:if\\|for\\|while\\)\\b") 'open)
+        ((looking-at "} *else\\b") 'middle)
+        ((looking-at "}") 'close)))
+
+(defun mmm-erb-orig-indent-function (mode)
+  (cadr (assoc 'indent-line-function (get mode 'mmm-local-variables))))
+
+(defvar mmm-erb-offset-var-alist
+  '((html-erb-mode . sgml-basic-offset)
+    (nxml-mode . nxml-child-indent)))
+
+(defun mmm-erb-indent-offset (mode)
+  (let ((name (cdr (assoc mode mmm-erb-offset-var-alist))))
+    (when name (symbol-value name))))
+
 (provide 'mmm-erb)



reply via email to

[Prev in Thread] Current Thread [Next in Thread]