diff --git a/elpa/elisp-format-20160508.952/elisp-format-autoloads.el b/elpa/elisp-format-20160508.952/elisp-format-autoloads.el new file mode 100644 index 00000000..d75d76c0 --- /dev/null +++ b/elpa/elisp-format-20160508.952/elisp-format-autoloads.el @@ -0,0 +1,68 @@ +;;; elisp-format-autoloads.el --- automatically extracted autoloads +;; +;;; Code: + +(add-to-list 'load-path (directory-file-name + (or (file-name-directory #$) (car load-path)))) + + +;;;### (autoloads nil "elisp-format" "elisp-format.el" (0 0 0 0)) +;;; Generated autoloads from elisp-format.el + +(autoload 'elisp-format-region "elisp-format" "\ +Format current region or buffer. +This function will format region from START to END. +Or try to format `defun' around point. + +\(fn &optional START END)" t nil) + +(autoload 'elisp-format-buffer "elisp-format" "\ +Format current buffer. + +\(fn)" t nil) + +(autoload 'elisp-format-file "elisp-format" "\ +Format file with FILENAME. + +\(fn FILENAME)" t nil) + +(autoload 'elisp-format-file-batch "elisp-format" "\ +Format elisp FILENAME. +But instead in `batch-mode'. +If SURPRESS-POPUP-WINDOW is non-nil, don't show output window. + +\(fn FILENAME &optional SURPRESS-POPUP-WINDOW)" t nil) + +(autoload 'elisp-format-directory "elisp-format" "\ +Format recursive elisp files under DIR. + +\(fn DIR)" t nil) + +(autoload 'elisp-format-directory-batch "elisp-format" "\ +Format recursive elisp files under DIR. +But instead in `batch-mode'. +If SURPRESS-POPUP-WINDOW is non-nil, don't show output window. + +\(fn DIR &optional SURPRESS-POPUP-WINDOW)" t nil) + +(autoload 'elisp-format-dired-mark-files "elisp-format" "\ +Format dired mark files. + +\(fn)" t nil) + +(autoload 'elisp-format-library "elisp-format" "\ +Format LIBRARY. + +\(fn LIBRARY)" t nil) + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "elisp-format" '("elisp-format-"))) + +;;;*** + +;; Local Variables: +;; version-control: never +;; no-byte-compile: t +;; no-update-autoloads: t +;; coding: utf-8 +;; End: +;;; elisp-format-autoloads.el ends here diff --git a/elpa/elisp-format-20160508.952/elisp-format-pkg.el b/elpa/elisp-format-20160508.952/elisp-format-pkg.el new file mode 100644 index 00000000..65392d9c --- /dev/null +++ b/elpa/elisp-format-20160508.952/elisp-format-pkg.el @@ -0,0 +1,2 @@ +;;; -*- no-byte-compile: t -*- +(define-package "elisp-format" "20160508.952" "Format elisp code" 'nil :commit "03cc293eb2f78ec58fc1d84279af06816a04b979" :authors '((nil . "Andy Stewart lazycat.manatee@gmail.com")) :maintainer '("Yuki Inoue inouetakahiroki _at_ gmail.com") :url "https://github.com/Yuki-Inoue/elisp-format") diff --git a/elpa/elisp-format-20160508.952/elisp-format.el b/elpa/elisp-format-20160508.952/elisp-format.el new file mode 100644 index 00000000..de162d66 --- /dev/null +++ b/elpa/elisp-format-20160508.952/elisp-format.el @@ -0,0 +1,1242 @@ +;;; elisp-format.el --- Format elisp code + +;; Copyright (C) 2016 Yuki Inoue +;; based on code by Andy Stewart: +;; Copyright (C) 2009 Andy Stewart +;; https://www.emacswiki.org/emacs/elisp-format.el + + +;; Filename: elisp-format.el +;; Description: Format elisp code +;; Author: Andy Stewart lazycat.manatee@gmail.com +;; Maintainer: Yuki Inoue inouetakahiroki _at_ gmail.com +;; Created: 2009-01-20 16:31:45 +;; Version: 0.5.8 +;; Package-Version: 20160508.952 +;; URL: https://github.com/Yuki-Inoue/elisp-format +;; Keywords: +;; Compatibility: GNU Emacs 22 ~ +;; +;; Features that might be required by this library: +;; +;; `newcomment' `cl' +;; + +;;; This file is NOT part of GNU Emacs + +;;; License +;; +;; This program 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 3, or (at your option) +;; any later version. + +;; This program 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 this program; see the file COPYING. If not, write to +;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth +;; Floor, Boston, MA 02110-1301, USA. + +;;; Commentary: +;; +;; This package is format elisp code. +;; This package is format by itself, so you can view format effect. +;; +;; Below are commands you can use: +;; +;; `elisp-format-region' +;; Format region or defun. +;; `elisp-format-buffer' +;; Format buffer. +;; `elisp-format-file' +;; Format file. +;; `elisp-format-file-batch' +;; Format file with `batch'. +;; `elisp-format-directory' +;; Format recursive elisp files in directory. +;; `elisp-format-directory-batch' +;; Format recursive elisp files in directory with `batch'. +;; `elisp-format-dired-mark-files' +;; Format dired marked files. +;; `elisp-format-library' +;; Format library. +;; +;; Tips: +;; +;; If current mark is active, command `elisp-format-region' +;; will format region you select, otherwise it will format +;; `defun' around point. +;; +;; If you want format many files, you can marked them in dired, +;; and use command `elisp-format-dired-mark-files' to format +;; marked files in dired. +;; +;; You can format special file through +;; command `elisp-format-file'. +;; +;; By default, when you format `huge' file, it will +;; hang emacs. +;; You can also use command `elisp-format-file-batch' +;; make format process at background. +;; +;; You also can use command `elisp-format-directory' +;; format all recursive elisp files in special directory. +;; +;; By default, when you use command `elisp-format-directory' +;; format too many elisp files, will hang emacs. +;; You can also use command `elisp-format-directory-batch' +;; make format process at background. +;; +;; If you're sure lazy, you can use command `elisp-format-library' +;; format special library and don't need input long file path. +;; +;; Note: +;; +;; I can't ensure this package can perfect work with all situations. +;; So please let me know if you have suggestion or bug. +;; + +;;; Installation: +;; +;; Put elisp-format.el to your load-path. +;; The load-path is usually ~/elisp/. +;; It's set in your ~/.emacs like this: +;; (add-to-list 'load-path (expand-file-name "~/elisp")) +;; +;; And the following to your ~/.emacs startup file. +;; +;; (require 'elisp-format) +;; +;; No need more. + +;;; Customize: +;; +;; `elisp-format-batch-program' +;; The program name for execute batch command. +;; +;; `elisp-format-column' +;; The column number to truncate long line. +;; +;; `elisp-format-indent-comment' +;; Whether indent comment. +;; +;; `elisp-format-dired-mark-files-confirm' +;; Whether confirmation is needed to format dired marked files. +;; +;; `elisp-format-newline-keyword-addons-list' +;; The list contain addons keywords for newline. +;; +;; `elisp-format-newline-keyword-except-list' +;; The list contain except keywords for newline. +;; +;; `elisp-format-split-subexp-keyword-addons-list' +;; The list contain addons keywords that will split it's sub-expression. +;; +;; `elisp-format-split-subexp-keyword-except-list' +;; The list contain except keywords that will split it's sub-expression. +;; +;; `elisp-format-split-subexp-keyword-keep-alist' +;; The alist contain keep keyword when split it's sub-expression. +;; +;; All of the above can customize by: +;; M-x customize-group RET elisp-format RET +;; + +;;; Change log: +;; +;; 2016/05/06 and later +;; * Refer https://github.com/Yuki-Inoue/elisp-format +;; +;; 2009/03/10 +;; * Fix the bug of +;; `elisp-format-directory-batch' and +;; `elisp-format-file-batch'. +;; * Improve `font-lock-add-keywords' format process. +;; * Setup 100 as default value of `elisp-format-column'. +;; +;; 2009/02/14 +;; * New command `elisp-format-file-batch' +;; format elisp file with `batch'. +;; * Improve `defalias' format process. +;; * Improve `with-output-to-temp-buffer' format process. +;; * Improve `lambda' format process. +;; * Improve `featurep' format process. +;; * Improve `loop' format process. +;; * Improve `:keyword' format process. +;; * Improve ,@ format process. +;; * Improve same level expression format process. +;; * Improve string format process. +;; * Remove option `elisp-format-split-last-sexp-string'. +;; not necessary. +;; * Improve performance. +;; * Fix many bugs. +;; * Refactory code. +;; +;; 2009/02/11 +;; * Fix documentation about `batch' mode. +;; * New command `elisp-format-directory-batch', +;; format elisp files with `batch'. +;; +;; 2009/02/10 +;; * Improve function `elisp-format-directory'. +;; +;; 2009/02/05 +;; * Don't format 'hide' elisp file in `elisp-format-directory'. +;; +;; 2009/02/03 +;; * Rename `elisp-format-dired' to `elisp-format-dired-mark-files'. +;; * Add new command `elisp-format-directory'. +;; * Display spend time for format each elisp file. +;; +;; 2009/01/31 +;; * Check parentheses before format. +;; Remove option `elisp-format-check-parens'. +;; * Add new option `elisp-format-indent-comment'. +;; * Fix bug. +;; +;; 2009/01/27 +;; * Join standalone ")". +;; * Format comments. +;; * Fix `undo-outer-limit' bug. +;; * Add new option `elisp-format-split-subexp-keyword-keep-alist'. +;; Remove option `elisp-format-split-subexp-keyword-keep-1-list'. +;; * Split same level expression. +;; * Don't newline build-in keyword when previous expression +;; is lisp data type keyword (beginning with ':'). +;; * Newline value field of define keyword if value field is longer +;; than `elisp-format-column', otherwise, don't split. +;; * Fix comment bug in `elisp-format-split-keyword-internal'. +;; +;; 2009/01/25 +;; * Support nesting format. +;; * Support split all sub-expression and except first one. +;; * Fix bug. +;; * Fix doc. +;; +;; 2009/01/20 +;; * First released. +;; + +;;; Acknowledgements: +;; +;; +;; + +;;; Bug +;; +;; + +;;; TODO +;; +;; Format long lines: +;; When occur huge files (above 7000 lines) and *deep* code level, +;; will got ugly *code column* at right side. +;; + +;;; Require +(require 'newcomment) +(eval-when-compile + (require 'cl)) + +;;; Code: + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Variable ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +(defvar elisp-format-buildin-keywords-regexp + (let (keywords-alist keywords-list keywords-regexp) + ;; Get value of `font-lock-keywords' + ;; with `emacs-lisp-mode'. + (with-temp-buffer + ;; Load `emacs-lisp-mode' and font-lock. + (emacs-lisp-mode) + (setq font-lock-mode t) + (font-lock-fontify-buffer) + (setq keywords-alist (cadr font-lock-keywords))) + ;; Get regexp string and add to `keywords-list'. + (dolist (element keywords-alist) + (setq element + (if (car-safe element) + (car element) + element)) + (when (stringp element) + ;; Remove "(" from front of regexp. + (setq element (replace-regexp-in-string "^(" "" element)) + (push element keywords-list))) + ;; Concat all regexp string in `keywords-list'. + (dolist (element keywords-list) + (setq keywords-regexp (concat keywords-regexp + (cond ((eq element (first keywords-list)) + (format "\\(%s\\|" element)) + ((eq element (car (last + keywords-list))) + (format "%s\\)" element)) + (t (format "%s\\|" element)))))) + ;; Return keywords regexp. + keywords-regexp) + "The regular expression that match `build-in' keywords.") + +(defvar elisp-format-define-keyword-regexp nil + "The regexp expression for `elisp-format-define-keyword-list'.") + +(defvar elisp-format-newline-keyword-addons-regexp nil + "The regular expression for `elisp-format-newline-keyword-addons-list'.") + +(defvar elisp-format-split-subexp-keyword-addons-regexp nil + "The regular expression for `elisp-format-split-subexp-keyword-addons-list'.") + +(defvar elisp-format-debug-mode nil + "Display details debug information when this option is `non-nil'.") + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Customize ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +(defgroup elisp-format nil + "Format elisp code." + :group 'tools) + +(defcustom elisp-format-batch-program "emacs" + "The program name for execute batch command." + :type 'string + :group 'elisp-format) + +(defcustom elisp-format-column 100 + "The column number to truncate long line." + :type 'integer + :group 'elisp-format) + +(defcustom elisp-format-indent-comment t + "Whether indent comment. +If `non-nil', will indent comment. +Default it t." + :type 'boolean + :group 'elisp-format) + +(defcustom elisp-format-dired-mark-files-confirm t + "Whether confirmation is needed to format dired mark files. +If `non-nil' will notify you before format dired mark files. +Default is t." + :type 'boolean + :group 'elisp-format) + +(defcustom elisp-format-define-keyword-list + '( + ;; Generic. + "defun" "defun*" "defsubst" "defmacro" "defadvice" "define-skeleton" + "define-minor-mode" "define-global-minor-mode" + "define-globalized-minor-mode" "define-derived-mode" "define-generic-mode" + "define-compiler-macro" "define-modify-macro" "defsetf" + "define-setf-expander" "define-method-combination" "defgeneric" "defmethod" + "defalias" + ;; Variable. + "defvar" "defconst" "defconstant" "defcustom" "defparameter" + "define-symbol-macro" + ;; Types. + "defgroup" "deftheme" "deftype" "defstruct" "defclass" "define-condition" + "define-widget" "defface" "defpackage") + "This list contain define-keywords for format. +Copy those value from `lisp-imenu-generic-expression' define. +Or have a exist variable contain those define-keywords?" + :type 'list + :set (lambda (symbol value) + (set symbol value) + (setq elisp-format-define-keyword-regexp (regexp-opt value))) + :group 'elisp-format) + +(defcustom elisp-format-newline-keyword-addons-list + '("interactive" "setq" "set" "buffer-substring" + "buffer-substring-no-properties") + "This list contain addons keywords for newline. +The line beginning match keywords in this list will be newline." + :type 'list + :set (lambda (symbol value) + (set symbol value) + (setq elisp-format-newline-keyword-addons-regexp (regexp-opt value))) + :group 'elisp-format) + +(defcustom elisp-format-newline-keyword-except-list '() + "The list contain except keywords for newline. +The line beginning match keywords in this list won't be newline." + :type 'list + :group 'elisp-format) + +(defcustom elisp-format-split-subexp-keyword-addons-list + '("and" "or" "buffer-substring" "buffer-substring-no-properties" + "font-lock-add-keywords") + "The list contain addons keywords that will split it's sub-expression." + :type 'list + :set (lambda (symbol value) + (set symbol value) + (setq elisp-format-split-subexp-keyword-addons-regexp (regexp-opt + value))) + :group 'elisp-format) + +(defcustom elisp-format-split-subexp-keyword-except-list + '("provide" "require" "loop" "throw" "featurep") + "The list contain except keywords that won't split it's sub-expression." + :type 'list + :group 'elisp-format) + +(defcustom elisp-format-split-subexp-keyword-keep-alist + '((1 . ("and" "or" "let" "let*" "while" "when" "catch" "unless" "if" "dolist" + "dotimes" "lambda" "cond" "condition-case" "with-current-buffer" + "with-temp-message" "with-selected-window" + "with-output-to-temp-buffer" "with-selected-frame")) + (2 . ( + ;; Generic. + "defun" "defun*" "defsubst" "defmacro" "defadvice" "define-skeleton" + "define-minor-mode" "define-global-minor-mode" + "define-globalized-minor-mode" "define-derived-mode" + "define-generic-mode" "define-compiler-macro" "define-modify-macro" + "defsetf" "define-setf-expander" "define-method-combination" + "defgeneric" "defmethod" "defalias" + ;; Variable. + "defvar" "defconst" "defconstant" "defcustom" "defparameter" + "define-symbol-macro" + ;; Types. + "defgroup" "deftheme" "deftype" "defstruct" "defclass" + "define-condition" "define-widget" "defface" "defpackage" )) + (5 . ("loop"))) + "The list contain keywords that will be split it's sub-expression." + :type 'alist + :group 'elisp-format) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Interactive Functions ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;;;###autoload +(defun elisp-format-region (&optional start end) + "Format current region or buffer. +This function will format region from START to END. +Or try to format `defun' around point." + (interactive) + (let ((start-time (elisp-format-get-current-time))) + ;; Display startup message. + (message "Format %s ..." (buffer-name)) + ;; Check parentheses before format. + (check-parens) + ;; Format start. + (save-excursion + ;; Get format area. + (unless (and start + end) + ;; Get format area. + (if mark-active + ;; Get activate mark region. + (progn + (setq start (region-beginning)) + (setq end (region-end)) + (deactivate-mark)) + ;; Or get current function. + (setq start + (progn + (beginning-of-defun) + (point))) + (setq end + (progn + (end-of-defun) + (point))))) + (setq end (copy-marker end)) + ;; Delete un-necessary whitespace. + (elisp-format-delete-whitespace start end) + (when elisp-format-debug-mode + (message "`elisp-format-delete-whitespace' module completed.")) + ;; Split same level expression. + (elisp-format-split-same-level-expression start end) + (when elisp-format-debug-mode + (message "`elisp-format-split-same-level-expression' module completed.")) + ;; Split list data type. + (elisp-format-split-list-data-type start end) + (when elisp-format-debug-mode + (message "`elisp-format-split-list-data-type' module completed.")) + ;; Split keyword. + (elisp-format-split-keyword start end) + (when elisp-format-debug-mode + (message "`elisp-format-split-keyword' module completed.")) + ;; Split keyword value. + (elisp-format-split-define-assoc-value start end) + (when elisp-format-debug-mode + (message "`elisp-format-split-define-assoc-value' module completed.")) + ;; Split sub-expression. + (elisp-format-split-subexp start end) + (when elisp-format-debug-mode + (message "`elisp-format-split-subexp' module completed.")) + ;; Split and indent lines. + (goto-char start) + (while (< (point) end) + ;; Format non-blank line. + (unless (and (bolp) + (eolp)) + ;; Split and indent lines. + (elisp-format-split-and-indent)) + ;; Forward line. + (forward-line +1)) + (when elisp-format-debug-mode + (message "`elisp-format-split-and-indent' module completed.")) + ;; Join standalone ")". + (elisp-format-join-close-parentheses) + (when elisp-format-debug-mode + (message "`elisp-format-join-close-parentheses' module completed.")) + ;; Indent comment. + (if elisp-format-indent-comment + (elisp-format-indent-comment-region start end)) + (when elisp-format-debug-mode + (message "`elisp-format-indent-comment-region' module completed.")) + ;; Display completed message and spend time. + (message "Format %s completed (%ss)." (buffer-name) + (/ (- (elisp-format-get-current-time) start-time) 1000000))))) + +;;;###autoload +(defun elisp-format-buffer () + "Format current buffer." + (interactive) + (elisp-format-region (point-min) + (point-max))) + +;;;###autoload +(defun elisp-format-file (filename) + "Format file with FILENAME." + (interactive "fFile name: ") + (with-current-buffer (find-file-noselect filename) + (elisp-format-buffer))) + +;;;###autoload +(defun elisp-format-file-batch (filename &optional surpress-popup-window) + "Format elisp FILENAME. +But instead in `batch-mode'. +If SURPRESS-POPUP-WINDOW is non-nil, don't show output window." + (interactive "fFile name: ") + ;; Format elisp file. + (elisp-format-batch-command "elisp-format-file-batch" + elisp-format-batch-program + (format + "-batch -l %s --eval=\"(progn (require 'elisp-format) (elisp-format-file \\\"%s\\\"))\"" + ;; Use `find-library-name' to find load path. + (find-library-name "elisp-format") filename) + surpress-popup-window)) + +;;;###autoload +(defun elisp-format-directory (dir) + "Format recursive elisp files under DIR." + (interactive "DDirectory: ") + (let ((suffix (format "^.*\\.el%s$" (regexp-opt load-file-rep-suffixes)))) + (dolist (file (directory-files dir t)) + (if (file-directory-p file) + ;; Don't match . or .. directory. + (unless (string-match "^\\.\\.?$" (file-name-nondirectory file)) + ;; Find files in sub-directory. + (elisp-format-directory file)) + ;; Not backup file. + (unless (string-match "^\\.?#" (file-name-nondirectory file)) + ;; Match elisp file or it's compress format. + (if (string-match suffix (file-name-nondirectory file)) + (elisp-format-file file))))))) + +;;;###autoload +(defun elisp-format-directory-batch (dir &optional surpress-popup-window) + "Format recursive elisp files under DIR. +But instead in `batch-mode'. +If SURPRESS-POPUP-WINDOW is non-nil, don't show output window." + (interactive "DDirectory: ") + ;; Format elisp file under specify directory. + (elisp-format-batch-command "elisp-format-directory-batch" + elisp-format-batch-program + (format + "-batch -l %s --eval=\"(progn (require 'elisp-format) (elisp-format-directory \\\"%s\\\"))\"" + ;; Use `find-library-name' to find load path. + (find-library-name "elisp-format") dir) + surpress-popup-window)) + +;;;###autoload +(defun elisp-format-dired-mark-files () + "Format dired mark files." + (interactive) + (if (or (not elisp-format-dired-mark-files-confirm) + (yes-or-no-p "Do you want format marked files? ")) + (dolist (filename (dired-get-marked-files)) + (elisp-format-file filename)))) + +;;;###autoload +(defun elisp-format-library (library) + "Format LIBRARY." + (interactive (list + (let* ((dirs load-path) + (suffixes (find-library-suffixes))) + (completing-read "Library name: " (apply-partially + 'locate-file-completion-table + dirs suffixes))))) + (elisp-format-file (find-library-name library))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Utilities Functions ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +(defun elisp-format-split-keyword-internal (subexp) + "Split keyword. +SUBEXP is sub-expression number for regexp match." + (let (match-beg-position match-length match-keyword) + ;; Record match beginning position and length. + ;; make below setup before `elisp-format-in-string-p' + ;; or `elisp-format-in-comment-p' to get correct + ;; match value. + (setq match-beg-position (match-beginning subexp)) + (setq match-length (length (match-string subexp))) + ;; Make sure jump to match beginning position first, + ;; to avoid search in `string' area. + (goto-char match-beg-position) + ;; Newline handle. + (cond + ;; Move to next line when in comment area. + ((or + (elisp-format-in-comment-p) + ;; or beginning of comment line. + (elisp-format-beginning-of-comment-line-p)) + (forward-line +1)) + ;; Move to end position of string. + ((elisp-format-in-string-p) + (goto-char (elisp-format-string-end-position))) + ;; Newline match keyword sexp. + (t + ;; Get match-keyword. + (setq match-keyword (elisp-format-get-match-keyword)) + ;; Newline when `match-keyword' is not match + ;; list `elisp-format-newline-except-keywords-list'. + (unless (member match-keyword elisp-format-newline-keyword-except-list) + ;; Newline beginning position when current + ;; point not first non-blank character of line, + ;; and previous subexp not lisp data type keyword. + (unless (or (elisp-format-first-non-blank-of-line-p) + (elisp-format-prev-sexp-list-data-type-p)) + (newline)) + ;; Newline end position when current + ;; sexp not last sexp of line. + (forward-list) ;Move to after of ")" + (unless (or (elisp-format-last-sexp-of-line-p)) + (newline)) ;Newline when not last sexp of line. + ) + ;; Jump to end position of match keyword, + ;; for continue search next keyword. + (goto-char match-beg-position) + (forward-char match-length))))) + +(defun elisp-format-split-subexp-internal (subexp) + "Split sub-expression that match keyword. +SUBEXP is sub-expression number for regexp match." + (let (match-beg-position match-length match-keyword subsexp-start subsexp-end + subsexp-keep (subsexp-counter 0)) + ;; Record match beginning position and length. + ;; make below setup before `elisp-format-in-string-p' + ;; or `elisp-format-in-comment-p' to get correct + ;; match value. + (setq match-beg-position (match-beginning subexp)) + (setq match-length (length (match-string subexp))) + ;; Make sure jump to match beginning position first, + ;; to avoid search in `string' area. + (goto-char match-beg-position) + ;; Newline handle. + (cond + ;; Move to next line when in comment area. + ((or + (elisp-format-in-comment-p) + ;; or beginning of comment line. + (elisp-format-beginning-of-comment-line-p)) + (forward-line +1)) + ;; Move to end position of string. + ((elisp-format-in-string-p) + (goto-char (elisp-format-string-end-position))) + ;; Newline match keyword sexp. + (t + ;; Get beginning and subsexp-end position of subsexp. + (setq subsexp-start match-beg-position) + (forward-list) + (setq subsexp-end (copy-marker (point))) + ;; Get match-keyword. + (goto-char subsexp-start) + (setq match-keyword (elisp-format-get-match-keyword)) + ;; Don't match except keyword. + (unless (member match-keyword + elisp-format-split-subexp-keyword-except-list) + ;; Go beginning position of subsexp. + (goto-char subsexp-start) + (search-forward-regexp " \\|$" nil t) + ;; Format sub-expression. + (catch 'reach-last-sexp + (while (< (point) subsexp-end) ;not out `subsexp-end' + ;; Skip whitespace before keyword. + (skip-chars-forward " \t\n") + ;; Skip any comment between two sub-expression. + (while (string-equal (string (char-after)) ";") + (move-end-of-line 1) + (skip-chars-forward " \t\n")) + ;; Increment subsexp counter. + (incf subsexp-counter) + ;; Get keep status. + (setq subsexp-keep (elisp-format-is-keep-subexp match-keyword + subsexp-counter)) + ;; Don't newline if match keep keyword. + (unless (or subsexp-keep + (elisp-format-first-non-blank-of-line-p) + (elisp-format-prev-sexp-list-data-type-p)) + (newline)) + ;; Forward sexp. + (unless + ;; Try to forward sexp and newline. + ;; or jump out `while' loop. + (ignore-errors + (forward-sexp) + ;; Don't newline if match keep keyword. + (unless (or subsexp-keep + (elisp-format-last-sexp-of-line-p) + (elisp-format-prev-sexp-list-data-type-p)) + (newline)) + ;; Make sure `t' at last. + t) + (throw 'reach-last-sexp "Can't find next sexp"))))) + ;; Move to end of next keyword for continue search. + (goto-char subsexp-start) + (search-forward-regexp " \\|$" nil t))))) + +(defun elisp-format-split-and-indent () + "Split and indent lines." + ;; Indent current line first. + (funcall indent-line-function) + ;; Split others. + (let ((original-line (elisp-format-line-number))) + (when elisp-format-debug-mode + (message "%s" original-line)) + ;; Move to real end position of current line, + ;; ignore trailing whitespace. + (call-interactively 'move-end-of-line) + (skip-chars-backward " \t") + ;; Split current line when length + ;; longer than `elisp-format-column'. + (when (> (current-column) elisp-format-column) + ;; Move to `elisp-format-column'. + (move-to-column elisp-format-column t) + (cond + ;; In comment area. + ((elisp-format-in-comment-p) + ;; Return original line before parse + ;; if current position is in comment. + (goto-line original-line)) + ;; In string area. + ((elisp-format-in-string-p) + ;; Split current string. + (elisp-format-split-string) + (when elisp-format-debug-mode + (message "Format string at %s completed." original-line))) + ;; In code area. + (t + ;; Split current code. + (elisp-format-split-code original-line) + (when elisp-format-debug-mode + (message "Format code at %s completed." original-line))))))) + +(defun elisp-format-split-string () + "Split current string with appropriate column. +Default this function will split current line to make +end column less than value of `elisp-format-column'. +And this action just advice, it don't split deep +if current line can't split any more." + (let (string-length indent-length) + ;; Jump to start position of string. + (goto-char (elisp-format-string-beg-position)) + ;; Newline and indent if + ;; string is not first sexp, + ;; or not first subsexp of current sexp. + (unless (or (elisp-format-first-non-blank-of-line-p) + (elisp-format-first-subsexp-of-sexp-p)) + (newline-and-indent)) + ;; Record indent length. + (setq indent-length (- (point) + (line-beginning-position))) + ;; Record string length. + (forward-char +1) + (setq string-length (elisp-format-string-length)) + ;; Jump to end position of string. + (goto-char (elisp-format-string-end-position)) + ;; Parse deep if string is not last non-blank character of line. + (unless (elisp-format-last-non-blank-of-line-p) + ;; Parse deep if string end position is still + ;; longer than `elisp-format-column' + (if (> (+ indent-length string-length) elisp-format-column) + ;; Newline string when string is not last sexp of line. + (unless (elisp-format-last-sexp-of-line-p) + (newline-and-indent) + (forward-line -1)) + ;; Otherwise return previous line. + (forward-line -1))))) + +(defun elisp-format-split-code (original-line) + "Split current code with appropriate column. +Default this function will split current line to make +end column less than value of `elisp-format-column'. +And this action just advice, it don't split deep +if current line can't split any more. +Argument ORIGINAL-LINE is position before parse." + ;; Ignore trailing whitespace after `elisp-format-column'. + (skip-chars-forward " \t") + ;; Jump to start position of previous sexp. + (search-backward-regexp " \\|^" nil t) + (skip-chars-forward " \t") + ;; Newline and indent if sexp + ;; is not define-keyword association name, + ;; and is not first non-blank character of line. + (unless (or (elisp-format-define-keyword-assoc-name-p) + (elisp-format-first-non-blank-of-line-p)) + (newline-and-indent)) + ;; Jump to end position of current sexp. + (search-forward-regexp " \\|$" nil t) + (skip-chars-backward " \t") + ;; Parse deep if current sexp is not last + ;; non-blank character of line. + (unless (elisp-format-last-non-blank-of-line-p) + (if (> (current-column) elisp-format-column) + ;; Newline and indent if sexp end position + ;; still after `elisp-format-column'. + (progn + (newline-and-indent) + (forward-line -1)) + ;; Otherwise return original line before parse. + (goto-line original-line)))) + +(defun elisp-format-line-number (&optional pos) + "Return (narrowed) buffer line number at position POS. +If POS is nil, use current buffer location." + (let ((original-position (or pos + (point))) start) + (save-excursion + (goto-char (point-min)) + (setq start (point)) + (goto-char original-position) + (forward-line 0) + (1+ (count-lines start (point)))))) + +(defun elisp-format-delete-whitespace (&optional start end) + "Delete un-necessary whitespace between START and END." + ;; Get area. + (or start + (setq start (point-min))) + (or end + (setq end (point-max))) + ;; Delete trailing whitespace. + (delete-trailing-whitespace) + ;; Delete whitespace between code lines. + (let (search-start search-end) + (goto-char start) + (while (re-search-forward "\n\\s-+" end t) + ;; Record `search-start' and `search-end' + ;; before `elisp-format-in-string-p' for correct search. + (setq search-start (match-beginning 0)) + (setq search-end (match-end 0)) + ;; Not in string. + (unless (elisp-format-in-string-p) + ;; Not comment at front or after + ;; search data. + (if (and + (progn + (goto-char search-start) + (not (elisp-format-in-comment-p))) + (progn + (goto-char search-end) + (forward-char +1) + (not (elisp-format-in-comment-p)))) + ;; Join line. + (progn + (goto-char search-end) + (join-line)) + ;; Move to `search-end'. + (goto-char search-end))))) + ;; Delete all whitespace after "(" in code area. + (goto-char start) + (while (re-search-forward "(\\s-+" end t) + (unless (and (elisp-format-in-comment-p) + (elisp-format-in-string-p)) + ;; Remove whitespace after '('. + (kill-region (1+ (match-beginning 0)) + (match-end 0))))) + +(defun elisp-format-split-subexp (&optional start end) + "Split sub-expression format START to END." + ;; Get area. + (or start + (setq start (point-min))) + (or end + (setq end (point-max))) + ;; Split sub-expression. + (goto-char start) + (let ((search-regexp (concat "\\s-*\\([`',]?@?(+" "\\(" + elisp-format-buildin-keywords-regexp "\\|" + elisp-format-split-subexp-keyword-addons-regexp + "\\)" "\\)\\b[^\\B\\s_-]"))) + (while (re-search-forward search-regexp end t) + (elisp-format-split-subexp-internal 1)))) + +(defun elisp-format-split-define-assoc-value (&optional start end) + "Split association value of keyword format START to END. +Keyword is match in `elisp-format-define-keyword-list'." + ;; Get area. + (or start + (setq start (point-min))) + (or end + (setq end (point-max))) + ;; Split association keyword value. + (goto-char start) + (let ((search-regexp (concat "\\s-*\\([`',]?@?(+" + elisp-format-define-keyword-regexp + "\\)\\b[^\\B\\s_-]")) search-start value-start + value-length) + (while (re-search-forward search-regexp end t) + (setq search-start (match-end 1)) + ;; Search deep when not in comment or string. + (unless (and (elisp-format-in-comment-p) + (elisp-format-in-string-p)) + ;; Search deep. + (unless + ;; Use `ignore-errors' avoid reach last + ;; sub-expression throw error. + (ignore-errors + (forward-sexp) + (skip-chars-forward " \t\n") + (setq value-start (point)) + (forward-sexp) + (setq value-length (- (point) value-start)) + (goto-char value-start) + ;; Newline if keyword value + ;; not first non-blank character of line. + ;; and value length longer than `elisp-format-column'. + (if (and (not (elisp-format-first-non-blank-of-line-p)) + (> (+ (current-column) value-length) elisp-format-column)) + (newline))) + ;; Otherwise goto search start. + (goto-char search-start)))))) + +(defun elisp-format-split-same-level-expression (&optional start end) + "Split same level expression from START to END." + ;; Get area. + (or start + (setq start (point-min))) + (or end + (setq end (point-max))) + ;; Split same level expression. + (goto-char start) + (let (search-end) + (while (re-search-forward "\\()\\|\\]\\)\\(\\s-*\\)[`',]?@?\\((\\|\\[\\)" + end t) + ;; Record search end before + ;; `elisp-format-in-comment-p' + ;; or + ;; `elisp-format-in-string-p'. + (setq search-end (match-end 2)) + ;; When not in comment or string. + (unless (or (elisp-format-in-comment-p) + (elisp-format-in-string-p)) + ;; Newline second expression. + (goto-char search-end) + (newline))))) + +(defun elisp-format-split-list-data-type (&optional start end) + "Split list type data (:keyword) from START to END." + ;; Get area. + (or start + (setq start (point-min))) + (or end + (setq end (point-max))) + ;; Split list data type. + (goto-char start) + (let (search-beg search-end) + (while (re-search-forward "'*\\B:+[^: \n]+\\b" end t) + ;; Record search end before + ;; `elisp-format-in-comment-p' + ;; or + ;; `elisp-format-in-string-p'. + (setq search-beg (match-beginning 0)) + (setq search-end (match-end 0)) + ;; When not in comment or string. + (unless (or (elisp-format-in-comment-p) + (elisp-format-in-string-p)) + ;; Jump to search beginning position. + (goto-char search-beg) + ;; Try to newline `:keyword'. + (save-excursion + ;; Not first non-blank of line + ;; and not first subsexp of current sexp. + (unless (or (elisp-format-first-non-blank-of-line-p) + (elisp-format-first-subsexp-of-sexp-p)) + ;; Newline `:keyword' if it is + ;; second sub-sexp of current sexp. + (ignore-errors + (skip-chars-backward " \t") + (backward-sexp) + (unless (elisp-format-first-subsexp-of-sexp-p) + (goto-char search-beg) + (newline))) + ;; Newline `:keyword' if next sexp + ;; is also `:keyword'. + (goto-char search-beg) + (forward-sexp) + (skip-chars-forward " \t\n") + (when (looking-at "'*:") + (goto-char search-beg) + (newline)))) + ;; Newline list data type `value'. + (forward-sexp) ;skip `:keyword' + (skip-chars-forward " \t") ;skip blank + ;; Not `:keyword' at behind + ;; and not last sexp. + (unless (looking-at "'*\\(:\\|)\\)") + (ignore-errors + ;; Forward sexp. + (forward-sexp) + ;; Not last sexp. + (unless (elisp-format-last-sexp-of-line-p) + ;; Newline `:keyword' if next + ;; subsexp is not last one in current sexp. + (forward-sexp) + (unless (elisp-format-last-sexp-of-line-p) + (backward-sexp) + (newline))))) + ;; Jump to match end for continue search. + (goto-char search-end))))) + +(defun elisp-format-split-keyword (&optional start end) + "Split keyword from START to END." + ;; Get area. + (or start + (setq start (point-min))) + (or end + (setq end (point-max))) + ;; Split keywords. + (goto-char start) + (let ((search-regexp (concat "\\s-*\\([`',]?@?(+" "\\(" + elisp-format-buildin-keywords-regexp "\\|" + elisp-format-newline-keyword-addons-regexp "\\)" + "\\)\\b[^\\B\\s_-]"))) + (while (re-search-forward search-regexp end t) + (elisp-format-split-keyword-internal 1)))) + +(defun elisp-format-join-close-parentheses (&optional start end) + "Join standalone close parentheses from START to END." + ;; Get area. + (or start + (setq start (point-min))) + (or end + (setq end (point-max))) + ;; Join standalone close parentheses. + (let (search-start search-end) + (goto-char start) + (while (re-search-forward "\\(\\s-*\n\\s-*\\))" end t) + ;; Record `search-start' and `search-end' + ;; before `elisp-format-in-string-p' for correct search. + (setq search-start (match-beginning 0)) + (setq search-end (match-end 0)) + ;; Not in string. + (unless (elisp-format-in-string-p) + ;; Not comment at front or after + ;; search data. + (if + (progn + (goto-char search-start) + (not (elisp-format-in-comment-p))) + ;; Join line. + (progn + (goto-char search-end) + (backward-char 1) + (join-line)) + ;; Move to `search-end'. + (goto-char search-end)))))) + +(defun elisp-format-indent-comment-region (&optional start end) + "Indent comment format START to END." + ;; Get area. + (or start + (setq start (point-min))) + (or end + (setq end (point-max))) + ;; Indent area. + (goto-char start) + (while (< (point) end) + (if (comment-search-forward end t) + (comment-indent) + (goto-char end)))) + +(defun elisp-format-get-match-keyword () + "Get match keyword after point." + (save-excursion + (search-forward "(") + (symbol-name (symbol-at-point)))) + +(defun elisp-format-define-keyword-assoc-name-p () + "Return t if current string around point is association keyword name. +And keyword in match `elisp-format-define-keyword-list'." + (let (define-keyword-name) + (if (looking-back "^\\s-*(\\([^() ]+\\)\\s-+") + (progn + (setq define-keyword-name (match-string 1)) + (member define-keyword-name elisp-format-define-keyword-list)) + nil))) + +(defun elisp-format-define-keyword-assoc-value-p () + "Return t if current string around point is association keyword value. +And keyword in match `elisp-format-define-keyword-list'." + (save-excursion + (let ((original-position (point))) + (if ;; In define area. + (beginning-of-defun) + ;; In value field of define area. + (progn + (search-forward-regexp " \\|$" nil t) + (forward-sexp 1) + (skip-chars-forward " \t\n") + (if (and (>= original-position (point)) + (<= original-position + (progn + (forward-list) + (point)))) + t + nil)) + nil)))) + +(defun elisp-format-first-non-blank-of-line-p () + "Return t if point is first non-blank character of line. +Otherwise return nil." + (let ((current-point (point))) + (save-excursion + (back-to-indentation) + (equal current-point (point))))) + +(defun elisp-format-last-non-blank-of-line-p () + "Return t if point is last non-blank character of line. +Otherwise return nil." + (let ((current-point (point))) + (save-excursion + (call-interactively 'move-end-of-line) + (skip-chars-backward " \t") + (equal current-point (point))))) + +(defun elisp-format-first-subsexp-of-sexp-p () + "Return t if point is first sub-sexp of sexp. +Otherwise return nil." + (looking-back "([ \t\n]*")) + +(defun elisp-format-last-sexp-of-line-p () + "Return t if point is last sexp of line. +Otherwise return nil." + (looking-at "\\([ \t\n)]*$\\|\\s-*;.*$\\)")) + +(defun elisp-format-prev-sexp-list-data-type-p () + "Return t if previous sexp is keyword beginning with ':'. +Otherwise return nil." + (save-excursion + (ignore-errors + (backward-sexp) + (string-match "^:[^ ]+$" + (buffer-substring-no-properties + (point) + (progn + (search-forward-regexp " \\|$" nil t) + (skip-chars-backward " \t") + (point))))))) + +(defun elisp-format-is-keep-subexp (keyword index) + "Return `non-nil' if KEYWORD is keep keyword. +This function will search KEYWORD with INDEX +in `elisp-format-split-subexp-keyword-keep-list'; +return `non-nil', when search match keyword. +Otherwise, return nil." + (catch 'match + (loop for (keep-index . keep-keyword-list) in + elisp-format-split-subexp-keyword-keep-alist do + (when (and (<= index keep-index) + (member keyword keep-keyword-list)) + (throw 'match t))) + nil)) + +(defun elisp-format-current-parse-state () + "Return parse state of point from beginning of defun." + (let ((point (point))) + (beginning-of-defun) + ;; Calling PARSE-PARTIAL-SEXP will advance the point to its second + ;; argument (unless parsing stops due to an error, but we assume it + ;; won't in elisp-format-mode). + (parse-partial-sexp (point) point))) + +(defun elisp-format-in-string-p (&optional state) + "True if the parse STATE is within a double-quote-delimited string. +If no parse state is supplied, compute one from the beginning of the + defun to the point." + ;; 3. non-nil if inside a string (the terminator character, really) + (and (nth 3 (or state + (elisp-format-current-parse-state))) + t)) + +(defun elisp-format-in-comment-p (&optional state) + "True if parse state STATE is within a comment. +If no parse state is supplied, compute one from the beginning of the + defun to the point." + ;; 4. nil if outside a comment, t if inside a non-nestable comment, + ;; else an integer (the current comment nesting) + (and (nth 4 (or state + (elisp-format-current-parse-state))) + t)) + +(defun elisp-format-string-start+end-points (&optional state) + "Return a cons of the points of open and close quotes of the string. +The string is determined from the parse state STATE, or the parse state + from the beginning of the defun to the point. +This assumes that `elisp-format-in-string-p' has already returned true, i.e. + that the point is already within a string." + (save-excursion + ;; 8. character address of start of comment or string; nil if not + ;; in one + (let ((start (nth 8 (or state + (elisp-format-current-parse-state))))) + (goto-char start) + (forward-sexp 1) + (cons start (1- (point)))))) + +(defun elisp-format-beginning-of-comment-line-p () + "Return t if current point is beginning of comment line. +And current line only have comment. +Otherwise return nil." + (and (bolp) + (looking-at "\\s-*;"))) + +(defun elisp-format-string-beg-position () + "Return the beginning position of string." + (car (elisp-format-string-start+end-points))) + +(defun elisp-format-string-end-position () + "Return the end position of string." + (1+ (cdr (elisp-format-string-start+end-points)))) + +(defun elisp-format-string-length () + "Return string length." + (- (elisp-format-string-end-position) + (elisp-format-string-beg-position))) + +(defun elisp-format-get-current-time () + "Get current time (microsecond)." + (let ((time (current-time))) + (+ (* 1000000 (string-to-number (concat (number-to-string (nth 0 time)) + (number-to-string (nth 1 time))))) + (nth 2 time)))) + +(defun elisp-format-batch-command (name command command-args &optional surpress-popup-window) + "Run special `batch' command. +NAME is sub-process buffer title. +COMMAND is command running under `batch'. +COMMAND-ARGS is command arguments for COMMAND. +If SURPRESS-POPUP-WINDOW is non-nil, don't show output window." + (let* ((time-now (current-time)) + ;; Get unique buffer. + (output-buffer (format "*%s<%s-%s-%s>" name (nth 0 time-now) + (nth 1 time-now) + (nth 2 time-now)))) + ;; Start sub-process to handle format work. + (start-process-shell-command name output-buffer command command-args) + ;; Popup window when option `surpress-popup-window' is nil. + (unless surpress-popup-window + (pop-to-buffer output-buffer)))) + +(provide 'elisp-format) + +;;; elisp-format.el ends here + +;;; LocalWords: ss fFile DDirectory dirs pos args diff --git a/elpa/elisp-format-20160508.952/elisp-format.elc b/elpa/elisp-format-20160508.952/elisp-format.elc new file mode 100644 index 00000000..e7b717fe Binary files /dev/null and b/elpa/elisp-format-20160508.952/elisp-format.elc differ diff --git a/elpa/elisp-lint-20200102.1550/elisp-lint-autoloads.el b/elpa/elisp-lint-20200102.1550/elisp-lint-autoloads.el new file mode 100644 index 00000000..212c9218 --- /dev/null +++ b/elpa/elisp-lint-20200102.1550/elisp-lint-autoloads.el @@ -0,0 +1,22 @@ +;;; elisp-lint-autoloads.el --- automatically extracted autoloads +;; +;;; Code: + +(add-to-list 'load-path (directory-file-name + (or (file-name-directory #$) (car load-path)))) + + +;;;### (autoloads nil "elisp-lint" "elisp-lint.el" (0 0 0 0)) +;;; Generated autoloads from elisp-lint.el + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "elisp-lint" '("elisp-lint-"))) + +;;;*** + +;; Local Variables: +;; version-control: never +;; no-byte-compile: t +;; no-update-autoloads: t +;; coding: utf-8 +;; End: +;;; elisp-lint-autoloads.el ends here diff --git a/elpa/elisp-lint-20200102.1550/elisp-lint-pkg.el b/elpa/elisp-lint-20200102.1550/elisp-lint-pkg.el new file mode 100644 index 00000000..fc320bf6 --- /dev/null +++ b/elpa/elisp-lint-20200102.1550/elisp-lint-pkg.el @@ -0,0 +1,2 @@ +;;; -*- no-byte-compile: t -*- +(define-package "elisp-lint" "20200102.1550" "basic linting for Emacs Lisp" '((emacs "24")) :commit "f8316b84513261b17817006f5fcc25599d8e12b2" :keywords '("lisp" "maint" "tools") :authors '(("Nikolaj Schumacher ,")) :maintainer '("Nikolaj Schumacher ,") :url "http://github.com/gonewest818/elisp-lint/") diff --git a/elpa/elisp-lint-20200102.1550/elisp-lint.el b/elpa/elisp-lint-20200102.1550/elisp-lint.el new file mode 100644 index 00000000..125347c6 --- /dev/null +++ b/elpa/elisp-lint-20200102.1550/elisp-lint.el @@ -0,0 +1,282 @@ +;;; elisp-lint.el --- basic linting for Emacs Lisp +;; +;; Copyright (C) 2013-2015 Nikolaj Schumacher +;; Copyright (C) 2018-2019 Neil Okamoto +;; +;; Author: Nikolaj Schumacher , +;; Author: Neil Okamoto +;; Version: 0.4.0-SNAPSHOT +;; Package-Version: 20200102.1550 +;; Keywords: lisp, maint, tools +;; Package-Requires: ((emacs "24")) +;; URL: http://github.com/gonewest818/elisp-lint/ +;; +;; This file is NOT part of GNU Emacs. +;; +;; This program 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 +;; of the License, or (at your option) any later version. +;; +;; This program 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 this program. If not, see . +;; +;;; Commentary: +;; +;; This is a tool for finding certain problems in Emacs Lisp files. Use it on +;; the command line like this: +;; +;; $(EMACS) -Q --batch -l elisp-lint.el -f elisp-lint-files-batch *.el +;; +;; You can disable individual checks by passing flags on the command line: +;; +;; $(EMACS) -Q --batch -l elisp-lint.el -f elisp-lint-files-batch \ +;; --no-indent *.el +;; +;; Alternatively, you can disable checks using file variables or the following +;; .dir-locals.el file: +;; +;; ((emacs-lisp-mode . ((elisp-lint-ignored-validators . ("fill-column"))))) +;; +;; For a full list of validators, see `elisp-lint-file-validators' and +;; `elisp-lint-buffer-validators'. +;; +;;; Change Log: +;; +;; * Version 0.4-SNAPSHOT (available in MELPA) +;; - Provide a summary report of all tests [#20] +;; * Version 0.3 (MELPA Stable, as of December 2019) +;; - Emacs 23 support is deprecated [#13] +;; - Adopt CircleCI and drop Travis CI [#9] [#14] +;; - Add check-declare validator [#16] +;; - Generate autoloads before bytecompile [#8] +;; * Version 0.2 (Feb 2018) +;; - Project transferred to new maintainer +;; - Whitespace check permits page-delimiter (^L) +;; - Indentation check prints the diff to console +;; - User can specify indent specs to tell the checker about macros +;; - Added checkdoc (available only Emacs 25 and newer) +;; - Cleared up the console output for easier reading in CI +;; - Expand Travis CI test matrix to include Emacs 25 and 26 +;; * Version 0.1 (2015) +;; - Basic linting functionality implemented +;; +;;; Code: + +(require 'bytecomp) +(require 'check-declare) +(require 'checkdoc nil t) +(require 'package nil t) + +(declare-function package-buffer-info "package" t) + +(defconst elisp-lint-file-validators + (nconc '("byte-compile" "check-declare") + (when (fboundp 'checkdoc-file) '("checkdoc")))) + +(defconst elisp-lint-buffer-validators + '("package-format" "indent" "indent-character" "fill-column" + "trailing-whitespace")) + +(defvar elisp-lint-ignored-validators nil + "List of validators that should not be run.") +(put 'elisp-lint-ignored-validators 'safe-local-variable 'listp) + +(defvar elisp-lint-indent-specs nil + "Alist of symbols and their indent specifiers. +The property 'lisp-indent-function will be set accordingly on +each of the provided symbols prior to running the indentation +check. Caller can set this variable as needed on the command +line or in \".dir-locals.el\". The alist should take the form +`((symbol1 . spec1) (symbol2 . spec2) ...)' where the specs are +identical to the `indent' declarations in defmacro.") +(put 'elisp-lint-indent-specs 'safe-local-variable 'listp) + +(defmacro elisp-lint--protect (&rest body) + "Handle errors raised in BODY." + (declare (indent 0) (debug t)) + `(condition-case err + (progn ,@body) + (error (message "%s" (error-message-string err)) nil))) + +(defmacro elisp-lint--run (validator &rest args) + "Run the VALIDATOR with ARGS." + `(or (member ,validator elisp-lint-ignored-validators) + (progn + (message "* Run %s" ,validator) + (elisp-lint--protect (funcall + (intern (concat "elisp-lint--" ,validator)) + ,@args))))) + +(defun elisp-lint--amend-ignored-validators-from-command-line () + "Parse command line and find flags to disable specific validators." + (while (string-match "^--no-\\([a-z-]*\\)" (car command-line-args-left)) + (add-to-list 'elisp-lint-ignored-validators + (match-string 1 (pop command-line-args-left))))) + +;;; Validators + +(defvar elisp-lint--autoloads-filename nil + "The autoloads file for this package.") + +(defun elisp-lint--generate-autoloads () + "Generate autoloads and set `elisp-lint--autoloads-filename`. +Assume `default-directory` name is also the package name, +e.g. for this package it will be \"elisp-lint-autoloads.el\"." + (let* ((dir (directory-file-name default-directory)) + (prefix (file-name-nondirectory dir)) + (pkg (intern prefix)) + (load-prefer-newer t)) + (package-generate-autoloads pkg dir) + (setq elisp-lint--autoloads-filename (format "%s-autoloads.el" prefix)))) + +(defun elisp-lint--byte-compile (file) + "Byte-compile FILE with warnings enabled. +Return nil if errors were found." + (let ((byte-compile-error-on-warn t) + (byte-compile-warnings t)) + (unless elisp-lint--autoloads-filename + (elisp-lint--generate-autoloads)) + (load-file elisp-lint--autoloads-filename) + (byte-compile-file file))) + +(defun elisp-lint--check-declare (file) + "Validate `declare-function` statements in FILE." + (let ((errlist (check-declare-file file))) + (or (null errlist) + (error "Check-declare failed")))) + +;; Checkdoc is available only Emacs 25 or newer +(when (fboundp 'checkdoc-file) + (defun elisp-lint--checkdoc (file) + "Run checkdoc on FILE and print the results. +Return nil if errors were found, else t." + (let* ((msgbuf (get-buffer "*Messages*")) + (tick (buffer-modified-tick msgbuf))) + (checkdoc-file file) + (or (equal tick (buffer-modified-tick msgbuf)) + (error "Checkdoc failed"))))) + +(defun elisp-lint--package-format () + "Call `package-buffer-info' to validate package metadata." + (or (null (require 'package nil t)) + (package-buffer-info))) + +(defun elisp-lint--indent () + "Confirm buffer indentation is consistent with `emacs-lisp-mode'. +Use `indent-region' to format the entire buffer, and compare the +results to the filesystem. Print diffs if there are any +discrepancies. Prior to indenting the buffer, apply the settings +provided in `elisp-lint-indent-specs' to configure specific +symbols (typically macros) that require special handling." + (dolist (s elisp-lint-indent-specs) + (put (car s) 'lisp-indent-function (cdr s))) + (let ((tick (buffer-modified-tick))) + (indent-region (point-min) (point-max)) + (or (equal tick (buffer-modified-tick)) + (progn + (diff-buffer-with-file) + (with-current-buffer "*Diff*" + (message "%s" (buffer-string)) + (kill-buffer)) + (error "Indentation is incorrect"))))) + +(defun elisp-lint--indent-character () + "Verify buffer indentation is consistent with `indent-tabs-mode`. +Use a file variable or \".dir-locals.el\" to override the default value." + (let ((lines nil) + (re (if indent-tabs-mode + (elisp-lint--not-tab-regular-expression) + "^\t")) + (msg (if indent-tabs-mode + "spaces instead of tabs" + "tabs instead of spaces"))) + (save-excursion + (goto-char (point-min)) + (while (re-search-forward re nil t) + (push (count-lines (point-min) (point)) lines))) + (or (null lines) + (error "Lines indented with %s: %s" msg + (elisp-lint--join-lines lines))))) + +(defun elisp-lint--not-tab-regular-expression () + "Regex to match a string of spaces with a length of `tab-width`." + (concat "^" (make-string tab-width ? ))) + +(defun elisp-lint--join-lines (line-numbers) + "Convert LINE-NUMBERS list into a comma delimited string." + (mapconcat (lambda (i) (format "#%d" i)) (sort line-numbers '<) ", ")) + +(defun elisp-lint--fill-column () + "Confirm buffer has no lines exceeding `fill-column` in length. +Use a file variable or \".dir-locals.el\" to override the default value." + (save-excursion + (let ((line-number 1) + (too-long-lines nil)) + (goto-char (point-min)) + (while (not (eobp)) + (goto-char (point-at-eol)) + (when (> (current-column) fill-column) + (push line-number too-long-lines)) + (setq line-number (1+ line-number)) + (forward-line 1)) + (or (null too-long-lines) + (error "Lines longer than %d characters: %s" + fill-column (elisp-lint--join-lines too-long-lines)))))) + +(defun elisp-lint--trailing-whitespace () + "Confirm buffer has no line with trailing whitespace. +Allow `page-delimiter` if it is alone on a line." + (save-excursion + (let ((lines nil)) + (goto-char (point-min)) + (while (re-search-forward "[[:space:]]+$" nil t) + (unless (string-match-p + (concat page-delimiter "$") ; allow a solo page-delimiter + (buffer-substring-no-properties (line-beginning-position) + (line-end-position))) + (push (count-lines (point-min) (point)) lines))) + (or (null lines) + (error "Line numbers with trailing whitespace: %s" + (elisp-lint--join-lines (sort lines '<))))))) + +;;; Linting + +(defun elisp-lint-file (file) + "Run validators on FILE." + (with-temp-buffer + (find-file file) + (when elisp-lint-ignored-validators + (message "** Ignoring validators: %s" + (mapconcat 'identity elisp-lint-ignored-validators ", "))) + (let ((success t)) + (mapc (lambda (validator) + (setq success (and (elisp-lint--run validator file) success))) + elisp-lint-file-validators) + (mapc (lambda (validator) + (setq success (and (elisp-lint--run validator) success))) + elisp-lint-buffer-validators) + success))) + +(defun elisp-lint-files-batch () + "Run validators on all files specified on the command line." + (elisp-lint--amend-ignored-validators-from-command-line) + (let ((success t)) + (while command-line-args-left + (message "%s" (make-string 75 ?\*)) + (message "** ELISP-LINT: check %s..." (car command-line-args-left)) + (if (elisp-lint-file (car command-line-args-left)) + (message "** ELISP-LINT: %s OK" (car command-line-args-left)) + (message "** ELISP:LINT: %s FAIL" (car command-line-args-left)) + (setq success nil)) + (pop command-line-args-left)) + (kill-emacs (if success 0 1)))) + +(provide 'elisp-lint) + +;;; elisp-lint.el ends here diff --git a/elpa/elisp-lint-20200102.1550/elisp-lint.elc b/elpa/elisp-lint-20200102.1550/elisp-lint.elc new file mode 100644 index 00000000..7d95470b Binary files /dev/null and b/elpa/elisp-lint-20200102.1550/elisp-lint.elc differ diff --git a/eww-bookmarks b/eww-bookmarks new file mode 100644 index 00000000..b3e51a1a --- /dev/null +++ b/eww-bookmarks @@ -0,0 +1,2 @@ +;; Auto-generated file; don't edit +((:url "https://htdp.org/2018-01-06/Book/" :title "How to Design Programs, Second Edition" :time "Sat Feb 15 10:57:02 2020"))