goal2.
#+end_src
+** Holes
+:PROPERTIES:
+:CUSTOM_ID: holes
+:DESCRIPTION: Commands for finding and filling holes for interactive term insertion
+:ALT_TITLE: Holes
+:END:
+
+#+CINDEX: holes
+When writing Prolog code in the usual way of typing in one character
+at a time, the buffer text is often found in a syntactically incorrect
+state while you edit it. This happens for example right after you
+insert an infix operator, before typing its expected right-hand side
+argument. ~sweep~ provides an alternative method for inserting Prolog
+terms in a way that maintains the syntactic correctness of the buffer
+text while allowing the user to incrementally refine it by using
+placeholder terms, called simply "holes". Holes indicate the location
+of missing terms that the user can later fill in, essentially they
+represent source-level unknown terms and their presence satisfies the
+Prolog parser. Holes are written in the buffer as regular Prolog
+variables, but they are annotated with a special text property[fn:2]
+that allows ~sweep~ to recognize them as holes needed to be filled.
+
+#+FINDEX: sweeprolog-insert-term-with-holes
+#+KINDEX: C-c C-m
+#+KINDEX: C-c RET
+The main command for inserting terms with holes is ~M-x
+sweeprolog-insert-term-with-holes~. This command, bound by default to
+~C-c C-m~ (or ~C-c RET~) in ~sweeprolog-mode~ buffers, prompts for a functor
+and an arity and inserts a corresponding term with holes in place of
+the term's arguments. It leaves point right after the first hole,
+sets the mark to its start and activates region such that the hole is
+marked. Call ~sweeprolog-insert-term-with-holes~ again to replace the
+active region which now covers the first hole with another term, that
+may again contain further holes. That way you can incrementally write
+down a Prolog term, including whole clauses, by working down the
+syntactic structure of the term and maintaining its all the while.
+Without a prefix argument, ~sweeprolog-insert-term-with-holes~ prompts
+for the functor and the arity to use. A non-negative prefix argument,
+e.g. ~C-2 C-c C-m~ or ~C-u C-c C-m~, is taken as to be the inserted term's
+arity and in this case ~sweeprolog-insert-term-with-holes~ only prompts
+for the functor to insert. A negative prefix argument, ~C-- C-c C-m~,
+inserts only a single hole without prompting for a functor. To
+further help with keeping the buffer syntactically correct, this
+command adds a comma (~,~) before or after the inserted term when needed
+according to the surrounding tokens. If you call it at the end of a
+term that doesn't have a closing fullstop, it adds the fullstop after
+the inserted term.
+
+Several other ~sweep~ commands insert holes in place of unknown terms,
+including ~C-M-i~ (see [[#code-completion][Code Completion]]), ~C-M-m~ (see [[#insert-term-at-point][Context-Based Term
+Insertion]]) and ~M-x sweeprolog-plunit-testset-skeleton~ (see [[#writing-tests][Writing
+Tests]]).
+
+#+VINDEX: sweeprolog-highlight-holes
+When the user option ~sweeprolog-highlight-holes~ is set to non-nil,
+holes in Prolog buffers are highlighted with a dedicated face, making
+them easily distinguishable from regular Prolog variables. Hole
+highlighting is enabled by default, to disable it customize
+~sweeprolog-highlight-holes~ to nil.
+
+#+FINDEX: sweeprolog-backward-hole
+#+FINDEX: sweeprolog-forward-hole
+#+KINDEX: C-c C-i
+#+KINDEX: C-c TAB
+#+KINDEX: C-- C-c C-i
+#+KINDEX: C-- C-c TAB
+To jump to the next hole in a ~sweeprolog-mode~ buffer, use the command
+~M-x sweeprolog-forward-hole~, bound by default to ~C-c TAB~ (or ~C-c C-i~).
+This command sets up the region to cover the next hole after point
+leaving the cursor at right after the hole. To jump to the previous
+hole instead, use ~sweeprolog-backward-hole~ or call
+~sweeprolog-forward-hole~ with a negative prefix argument (~C-- C-c TAB~).
+
+#+FINDEX: sweeprolog-forward-hole-on-tab-mode
+#+KINDEX: TAB (sweeprolog-forward-hole-on-tab-mode)
+#+KINDEX: C-i (sweeprolog-forward-hole-on-tab-mode)
+When the minor mode ~sweeprolog-forward-hole-on-tab-mode~ is enabled,
+the ~TAB~ key is bound to a command moves to the next hole when called
+in a properly indented line (otherwise it indents the line). This
+makes moving between holes in the buffer easier since ~TAB~ can be used
+instead of ~C-c TAB~ in most cases. To enable this mode in a Prolog
+buffer, type ~M-x sweeprolog-forward-hole-on-tab-mode-map~. This step
+can be automated by adding ~sweeprolog-forward-hole-on-tab-mode~ to
+~sweeprolog-mode-hook~:
+
+#+begin_src emacs-lisp
+ (add-hook 'sweeprolog-mode-hook #'sweeprolog-forward-hole-on-tab-mode)
+#+end_src
+
+To "fill" a hole marked by one of the aforementioned commands, either
+use ~C-c C-m~ as described above or type ~C-w~ (~M-x kill-region~) to kill
+the region and remove the placeholder variable, and then insert Prolog
+code as usual. As an alternative to manually killing the region with
+~C-w~, with ~delete-selection-mode~ enabled the placeholder is
+automatically deleted when you insert a character while the region is
+active (see also [[info:emacs#Using Region][Using Region in the Emacs manual]]).
+
+[fn:2] see [[info:elisp#Text Properties][Text Properties in the Elisp manual]]
+
** Definitions and references
:PROPERTIES:
:CUSTOM_ID: sweeprolog-xref
~completion-at-point~ suggests matching predicates as completion
candidates. Predicate calls are inserted as complete term. If the
chosen predicate takes arguments, holes are inserted in their places
- (see [[#filling-holes][Filling Holes]]).
+ (see [[#holes][Holes]]).
- Atom completion :: If point is at a non-callable,
~completion-at-point~ suggests matching atoms as completion
candidates.
~sweeprolog-new-predicate-location-function~ can be customized to
control where this function inserts new predicate definitions.
-*** Filling Holes
-:PROPERTIES:
-:CUSTOM_ID: filling-holes
-:DESCRIPTION: Commands for finding and filling holes for interactive term insertion
-:ALT_TITLE: Filling Holes
-:END:
-
-#+CINDEX: holes
-The default term insertion functions used by
-~sweeprolog-insert-term-dwim~ create a new clause in the buffer, with
-placeholders for the arguments of the head term (if any) and for the
-clause's body. These placeholders, called simply "holes", represent
-the Prolog terms that remain to be given by the user. Holes are
-written in the buffer as regular Prolog variables, but they are
-annotated with a special text property[fn:2] that allows
-~sweeprolog-mode~ to recognize them as holes needed to be filled. After
-a term is inserted with ~sweeprolog-insert-term-dwim~, the region is set
-to the first hole and the cursor left at the its end.
-
-#+VINDEX: sweeprolog-highlight-holes
-When the user option ~sweeprolog-highlight-holes~ is set to non-nil,
-holes in Prolog buffers are highlighted with a dedicated face, making
-them easily distinguishable from regular Prolog variables. Hole
-highlighting is enabled by default, to disable it customize
-~sweeprolog-highlight-holes~ to nil.
-
-#+FINDEX: sweeprolog-backward-hole
-#+FINDEX: sweeprolog-forward-hole
-#+KINDEX: C-c C-i
-#+KINDEX: C-c TAB
-#+KINDEX: C-- C-c C-i
-#+KINDEX: C-- C-c TAB
-To jump to the next hole in a ~sweeprolog-mode~ buffer, use the command
-~M-x sweeprolog-forward-hole~, bound by default to ~C-c TAB~ (or ~C-c C-i~).
-This command sets up the region to cover the next hole after point
-leaving the cursor at right after the hole. To jump to the previous
-hole instead, use ~sweeprolog-backward-hole~ or call
-~sweeprolog-forward-hole~ with a negative prefix argument (~C-- C-c TAB~).
-
-#+FINDEX: sweeprolog-forward-hole-on-tab-mode
-#+KINDEX: TAB (sweeprolog-forward-hole-on-tab-mode)
-#+KINDEX: C-i (sweeprolog-forward-hole-on-tab-mode)
-When the minor mode ~sweeprolog-forward-hole-on-tab-mode~ is enabled,
-the ~TAB~ key is bound to a command moves to the next hole when called
-in a properly indented line (otherwise it indents the line). This
-makes moving between holes in the buffer easier since ~TAB~ can be used
-instead of ~C-c TAB~ in most cases. To enable this mode in a Prolog
-buffer, type ~M-x sweeprolog-forward-hole-on-tab-mode-map~. This step
-can be automated by adding ~sweeprolog-forward-hole-on-tab-mode~ to
-~sweeprolog-mode-hook~:
-
-#+begin_src emacs-lisp
- (add-hook 'sweeprolog-mode-hook #'sweeprolog-forward-hole-on-tab-mode)
-#+end_src
-
-To "fill" a hole marked by one of the aforementioned commands, type
-~C-w~ (~M-x kill-region~) to kill the region and remove the placeholder
-variable, then insert Prolog code as usual. As an alternative to
-manually killing the region with ~C-w~, with ~delete-selection-mode~
-enabled the placeholder is automatically deleted when the user inserts
-a character while the region is active (see also [[info:emacs#Using Region][Using Region in the
-Emacs manual]]).
-
-[fn:2] see [[info:elisp#Text Properties][Text Properties in the Elisp manual]]
+This command inserts holes as placeholders for the body term and the
+head's arguments, if any. See also [[#holes][Holes]].
** Writing Tests
:PROPERTIES:
#+end_src
The cursor is left between the parentheses of the ~test()~ head term,
-and the ~TestBody~ variable is marked as a hole (see [[#filling-holes][Filling Holes]]). To
-insert another unit test, place point after a complete test case and
-type ~C-M-m~ or ~M-RET~ to invoke ~sweeprolog-insert-term-dwim~ (see
+and the ~TestBody~ variable is marked as a hole (see [[#holes][Holes]]). To insert
+another unit test, place point after a complete test case and type
+~C-M-m~ or ~M-RET~ to invoke ~sweeprolog-insert-term-dwim~ (see
[[#insert-term-at-point][Context-Based Term Insertion]]).
[fn:3] See [[https://www.swi-prolog.org/pldoc/doc_for?object=section(%27packages/plunit.html%27)][Prolog Unit Tests in the SWI-Prolog manual]].
sweep_string_to_atom/2,
sweep_file_path_in_library/2,
sweep_file_missing_dependencies/2,
- sweep_format_head/2
+ sweep_format_head/2,
+ sweep_format_term/2,
+ sweep_current_functors/2
]).
:- use_module(library(pldoc)).
pi_head(F/A, H),
sweep_current_module(M),
sweep_format_predicate(M, 0, H, R).
+
+sweep_format_term([F0,N,P], [S|SP]) :-
+ atom_string(F, F0),
+ pi_head(F/N, H),
+ length(NamedArgs, N),
+ maplist(=('$VAR'('_')), NamedArgs),
+ H =.. [F|NamedArgs],
+ term_string(H, S, [quoted(true),
+ character_escapes(true),
+ spacing(next_argument),
+ numbervars(true),
+ priority(P)]),
+ term_string(_, S, [subterm_positions(SP)]).
+
+sweep_current_functors(A0, Col) :-
+ ( A0 == []
+ -> true
+ ; A = A0
+ ),
+ findall([F|A],
+ ( current_functor(F0, A),
+ atom(F0),
+ atom_string(F0, F)
+ ),
+ Col).
'(sweeprolog-undefined-default-face
sweeprolog-body-default-face)))))
+(ert-deftest insert-term-with-holes ()
+ "Test `sweeprolog-insert-term-with-holes'."
+ (let ((temp (make-temp-file "sweeprolog-test"
+ nil
+ "pl"
+ "")))
+ (find-file-literally temp)
+ (sweeprolog-mode)
+ (sweeprolog-insert-term-with-holes ":-" 2)
+ (call-interactively #'kill-region)
+ (sweeprolog-insert-term-with-holes "foo" 3)
+ (call-interactively #'kill-region)
+ (sweeprolog-insert-term-with-holes "bar" 0)
+ (call-interactively #'kill-region)
+ (sweeprolog-insert-term-with-holes ";" 2)
+ (call-interactively #'kill-region)
+ (sweeprolog-insert-term-with-holes "->" 2)
+ (should (string= (buffer-string)
+ "foo(bar, (_->_;_), _):-_."))))
+
(ert-deftest plunit-testset-skeleton ()
"Tests inserting PlUnit test-set blocks."
(let ((temp (make-temp-file "sweeprolog-test"
(defvar sweeprolog-read-module-history nil)
+(defvar sweeprolog-read-functor-history nil)
+
(defvar sweeprolog-top-level-signal-goal-history nil)
(defvar sweeprolog--extra-init-args nil)
(defvar sweeprolog-mode-map
(let ((map (make-sparse-keymap)))
- (define-key map (kbd "C-c C-l") #'sweeprolog-load-buffer)
(define-key map (kbd "C-c C-c") #'sweeprolog-analyze-buffer)
- (define-key map (kbd "C-c C-t") #'sweeprolog-top-level)
- (define-key map (kbd "C-c C-o") #'sweeprolog-find-file-at-point)
(define-key map (kbd "C-c C-d") #'sweeprolog-document-predicate-at-point)
(define-key map (kbd "C-c C-e") #'sweeprolog-export-predicate)
(define-key map (kbd "C-c C-i") #'sweeprolog-forward-hole)
+ (define-key map (kbd "C-c C-l") #'sweeprolog-load-buffer)
+ (define-key map (kbd "C-c C-m") #'sweeprolog-insert-term-with-holes)
+ (define-key map (kbd "C-c C-o") #'sweeprolog-find-file-at-point)
+ (define-key map (kbd "C-c C-t") #'sweeprolog-top-level)
(define-key map (kbd "C-c C-u") #'sweeprolog-update-dependencies)
(define-key map (kbd "C-c C-`")
(if (fboundp 'flymake-show-buffer-diagnostics) ;; Flymake 1.2.1+
map)
"Keymap for `sweeprolog-mode'.")
-(defvar sweeprolog-forward-hole-repeat-mode
+(defvar sweeprolog-forward-hole-repeat-map
(let ((map (make-sparse-keymap)))
(define-key map (kbd "C-i") #'sweeprolog-forward-hole)
- (define-key map (kbd "p") #'sweeprolog-backward-hole)
- (define-key map (kbd "n") #'sweeprolog-forward-hole)
+ (define-key map (kbd "C-n") #'sweeprolog-forward-hole)
+ (define-key map (kbd "C-p") #'sweeprolog-backward-hole)
+ (define-key map (kbd "C-m") #'sweeprolog-insert-term-with-holes)
map)
"Repeat map for \\[sweeprolog-forward-hole].")
"Return a list of predicates whose name resembeles PATTERN."
(sweeprolog--query-once "sweep" "sweep_predicate_apropos" pattern))
+(defun sweeprolog-read-functor (&optional arity)
+ "Read a Prolog functor/arity pair from the minibuffer.
+
+If ARITY is nil, prompt for the arity after reading the functor.
+Otherwise, read only the functor, with completion candidates are
+restricted to functors with arity ARITY, and return ARITY as the
+arity.
+
+Return a cons cell of the functor as a string and the arity."
+ (let* ((col (sweeprolog--query-once "sweep" "sweep_current_functors"
+ arity))
+ (completion-extra-properties
+ (list :annotation-function
+ (lambda (key)
+ (when-let ((val (cdr (assoc-string key col))))
+ (concat "/" (number-to-string val)))))))
+ (let ((functor (completing-read "Functor: "
+ col nil nil nil
+ 'sweeprolog-read-functor-history)))
+ (cons functor
+ (or arity (read-number (concat functor "/")))))))
+
(defun sweeprolog-read-predicate (&optional prompt)
"Read a Prolog predicate from the minibuffer with prompt PROMPT.
If PROMPT is nil, `sweeprolog-read-predicate-prompt' is used by
(narrow-to-region beg end)
(let ((hole (sweeprolog--next-hole)))
(while hole
- (font-lock--add-text-property (car hole) (cdr hole)
- 'font-lock-face
- (sweeprolog-hole-face)
- (current-buffer)
- nil)
- (setq hole (sweeprolog--next-hole)))))))))
+ (let ((hbeg (car hole))
+ (hend (cdr hole)))
+ (font-lock--add-text-property hbeg hend
+ 'font-lock-face
+ (sweeprolog-hole-face)
+ (current-buffer)
+ nil)
+ (goto-char hend)
+ (setq hole (sweeprolog--next-hole))))))))))
(defun sweeprolog-analyze-start-flymake (&rest _)
(flymake-start))
(or (re-search-forward (rx "." (or white "\n")) nil t)
(goto-char (point-max))))))
+(defun sweeprolog-at-hole-p (&optional point)
+ (setq point (or point (point)))
+ (get-text-property point 'sweeprolog-hole))
+
+(defun sweeprolog-beginning-of-hole (&optional point)
+ (let ((beg (or point (point))))
+ (when (sweeprolog-at-hole-p beg)
+ (while (and (< (point-min) beg)
+ (sweeprolog-at-hole-p (1- beg)))
+ (setq beg (1- beg)))
+ beg)))
+
+(defun sweeprolog-end-of-hole (&optional point)
+ (let ((end (or point (point))))
+ (when (sweeprolog-at-hole-p end)
+ (while (and (< end (point-max))
+ (sweeprolog-at-hole-p (1+ end)))
+ (setq end (1+ end)))
+ (1+ end))))
+
(defun sweeprolog--next-hole (&optional wrap)
"Return the bounds of the next hole in the current buffer.
When WRAP in non-nil, wrap around if no holes are found between
point and the end of the buffer."
- (let ((current-hole-beg
- (save-excursion
- (while (and (get-text-property (point) 'sweeprolog-hole)
- (not (bobp)))
- (forward-char -1))
- (point))))
- (while (and (get-text-property (point) 'sweeprolog-hole)
- (not (eobp)))
- (forward-char))
- (while (not (or (get-text-property (point) 'sweeprolog-hole)
- (eobp)))
- (forward-char))
- (if (eobp)
- (when wrap
- (save-restriction
- (goto-char (point-min))
- (narrow-to-region (point) current-hole-beg)
- (sweeprolog--next-hole)))
- (let ((beg (point)))
- (while (and (get-text-property (point) 'sweeprolog-hole)
- (not (eobp)))
- (forward-char))
- (cons beg (point))))))
+ (if-let ((current-hole-beg (sweeprolog-beginning-of-hole)))
+ (cons current-hole-beg
+ (sweeprolog-end-of-hole))
+ (let ((point (point)))
+ (while (not (or (sweeprolog-at-hole-p) (eobp)))
+ (forward-char))
+ (if (eobp)
+ (when wrap
+ (save-restriction
+ (goto-char (point-min))
+ (narrow-to-region (point) point)
+ (sweeprolog--next-hole)))
+ (cons (point)
+ (sweeprolog-end-of-hole))))))
+
+(defun sweeprolog--backward-wrap (&optional wrap)
+ (if (bobp)
+ (when wrap
+ (goto-char (point-max))
+ t)
+ (forward-char -1)
+ t))
(defun sweeprolog--previous-hole (&optional wrap)
"Return the bounds of the previous hole in the current buffer.
When WRAP in non-nil, wrap around if no holes are found between
point and the beginning of the buffer."
- (let ((current-hole-end
- (save-excursion
- (while (and (get-text-property (point) 'sweeprolog-hole)
- (not (eobp)))
- (forward-char))
- (point))))
- (forward-char -1)
- (while (and (get-text-property (point) 'sweeprolog-hole)
- (not (bobp)))
- (forward-char -1))
- (while (not (or (get-text-property (point) 'sweeprolog-hole)
- (bobp)))
- (forward-char -1))
- (if (bobp)
- (when wrap
- (save-restriction
- (goto-char (point-max))
- (narrow-to-region current-hole-end (point))
- (sweeprolog--previous-hole)))
- (let ((end (point)))
- (while (and (get-text-property (point) 'sweeprolog-hole)
- (not (bobp)))
- (forward-char -1))
- (cons (1+ (point)) (1+ end))))))
+ (let ((start (point)))
+ (when (use-region-p)
+ (goto-char (region-beginning))
+ (deactivate-mark))
+ (when (sweeprolog--backward-wrap wrap)
+ (if-let ((current-hole-beg (sweeprolog-beginning-of-hole)))
+ (cons current-hole-beg
+ (sweeprolog-end-of-hole))
+ (let ((point (point)))
+ (while (not (or (sweeprolog-at-hole-p) (bobp)))
+ (forward-char -1))
+ (if (bobp)
+ (or (and wrap
+ (save-restriction
+ (goto-char (point-max))
+ (narrow-to-region point (point))
+ (sweeprolog--previous-hole)))
+ (and (goto-char start) nil))
+ (cons (sweeprolog-beginning-of-hole)
+ (sweeprolog-end-of-hole))))))))
(defun sweeprolog--forward-hole (&optional wrap)
(if-let ((hole (sweeprolog--next-hole wrap))
(put 'sweeprolog-backward-hole
'repeat-map
- 'sweeprolog-forward-hole-repeat-mode)
+ 'sweeprolog-forward-hole-repeat-map)
(put 'sweeprolog-forward-hole
'repeat-map
- 'sweeprolog-forward-hole-repeat-mode)
+ 'sweeprolog-forward-hole-repeat-map)
+
+(put 'sweeprolog-insert-term-with-holes
+ 'repeat-map
+ 'sweeprolog-forward-hole-repeat-map)
(defun sweeprolog--hole (&optional string)
(propertize (or string "_")
cursor-sensor-functions
font-lock-face)))
+(defun sweeprolog--precedence-at-point (&optional point)
+ (setq point (or point (point)))
+ (pcase (sweeprolog-last-token-boundaries point)
+ ((or `(operator ,obeg ,oend)
+ `(symbol ,obeg ,oend))
+ (let ((op (buffer-substring-no-properties obeg oend)))
+ (or (and (string= "." op)
+ (or (not (char-after (1+ obeg)))
+ (member (char-syntax (char-after (1+ obeg)))
+ '(?> ? )))
+ 1200)
+ (sweeprolog-op-infix-precedence op)
+ (sweeprolog-op-prefix-precedence op)
+ 1200)))
+ (_ 1200)))
+
+(defun sweeprolog-insert-term-with-holes (functor arity)
+ "Insert a term with functor FUNCTOR and arity ARITY.
+
+If ARITY is negative, just insert a single hole at point.
+Otherwise, insert FUNCTOR along with ARITY holes, one for each of
+the term's arguments.
+
+Interactively, prompt for FUNCTOR. Without a prefix argument,
+prompt for ARITY as well. Otherwise, ARITY is the numeric value
+of the prefix argument."
+ (interactive
+ (let* ((arity (and current-prefix-arg
+ (prefix-numeric-value current-prefix-arg))))
+ (if (and (numberp arity)
+ (< arity 0))
+ (list "_" arity)
+ (let ((functor-arity (sweeprolog-read-functor arity)))
+ (list (car functor-arity) (cdr functor-arity))))))
+ (combine-after-change-calls
+ (when (use-region-p)
+ (delete-region (region-beginning)
+ (region-end)))
+ (let* ((beg (point)))
+ (when
+ (pcase (sweeprolog-last-token-boundaries beg)
+ (`(symbol ,obeg ,oend)
+ (let ((op (buffer-substring-no-properties obeg oend)))
+ (not (or (sweeprolog-op-infix-precedence op)
+ (sweeprolog-op-prefix-precedence op)))))
+ (`(close . ,_) t))
+ (insert ", "))
+ (if (<= 0 arity)
+ (let ((term-format
+ (sweeprolog--query-once
+ "sweep" "sweep_format_term"
+ (list functor arity
+ (sweeprolog--precedence-at-point beg)))))
+ (insert (car term-format))
+ (pcase (cdr term-format)
+ ((or `(compound
+ "term_position"
+ 0 ,length
+ ,_ ,_
+ ,holes)
+ `(compound
+ "parentheses_term_position"
+ 0 ,length
+ (compound
+ "term_position"
+ ,_ ,_ ,_ ,_
+ ,holes)))
+ (with-silent-modifications
+ (dolist (hole holes)
+ (pcase hole
+ (`(compound "-" ,hbeg ,hend)
+ (add-text-properties
+ (- (point) length (- hbeg))
+ (- (point) length (- hend))
+ (list
+ 'sweeprolog-hole t
+ 'font-lock-face (list (sweeprolog-hole-face))
+ 'rear-nonsticky '(sweeprolog-hole
+ cursor-sensor-functions
+ font-lock-face))))))))))
+ (insert (sweeprolog--hole functor)))
+ (pcase (sweeprolog-next-token-boundaries)
+ ('nil (insert "."))
+ (`(,kind ,obeg ,oend)
+ (if (save-excursion
+ (goto-char obeg)
+ (sweeprolog-at-beginning-of-top-term-p))
+ (insert ".")
+ (when (or (and (member kind '(symbol operator))
+ (let ((op (buffer-substring-no-properties obeg oend)))
+ (not (or (sweeprolog-op-infix-precedence op)
+ (sweeprolog-op-suffix-precedence op)))))
+ (member kind '(open functor)))
+ (insert ", ")))))
+ (unless (= 0 arity)
+ (goto-char beg))
+ (sweeprolog-forward-hole))))
+
(defun sweeprolog-insert-clause (functor arity &optional neck module)
(let ((point (point))
(neck (or neck ":-"))