From 27d394ea8938bafd05323b8c34414293f9bf6c0c Mon Sep 17 00:00:00 2001 From: Eshel Yaron Date: Mon, 14 Nov 2022 18:19:31 +0200 Subject: [PATCH] ADDED: minor mode for automatic whitespace insertion * sweep.pl (sweep_context_callable/2): only consider the context to be callable if a neck is present up the tree, i.e. not in the head. * sweeprolog.el (sweeprolog-context-callable-p): new function, extracted from (sweeprolog-predicate-completion-at-point) (sweeprolog-electric-layout-post-self-insert-function): new function. (sweeprolog-electric-layout-mode): new minor mode. --- sweep.pl | 26 ++++++++++++++++++------ sweeprolog-tests.el | 4 ++-- sweeprolog.el | 48 ++++++++++++++++++++++++++++++++++++++------- 3 files changed, 63 insertions(+), 15 deletions(-) diff --git a/sweep.pl b/sweep.pl index fbbddf8..13933d8 100644 --- a/sweep.pl +++ b/sweep.pl @@ -758,22 +758,36 @@ sweep_format_predicate(H, S) :- spacing(next_argument), numbervars(true)]). -sweep_context_callable([], true) :- !. -sweep_context_callable([[":"|2]], true) :- !. sweep_context_callable([H|T], R) :- + H = [F0|_], + atom_string(F, F0), + ( xref_op(_, op(1200, _, F)) + -> true + ; current_op(1200, _, F) + ), + !, + sweep_context_callable_(T, R). +sweep_context_callable([_|T], R) :- + sweep_context_callable(T, R). + +sweep_context_callable_([], true) :- !. +sweep_context_callable_([[":"|2]], true) :- !. +sweep_context_callable_([["("|_]|T], R) :- + sweep_context_callable_(T, R). +sweep_context_callable_([H|T], R) :- H = [F0|N], atom_string(F, F0), - ( sweep_context_callable_(F, N) - -> sweep_context_callable(T, R) + ( sweep_context_callable_arg(F, N) + -> sweep_context_callable_(T, R) ; R = [] ). -sweep_context_callable_(Neck, _) :- +sweep_context_callable_arg(Neck, _) :- ( xref_op(_, op(1200, _, Neck)) -> true ; current_op(1200, _, Neck) ). -sweep_context_callable_(F, N) :- +sweep_context_callable_arg(F, N) :- ( current_predicate(F/M), pi_head(F/M,Head) ; xref_defined(_, Head, _), pi_head(F/M,Head) ), diff --git a/sweeprolog-tests.el b/sweeprolog-tests.el index f5b295e..518c796 100644 --- a/sweeprolog-tests.el +++ b/sweeprolog-tests.el @@ -111,7 +111,7 @@ foo(Foo) :- bar. nil ".pl" " -baz(Baz) :- Baz = emacsc +baz(Baz) :- Baz = opa " ))) (find-file-literally temp) @@ -121,7 +121,7 @@ baz(Baz) :- Baz = emacsc (call-interactively #'completion-at-point) (should (string= (buffer-string) " -baz(Baz) :- Baz = emacsclient +baz(Baz) :- Baz = opaque " )))) diff --git a/sweeprolog.el b/sweeprolog.el index 09c680c..2d8a691 100644 --- a/sweeprolog.el +++ b/sweeprolog.el @@ -1015,7 +1015,9 @@ resulting list even when found in the current clause." (ppre (sweeprolog-op-prefix-precedence op))) (cond ((and (string= "." op) - (member (char-syntax (char-after (1+ obeg))) '(?> ? ))) + (or (not (char-after (1+ obeg))) + (member (char-syntax (char-after (1+ obeg))) + '(?> ? )))) nil) ((string= "," op) (setq pos @@ -1038,6 +1040,10 @@ resulting list even when found in the current clause." (setq commas 0))))))) context))) +(defun sweeprolog-context-callable-p () + (sweeprolog--query-once "sweep" "sweep_context_callable" + (sweeprolog--parse-context))) + (defun sweeprolog-predicate-completion-at-point () "Prolog predicate completion backend for `completion-at-point'." (when-let ((bounds (bounds-of-thing-at-point 'symbol)) @@ -1047,9 +1053,7 @@ resulting list even when found in the current clause." (let ((first (char-after beg))) (not (or (sweeprolog--char-uppercase-p first) (= first ?_)))) - (sweeprolog--query-once "sweep" - "sweep_context_callable" - (sweeprolog--parse-context))) + (sweeprolog-context-callable-p)) (when-let ((col (sweeprolog--query-once "sweep" "sweep_predicate_completion_candidates" nil))) @@ -1833,8 +1837,8 @@ resulting list even when found in the current clause." (setq cur (point))) (skip-chars-forward " \t\n") (push (list cur (point) nil) ws) - (cons (list beg end nil) - (cons (list beg end (sweeprolog-fullstop-face)) + (cons (list beg (point) nil) + (cons (list beg end (sweeprolog-fullstop-face)) ws))))) ("functor" (list (list beg end (sweeprolog-functor-face)))) @@ -2884,7 +2888,9 @@ predicate definition at or directly above POINT." oend))) (`(operator ,obeg ,oend) (if (and (string= "." (buffer-substring-no-properties obeg oend)) - (member (char-syntax (char-after (1+ obeg))) '(?> ? ))) + (or (not (char-after (1+ obeg))) + (member (char-syntax (char-after (1+ obeg))) + '(?> ? )))) (signal 'scan-error (list "Cannot scan backwards beyond fullstop." obeg @@ -3122,6 +3128,34 @@ if-then-else constructs in SWI-Prolog." (delete-horizontal-space) (insert (make-string num ? )))))))))) +(defun sweeprolog-electric-layout-post-self-insert-function () + (if (nth 8 (syntax-ppss)) + (when (member (buffer-substring-no-properties (line-beginning-position) + (point)) + '("%%" "%!")) + (insert " ")) + (when (member (char-before) (string-to-list "(;>")) + (pcase (sweeprolog-last-token-boundaries) + ((or `(open ,beg ,end) + `(operator ,beg ,end)) + (when (and (member (buffer-substring-no-properties beg end) + '("(" ";" "->" "*->")) + (sweeprolog-context-callable-p)) + (insert (make-string (+ 4 beg (- end)) ? )))))))) + +;;;###autoload +(define-minor-mode sweeprolog-electric-layout-mode + "Automatically insert whitespace in `sweeprolog-mode' buffers." + :group 'sweeprolog + (if sweeprolog-electric-layout-mode + (progn + (add-hook 'post-self-insert-hook + #'sweeprolog-electric-layout-post-self-insert-function + nil t)) + (remove-hook 'post-self-insert-hook + #'sweeprolog-electric-layout-post-self-insert-function + t))) + (defun sweeprolog--update-buffer-last-modified-time (&rest _) (setq sweeprolog--buffer-last-modified-time (float-time) sweeprolog--buffer-modified t)) -- 2.39.2