From: Eshel Yaron Date: Fri, 23 Sep 2022 09:43:52 +0000 (+0300) Subject: ADDED: new user option for choosing indentation increments X-Git-Tag: v0.3.1 X-Git-Url: http://git.eshelyaron.com/gitweb/?a=commitdiff_plain;h=9dfbbf9e9baf19355608e8442d7d38ec9f374a47;p=sweep.git ADDED: new user option for choosing indentation increments * sweep.el: ** sweep-indent-offset: new user option ** (sweep-indent-line): use it * README.org: document new indentation engine --- diff --git a/NEWS.org b/NEWS.org index 9ce726f..cfc5222 100644 --- a/NEWS.org +++ b/NEWS.org @@ -30,6 +30,11 @@ Follows file specifications in =sweep-mode= buffers. * New user options available in =sweep= {{{version({{{input-file}}})}}} +** New user option =sweep-indent-offset= + +This option, set by default to 4, is an integer denoting the number of +columns used as the indent increment in =sweep-mode= buffers. + ** New user option =sweep-colourise-buffer-on-idle= This option is a boolean flag that determines whether to enable diff --git a/README.org b/README.org index 9336dcb..2657d9c 100644 --- a/README.org +++ b/README.org @@ -278,6 +278,111 @@ sweep-mode=. To instruct Emacs to always open Prolog files in (add-to-list 'auto-mode-alist '("\\.plt\\'" . sweep-mode)) #+end_src +** Indentation +:PROPERTIES: +:CUSTOM_ID: indentation +:END: + +#+CINDEX: indentation + +In =sweep-mode= buffers, the appropriate indentation for each line is +determined by a bespoke /indentation engine/. The indentation engine +analyses the syntactic context of a given line and determines the +appropriate indentation to apply based on a set of rules. + +#+FINDEX: sweep-indent-line +The entry point of the indentation engine is the function +=sweep-indent-line= which takes no arguments and indents that line at +point. =sweep-mode= supports the standard Emacs interface for +indentation by arranging for =sweep-indent-line= to be called whenever a +line should be indented, notably after pressing =TAB=. For more a full +description of the available commands and options that pertain to +indentation, see [[info:emacs#Indentation][Indentation in the Emacs manual]]. + +*** Indentation rules +:PROPERTIES: +:CUSTOM_ID: indentation-rules +:END: + +Lines in =sweep-mode= buffers are indented according to the following +rules: + +1. If the current line starts inside a string or a multi-line comment, + do not indent. +2. If the current line starts with a top term, do not indent. +3. If the current line starts with a closing parenthesis and the + matching opening parenthesis is part of a functor, indent to the + column of the opening parenthesis if any arguments appear on the + same line as the functor, otherwise indent to the start of the + functor. + + This rule yields the following layouts: + + #+begin_src prolog + some_functor( + some_arg + ). + + some_functor( some_arg + ). + #+end_src + +#+VINDEX: sweep-indent-offset +4. If the current line is the first non-comment line of a clause body, + indent to the starting column of the head term plus the value of + the user option =sweep-indent-offset= (by default, four extra + columns). + + As an example, this rule yields the following layouts when + =sweep-indent-offset= is set to the default value of four columns: + + #+begin_src prolog + some_functor(arg1, arg2) :- + body_term. + + asserta( some_functor(arg1, arg2) :- + body_term + ). + #+end_src + +5. If the current line starts with the right hand side operand of an + infix operator, indent to the starting column of the first operand + in the chain of infix operators of the same precedence. + + This rule yields the following layouts: + + #+begin_src prolog + head :- body1, body2, body3, + body4, body5. + + A is 1 * 2 ^ 3 * 4 * + 5. + + A is 1 * 2 + 3 * 4 * + 5. + #+end_src + +6. If the last non-comment line ends with a functor and its opening + parenthesis, indent to the starting column of the functor plus + =sweep-indent-offset=. + + This rule yields the following layout: + + #+begin_src prolog + some_functor( + arg1, ... + #+end_src + +7. If the last non-comment line ends with a prefix operator, indent to + starting column of the operator plus =sweep-indent-offset=. + + This rule yields the following layout: + + #+begin_src prolog + :- multifile + predicate/3. + #+end_src + ** Semantic highlighting :PROPERTIES: :CUSTOM_ID: semantic-highlighting diff --git a/sweep-tests.el b/sweep-tests.el index 347f485..6733838 100644 --- a/sweep-tests.el +++ b/sweep-tests.el @@ -40,6 +40,86 @@ "Tests indentation rules." (sweep-test-indentation " +some_functor( +arg1, +arg2, +)." + " +some_functor( + arg1, + arg2, +)." + ) + (sweep-test-indentation + " +asserta( some_functor(arg1, arg2) :- +body_term +). +" + " +asserta( some_functor(arg1, arg2) :- + body_term + ). +" + ) + (sweep-test-indentation + " +:- module(spam, [ foo, +bar, +baz +] +). +" + " +:- module(spam, [ foo, + bar, + baz + ] + ). +" + ) + (sweep-test-indentation + " +:- module(spam, [ +foo, +bar, +baz +] +). +" + " +:- module(spam, [ + foo, + bar, + baz + ] + ). +" + ) + (sweep-test-indentation + " +[ + ]. +" + " +[ +]. +" + ) + (sweep-test-indentation + " +:- +use_module(foo), +use_module(bar). +" + " +:- + use_module(foo), + use_module(bar). +" + ) + (sweep-test-indentation + " colourise_declaration(Module:PI, _, TB, term_position(_,_,QF,QT,[PM,PG])) :- atom(Module), nonvar(PI), PI = Name/Arity, diff --git a/sweep.el b/sweep.el index 60f825c..a9c9c31 100644 --- a/sweep.el +++ b/sweep.el @@ -6,7 +6,7 @@ ;; Maintainer: Eshel Yaron ;; Keywords: prolog languages extensions ;; URL: https://git.sr.ht/~eshel/sweep -;; Package-Version: 0.3.0 +;; Package-Version: 0.3.1 ;; Package-Requires: ((emacs "28")) ;; This file is NOT part of GNU Emacs. @@ -34,6 +34,12 @@ "SWI-Prolog Embedded in Emacs." :group 'prolog) +(defcustom sweep-indent-offset 4 + "Number of columns to indent lines with in `sweep-mode' buffers." + :package-version '((sweep . "0.3.1")) + :type 'integer + :group 'sweep) + (defcustom sweep-colourise-buffer-on-idle t "If non-nil, update highlighting of `sweep-mode' buffers on idle." :package-version '((sweep . "0.2.0")) @@ -1299,12 +1305,12 @@ Interactively, a prefix arg means to prompt for BUFFER." (defun sweep-indent-line-after-functor (fbeg _fend) (save-excursion (goto-char fbeg) - (+ (current-column) 4))) + (+ (current-column) sweep-indent-offset))) (defun sweep-indent-line-after-open (fbeg _fend) (save-excursion (goto-char fbeg) - (+ (current-column) 4))) + (+ (current-column) sweep-indent-offset))) (defun sweep-indent-line-after-prefix (fbeg _fend _pre) (save-excursion @@ -1322,7 +1328,7 @@ Interactively, a prefix arg means to prompt for BUFFER." (save-excursion (goto-char fbeg) (sweep-backward-term 1200) - (+ (current-column) 4))) + (+ (current-column) sweep-indent-offset))) (defun sweep-indent-line-after-infix (fbeg _fend pre) (save-excursion @@ -1340,36 +1346,49 @@ Interactively, a prefix arg means to prompt for BUFFER." (current-column))) (defun sweep-indent-line () + "Indent the current line in a `sweep-mode' buffer." (interactive) (let ((pos (- (point-max) (point)))) (back-to-indentation) (let ((indent (if (nth 8 (syntax-ppss)) 'noindent - (pcase (sweep-last-token-boundaries) - ('nil 'noindent) - (`(functor ,lbeg ,lend) - (sweep-indent-line-after-functor lbeg lend)) - (`(open ,lbeg ,lend) - (sweep-indent-line-after-open lbeg lend)) - (`(symbol ,lbeg ,lend) - (let ((sym (buffer-substring-no-properties lbeg lend))) - (cond - ((pcase (sweep-op-prefix-precedence sym) - ('nil (sweep-indent-line-after-term)) - (pre (sweep-indent-line-after-prefix lbeg lend pre))))))) - (`(operator ,lbeg ,lend) - (let ((op (buffer-substring-no-properties lbeg lend))) - (cond - ((string= op ".") 'noindent) - ((pcase (sweep-op-infix-precedence op) - ('nil nil) - (1200 (sweep-indent-line-after-neck lbeg lend)) - (pre (sweep-indent-line-after-infix lbeg lend pre)))) - ((pcase (sweep-op-prefix-precedence op) - ('nil nil) - (pre (sweep-indent-line-after-prefix lbeg lend pre))))))) - (`(,_ltyp ,_lbeg ,_lend) - (sweep-indent-line-after-term)))))) + (if-let ((open (and (= (char-syntax (char-after)) ?\)) + (nth 1 (syntax-ppss))))) + (save-excursion + (goto-char open) + (when (or (= (char-syntax (char-before)) ?w) + (= (char-syntax (char-before)) ?_)) + (when (save-excursion + (forward-char) + (skip-syntax-forward " " (line-end-position)) + (eolp)) + (skip-syntax-backward "w_"))) + (current-column)) + (pcase (sweep-last-token-boundaries) + ('nil 'noindent) + (`(functor ,lbeg ,lend) + (sweep-indent-line-after-functor lbeg lend)) + (`(open ,lbeg ,lend) + (sweep-indent-line-after-open lbeg lend)) + (`(symbol ,lbeg ,lend) + (let ((sym (buffer-substring-no-properties lbeg lend))) + (cond + ((pcase (sweep-op-prefix-precedence sym) + ('nil (sweep-indent-line-after-term)) + (pre (sweep-indent-line-after-prefix lbeg lend pre))))))) + (`(operator ,lbeg ,lend) + (let ((op (buffer-substring-no-properties lbeg lend))) + (cond + ((string= op ".") 'noindent) + ((pcase (sweep-op-infix-precedence op) + ('nil nil) + (1200 (sweep-indent-line-after-neck lbeg lend)) + (pre (sweep-indent-line-after-infix lbeg lend pre)))) + ((pcase (sweep-op-prefix-precedence op) + ('nil nil) + (pre (sweep-indent-line-after-prefix lbeg lend pre))))))) + (`(,_ltyp ,_lbeg ,_lend) + (sweep-indent-line-after-term))))))) (when (numberp indent) (unless (= indent (current-column)) (combine-after-change-calls