|
|
- ;;; haskell-sort-imports.el --- Sort the list of Haskell imports at the point alphabetically -*- 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:
-
- ;; If the region is active it sorts the imports within the
- ;; region.
-
- ;; This will align and sort the columns of the current import
- ;; list. It's more or less the coolest thing on the planet.
-
- ;;; Code:
-
- (require 'cl-lib)
-
- (defvar haskell-sort-imports-regexp
- (concat "^import[ ]+"
- "\\(qualified \\)?"
- "[ ]*\\(\"[^\"]*\" \\)?"
- "[ ]*\\([A-Za-z0-9_.']*.*\\)"))
-
- ;;;###autoload
- (defun haskell-sort-imports ()
- "Sort the import list at point. It sorts the current group
- i.e. an import list separated by blank lines on either side.
-
- If the region is active, it will restrict the imports to sort
- within that region."
- (interactive)
- (when (haskell-sort-imports-at-import)
- (let* ((points (haskell-sort-imports-decl-points))
- (current-string (buffer-substring-no-properties (car points)
- (cdr points)))
- (current-offset (- (point) (car points))))
- (if (region-active-p)
- (progn (goto-char (region-beginning))
- (haskell-sort-imports-goto-import-start))
- (haskell-sort-imports-goto-group-start))
- (let* ((start (point))
- (imports (haskell-sort-imports-collect-imports))
- (sorted (sort (cl-copy-list imports)
- (lambda (a b)
- (string< (haskell-sort-imports-normalize a)
- (haskell-sort-imports-normalize b))))))
- (when (not (equal imports sorted))
- (delete-region start (point))
- (mapc (lambda (import) (insert import "\n")) sorted))
- (goto-char start)
- (when (search-forward current-string nil t 1)
- (forward-char (- (length current-string)))
- (forward-char current-offset))))))
-
- (defun haskell-sort-imports-normalize (i)
- "Normalize an import, if possible, so that it can be sorted."
- (if (string-match haskell-sort-imports-regexp
- i)
- (match-string 3 i)
- i))
-
- (defun haskell-sort-imports-collect-imports ()
- (let ((imports (list)))
- (while (looking-at "import")
- (let* ((points (haskell-sort-imports-decl-points))
- (string (buffer-substring-no-properties (car points)
- (cdr points))))
- (goto-char (min (1+ (cdr points))
- (point-max)))
- (setq imports (cons string imports))))
- (reverse (delq nil (delete-dups imports)))))
-
- (defun haskell-sort-imports-goto-group-start ()
- "Go to the start of the import group."
- (or (and (search-backward "\n\n" nil t 1)
- (goto-char (+ 2 (line-end-position))))
- (when (search-backward-regexp "^module " nil t 1)
- (goto-char (1+ (line-end-position))))
- (goto-char (point-min))))
-
- (defun haskell-sort-imports-at-import ()
- "Are we at an import?"
- (save-excursion
- (haskell-sort-imports-goto-import-start)
- (looking-at "import")))
-
- (defun haskell-sort-imports-goto-import-start ()
- "Go to the start of the import."
- (goto-char (car (haskell-sort-imports-decl-points))))
-
- (defun haskell-sort-imports-decl-points ()
- "Get the points of the declaration."
- (save-excursion
- (let ((start (or (progn (goto-char (line-end-position))
- (search-backward-regexp "^[^ \n]" nil t 1)
- (unless (or (looking-at "^-}$")
- (looking-at "^{-$"))
- (point)))
- 0))
- (end (progn (goto-char (1+ (point)))
- (or (when (search-forward-regexp "[\n]+[^ \n]" nil t 1)
- (forward-char -1)
- (search-backward-regexp "[^\n ]" nil t)
- (line-end-position))
- (when (search-forward-regexp "\n" nil t 1)
- (1- (point)))
- (point-max)))))
- (cons start end))))
-
- (provide 'haskell-sort-imports)
-
- ;;; haskell-sort-imports.el ends here
|