+\f
+;;; Comment sexp
+(defun sotlisp-uncomment-sexp (&optional n)
+ "Uncomment a sexp around point."
+ (interactive "P")
+ (let* ((initial-point (point-marker))
+ (inhibit-field-text-motion t)
+ (p)
+ (end (save-excursion
+ (when (elt (syntax-ppss) 4)
+ (re-search-backward comment-start-skip
+ (line-beginning-position)
+ t))
+ (setq p (point-marker))
+ (comment-forward (point-max))
+ (point-marker)))
+ (beg (save-excursion
+ (forward-line 0)
+ (while (and (not (bobp))
+ (= end (save-excursion
+ (comment-forward (point-max))
+ (point))))
+ (forward-line -1))
+ (goto-char (line-end-position))
+ (re-search-backward comment-start-skip
+ (line-beginning-position)
+ t)
+ (ignore-errors
+ (while (looking-at comment-start-skip)
+ (forward-char -1))
+ (unless (looking-at "[\n\r[:blank]]")
+ (forward-char 1)))
+ (point-marker))))
+ (unless (= beg end)
+ (uncomment-region beg end)
+ (goto-char p)
+ ;; Indentify the "top-level" sexp inside the comment.
+ (ignore-errors
+ (while (>= (point) beg)
+ (backward-prefix-chars)
+ (skip-chars-backward "\r\n[:blank:]")
+ (setq p (point-marker))
+ (backward-up-list)))
+ ;; Re-comment everything before it.
+ (ignore-errors
+ (comment-region beg p))
+ ;; And everything after it.
+ (goto-char p)
+ (forward-sexp (or n 1))
+ (skip-chars-forward "\r\n[:blank:]")
+ (if (< (point) end)
+ (ignore-errors
+ (comment-region (point) end))
+ ;; If this is a closing delimiter, pull it up.
+ (goto-char end)
+ (skip-chars-forward "\r\n[:blank:]")
+ (when (eq 5 (car (syntax-after (point))))
+ (delete-indentation))))
+ ;; Without a prefix, it's more useful to leave point where
+ ;; it was.
+ (unless n
+ (goto-char initial-point))))
+
+(defun sotlisp--comment-sexp-raw ()
+ "Comment the sexp at point or ahead of point."
+ (pcase (or (bounds-of-thing-at-point 'sexp)
+ (save-excursion
+ (skip-chars-forward "\r\n[:blank:]")
+ (bounds-of-thing-at-point 'sexp)))
+ (`(,l . ,r)
+ (goto-char r)
+ (skip-chars-forward "\r\n[:blank:]")
+ (save-excursion
+ (comment-region l r))
+ (skip-chars-forward "\r\n[:blank:]"))))
+
+(defun sotlisp-comment-or-uncomment-sexp (&optional n)
+ "Comment the sexp at point and move past it.
+If already inside (or before) a comment, uncomment instead.
+With a prefix argument N, (un)comment that many sexps."
+ (interactive "P")
+ (if (or (elt (syntax-ppss) 4)
+ (< (save-excursion
+ (skip-chars-forward "\r\n[:blank:]")
+ (point))
+ (save-excursion
+ (comment-forward 1)
+ (point))))
+ (sotlisp-uncomment-sexp n)
+ (dotimes (_ (or n 1))
+ (sotlisp--comment-sexp-raw))))
+