about summary refs log tree commit diff
path: root/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-align-imports.el
diff options
context:
space:
mode:
authorWilliam Carroll <wpcarro@gmail.com>2018-09-10T18·51-0400
committerWilliam Carroll <wpcarro@gmail.com>2018-09-10T18·53-0400
commit17ee0e400bef47c371afcae76037f9ea6a44ad13 (patch)
tree0e5efee6f00e402890e91f3eceb4b29408a498b6 /configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-align-imports.el
parent8b2fadf4776b7ddb4a67b4bc8ff6463770e56028 (diff)
Support Vim, Tmux, Emacs with Stow
After moving off of Meta, Dotfiles has a greater responsibility to
manage configs. Vim, Tmux, and Emacs are now within Stow's purview.
Diffstat (limited to 'configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-align-imports.el')
-rw-r--r--configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-align-imports.el231
1 files changed, 231 insertions, 0 deletions
diff --git a/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-align-imports.el b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-align-imports.el
new file mode 100644
index 000000000000..694ee259295b
--- /dev/null
+++ b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-align-imports.el
@@ -0,0 +1,231 @@
+;;; haskell-align-imports.el --- Align the import lines in a Haskell file -*- lexical-binding: t -*-
+
+;; Copyright (C) 2010  Chris Done
+
+;; Author: Chris Done <chrisdone@gmail.com>
+
+;; 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 3 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
+;; <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; Consider the following imports list:
+;;
+;; import One
+;; import Two as A
+;; import qualified Three
+;; import qualified Four as PRELUDE
+;; import Five (A)
+;; import Six (A,B)
+;; import qualified Seven (A,B)
+;; import "abc" Eight
+;; import "abc" Nine as TWO
+;; import qualified "abc" Ten
+;; import qualified "defg" Eleven as PRELUDE
+;; import "barmu" Twelve (A)
+;; import "zotconpop" Thirteen (A,B)
+;; import qualified "z" Fourteen (A,B)
+;; import Fifteen hiding (A)
+;; import Sixteen as TWO hiding (A)
+;; import qualified Seventeen hiding (A)
+;; import qualified Eighteen as PRELUDE hiding (A)
+;; import "abc" Nineteen hiding (A)
+;; import "abc" Twenty as TWO hiding (A)
+;;
+;; When haskell-align-imports is run within the same buffer, the
+;; import list is transformed to:
+;;
+;; import "abc"            Eight
+;; import qualified        Eighteen as PRELUDE hiding (A)
+;; import qualified "defg" Eleven as PRELUDE
+;; import                  Fifteen hiding (A)
+;; import                  Five (A)
+;; import qualified        Four as PRELUDE
+;; import qualified "z"    Fourteen  (A,B)
+;; import "abc"            Nine as TWO
+;; import "abc"            Nineteen hiding (A)
+;; import                  One
+;; import qualified        Seven (A,B)
+;; import qualified        Seventeen hiding (A)
+;; import                  Six (A,B)
+;; import                  Sixteen as TWO hiding (A)
+;; import qualified "abc"  Ten
+;; import "zotconpop"      Thirteen (A,B)
+;; import qualified        Three
+;; import "barmu"          Twelve (A)
+;; import "abc"            Twenty as TWO hiding (A)
+;; import                  Two as A
+;;
+;; If you want everything after module names to be padded out, too,
+;; customize `haskell-align-imports-pad-after-name', and you'll get:
+;;
+;; import                  One
+;; import                  Two       as A
+;; import qualified        Three
+;; import qualified        Four      as PRELUDE
+;; import                  Five      (A)
+;; import                  Six       (A,B)
+;; import qualified        Seven     (A,B)
+;; import "abc"            Eight
+;; import "abc"            Nine      as TWO
+;; import qualified "abc"  Ten
+;; import qualified "defg" Eleven    as PRELUDE
+;; import "barmu"          Twelve    (A)
+;; import "zotconpop"      Thirteen  (A,B)
+;; import qualified "z"    Fourteen  (A,B)
+;; import                  Fifteen   hiding (A)
+;; import                  Sixteen   as TWO hiding (A)
+;; import qualified        Seventeen hiding (A)
+;; import qualified        Eighteen  as PRELUDE hiding (A)
+;; import "abc"            Nineteen  hiding (A)
+;; import "abc"            Twenty    as TWO hiding (A)
+
+;;; Code:
+
+(require 'cl-lib)
+
+(defvar haskell-align-imports-regexp
+  (concat "^\\(import[ ]+\\)"
+          "\\(qualified \\)?"
+          "[ ]*\\(\"[^\"]*\" \\)?"
+          "[ ]*\\([A-Za-z0-9_.']+\\)"
+          "[ ]*\\([ ]*as [A-Z][^ ]*\\)?"
+          "[ ]*\\((.*)\\)?"
+          "\\([ ]*hiding (.*)\\)?"
+          "\\( -- .*\\)?[ ]*$")
+  "Regex used for matching components of an import.")
+
+(defcustom haskell-align-imports-pad-after-name
+  nil
+  "Pad layout after the module name also."
+  :type 'boolean
+  :group 'haskell-interactive)
+
+;;;###autoload
+(defun haskell-align-imports ()
+  "Align all the imports in the buffer."
+  (interactive)
+  (when (haskell-align-imports-line-match)
+    (save-excursion
+      (goto-char (point-min))
+      (let* ((imports (haskell-align-imports-collect))
+             (padding (haskell-align-imports-padding imports)))
+        (mapc (lambda (x)
+                (goto-char (cdr x))
+                (delete-region (point) (line-end-position))
+                (insert (haskell-align-imports-chomp
+                         (haskell-align-imports-fill padding (car x)))))
+              imports))))
+  nil)
+
+(defun haskell-align-imports-line-match ()
+  "Try to match the current line as a regexp."
+  (let ((line (buffer-substring-no-properties (line-beginning-position)
+                                              (line-end-position))))
+    (if (string-match "^import " line)
+        line
+      nil)))
+
+(defun haskell-align-imports-collect ()
+  "Collect a list of mark / import statement pairs."
+  (let ((imports '()))
+    (while (not (or (equal (point) (point-max)) (haskell-align-imports-after-imports-p)))
+      (let ((line (haskell-align-imports-line-match-it)))
+        (when line
+          (let ((match
+                 (haskell-align-imports-merge-parts
+                  (cl-loop for i from 1 to 8
+                           collect (haskell-align-imports-chomp (match-string i line))))))
+            (setq imports (cons (cons match (line-beginning-position))
+                                imports)))))
+      (forward-line))
+    imports))
+
+(defun haskell-align-imports-merge-parts (l)
+  "Merge together parts of an import statement that shouldn't be separated."
+  (let ((parts (apply #'vector l))
+        (join (lambda (ls)
+                (cl-reduce (lambda (a b)
+                             (concat a
+                                     (if (and (> (length a) 0)
+                                              (> (length b) 0))
+                                         " "
+                                       "")
+                                     b))
+                           ls))))
+    (if haskell-align-imports-pad-after-name
+        (list (funcall join (list (aref parts 0)
+                                  (aref parts 1)
+                                  (aref parts 2)))
+              (aref parts 3)
+              (funcall join (list (aref parts 4)
+                                  (aref parts 5)
+                                  (aref parts 6)))
+              (aref parts 7))
+      (list (funcall join (list (aref parts 0)
+                                (aref parts 1)
+                                (aref parts 2)))
+            (funcall join (list (aref parts 3)
+                                (aref parts 4)
+                                (aref parts 5)
+                                (aref parts 6)
+                                (aref parts 7)))))))
+
+(defun haskell-align-imports-chomp (str)
+  "Chomp leading and tailing whitespace from STR."
+  (if str
+      (replace-regexp-in-string "\\(^[[:space:]\n]*\\|[[:space:]\n]*$\\)" ""
+                                str)
+    ""))
+
+(defun haskell-align-imports-padding (imports)
+  "Find the padding for each part of the import statements."
+  (if (null imports)
+      imports
+    (cl-reduce (lambda (a b) (cl-mapcar #'max a b))
+               (mapcar (lambda (x) (mapcar #'length (car x)))
+                       imports))))
+
+(defun haskell-align-imports-fill (padding line)
+  "Fill an import line using the padding worked out from all statements."
+  (mapconcat #'identity
+             (cl-mapcar (lambda (pad part)
+                          (if (> (length part) 0)
+                              (concat part (make-string (- pad (length part)) ? ))
+                            (make-string pad ? )))
+                        padding
+                        line)
+             " "))
+
+(defun haskell-align-imports-line-match-it ()
+  "Try to match the current line as a regexp."
+  (let ((line (buffer-substring-no-properties (line-beginning-position)
+                                              (line-end-position))))
+    (if (string-match haskell-align-imports-regexp line)
+        line
+      nil)))
+
+(defun haskell-align-imports-after-imports-p ()
+  "Are we after the imports list?"
+  (save-excursion
+    (goto-char (line-beginning-position))
+    (let ((case-fold-search nil))
+      (not (not (search-forward-regexp "\\( = \\|\\<instance\\>\\| :: \\| ∷ \\)"
+                                       (line-end-position) t 1))))))
+
+(provide 'haskell-align-imports)
+
+;;; haskell-align-imports.el ends here