@@ -114,6 +114,51 @@ be used as a prefix for the message."
114114 (if (eq (car , always ) 'lambda ) (funcall , always proc msg)
115115 (apply (car , always ) (cdr , always ))))))))))
116116
117+ (defun dbml-mode--highlight-index-composite (pos word )
118+ " Find each column in the composite index and highlight appropriately."
119+ (let ((left 0 ) (right (length word)))
120+ (while (or (string-prefix-p " " (substring-no-properties word left right))
121+ (string-prefix-p " ," (substring-no-properties word left right)))
122+ (setq left (1+ left)))
123+ (while (or (string-suffix-p " " (substring-no-properties word left right))
124+ (string-suffix-p " ," (substring-no-properties word left right)))
125+ (setq right (1- right)))
126+ (add-face-text-property
127+ (+ pos left) (+ pos right) 'font-lock-variable-name-face )))
128+
129+ (defun dbml-mode--validate-index-syntax (num &optional highlight )
130+ " Validate whether composite index syntax matches DBML spec.
131+ Argument NUM `match-data' group containing composite index
132+ columns separated by =,=, ignoring whitespace.
133+ Argument HIGHLIGHT propertizes text on top of validation marks, if non-nil."
134+ (save-excursion
135+ (let ((block-begin (match-beginning num))
136+ (pattern
137+ (rx (or line-start (+? blank))
138+ (group (literal " (" )) (group (*? anychar)) (group (literal " )" ))
139+ (or line-end (+? blank)))))
140+ (save-match-data
141+ (while (and (> (point ) block-begin)
142+ (re-search-backward pattern block-begin t ))
143+ (when highlight
144+ (dolist (idx '(1 3 ))
145+ (add-face-text-property
146+ (match-beginning idx) (match-end idx) 'bold )))
147+ (let* ((begin (match-beginning 2 ))
148+ (end (match-end 2 ))
149+ (text (match-string 2 ))
150+ (pos begin))
151+ (dolist (item (split-string text " ," nil ))
152+ (if (string= " " (string-trim item))
153+ ; ; bad syntax, double-comma, possibly with spaces in-between
154+ (if (eq pos end)
155+ (add-face-text-property (1- pos) pos '(underline error ))
156+ (add-face-text-property pos (1+ pos) '(underline error )))
157+ ; ; normal behavior, get words and highlight
158+ (when highlight
159+ (dbml-mode--highlight-index-composite pos item)))
160+ (setq pos (+ pos (length item) 1 )))))))))
161+
117162(defun dbml-mode--validate-table-names (num )
118163 " Validate whether table declaration exists.
119164Argument NUM `match-data' group containing table name."
@@ -157,7 +202,7 @@ Argument COLUMN-MATCH-NUM `match-data' group containing column name."
157202 (put-text-property begin end 'face '(underline error )))))))
158203
159204(defun dbml-mode--validate-unique-column (num )
160- " Validate whether table is declared only once.
205+ " Validate whether column is declared only once.
161206Argument NUM `match-data' group containing column name."
162207 ; ; TODO: fix me for matching columns names when [] is split
163208 ; ; over multiple lines (fix regex or make it anchored)
@@ -433,7 +478,7 @@ Argument PROC is a handle from previous process checking for image presence."
433478 ; ; then keep the anchored match loop within the block
434479 (match-end 0 ))
435480 ; ; post-match form
436- nil
481+ ( progn (dbml-mode--validate-unique-column 1 ))
437482 (1 'font-lock-variable-name-face t )))
438483 ; ; part 2: composite
439484 (, dbml-mode--pattern-table-indexes
@@ -449,7 +494,8 @@ Argument PROC is a handle from previous process checking for image presence."
449494 ; ; then keep the anchored match loop within the block
450495 (match-end 0 ))
451496 ; ; post-match form
452- nil ))
497+ ; ; TODO: font-lock-maximum-decoration [1, 3 or 4] / t
498+ (progn (dbml-mode--validate-index-syntax 1 t ))))
453499
454500 ; ; TODO: prefix with braces, anchored as a block?
455501 ; ; individual column settings (non-value keywords in angle brackets)
0 commit comments