| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
 100
 101
 102
 103
 104
 105
 106
 107
 108
 109
 110
 111
 112
 113
 114
 115
 116
 117
 118
 119
 120
 121
 122
 123
 124
 125
 126
 127
 128
 129
 130
 131
 132
 133
 134
 135
 136
 137
 138
 139
 140
 141
 142
 143
 144
 145
 
 | ;;; racket-parens.el -*- lexical-binding: t; -*-
;; Copyright (c) 2013-2024 by Greg Hendershott.
;; Portions Copyright (C) 1985-1986, 1999-2013 Free Software Foundation, Inc.
;; Author: Greg Hendershott
;; URL: https://github.com/greghendershott/racket-mode
;; SPDX-License-Identifier: GPL-3.0-or-later
;; Things related to parens, paredit, electric-pair-mode
(require 'racket-custom)
(require 'racket-ppss)
(require 'racket-util)
;;; racket--self-insert
(defun racket--self-insert (event)
  "Simulate a `self-insert-command' of EVENT.
Using this intead of `insert' allows self-insert hooks to run,
which is important for things like `electric-pair-mode'.
A command using this should probably set its delete-selection
property to t so that `delete-selection-mode' works:
  (put \\='racket-command \\='delete-selection t)
If necessary the value of the property can be a function, for
example `racket--electric-pair-mode-not-active'."
  (let ((last-command-event event))     ;set this for hooks
    (self-insert-command (prefix-numeric-value nil))))
(defun racket--electric-pair-mode-not-active ()
  "A suitable value for the delete-selection property of commands
that insert parens: Inserted text should replace the selection
unless a mode like `electric-pair-mode' is enabled, in which case
the selection is to be wrapped in parens."
  (not (and (boundp 'electric-pair-mode)
            electric-pair-mode)))
;;; Automatically insert matching \?) \?] or \?}
(defconst racket--matching-parens
  '(( ?\( . ?\) )
    ( ?\[ . ?\] )
    ( ?\{ . ?\} )))
(defun racket-insert-closing (&optional prefix)
  "Insert a matching closing delimiter.
With \\[universal-argument] insert the typed character as-is.
This is handy if you're not yet using something like
`paredit-mode', `smartparens-mode', `parinfer-mode', or simply
`electric-pair-mode' added in Emacs 24.5."
  (interactive "P")
  (let* ((do-it (not (or prefix
                         (and (string= "#\\"
                                       (buffer-substring-no-properties
                                        (- (point) 2) (point) )))
                         (racket--ppss-string-p (syntax-ppss)))))
         (open-char  (and do-it        (racket--open-paren #'backward-up-list)))
         (close-pair (and open-char    (assq open-char racket--matching-parens)))
         (close-char (and close-pair   (cdr close-pair))))
    (racket--self-insert (or close-char last-command-event))))
(put 'racket-insert-closing 'delete-selection
     #'racket--electric-pair-mode-not-active)
(defun racket--open-paren (back-func)
  "Use BACK-FUNC to find an opening ( [ or { if any.
BACK-FUNC should be something like #\\='backward-sexp or #\\='backward-up-list."
  (save-excursion
    (ignore-errors
      (funcall back-func)
      (let ((ch (char-after)))
        (and (eq ?\( (char-syntax ch))
             ch)))))
;;; paredit spaces in reader literals and at-expressions
(defun racket--paredit-space-for-delimiter-predicate (endp delimiter)
  "A value for hook `paredit-space-for-delimiter-predicates'."
  (if (and (racket--mode-edits-racket-p)
           (not endp))
      (not
       (or
        ;; reader literal: e.g. #(), #hasheq(), #"bstr", #px".*"
        (looking-back (rx ?# (* (or (syntax word)
                                    (syntax symbol)
                                    (syntax punctuation))))
                      nil)
        ;; at-expression: @foo[ @foo{
        (and (memq delimiter '(?\[ ?\{))
             (looking-back (rx ?@ (* (or (syntax word)
                                         (syntax symbol)
                                         (syntax punctuation))))
                           nil))
        ;; at-expression: @foo[]{
        (and (eq delimiter ?\{)
             (looking-back (rx ?@ (* (or (syntax word)
                                         (syntax symbol)
                                         (syntax punctuation)))
                               ?\[
                               (* (or (syntax word)
                                      (syntax symbol)
                                      (syntax punctuation)))
                               ?\])
                           nil))
        ))
    t))
;;; Cycle paren shapes
(defconst racket--paren-shapes
  '( (?\( ?\[ ?\] )
     (?\[ ?\{ ?\} )
     (?\{ ?\( ?\) ))
  "This is not user-configurable because we expect them have to
  have actual ?\( and ?\) char syntax.")
(defun racket-cycle-paren-shapes ()
  "Cycle the sexpr among () [] {}."
  (interactive)
  (racket--assert-sexp-edit-mode)
  (save-excursion
    (unless (eq ?\( (char-syntax (char-after)))
      (backward-up-list))
    (pcase (assq (char-after) racket--paren-shapes)
      (`(,_ ,open ,close)
       (delete-char 1)
       (insert open)
       (backward-char 1)
       (forward-sexp 1)
       (delete-char -1)
       (insert close))
      (_
       (user-error "Don't know that paren shape")))))
(provide 'racket-parens)
;; racket-parens.el ends here
 |