X-Git-Url: https://git.donarmstrong.com/?a=blobdiff_plain;f=emacs_el%2Fsql-indent.el;fp=emacs_el%2Fsql-indent.el;h=4b0a79c35f7ed799bb48eb21e56af99b3fcfd134;hb=d553f569722861547814858b9aa5946eb7ad92eb;hp=0000000000000000000000000000000000000000;hpb=eeeaf58f48c148afcaffbb17673809cefa5ee058;p=lib.git diff --git a/emacs_el/sql-indent.el b/emacs_el/sql-indent.el new file mode 100644 index 0000000..4b0a79c --- /dev/null +++ b/emacs_el/sql-indent.el @@ -0,0 +1,240 @@ +;;; sql-indent.el --- indentation of SQL statements + +;; Copyright (C) 2000 Alex Schroeder + +;; Authors: Alex Schroeder +;; Matt Henry +;; Maintainer: Matt Henry +;; Version: $Id: sql-indent.el,v 1.10 2009/03/25 22:52:25 mhenry Exp $ + +;; Keywords: languages +;; URL: http://www.emacswiki.org/cgi-bin/wiki.pl?SqlIndent + +;; This file is not part of GNU Emacs. + +;; This is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 2, or (at your option) +;; any later version. + +;; This is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs; see the file COPYING. If not, write to the +;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, +;; Boston, MA 02111-1307, USA. + +;;; Commentary: + +;; Indent SQL statements. + +;; As the indentation of SQL statements depends not only on the previous +;; line but also on the current line, empty lines cannot always be +;; indented correctly. + +;; Usage note: Loading this file will make all SQL mode buffers created +;; from then on use `sql-indent-line' for indentation. A possible way +;; to install sql-indent.el would be to add the following to your +;; .emacs: + +;; (eval-after-load "sql" +;; '(load-library "sql-indent")) + +;; Thanks: +;; Arcady Genkin + + +;;; History: +;; 2009-03-22* +;; * mhenry +;; Added `sql-indent-buffer' for efficient full buffer processing. +;; Modified `sql-indent' to be savvy to comments and strings. +;; Removed "and", "or" and "exists" from `sql-indent-first-column-regexp' +;; Added "create", "drop" and "truncate" to `sql-indent-first-column-regexp' + +;;; Code: + +(require 'sql) + +;; Need the following to allow GNU Emacs 19 to compile the file. +(require 'regexp-opt) + +(defcustom sql-indent-first-column-regexp + (concat "^\\s-*" (regexp-opt '( + "select" "update" "insert" "delete" + "union" "intersect" + "from" "where" "into" "group" "having" "order" + "set" + "create" "drop" "truncate" + "--") t) "\\(\\b\\|\\s-\\)") + "Regexp matching keywords relevant for indentation. +The regexp matches lines which start SQL statements and it matches lines +that should be indented at the same column as the start of the SQL +statement. The regexp is created at compile-time. Take a look at the +source before changing it. All lines not matching this regexp will be +indented by `sql-indent-offset'." + :type 'regexp + :group 'SQL) + +(defcustom sql-indent-offset 4 + "*Offset for SQL indentation." + :type 'number + :group 'SQL) + +(defcustom sql-indent-maybe-tab nil + "If non-nil, call `insert-tab' if `current-column' did not change." + :type 'boolean + :group 'SQL) + +(defvar sql-indent-debug nil + "If non-nil, `sql-indent-line' will output debugging messages.") + +(defun sql-indent-is-string-or-comment () + "Return nil if point is not in a comment or string; non-nil otherwise." + (let ((parse-state (syntax-ppss))) + (or (nth 3 parse-state) ; String + (nth 4 parse-state))) ; Comment + ) + +(defun sql-indent-get-last-line-start () + "Find the last non-blank line. Return the beginning position of that line and its indentation." + + (save-excursion + (forward-line -1) + + (while (and (not (bobp)) + (or + (looking-at "^\\s-*$") + (sql-indent-is-string-or-comment)) ; Skip comments or strings + ) + + (forward-line -1)) + (list (point) (current-indentation)) + ) + ) + +(defun sql-indent-level-delta (&optional prev-start prev-indent) + "Calculate the change in level from the previous non-blank line. +Given the optional parameter `PREV-START' and `PREV-INDENT', assume that to be +the previous non-blank line. +Return a list containing the level change and the previous indentation." + + (save-excursion + ;; Go back to the previous non-blank line + (let* ((p-line (cond ((and prev-start prev-indent) + (list prev-start prev-indent)) + ((sql-indent-get-last-line-start)))) + (curr-start (progn (beginning-of-line) + (point))) + (paren (nth 0 (parse-partial-sexp (nth 0 p-line) curr-start)))) + + ;; Add opening or closing parens. + ;; If the current line starts with a keyword statement (e.g. SELECT, FROM, ...) back up one level + ;; If the previous line starts with a keyword statement then add one level + + (list + (+ paren + (if (progn (goto-char (nth 0 p-line)) + (looking-at sql-indent-first-column-regexp)) + 1 + 0) + (if (progn (goto-char curr-start) + (looking-at sql-indent-first-column-regexp)) + -1 + 0) + ) + (nth 1 p-line)) + ) + ) + ) + +(defun sql-indent-buffer () + "Indent the buffer's SQL statements." + (interactive) + (save-excursion + (beginning-of-buffer) + (let* + ((line 0) + (level 0) + (start (point)) + (indent (if (looking-at "^\\s-*$") + 0 + (current-indentation))) + (this-indent 0) + (vals '())) + + (while (/= (point) (point-max)) + (forward-line) + + (setq vals + (sql-indent-level-delta start indent) + ) + (setq level (nth 0 vals) + indent (nth 1 vals)) + + (setq this-indent + (max 0 ; Make sure the indentation is at least to column 0 + (* sql-indent-offset + (if (< level 0) + 0 + level)))) + + (if sql-indent-debug + (progn + (setq line (1+ line)) + (message "Line %3d; level %3d; indent was %3d; at %d" line level indent (point)))) + + (beginning-of-line) + (if (and (not (looking-at "^\\s-*$")) ; Leave blank lines alone + (not (sql-indent-is-string-or-comment)) ; Don't mess with comments or strings + (/= this-indent (current-indentation))) ; Don't change the line if already ok. + + (indent-line-to this-indent) + ) + + (end-of-line) + ) + ) + ) + ) + +(defun sql-indent-line () + "Indent current line in an SQL statement." + (interactive) + (let* ((pos (point)) + (indent-info (sql-indent-level-delta)) + (level-delta (nth 0 indent-info)) + (prev-indent (nth 1 indent-info)) + (this-indent (max 0 ; Make sure the indentation is at least 0 + (+ prev-indent + (* sql-indent-offset + (nth 0 indent-info))))) + ) + + (if sql-indent-debug + (message "SQL Indent: level delta: %3d; prev: %3d; this: %3d" + level-delta prev-indent this-indent)) + + (save-excursion + + (beginning-of-line) + + (if (and (not (looking-at "^\\s-*$")) ; Leave blank lines alone + (not (sql-indent-is-string-or-comment)) ; Don't mess with comments or strings + (/= this-indent (current-indentation))) ; Don't change the line if already ok. + (indent-line-to this-indent)) + ) + ) + ) + +(add-hook 'sql-mode-hook + (function (lambda () + (make-local-variable 'indent-line-function) + (setq indent-line-function 'sql-indent-line)))) + +(provide 'sql-indent) + +;;; sql-indent.el ends here