branch: externals/sql-indent
commit 95df3b0656a24d1898668b3e6f88c1532b9d4792
Author: Alex Harsanyi <[email protected]>
Commit: Alex Harsanyi <[email protected]>

    Recognize syntax of CASE statements which are not nested
    
    Based on an example in https://github.com/bsvingen/sql-indent/issues/1
    
    Also added test case for this syntax type.
---
 sql-indent-test.el          |  3 +++
 sql-indent.el               | 51 ++++++++++++++++++++++++++++++++-------------
 test-data/case-stmt-syn.eld | 22 +++++++++++++++++++
 test-data/case-stmt.sql     |  8 +++++++
 4 files changed, 69 insertions(+), 15 deletions(-)

diff --git a/sql-indent-test.el b/sql-indent-test.el
index 9ba6baa..1e9d5ad 100644
--- a/sql-indent-test.el
+++ b/sql-indent-test.el
@@ -234,6 +234,9 @@ information read from DATA-FILE (as generated by
 (ert-deftest sqlind-ert-pr7 ()
   (sqlind-ert-check-file-syntax "test-data/pr7.sql" "test-data/pr7-syn.eld"))
 
+(ert-deftest sqlind-ert-case-stmt ()
+  (sqlind-ert-check-file-syntax "test-data/case-stmt.sql" 
"test-data/case-stmt-syn.eld"))
+
 (ert-deftest sqlind-ert-m-syn ()
   (sqlind-ert-check-file-syntax "test-data/m.sql" "test-data/m-syn.eld"))
 
diff --git a/sql-indent.el b/sql-indent.el
index 9f0296e..17b387e 100644
--- a/sql-indent.el
+++ b/sql-indent.el
@@ -179,10 +179,27 @@ block label might be empty."
   "Return t if POINT is at the same syntactic level as START.
 This means that POINT is at the same nesting level and not inside
 a strinf or comment."
-  (let ((parse-info (parse-partial-sexp start point)))
-    (not (or (nth 3 parse-info)                 ; inside a string
-            (nth 4 parse-info)                 ; inside a comment
-            (> (nth 0 parse-info) 0))))) ; inside a nested paren
+  (save-excursion
+    (let ((parse-info (parse-partial-sexp start point)))
+      (not (or (nth 3 parse-info)                 ; inside a string
+               (nth 4 parse-info)                 ; inside a comment
+               (> (nth 0 parse-info) 0))))))      ; inside a nested paren
+
+(defun sqlind-column-definition-start (pos limit)
+  "Find the beginning of a column definition in a select statement.
+POS is the current position of the line to be indented, assumed
+to be in a 'select-column-continuation syntax.
+
+LIMIT is the limit of the search, the beginning of the select
+statement."
+  (save-excursion
+    (goto-char pos)
+    (catch 'found
+      (while (re-search-backward "," limit 'noerror)
+        (when (sqlind-same-level-statement (point) pos)
+          (forward-char 1)
+          (sqlind-forward-syntactic-ws)
+          (throw 'found (point)))))))
 
 ;;;;; Find the beginning of the current statement
 
@@ -291,8 +308,9 @@ But don't go before LIMIT."
 ;;;;; Find the syntax and beginning of the current block
 
 (defconst sqlind-end-statement-regexp
-  "end\\_>\\(?:[ \n\r\t]*\\)\\(if\\_>\\|loop\\_>\\|case\\_>\\)?\\(?:[ 
\n\r\f]*\\)\\([a-z0-9_]+\\)?\\(?:[ \n\r\f]*\\);"
-  "Match an end of statement.")
+  "end\\_>\\(?:[ \n\r\t]*\\)\\(if\\_>\\|loop\\_>\\|case\\_>\\)?\\(?:[ 
\n\r\f]*\\)\\([a-z0-9_]+\\)?"
+  "Match an end of statement.
+Matches a string like \"end if|loop|case MAYBE-LABEL\".")
 
 (defvar sqlind-end-stmt-stack nil
   "Stack of end-of-statement positions.
@@ -635,10 +653,12 @@ See also `sqlind-beginning-of-block'"
   "Return the syntax inside a CASE expression begining at START."
   (save-excursion
     (goto-char pos)
-    (cond ((looking-at "when\\|end\\|else")
-           ;; A WHEN, or END clause is indented relative to the start of the 
case
-           ;; expression
+    (cond ((looking-at "when\\|else")
+           ;; A WHEN, or ELSE clause is indented relative to the start of the
+           ;; case expression
            (cons 'case-clause start))
+          ((looking-at "end")
+           (cons (list 'block-end 'case "") start))
           ((looking-at "then")
            ;; THEN and ELSE clauses are indented relative to the start of the
            ;; when clause, which we must find
@@ -1155,12 +1175,13 @@ purposes. "
                      ((looking-at "update")
                       (push (sqlind-syntax-in-update pos (point)) context))))
 
-                 ;; (when (eq (car (car context)) 'select-column-continuation)
-                 ;;   ;; case expressions can show up here, maybe refine this
-                 ;;   ;; syntax
-                 ;;   t
-                 ;;   )
-
+                 (when (eq (car (car context)) 'select-column-continuation)
+                   (let ((cdef (sqlind-column-definition-start pos (cdar 
context))))
+                     (when cdef
+                       (save-excursion
+                         (goto-char cdef)
+                         (when (looking-at "case")
+                           (push (sqlind-syntax-in-case pos (point)) 
context))))))
                  )))
 
             ;; create block start syntax if needed
diff --git a/test-data/case-stmt-syn.eld b/test-data/case-stmt-syn.eld
new file mode 100644
index 0000000..f9b4e25
--- /dev/null
+++ b/test-data/case-stmt-syn.eld
@@ -0,0 +1,22 @@
+(((comment-start . 1)
+  (toplevel . 1))
+ ((toplevel . 1))
+ ((select-column . 52)
+  (statement-continuation . 52))
+ ((case-clause . 70)
+  (select-column-continuation . 52)
+  (statement-continuation . 52))
+ ((case-clause . 70)
+  (select-column-continuation . 52)
+  (statement-continuation . 52))
+ ((case-clause . 70)
+  (select-column-continuation . 52)
+  (statement-continuation . 52))
+ (((block-end case "")
+   . 70)
+  (select-column-continuation . 52)
+  (statement-continuation . 52))
+ ((select-clause . 52)
+  (statement-continuation . 52))
+ ((toplevel . 1)))
+ 
diff --git a/test-data/case-stmt.sql b/test-data/case-stmt.sql
new file mode 100644
index 0000000..8a6e32e
--- /dev/null
+++ b/test-data/case-stmt.sql
@@ -0,0 +1,8 @@
+-- https://github.com/bsvingen/sql-indent/issues/1
+SELECT y ,
+       CASE
+       WHEN foo>5 THEN "great"
+       WHEN foo=5 THEN "normal"
+       ELSE "poor"
+       END AS level
+  FROM bar;

Reply via email to