diff options
Diffstat (limited to 'configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180913.348/haskell-indentation.el')
-rw-r--r-- | configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180913.348/haskell-indentation.el | 1255 |
1 files changed, 0 insertions, 1255 deletions
diff --git a/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180913.348/haskell-indentation.el b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180913.348/haskell-indentation.el deleted file mode 100644 index 0ab735ff2ad3..000000000000 --- a/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180913.348/haskell-indentation.el +++ /dev/null @@ -1,1255 +0,0 @@ -;;; haskell-indentation.el --- indentation module for Haskell Mode -*- lexical-binding: t -*- - -;; Copyright (C) 2013 Kristof Bastiaensen, Gergely Risko - -;; Author: Kristof Bastiaensen <kristof.bastiaensen@vleeuwen.org> -;; Author: Gergely Risko <errge@nilcons.com> -;; Keywords: indentation haskell -;; URL: https://github.com/haskell/haskell-mode - -;; This file is not part of GNU Emacs. - -;; This file 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 file 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: - -;; Installation: -;; -;; To turn indentation on for all Haskell buffers under Haskell mode add -;; this to your configuration file: -;; -;; (add-hook haskell-mode-hook 'haskell-indentation-mode) -;; -;; Otherwise, call `haskell-indentation-mode'. - -;;; Code: - -;; TODO eliminate magic number 2 where possible, use a variable - -;; TODO `haskell-indentation-find-indentation' — fix it, get rid of "safe" -;; version - -(require 'cl-lib) -(require 'haskell-lexeme) - -;;;###autoload -(defgroup haskell-indentation nil - "Haskell indentation." - :link '(custom-manual "(haskell-mode)Indentation") - :group 'haskell - :prefix "haskell-indentation-") - -(defcustom haskell-indentation-layout-offset 2 - "Extra indentation to add before expressions in a Haskell layout list." - :type 'integer - :group 'haskell-indentation) - -(defcustom haskell-indentation-starter-offset 2 - "Extra indentation after an opening keyword (e.g. \"let\")." - :type 'integer - :group 'haskell-indentation) - -(defcustom haskell-indentation-left-offset 2 - "Extra indentation after an indentation to the left (e.g. after \"do\")." - :type 'integer - :group 'haskell-indentation) - -(defcustom haskell-indentation-where-pre-offset 2 - "Extra indentation before the keyword \"where\"." - :type 'integer - :group 'haskell-indentation) - -(defcustom haskell-indentation-where-post-offset 2 - "Extra indentation after the keyword \"where\"." - :type 'integer - :group 'haskell-indentation) - -(defcustom haskell-indentation-electric-flag nil - "Non-nil means insertion of some characters may auto reindent the line. -If the variable `electric-indent-mode' is non-nil then this variable is -overridden." - :type 'symbol - :group 'haskell-indentation) -(make-variable-buffer-local 'haskell-indentation-electric-flag) - -(defvar haskell-indentation-mode-map - (let ((map (make-sparse-keymap))) - (define-key map (kbd "RET") #'haskell-indentation-newline-and-indent) - (define-key map (kbd "<backtab>") #'haskell-indentation-indent-backwards) - (define-key map (kbd ",") #'haskell-indentation-common-electric-command) - (define-key map (kbd ";") #'haskell-indentation-common-electric-command) - (define-key map (kbd ")") #'haskell-indentation-common-electric-command) - (define-key map (kbd "}") #'haskell-indentation-common-electric-command) - (define-key map (kbd "]") #'haskell-indentation-common-electric-command) - map) - "Keymap for `haskell-indentation-mode'.") - -;;;###autoload -(define-minor-mode haskell-indentation-mode - "Haskell indentation mode that deals with the layout rule. -It rebinds RET, DEL and BACKSPACE, so that indentations can be -set and deleted as if they were real tabs." - :keymap haskell-indentation-mode-map - (kill-local-variable 'indent-line-function) - (kill-local-variable 'indent-region-function) - - (when haskell-indentation-mode - (when (and (bound-and-true-p haskell-indent-mode) - (fboundp 'turn-off-haskell-indent)) - (turn-off-haskell-indent)) - (setq-local indent-line-function #'haskell-indentation-indent-line) - (setq-local indent-region-function #'haskell-indentation-indent-region))) - -;;;###autoload -(defun turn-on-haskell-indentation () - "Turn on the haskell-indentation minor mode." - (interactive) - (haskell-indentation-mode t)) - -(make-obsolete 'turn-on-haskell-indentation - 'haskell-indentation-mode - "2015-05-25") - -(defvar haskell-literate) ; defined in haskell-mode.el - -(defun haskell-indentation-bird-p () - "Return t if this is a literate Haskell buffer in bird style, NIL otherwise." - (eq haskell-literate 'bird)) - -;;---------------------------------------------------------------------------- -;; UI starts here - -(defun haskell-indentation-reindent-to (col &optional move) - "Reindent current line to COL, move the point there if MOVE is non-NIL." - (let* ((ci (haskell-indentation-current-indentation))) - (save-excursion - (move-to-column ci) - (if (<= ci col) - (insert-before-markers (make-string (- col ci) ? )) - (delete-char (- col ci)))) - (when move - (move-to-column col)))) - -(defun haskell-indentation-indent-rigidly (start end arg) - "Indent all lines starting in the region sideways by ARG columns. -Called from a program, takes three arguments, START, END and ARG. -You can remove all indentation from a region by giving a large -negative ARG. Handles bird style literate Haskell too." - (interactive "*r\np") - (save-excursion - (goto-char end) - (let ((end-marker (point-marker))) - (goto-char start) - (or (bolp) (forward-line 0)) - (while (< (point) end-marker) - (let ((ci (haskell-indentation-current-indentation))) - (when (and t - (eq (char-after) ?>)) - (forward-char 1)) - (skip-syntax-forward "-") - (unless (eolp) - (haskell-indentation-reindent-to (max 0 (+ ci arg)))) - (forward-line 1))) - (move-marker end-marker nil)))) - -(defun haskell-indentation-current-indentation () - "Column position of first non-whitespace character in current line." - (save-excursion - (beginning-of-line) - (when (haskell-indentation-bird-p) - (forward-char)) - (skip-syntax-forward "-") - (current-column))) - -(defun haskell-indentation-bird-outside-code-p () - "Non-NIL if we are in bird literate mode, but outside of code." - (and (haskell-indentation-bird-p) - (or (< (current-column) 2) - (save-excursion - (beginning-of-line) - (not (eq (char-after) ?>)))))) - -(defun haskell-indentation-newline-and-indent () - "Insert newline and indent." - (interactive "*") - ;; On RET (or C-j), we: - ;; - just jump to the next line if literate haskell, but outside code - (if (haskell-indentation-bird-outside-code-p) - (progn - (delete-horizontal-space) - (newline)) - ;; - save the current column - (let ((ci (haskell-indentation-current-indentation))) - ;; - jump to the next line and reindent to at the least same level - (delete-horizontal-space) - (newline) - ;; calculate indentation after newline is inserted because if we - ;; break an identifier we might create a keyword, for example - ;; "dowhere" => "do where" - (let ((indentations (or (haskell-indentation-find-indentations) - '(0)))) - (when (haskell-indentation-bird-p) - (insert "> ")) - (haskell-indentation-reindent-to - (haskell-indentation-next-indentation (- ci 1) indentations 'nofail) - 'move))))) - -(defun haskell-indentation-next-indentation (col indentations &optional nofail) - "Find the leftmost indentation which is greater than COL. -Indentations are taken from INDENTATIONS, which should be a -list. Return the last indentation if there are no bigger ones and -NOFAIL is non-NIL." - (when (null indentations) - (error "haskell-indentation-next-indentation called with empty list")) - (or (cl-find-if (lambda (i) (> i col)) indentations) - (when nofail - (car (last indentations))))) - -(defun haskell-indentation-previous-indentation (col indentations &optional nofail) - "Find the rightmost indentation less than COL from INDENTATIONS. -When no indentations are less than COL, return the rightmost indentation -if NOFAIL is non-nil, or nil otherwise." - (when (null indentations) - (error "haskell-indentation-previous-indentation called with empty list")) - (let ((rev (reverse indentations))) - (or (cl-find-if (lambda (i) (< i col)) rev) - (when nofail - (car rev))))) - -(defvar haskell-indentation-dyn-last-direction nil - "") ; FIXME -(defvar haskell-indentation-dyn-last-indentations nil - "") ; FIXME - -(defun haskell-indentation-indent-line () - "Indent current line, cycle though indentation positions. -Do nothing inside multiline comments and multiline strings. -Start enumerating the indentation points to the right. The user -can continue by repeatedly pressing TAB. When there is no more -indentation points to the right, we switch going to the left." - (interactive "*") - ;; try to repeat - (when (not (haskell-indentation-indent-line-repeat)) - (setq haskell-indentation-dyn-last-direction nil) - ;; parse error is intentionally not cought here, it may come from - ;; `haskell-indentation-find-indentations', but escapes the scope - ;; and aborts the opertaion before any moving happens - (let* ((cc (current-column)) - (ci (haskell-indentation-current-indentation)) - (inds (save-excursion - (move-to-column ci) - (or (haskell-indentation-find-indentations) - '(0)))) - (valid (memq ci inds)) - (cursor-in-whitespace (< cc ci))) - - (if (and valid cursor-in-whitespace) - (move-to-column ci) - (haskell-indentation-reindent-to - (haskell-indentation-next-indentation ci inds 'nofail) - cursor-in-whitespace)) - (setq haskell-indentation-dyn-last-direction 'right - haskell-indentation-dyn-last-indentations inds)))) - -(defun haskell-indentation-indent-line-repeat () - "Cycle though indentation positions." - (cond - ((and (memq last-command - '(indent-for-tab-command - haskell-indentation-indent-backwards)) - (eq haskell-indentation-dyn-last-direction 'region)) - (let ((mark-even-if-inactive t)) - (haskell-indentation-indent-rigidly - (region-beginning) - (region-end) - 1)) - t) - ((and (eq last-command 'indent-for-tab-command) - (memq haskell-indentation-dyn-last-direction '(left right)) - haskell-indentation-dyn-last-indentations) - (let ((ci (haskell-indentation-current-indentation))) - (if (eq haskell-indentation-dyn-last-direction 'left) - (haskell-indentation-reindent-to - (haskell-indentation-previous-indentation - ci haskell-indentation-dyn-last-indentations 'nofail)) - ;; right - (if (haskell-indentation-next-indentation - ci haskell-indentation-dyn-last-indentations) - (haskell-indentation-reindent-to - (haskell-indentation-next-indentation - ci haskell-indentation-dyn-last-indentations 'nofail)) - ;; but failed, switch to left - (setq haskell-indentation-dyn-last-direction 'left) - (haskell-indentation-indent-line-repeat))) - t)) - (t nil))) - -(defun haskell-indentation-indent-region (_start _end) - "This function does nothing. - -It is better to do nothing to indent region in Haskell than to -break the semantics of indentation. This function is used for -`indent-region-function' because the default is to call -`indent-line-function' on every line from START to END and that -also produces catastrophic results. - -Someday we will have indent region that preserves semantics and -fixes up only indentation." - nil) - -(defun haskell-indentation-indent-backwards () - "Indent the current line to the previous indentation point." - (interactive "*") - (cond - ((and (memq last-command - '(indent-for-tab-command haskell-indentation-indent-backwards)) - (eq haskell-indentation-dyn-last-direction 'region)) - (let ((mark-even-if-inactive t)) - (haskell-indentation-indent-rigidly (region-beginning) (region-end) -1))) - ((use-region-p) - (setq haskell-indentation-dyn-last-direction 'region) - (haskell-indentation-indent-rigidly (region-beginning) (region-end) -1) - (message "Press TAB or S-TAB again to indent the region more")) - (t - (setq haskell-indentation-dyn-last-direction nil) - (let* ((cc (current-column)) - (ci (haskell-indentation-current-indentation)) - (inds (save-excursion - (move-to-column ci) - (or (haskell-indentation-find-indentations) - '(0)))) - (cursor-in-whitespace (< cc ci)) - (pi (haskell-indentation-previous-indentation ci inds))) - (if (null pi) - ;; if there are no more indentations to the left, just go to column 0 - (haskell-indentation-reindent-to - (car (haskell-indentation-first-indentation)) cursor-in-whitespace) - (haskell-indentation-reindent-to pi cursor-in-whitespace)))))) - -(defun haskell-indentation-common-electric-command (arg) - "Call `self-insert-command' to insert the character typed ARG times -and indent when all of the following are true: -1) The character is the first non-whitespace character on the line. -2) There is only one possible indentation position. -3) The variable `electric-indent-mode' or `haskell-indentation-electric-flag' - is non-nil. -4) The point is not in a comment, string, or quasiquote." - (interactive "*p") - (let ((col (current-column)) - ind) - (self-insert-command arg) - (when (and (or haskell-indentation-electric-flag - electric-indent-mode) - (= (haskell-indentation-current-indentation) - col) - (> arg 0) - (not (nth 8 (syntax-ppss))) - (= 1 (save-excursion - (move-to-column col) - (length (setq ind (haskell-indentation-find-indentations)))))) - (haskell-indentation-reindent-to (car ind))))) - - -;;---------------------------------------------------------------------------- -;; Parser Starts Here - -;; The parser is implemented as a recursive descent parser. Each parser -;; advances the point to after the expression it parses, and sets the -;; dynamic scoped variables containing the information about the -;; indentations. The dynamic scoping allows transparent backtracking to -;; previous states of these variables. A new state can be set using `let'. -;; When the scope of this function ends, the variable is automatically -;; reverted to its old value. - -;; This is basicly a performance hack. It would have been possible to -;; thread this state using a association-list through the parsers, but it -;; would be probably more complicated and slower due to the lack of real -;; closures in Emacs Lisp. -;; -;; When finished parsing, the tokenizer returns 'end-token, and -;; following-token is set to the token after point. The parser adds its -;; indentations to possible-indentations and returns to it's parent, or -;; exits non-locally by throwing parse-end, so that the parent will not add -;; new indentations to it. - -;; the parse state: -(defvar following-token) ;; the next token after parsing finished -;; the token at the current parser point or a pseudo-token (see -;; `haskell-indentation-read-next-token') -(defvar current-token) -(defvar previous-token) -(defvar left-indent) ;; most left possible indentation -(defvar starter-indent) ;; column at a keyword -(defvar current-indent) ;; the most right indentation -(defvar layout-indent) ;; the column of the layout list -(defvar possible-indentations) ;; the return value of the indentations -(defvar indentation-point) ;; where to stop parsing -(defvar implicit-layout-active) ;; is "off-side" rule active? - -(defun haskell-indentation-goto-least-indentation () - "" ; FIXME - (beginning-of-line) - (if (haskell-indentation-bird-p) - (catch 'return - (while t - (when (not (eq (char-after) ?>)) - (forward-line) - (forward-char 2) - (throw 'return nil)) - (let ((ps (nth 8 (syntax-ppss)))) - (when ps ;; inside comment or string - (goto-char ps) - (beginning-of-line))) - (when (and (>= 2 (haskell-indentation-current-indentation)) - (not (looking-at ">\\s-*$"))) - (forward-char 2) - (throw 'return nil)) - (when (bobp) - (forward-char 2) - (throw 'return nil)) - (forward-line -1))) - ;; not bird style - (catch 'return - (while (not (bobp)) - (let ((point (point))) - ;; (forward-comment -1) gets lost if there are unterminated - ;; string constants and does not move point anywhere. We fix - ;; that case with (forward-line -1) - (forward-comment (- (buffer-size))) - (if (equal (point) point) - (forward-line -1) - (beginning-of-line))) - (let* ((ps (syntax-ppss)) - (start-of-comment-or-string (nth 8 ps)) - (start-of-list-expression (nth 1 ps))) - (cond - (start-of-comment-or-string - ;; inside comment or string - (goto-char start-of-comment-or-string)) - (start-of-list-expression - ;; inside a parenthesized expression - (goto-char start-of-list-expression)) - ((= 0 (haskell-indentation-current-indentation)) - (throw 'return nil)))))) - (beginning-of-line) - (when (bobp) - (forward-comment (buffer-size))))) - -(defun haskell-indentation-parse-to-indentations () - "" ; FIXME - (save-excursion - (skip-syntax-forward "-") - (let ((indentation-point (point)) - (layout-indent 0) - (current-indent haskell-indentation-layout-offset) - (starter-indent haskell-indentation-layout-offset) - (left-indent haskell-indentation-layout-offset) - (case-fold-search nil) - current-token - previous-token - following-token - possible-indentations - implicit-layout-active) - (haskell-indentation-goto-least-indentation) - (if (<= indentation-point (point)) - (haskell-indentation-first-indentation) - (setq current-token (haskell-indentation-peek-token)) - (catch 'parse-end - (haskell-indentation-toplevel)) - possible-indentations)))) - -(defun haskell-indentation-first-indentation () - "Return column of first indentation." - (list (if (haskell-indentation-bird-p) 2 0))) - -(defun haskell-indentation-find-indentations () - "Return list of indentation positions corresponding to actual cursor position." - (let ((ppss (syntax-ppss))) - (cond - ((nth 3 ppss) - (if (save-excursion - (and (forward-line -1) - (< (nth 8 ppss) (point)))) - ;; if this string goes over more than one line we want to - ;; sync with the last line, not the first one - (list (save-excursion - (forward-line -1) - (current-indentation))) - - (append - (haskell-indentation-first-indentation) - (list (save-excursion - (goto-char (nth 8 ppss)) - (current-column)))))) - ((nth 4 ppss) - (if (save-excursion - (and (skip-syntax-forward "-") - (eolp) - (not (> (forward-line 1) 0)) - (not (nth 4 (syntax-ppss))))) - (haskell-indentation-parse-to-indentations) - (haskell-indentation-first-indentation))) - (t - (haskell-indentation-parse-to-indentations))))) - -(defconst haskell-indentation-unicode-tokens - '(("→" . "->") ;; #x2192 RIGHTWARDS ARROW - ("∷" . "::") ;; #x2237 PROPORTION - ("←" . "<-") ;; #x2190 LEFTWARDS ARROW - ("⇒" . "=>") ;; #x21D2 RIGHTWARDS DOUBLE ARROW - ("∀" . "forall") ;; #x2200 FOR ALL - ("⤙" . "-<") ;; #x2919 LEFTWARDS ARROW-TAIL - ("⤚" . ">-") ;; #x291A RIGHTWARDS ARROW-TAIL - ("⤛" . "-<<") ;; #x291B LEFTWARDS DOUBLE ARROW-TAIL - ("⤜" . ">>-") ;; #x291C RIGHTWARDS DOUBLE ARROW-TAIL - ("★" . "*")) ;; #x2605 BLACK STAR - "Translation from UnicodeSyntax tokens to their ASCII representation.") - -(defconst haskell-indentation-toplevel-list - `(("module" . haskell-indentation-module) - ("signature" . haskell-indentation-module) - ("data" . haskell-indentation-data) - ("type" . haskell-indentation-data) - ("newtype" . haskell-indentation-data) - ("import" . haskell-indentation-import) - ("foreign" . haskell-indentation-foreign) - ("where" . haskell-indentation-toplevel-where) - ("class" . haskell-indentation-class-declaration) - ("instance" . haskell-indentation-class-declaration) - ("deriving" . haskell-indentation-deriving)) - "Alist of toplevel keywords with associated parsers.") - -(defconst haskell-indentation-type-list - `(("::" . - ,(apply-partially 'haskell-indentation-with-starter - (apply-partially 'haskell-indentation-separated - 'haskell-indentation-type '("->" "=>")))) - ("(" . - ,(apply-partially 'haskell-indentation-list - 'haskell-indentation-type ")" ",")) - ("[" . - ,(apply-partially 'haskell-indentation-list - 'haskell-indentation-type "]" ",")) - ("{" . - ,(apply-partially 'haskell-indentation-list - 'haskell-indentation-type "}" ","))) - "Alist of tokens in type declarations with associated parsers.") - -(defconst haskell-indentation-expression-list - `(("data" . haskell-indentation-data) - ("type" . haskell-indentation-data) - ("newtype" . haskell-indentation-data) - ("if" . haskell-indentation-if) - ("let" . - ,(apply-partially 'haskell-indentation-phrase - '(haskell-indentation-declaration-layout - "in" haskell-indentation-expression))) - ("do" . - ,(apply-partially 'haskell-indentation-with-starter - 'haskell-indentation-expression-layout)) - ("mdo" . - ,(apply-partially 'haskell-indentation-with-starter - 'haskell-indentation-expression-layout)) - ("rec" . - ,(apply-partially 'haskell-indentation-with-starter - 'haskell-indentation-expression-layout)) - ("case" . - ,(apply-partially 'haskell-indentation-phrase - '(haskell-indentation-expression - "of" haskell-indentation-case-layout))) - ("\\" . - ,(apply-partially 'haskell-indentation-with-starter - 'haskell-indentation-lambda-maybe-lambdacase)) - ("proc" . - ,(apply-partially 'haskell-indentation-phrase - '(haskell-indentation-expression - "->" haskell-indentation-expression))) - ("where" . - ,(apply-partially 'haskell-indentation-with-starter - 'haskell-indentation-declaration-layout nil t)) - ("::" . haskell-indentation-scoped-type) - ("=" . - ,(apply-partially 'haskell-indentation-statement-right - 'haskell-indentation-expression)) - ("<-" . - ,(apply-partially 'haskell-indentation-statement-right - 'haskell-indentation-expression)) - ("(" . - ,(apply-partially 'haskell-indentation-list - 'haskell-indentation-expression - ")" - '(list "," "->"))) - ("[" . - ,(apply-partially 'haskell-indentation-list - 'haskell-indentation-expression "]" "," "|")) - ("{" . - ,(apply-partially 'haskell-indentation-list - 'haskell-indentation-expression "}" ","))) - "Alist of keywords in expressions with associated parsers.") - -(defun haskell-indentation-expression-layout () - "Parse layout list with expressions, such as after \"do\"." - (haskell-indentation-layout #'haskell-indentation-expression)) - -(defun haskell-indentation-declaration-layout () - "Parse layout list with declarations, such as after \"where\"." - (haskell-indentation-layout #'haskell-indentation-declaration)) - -(defun haskell-indentation-case-layout () - "Parse layout list with case expressions." - (haskell-indentation-layout #'haskell-indentation-case)) - -(defun haskell-indentation-lambda-maybe-lambdacase () - "Parse lambda or lambda-case expression. -After a lambda (backslash) there are two possible cases: - -- the new lambdacase expression, that can be recognized by the - next token being \"case\"; - -- or simply an anonymous function definition in the form of - \"expression -> expression\"." - (if (string= current-token "case") - (haskell-indentation-with-starter - #'haskell-indentation-case-layout) - (haskell-indentation-phrase-rest - '(haskell-indentation-expression "->" haskell-indentation-expression)))) - -(defun haskell-indentation-fundep () - "Parse functional dependency." - (haskell-indentation-with-starter - (apply-partially #'haskell-indentation-separated - #'haskell-indentation-fundep1 ","))) - -(defun haskell-indentation-fundep1 () - "Parse an item in functional dependency declaration." - (let ((current-indent (current-column))) - (while (member current-token '(value "->")) - (haskell-indentation-read-next-token)) - (when (and (eq current-token 'end-tokens) - (member following-token '(value "->"))) - (haskell-indentation-add-indentation current-indent)))) - -(defun haskell-indentation-toplevel () - "Parse toplevel statements." - (haskell-indentation-layout - (lambda () - (let ((parser (assoc current-token haskell-indentation-toplevel-list))) - (if parser - (funcall (cdr parser)) - (haskell-indentation-declaration)))))) - -(defun haskell-indentation-type () - "Parse type declaration." - (let ((current-indent (current-column))) - (catch 'return - (while t - (cond - ((member current-token '(value operator "->" "=>")) - (haskell-indentation-read-next-token)) - - ((eq current-token 'end-tokens) - (when (member following-token - '(value operator no-following-token - "(" "[" "{" "::")) - (if (equal following-token "=>") - (haskell-indentation-add-indentation starter-indent) - (haskell-indentation-add-indentation current-indent)) - (haskell-indentation-add-indentation left-indent)) - (throw 'return nil)) - (t (let ((parser (assoc current-token haskell-indentation-type-list))) - (if (not parser) - (throw 'return nil) - (funcall (cdr parser)))))))))) - -(defun haskell-indentation-type-1 () - "Parse a single type declaration." - (let ((current-indent (current-column))) - (catch 'return - (cond - ((member current-token '(value operator "->" "=>")) - (haskell-indentation-read-next-token)) - - ((eq current-token 'end-tokens) - (when (member following-token - '(value operator no-following-token - "->" "=>" "(" "[" "{" "::")) - (haskell-indentation-add-indentation current-indent)) - (throw 'return nil)) - (t (let ((parser (assoc current-token haskell-indentation-type-list))) - (if (not parser) - (throw 'return nil) - (funcall (cdr parser))))))))) - -(defun haskell-indentation-scoped-type () - "Parse scoped type declaration. - -For example - let x :: Int = 12 - do x :: Int <- return 12" - (haskell-indentation-with-starter - (apply-partially #'haskell-indentation-separated #'haskell-indentation-type '("->" "=>"))) - (when (member current-token '("<-" "=")) - (haskell-indentation-statement-right #'haskell-indentation-expression))) - -(defun haskell-indentation-data () - "Parse data or type declaration." - (haskell-indentation-read-next-token) - (when (string= current-token "instance") - (haskell-indentation-read-next-token)) - (haskell-indentation-type) - (cond ((eq current-token 'end-tokens) - (when (member following-token '("=" "where")) - (haskell-indentation-add-indentation current-indent) - (throw 'parse-end nil))) - ((string= current-token "=") - (let ((starter-indent-inside (current-column))) - (haskell-indentation-with-starter - (lambda () - (haskell-indentation-separated - #'haskell-indentation-expression "|"))) - (cond - ((equal current-token 'end-tokens) - (when (string= following-token "deriving") - (haskell-indentation-push-indentation starter-indent-inside) - (haskell-indentation-add-left-indent))) - ((equal current-token "deriving") - (haskell-indentation-with-starter - #'haskell-indentation-type-1))))) - ((string= current-token "where") - (haskell-indentation-with-starter - #'haskell-indentation-expression-layout nil) - (cond - ((equal current-token 'end-tokens) - (when (string= following-token "deriving") - (haskell-indentation-add-left-indent))) - ((equal current-token "deriving") - (haskell-indentation-with-starter - #'haskell-indentation-type-1)))))) - -(defun haskell-indentation-import () - "Parse import declaration." - (haskell-indentation-with-starter #'haskell-indentation-expression)) - -(defun haskell-indentation-foreign () - "Parse foreign import declaration." - (haskell-indentation-with-starter (apply-partially #'haskell-indentation-expression '(value operator "import")))) - -(defun haskell-indentation-class-declaration () - "Parse class declaration." - (haskell-indentation-with-starter - (lambda () - (haskell-indentation-type) - (when (string= current-token "|") - (haskell-indentation-fundep)) - (when (string= current-token "where") - (haskell-indentation-with-starter - #'haskell-indentation-declaration-layout nil))))) - -(defun haskell-indentation-deriving () - "Parse standalone declaration." - (haskell-indentation-with-starter - (lambda () - (when (string= "instance" current-token) - (haskell-indentation-read-next-token)) - (when (equal current-token 'end-tokens) - (haskell-indentation-add-left-indent) - (throw 'parse-end nil)) - (haskell-indentation-type) - (when (string= current-token "|") - (haskell-indentation-fundep))))) - -(defun haskell-indentation-module () - "Parse module declaration." - (haskell-indentation-with-starter - (lambda () - (haskell-indentation-read-next-token) - (when (equal current-token 'layout-item) - (haskell-indentation-read-next-token)) - (when (string= current-token "(") - (haskell-indentation-list - #'haskell-indentation-module-export - ")" ",")) - (if (string= current-token "where") - (haskell-indentation-read-next-token) - - (when (eq current-token 'end-tokens) - (when (member following-token '(value no-following-token "(")) - (haskell-indentation-add-indentation - (+ starter-indent haskell-indentation-starter-offset)) - (haskell-indentation-add-indentation - (+ left-indent haskell-indentation-starter-offset)) - (throw 'parse-end nil)) - (haskell-indentation-add-layout-indent) - (throw 'parse-end nil)))))) - -(defun haskell-indentation-toplevel-where () - "Parse 'where' that we may hit as a standalone in module declaration." - (haskell-indentation-read-next-token) - - (when (eq current-token 'end-tokens) - (haskell-indentation-add-layout-indent) - (throw 'parse-end nil))) - -(defun haskell-indentation-module-export () - "Parse export list." - (cond ((string= current-token "module") - (let ((current-indent (current-column))) - (haskell-indentation-read-next-token) - (cond ((eq current-token 'end-tokens) - (haskell-indentation-add-indentation current-indent)) - ((eq current-token 'value) - (haskell-indentation-read-next-token))))) - (t (haskell-indentation-type)))) - -(defun haskell-indentation-list (parser end sep &optional stmt-sep) - "Parse a list, pair or other expression containing multiple -items parsed by PARSER, separated by SEP or STMT-SEP, and ending -with END." - ;; note that we use macro expansion here to preserver Emacs 23 - ;; compatibility and its lack of lexical binding - (haskell-indentation-with-starter - `(lambda () - (let ((implicit-layout-active nil)) - (haskell-indentation-separated - #',parser ,sep ,stmt-sep))) - end)) - -(defun haskell-indentation-with-starter (parser &optional end where-expr?) - "Parse an expression starting with a keyword or parenthesis. -Skip the keyword or parenthesis." ; FIXME: better description needed - (let ((starter-column (current-column)) - (current-indent current-indent) - (left-indent - (if (= (current-column) (haskell-indentation-current-indentation)) - (current-column) - left-indent))) - (haskell-indentation-read-next-token) - (when (eq current-token 'end-tokens) - (cond ((equal following-token end) - ;; indent before keyword or parenthesis - (haskell-indentation-add-indentation starter-column)) - (where-expr? - ;; left indent + where post indent - (haskell-indentation-add-where-post-indent left-indent)) - (t - (haskell-indentation-add-left-indent))) - (throw 'parse-end nil)) - (let* ((current-indent (current-column)) - (starter-indent (min starter-column current-indent)) - (left-indent - (if end - (+ starter-indent haskell-indentation-starter-offset) - left-indent))) - (funcall parser) - (cond ((eq current-token 'end-tokens) - (when (equal following-token end) - ;; indent before keyword or parenthesis - (haskell-indentation-add-indentation starter-indent)) - ;; add no more indentations if we expect a closing keyword - (when end - (throw 'parse-end nil))) - ((equal current-token end) - (haskell-indentation-read-next-token)))))) - -(defun haskell-indentation-case-alternative () - "" ; FIXME - (setq left-indent (current-column)) - (haskell-indentation-separated #'haskell-indentation-expression "," nil) - (cond ((eq current-token 'end-tokens) - (haskell-indentation-add-indentation current-indent)) - ((string= current-token "->") - (haskell-indentation-statement-right #'haskell-indentation-expression)) - ;; otherwise fallthrough - )) - -(defun haskell-indentation-case () - "" ; FIXME - (haskell-indentation-expression) - (cond ((eq current-token 'end-tokens) - (haskell-indentation-add-indentation current-indent)) - ((string= current-token "|") - (haskell-indentation-with-starter - (apply-partially #'haskell-indentation-separated - #'haskell-indentation-case-alternative "|" nil) - nil)) - ((string= current-token "->") - (haskell-indentation-statement-right #'haskell-indentation-expression)) - ;; otherwise fallthrough - )) - -(defun haskell-indentation-statement-right (parser) - "Process right side of a statement. -Set `current-indent' to the current column and calls the given -parser. If parsing ends here, set indentation to left-indent." - (haskell-indentation-read-next-token) - (when (eq current-token 'end-tokens) - (haskell-indentation-add-left-indent) - (haskell-indentation-add-indentation current-indent) - (throw 'parse-end nil)) - (funcall parser) - (when (equal current-token "where") - (haskell-indentation-with-starter - #'haskell-indentation-expression-layout nil))) - -(defun haskell-indentation-guard () - "Parse \"guard\" statement." - (setq left-indent (current-column)) - (haskell-indentation-separated - #'haskell-indentation-expression "," nil)) - -(defun haskell-indentation-declaration () - "Parse function or type declaration." - (haskell-indentation-separated #'haskell-indentation-expression "," nil) - (when (string= current-token "|") - (haskell-indentation-with-starter - (apply-partially #'haskell-indentation-separated - #'haskell-indentation-guard "|" nil) - nil)) - (when (eq current-token 'end-tokens) - (when (member following-token '("|" "=" "::" ",")) - (haskell-indentation-add-indentation current-indent) - (throw 'parse-end nil)))) - -(defun haskell-indentation-layout (parser) - "Parse layout list, where each layout item is parsed by parser." - (if (string= current-token "{") - (haskell-indentation-list parser "}" ";") ; explicit layout - (haskell-indentation-implicit-layout-list parser))) - -(defun haskell-indentation-expression-token-p (token) - "Return non-NIL value if TOKEN is an expression token." - (member token - '("if" "let" "do" "case" "\\" "(" "{" "[" "::" - value operator no-following-token))) - -(defun haskell-indentation-expression (&optional accepted-tokens) - "Parse an expression until an unknown token is encountered." - (catch 'return - (let ((current-indent (current-column))) - (unless accepted-tokens - (setq accepted-tokens '(value operator))) - (while t - (cond - ((memq current-token accepted-tokens) - (haskell-indentation-read-next-token)) - ((eq current-token 'end-tokens) - (cond ((string= following-token "where") - (haskell-indentation-add-where-pre-indent)) ; before a where - ((haskell-indentation-expression-token-p following-token) - ;; a normal expression can be either continued or have - ;; left indent - (haskell-indentation-add-indentation - current-indent) - (haskell-indentation-add-indentation - left-indent))) - (throw 'return nil)) - (t (let ((parser (assoc current-token - haskell-indentation-expression-list))) - (when (null parser) - (throw 'return nil)) ; not expression token, so exit - (funcall (cdr parser)) ; run parser - - ;; after an 'open' expression such as 'if', exit - (unless (member (car parser) '("(" "[" "{" "case")) - (throw 'return nil))))))))) - -(defun haskell-indentation-separated (parser separator &optional stmt-separator) - "Evaluate PARSER separated by SEPARATOR and STMT-SEPARATOR. -If STMT-SEPARATOR is not NIL, it will be used to set a new starter-indent. - -For example: - - [ i | i <- [1..10] - ," - (catch 'return - (unless (listp separator) - (setq separator (list separator))) - (unless (listp stmt-separator) - (setq stmt-separator (list stmt-separator))) - (while t - (funcall parser) - (cond ((member current-token separator) - (haskell-indentation-at-separator)) - - ((member current-token stmt-separator) - (setq starter-indent (current-column)) - (haskell-indentation-at-separator)) - - ((eq current-token 'end-tokens) - (when (or (member following-token separator) - (member following-token stmt-separator)) - ;; Set an indentation before a separator, for example: - ;; [ 1 or [ 1 | a - ;; , 2 , 20 - (haskell-indentation-add-indentation starter-indent) - (when (< left-indent starter-indent) - (haskell-indentation-add-indentation left-indent)) - (throw 'parse-end nil)) - (when (equal following-token 'no-following-token) - ;; Set an indentation before a separator, for example: - ;; [ 1 or [ 1 | a - ;; , 2 , 20 - (haskell-indentation-add-indentation starter-indent) - (haskell-indentation-add-indentation left-indent)) - (throw 'return nil)) - (t (throw 'return nil)))))) - -(defun haskell-indentation-at-separator () - "At a separator. - -If at a new line, set starter-indent at the separator -and current-indent after the separator, for example: - -l = [ 1 - , 2 - , -- start now here." - (let ((separator-column - (and (= (current-column) (haskell-indentation-current-indentation)) - (current-column)))) - (haskell-indentation-read-next-token) - (cond ((eq current-token 'end-tokens) - (haskell-indentation-add-indentation current-indent) - (haskell-indentation-add-indentation left-indent) - (throw 'return nil)) - (separator-column ; on the beginning of the line - (setq current-indent (current-column)) - (setq starter-indent separator-column) - (setq left-indent - (+ starter-indent haskell-indentation-starter-offset)))))) - -(defun haskell-indentation-implicit-layout-list (parser) - "An implicit layout list, elements are parsed with PARSER. -This sets the `layout-indent' variable to the column where the -layout starts." - (let* ((layout-indent (current-column)) - (current-indent (current-column)) - (left-indent (current-column)) - (implicit-layout-active t)) - (catch 'return - (while t - (let ((left-indent left-indent)) - (funcall parser)) - (cond ((member current-token '(layout-item ";")) - (haskell-indentation-read-next-token)) - ((eq current-token 'end-tokens) - (when (or (and - (not (member following-token '("{" operator))) - (not (member previous-token '(operator))) - (haskell-indentation-expression-token-p following-token)) - (string= following-token ";") - (and (equal layout-indent 0) - (member following-token (mapcar #'car haskell-indentation-toplevel-list)) - (not (string= following-token "where")))) - (haskell-indentation-add-layout-indent)) - (throw 'return nil)) - (t (throw 'return nil)))))) - ;; put `haskell-indentation-read-next-token' outside the current-indent - ;; definition so it will not return 'layout-end again - (when (eq current-token 'layout-end) - (let ((implicit-layout-active t)) - ;; leave layout at 'layout-end or illegal token - (haskell-indentation-read-next-token)))) - -(defun haskell-indentation-if () - "" ; FIXME - (haskell-indentation-with-starter - (lambda () - (if (string= current-token "|") - (haskell-indentation-with-starter - (lambda () - (haskell-indentation-separated - #'haskell-indentation-case-alternative "|" nil)) - nil) - (haskell-indentation-phrase-rest - '(haskell-indentation-expression - "then" haskell-indentation-expression - "else" haskell-indentation-expression)))) - nil)) - -(defun haskell-indentation-phrase (phrase) - "" ; FIXME - (haskell-indentation-with-starter - (apply-partially #'haskell-indentation-phrase-rest phrase) - nil)) - -(defun haskell-indentation-phrase-rest (phrase1) - "" ; FIXME - (while phrase1 - (let ((phrase phrase1)) - (setq phrase1 nil) - (let ((current-indent (current-column)) - (left-indent left-indent) - (layout-indent layout-indent)) - (funcall (car phrase))) - (cond - ((eq current-token 'end-tokens) - (cond ((null (cdr phrase))) ;; fallthrough - ((equal following-token (cadr phrase)) - (haskell-indentation-add-indentation starter-indent) - (unless (member following-token '("," ";")) - ;; we want to keep comma and semicolon aligned always - (haskell-indentation-add-indentation left-indent)) - (throw 'parse-end nil)) - ((string= (cadr phrase) "in") - (when (= left-indent layout-indent) - (haskell-indentation-add-layout-indent) - (throw 'parse-end nil))) - (t (throw 'parse-end nil)))) - ((null (cdr phrase))) - ((equal (cadr phrase) current-token) - (haskell-indentation-read-next-token) - (when (eq current-token 'end-tokens) - (haskell-indentation-add-indentation - (+ starter-indent haskell-indentation-starter-offset)) - (haskell-indentation-add-indentation - (+ left-indent haskell-indentation-starter-offset)) - (throw 'parse-end nil)) - (setq phrase1 (cddr phrase))) - ((string= (cadr phrase) "in")))))) - -(defun haskell-indentation-add-indentation (indent) - "" ; FIXME - (haskell-indentation-push-indentation - (if (<= indent layout-indent) - (+ layout-indent haskell-indentation-layout-offset) - indent))) - -(defun haskell-indentation-add-layout-indent () - "" ; FIXME - (haskell-indentation-push-indentation layout-indent)) - -(defun haskell-indentation-add-where-pre-indent () - "" ; FIXME - (haskell-indentation-push-indentation - (+ layout-indent haskell-indentation-where-pre-offset)) - (if (= layout-indent haskell-indentation-layout-offset) - (haskell-indentation-push-indentation - haskell-indentation-where-pre-offset))) - -(defun haskell-indentation-add-where-post-indent (indent) - "" ; FIXME - (haskell-indentation-push-indentation - (+ indent haskell-indentation-where-post-offset))) - -(defun haskell-indentation-add-left-indent () - "" ; FIXME - (haskell-indentation-add-indentation - (+ left-indent haskell-indentation-left-offset))) - -(defun haskell-indentation-push-indentation (indent) - "Add INDENT to list of possible indentations. - -Add INDENT to `possible-indentations' if it is not there -yet. Keep the list in ascending order." - (unless (member indent possible-indentations) - (setq possible-indentations - (sort (cons indent possible-indentations) #'<)))) - -(defun haskell-indentation-read-next-token () - "Go to the next token and set current-token to the next token. - -The following symbols are used as pseudo tokens: - -'layout-item: A new item in a layout list. The next token - will be the first token from the item. - -'layout-end: the end of a layout list. Next token will be - the first token after the layout list. - -'end-tokens: back at point where we started, following-token - will be set to the next token. - -Pseudo tokens are used only when implicit-layout-active is -t. That is the case only after keywords \"do\", \"where\", -\"let\" and \"of\". - -If we are at a new line, parse-line is increased, and -current-indent and left-indent are set to the indentation of the -line." - (cond ((and implicit-layout-active - (eq current-token 'end-tokens)) - 'end-tokens) - ((and implicit-layout-active - (eq current-token 'layout-end)) - (cond ((> layout-indent (current-column)) - 'layout-end) - ((= layout-indent (current-column)) - (setq current-token 'layout-item)) - ((< layout-indent (current-column)) - (setq current-token (haskell-indentation-peek-token))))) - ((and implicit-layout-active - (eq current-token 'layout-item)) - (setq current-token (haskell-indentation-peek-token))) - ((and implicit-layout-active - (> layout-indent (current-column))) - (setq current-token 'layout-end)) - (t - (setq previous-token (haskell-indentation-peek-token)) - (haskell-indentation-skip-token) - (if (>= (point) indentation-point) - (progn - (setq following-token - (if (and (not (eobp)) - (= (point) indentation-point)) - (haskell-indentation-peek-token) - 'no-following-token)) - (setq current-token 'end-tokens)) - (when (= (current-column) (haskell-indentation-current-indentation)) - ;; on a new line - (setq current-indent (current-column))) - (cond ((and implicit-layout-active - (> layout-indent (current-column))) - (setq current-token 'layout-end)) - ((and implicit-layout-active - (= layout-indent (current-column))) - (setq current-token 'layout-item)) - (t (setq current-token (haskell-indentation-peek-token)))))))) - -(defun haskell-indentation-peek-token () - "Return token starting at point." - (cond ((looking-at "\\(if\\|then\\|else\\|let\\|in\\|mdo\\|rec\\|do\\|proc\\|case\\|of\\|where\\|module\\|signature\\|deriving\\|import\\|data\\|type\\|newtype\\|class\\|instance\\)\\([^[:alnum:]'_]\\|$\\)") - (match-string-no-properties 1)) - ((looking-at "[][(){}[,;]") - (match-string-no-properties 0)) - ((looking-at "\\(\\\\\\|->\\|<-\\|::\\|=\\||\\|=>\\)\\([^-:!#$%&*+./<=>?@\\\\^|~]\\|$\\)") - (match-string-no-properties 1)) - ((looking-at "\\(→\\|←\\|∷\\|⇒\\)\\([^-:!#$%&*+./<=>?@\\\\^|~]\\|$\\)") - (let ((tok (match-string-no-properties 1))) - (or (cdr (assoc tok haskell-indentation-unicode-tokens)) tok))) - ((looking-at"[-:!#$%&*+./<=>?@\\\\^|~`]" ) - 'operator) - (t 'value))) - -(defun haskell-indentation-skip-token () - "Skip to the next token." - (if (haskell-lexeme-looking-at-token) - (goto-char (match-end 0)) - ;; otherwise skip until space found - (skip-syntax-forward "^-")) - ;; we have to skip unterminated string fence at the end of line - (skip-chars-forward "\n") - (forward-comment (buffer-size)) - (while (and (haskell-indentation-bird-p) - (bolp) - (eq (char-after) ?>)) - (forward-char) - (forward-comment (buffer-size)))) - -(provide 'haskell-indentation) - -;; Local Variables: -;; tab-width: 8 -;; End: - -;;; haskell-indentation.el ends here |