Function: sqlind-refine-syntax
sqlind-refine-syntax is a natively compiled function defined in
sql-indent.el.
Signature
(sqlind-refine-syntax CONTEXT POS HAVE-BLOCK-CONTEXT)
Documentation
Refine a basic syntax CONTEXT at POS.
CONTEXT is a syntactic context obtained by looking at the
statement start and block start, see sqlind-syntax-of-line. We
refine it by looking at the contents of the current line and the
contents of the anchor.
HAVE-BLOCK-CONTEXT indicates that we are indenting a statement,
not a statement-continuation POS is the same as the
sqlind-beginning-of-statement.
Source Code
;; Defined in /nix/store/jxjf2h9nnkdqnn1w1mr0ag8bqng2rlrs-emacs-packages-deps/share/emacs/site-lisp/elpa/sql-indent-1.7/sql-indent.el
;;;;; sqlind-syntax-of-line
(defun sqlind-refine-syntax (context pos have-block-context)
"Refine a basic syntax CONTEXT at POS.
CONTEXT is a syntactic context obtained by looking at the
statement start and block start, see `sqlind-syntax-of-line'. We
refine it by looking at the contents of the current line and the
contents of the anchor.
HAVE-BLOCK-CONTEXT indicates that we are indenting a statement,
not a statement-continuation POS is the same as the
`sqlind-beginning-of-statement'."
(let ((syntax (sqlind-syntax context))
(anchor (sqlind-anchor-point context))
(syntax-symbol (sqlind-syntax-symbol context)))
(goto-char pos)
(cond
;; do we start a comment?
((and (not (eq syntax-symbol 'comment-continuation))
(looking-at sqlind-comment-start-skip))
(push (cons 'comment-start anchor) context))
;; Refine a statement continuation
((memq syntax-symbol '(statement-continuation nested-statement-continuation))
;; a (nested) statement continuation which starts with loop
;; or then is a block start
(if (and have-block-context (looking-at "\\(loop\\|then\\|when\\)\\_>"))
(push (cons (list 'block-start (intern (sqlind-match-string 0))) anchor)
context)
;; else
(goto-char anchor)
(when (eq syntax 'nested-statement-continuation)
(forward-char 1)
(sqlind-forward-syntactic-ws)
(setq anchor (point)))
;; when all we have before `pos' is a label, we have a
;; labeled-statement-start
(when (looking-at "<<\\([a-z0-9_]+\\)>>")
(goto-char (match-end 0))
(forward-char 1)
(sqlind-forward-syntactic-ws)
(when (eq (point) pos)
(push (cons 'labeled-statement-start anchor) context)))
(when (looking-at "when\\_>")
(let* ((acontext (sqlind-syntax-of-line))
(asyntax (sqlind-syntax acontext)))
(cond ((equal asyntax '(in-block exception ""))
(push (cons '(in-block exception-handler "") (point)) context))
((equal asyntax '(block-start when))
;; Refine again in the context of the when line
(setq context (sqlind-refine-syntax (cdr acontext) pos have-block-context))))))
;; maybe we have a DML statement (select, insert, update and
;; delete)
;; skip a cursor definition if it is before our point, in the
;; following format:
;;
;; CURSOR name IS
;; CURSOR name type IS
(when (looking-at "cursor\\b")
(let ((origin (point)))
(forward-sexp 1) ; skip "cursor"
(sqlind-forward-syntactic-ws)
(forward-sexp 1)
(sqlind-forward-syntactic-ws)
(if (looking-at "is\\b")
(progn
(goto-char (match-end 0))
(sqlind-forward-syntactic-ws))
(forward-sexp 1)
(sqlind-forward-syntactic-ws)
(when (looking-at "is\\b")
(goto-char (match-end 0))
(sqlind-forward-syntactic-ws)))
(unless (<= (point) pos)
(goto-char origin))))
;; Skip a PostgreSQL cursor declaration
(when (and (eq sql-product 'postgres)
(looking-at "\\(\\(declare\\)\\|\\(cursor\\)\\|\\(for\\)\\)\\b"))
(when (re-search-forward "\\b\\(select\\|update\\|delete\\|insert\\)\\b" pos 'noerror)
(goto-char (match-beginning 0))))
;; skip a forall statement if it is before our point
(when (looking-at "forall\\b")
(when (re-search-forward "\\b\\(select\\|update\\|delete\\|insert\\)\\b" pos 'noerror)
(goto-char (match-beginning 0))))
;; only check for syntax inside DML clauses if we are not
;; at the start of one.
(when (< (point) pos)
(cond
;; NOTE: We only catch here "CASE" expressions, not CASE
;; statements. We also catch assignments with case (var
;; := CASE ...)
((looking-at "\\(\\w+[ \t\r\n\f]+:=[ \t\r\n\f]+\\)?\\(case\\)")
(when (< (match-beginning 2) pos)
(push (sqlind-syntax-in-case pos (match-beginning 2)) context)))
((looking-at "with")
(push (sqlind-syntax-in-with pos (point)) context))
((looking-at "select")
(push (sqlind-syntax-in-select pos (point)) context))
((and (eq sql-product 'postgres)
(looking-at "perform"))
(push (sqlind-syntax-in-select pos (point)) context))
((looking-at "insert")
(push (sqlind-syntax-in-insert pos (point)) context))
((looking-at "delete")
(push (sqlind-syntax-in-delete pos (point)) context))
((looking-at "update")
(push (sqlind-syntax-in-update pos (point)) context))))
(when (eq (sqlind-syntax-symbol context) 'select-column-continuation)
(let ((cdef (sqlind-column-definition-start pos (sqlind-anchor-point context))))
(when cdef
(save-excursion
(goto-char cdef)
(when (looking-at "case")
(push (sqlind-syntax-in-case pos (point)) context))))))
(when (eq (sqlind-syntax-symbol context) 'nested-statement-continuation)
(save-excursion
;; Look for a join expression inside a nested statement, see #70
(goto-char pos)
(when (or (looking-at sqlind-join-condition-regexp)
(progn (forward-word -1) (looking-at sqlind-join-condition-regexp)))
;; look for the join start, that will be the anchor
(let ((jstart (sqlind-find-join-start (point) anchor)))
(when jstart
(push (cons 'select-join-condition jstart) context))))))
))
;; create block start syntax if needed
((and (eq syntax-symbol 'in-block)
(memq (nth 1 syntax) '(if elsif elseif then case))
(looking-at "\\(then\\|\\(els\\(e\\|e?if\\)\\)\\)\\_>"))
(let ((what (intern (sqlind-match-string 0))))
;; the only invalid combination is a then statement in
;; an (in-block "then") context
(unless (and (eq what 'then) (equal (nth 1 syntax) 'then))
(push (cons (list 'block-start what) anchor) context))))
((and (eq syntax-symbol 'in-block)
(eq (nth 1 syntax) 'exception)
(not (looking-at "\\(when\\|end\\)\\_>")))
(save-excursion
(when (sqlind-search-backward pos "when\\_>" anchor)
(push (cons (list 'in-block 'exception-handler) (point)) context))))
;; note that begin is not a block-start in a 'in-begin-block
;; context
((and (memq syntax-symbol '(defun-start declare-statement toplevel
package package-body))
(or (looking-at "begin\\_>")
(and (eq sql-product 'postgres) (looking-at "\\$\\$"))))
(push (cons (list 'block-start 'begin) anchor) context))
((and (memq syntax-symbol '(defun-start package package-body))
(looking-at "\\(is\\|as\\)\\_>"))
(push (cons (list 'block-start 'is-or-as) anchor) context))
((and (memq syntax-symbol '(in-begin-block in-block))
(looking-at "exception\\_>"))
(push (cons (list 'block-start 'exception) anchor) context))
((and (eq syntax-symbol 'in-block)
(memq (nth 1 syntax) '(then case))
(not (looking-at "end\\s-*\\_<\\(if\\|case\\)\\_>")))
(if (looking-at "when\\_>")
(push (cons (list 'block-start 'when) anchor) context)
;; NOTE: the "when" case is handed above
(when (sqlind-search-backward pos "when\\_>" anchor)
(push (cons '(in-block when) (point)) context))))
;; indenting the select clause inside a view or a "create table as"
;; statement.
((and (eq syntax-symbol 'create-statement)
(memq (nth 1 syntax) '(view table)))
(goto-char anchor)
(catch 'done
(while (re-search-forward "\\bselect\\b" pos 'noerror)
(goto-char (match-beginning 0))
(when (sqlind-same-level-statement (point) anchor)
(push (sqlind-syntax-in-select pos (point)) context)
(throw 'done nil))
(goto-char (match-end 0)))))
;; create a block-end syntax if needed
((and (not (eq syntax-symbol 'comment-continuation))
(looking-at "end[ \t\r\n\f]*\\(\\_<\\(?:if\\|loop\\|case\\)\\_>\\)?[ \t\r\n\f]*\\(\\_<\\(?:[a-z0-9_]+\\)\\_>\\)?"))
;; so we see the syntax which closes the current block. We still
;; need to check if the current end is a valid closing block
(let ((kind (or (sqlind-match-string 1) ""))
(label (or (sqlind-match-string 2) "")))
(push (sqlind-refine-end-syntax
(if (equal kind "") nil (intern kind))
label (point) context)
context)))
((and (eq sql-product 'postgres)
(not (eq syntax-symbol 'comment-continuation))
(looking-at "\\$\\$"))
(push (sqlind-refine-end-syntax
nil "" (point) context)
context))
;; See #92 and pr92b.sql, no such thing as a nested declare statement, use
;; the context of the previous declare-statement!
((and (eq sql-product 'postgres)
(eq syntax-symbol 'declare-statement)
(looking-at "declare\\_>"))
(goto-char anchor)
(setq context (sqlind-syntax-of-line)))
)
context))