Single quote autocompletion in racket-hash-lang-mode
sorawee opened this issue · comments
In racket-mode
, when I type '
, only one '
appears.
But in racket-hash-lang-mode
, when I type '
, ''
appears.
I file this as a feature request and not as a bug report because it could totally be the case that I have a minor mode that pairs '
up, so it could be my fault. But the fact that things work fine in racket-mode
suggests that perhaps racket-hash-lang-mode
could offer something that works out of the box.
Maybe relevant: DrRacket reads this preference to determine if a character should be paired up or not:
This makes '
to not be paired up in #lang racket
, but makes '
paired up in #lang rhombus
, within DrRacket.
((alist-get 'racket-mode package-alist)) ((emacs-version "29.1") (system-type darwin) (x-gtk-use-system-tooltips UNDEFINED) (major-mode help-mode) (racket--el-source-dir "/Users/sorawee/.config/emacs/.local/straight/build-29.1/racket-mode/") (racket--rkt-source-dir "/Users/sorawee/.config/emacs/.local/straight/build-29.1/racket-mode/racket/") (racket-program "racket") (racket-command-timeout 10) (racket-path-from-emacs-to-racket-function UNDEFINED) (racket-path-from-racket-to-emacs-function UNDEFINED) (racket-browse-url-function racket-browse-url-using-temporary-file) (racket-documentation-search-location "https://docs.racket-lang.org/search/index.html?q=%s") (racket-xp-after-change-refresh-delay 1) (racket-xp-mode-lighter (:eval (racket--xp-mode-lighter))) (racket-xp-highlight-unused-regexp "^[^_]") (racket-repl-buffer-name-function nil) (racket-submodules-to-run ((test) (main))) (racket-memory-limit 2048) (racket-error-context medium) (racket-repl-history-directory "~/.config/emacs/.local/cache/racket-mode/") (racket-history-filter-regexp "\\`\\s *\\'") (racket-images-inline t) (racket-imagemagick-props nil) (racket-images-keep-last 100) (racket-images-system-viewer "open") (racket-pretty-print t) (racket-use-repl-submit-predicate nil) (racket-pretty-print t) (racket-indent-curly-as-sequence t) (racket-indent-sequence-depth 0) (racket-pretty-lambda nil) (racket-smart-open-bracket-enable nil) (racket-module-forms "\\s(\\(?:module[*+]?\\|library\\)") (racket-logger-config ((cm-accomplice . warning) (GC . info) (module-prefetch . warning) (optimizer . info) (racket/contract . error) (racket-mode-debugger . info) (sequence-specialization . info) (* . fatal))) (racket-show-functions (racket-show-pseudo-tooltip))) (enabled-minor-modes (+popup-mode) (anzu-mode) (auto-composition-mode) (auto-compression-mode) (auto-encryption-mode) (auto-fill-mode) (auto-save-mode) (better-jumper-local-mode) (better-jumper-mode) (buffer-read-only) (centaur-tabs-mode) (column-number-mode) (delete-selection-mode) (doom-modeline-mode) (electric-indent-mode) (eros-mode) (evil-escape-mode) (evil-goggles-mode) (evil-local-mode) (evil-mode) (evil-snipe-local-mode) (evil-snipe-mode) (evil-snipe-override-local-mode) (evil-snipe-override-mode) (evil-surround-mode) (file-name-shadow-mode) (flyspell-lazy-mode) (font-lock-mode) (gcmh-mode) (general-override-mode) (global-anzu-mode) (global-company-mode) (global-eldoc-mode) (global-evil-surround-mode) (global-flycheck-mode) (global-font-lock-mode) (global-git-commit-mode) (global-hl-line-mode) (global-so-long-mode) (global-visual-line-mode) (hl-line-mode) (isearch-fold-quotes-mode) (line-number-mode) (mac-mouse-wheel-mode) (marginalia-mode) (ns-auto-titlebar-mode) (override-global-mode) (persp-mode) (projectile-mode) (recentf-mode) (save-place-mode) (savehist-mode) (semantic-minor-modes-format) (server-mode) (shell-dirtrack-mode) (show-paren-mode) (show-smartparens-global-mode) (size-indication-mode) (smartparens-global-mode) (solaire-global-mode) (solaire-mode) (transient-mark-mode) (undo-fu-mode) (undo-fu-session-global-mode) (vertico-mode) (visual-line-mode) (which-key-mode) (window-divider-mode) (winner-mode) (ws-butler-global-mode) (yas-global-mode) (yas-minor-mode)) (disabled-minor-modes (+emacs-lisp-ert-mode) (+emacs-lisp-non-package-mode) (+javascript-gulp-mode) (+javascript-npm-mode) (+lsp-optimization-mode) (+org-pretty-mode) (+popup-buffer-mode) (+web-angularjs-mode) (+web-django-mode) (+web-jekyll-mode) (+web-phaser-mode) (+web-react-mode) (+web-wordpress-mode) (abbrev-mode) (auto-fill-function) (auto-image-file-mode) (auto-revert-mode) (auto-revert-tail-mode) (auto-save-visited-mode) (blink-cursor-mode) (buffer-face-mode) (bug-reference-mode) (bug-reference-prog-mode) (button-mode) (centaur-tabs-local-mode) (cl-old-struct-compat-mode) (comint-fontify-input-mode) (company-box-mode) (company-mode) (company-search-mode) (compilation-minor-mode) (compilation-shell-minor-mode) (completion-in-region-mode) (consult-preview-at-point-mode) (context-menu-mode) (copilot-mode) (cursor-face-highlight-mode) (cursor-intangible-mode) (cursor-sensor-mode) (dash-fontify-mode) (defining-kbd-macro) (diff-auto-refine-mode) (diff-minor-mode) (dired-hide-details-mode) (display-fill-column-indicator-mode) (display-line-numbers-mode) (doom-docs-mode) (dtrt-indent-global-mode) (dtrt-indent-mode) (edebug-backtrace-mode) (edebug-mode) (edit-indirect--overlay) (editorconfig-mode) (eldoc-mode) (electric-layout-mode) (electric-quote-mode) (evil-collection-magit-toggle-text-minor-mode) (evil-markdown-mode) (evil-mc-mode) (evil-org-mode) (evil-visualstar-mode) (flycheck-mode) (flycheck-popup-tip-mode) (flyspell-mode) (general-override-local-mode) (git-commit-mode) (git-gutter-mode) (global-auto-revert-mode) (global-copilot-mode) (global-dash-fontify-mode) (global-display-fill-column-indicator-mode) (global-display-line-numbers-mode) (global-evil-mc-mode) (global-evil-visualstar-mode) (global-git-gutter-mode) (global-goto-address-mode) (global-hide-mode-line-mode) (global-hl-todo-mode) (global-prettify-symbols-mode) (global-reveal-mode) (global-semantic-highlight-edits-mode) (global-semantic-highlight-func-mode) (global-semantic-show-parser-state-mode) (global-semantic-show-unmatched-syntax-mode) (global-semantic-stickyfunc-mode) (global-vi-tilde-fringe-mode) (global-whitespace-mode) (global-whitespace-newline-mode) (goto-address-mode) (goto-address-prog-mode) (header-line-indent-mode) (hide-mode-line-mode) (highlight-numbers-mode) (highlight-quoted-mode) (hl-todo-mode) (horizontal-scroll-bar-mode) (hs-minor-mode) (ibuffer-auto-mode) (indent-tabs-mode) (isearch-mode) (ispell-minor-mode) (jit-lock-debug-mode) (lock-file-mode) (lost-selection-mode) (mac-auto-ascii-mode) (mac-auto-operator-composition-mode) (mac-font-panel-mode) (magit-auto-revert-mode) (magit-blame-mode) (magit-blame-read-only-mode) (magit-blob-mode) (magit-todos-mode) (magit-wip-after-apply-mode) (magit-wip-after-save-local-mode) (magit-wip-after-save-mode) (magit-wip-before-change-mode) (magit-wip-initial-backup-mode) (magit-wip-mode) (mail-abbrevs-mode) (markdown-live-preview-mode) (menu-bar-mode) (mml-mode) (mouse-wheel-mode) (next-error-follow-minor-mode) (org-capture-mode) (org-cdlatex-mode) (org-indent-mode) (org-list-checkbox-radio-mode) (org-num-mode) (org-src-mode) (org-table-follow-field-mode) (org-table-header-line-mode) (orgtbl-mode) (outline-minor-mode) (overwrite-mode) (paragraph-indent-minor-mode) (pcre-mode) (prettify-symbols-mode) (racket-hash-lang-repl-mode) (racket-smart-open-bracket-mode) (racket-xp-mode) (rainbow-delimiters-mode) (read-extended-command-mode) (rectangle-mark-mode) (reveal-mode) (rxt--read-pcre-mode) (rxt-global-mode) (rxt-mode) (semantic-highlight-edits-mode) (semantic-highlight-func-mode) (semantic-mode) (semantic-show-parser-state-mode) (semantic-show-unmatched-syntax-mode) (semantic-stickyfunc-mode) (sh-electric-here-document-mode) (shell-command-with-editor-mode) (shell-highlight-undef-mode) (show-smartparens-mode) (smartparens-global-strict-mode) (smartparens-mode) (smartparens-strict-mode) (smerge-mode) (so-long-minor-mode) (tab-bar-history-mode) (tab-bar-mode) (temp-buffer-resize-mode) (text-scale-mode) (toc-org-mode) (tool-bar-mode) (tooltip-mode) (transient-resume-mode) (treesit-explore-mode) (treesit-inspect-mode) (undelete-frame-mode) (undo-fu-session-mode) (url-handler-mode) (use-hard-newlines) (vc-dir-git-mode) (vc-parent-buffer) (vi-tilde-fringe-mode) (view-mode) (visible-mode) (which-function-mode) (whitespace-mode) (whitespace-newline-mode) (with-editor-mode) (ws-butler-mode) (xref-etags-mode))
I guess another way to look at it is, this is a feature request to implement the support for drracket:quote-matches
. This would make '
paired up in #lang rhombus
, but not in #lang racket
. On the other hand, this would make |
paired in #lang racket
, but not in #lang rhombus
.
It already does use both paren-matches and quote-matches from the #lang
to make an Emacs "char syntax table".
As a result, for me racket-hash-lang-mode
already behaves as you describe.
With #lang racket
pressing '
gives just that.
With #lang rhombus
it gives you a pair, ''
-- provided you have something like electric-pair-mode
or electric-pair-local-mode
enabled, which does this kind of thing.
Hmm. You are right about single quote. If I disable smartparens-mode
(which is what I mainly use) and enable electric-pair-mode
, I get the behavior that you described. I assumed that racket-hash-lang-mode
didn't consult quote-matches
because I grepped it (incorrectly) from the repo and found no match.
But what is confusing to me is that there's still a problem with vertical bar |
. In #lang racket
, |
is a part of drracket:quote-matches
, so it should be paired up. However, even with electric-pair-mode
on (and smartparens-mode
off), I can't get |
to be paired up. Can you reproduce this issue?
To sum up in my understanding (which could be wrong), there are two issues here:
- The first issue is that
smartparens-mode
will always insert paired'
. The fix on my end is to disable it and useelectric-pair-mode
instead. - The second issue is that
|
is not paired. I don't know what is going on here.
In classic racket-mode
|
doesn't electric-pair, FWIW.
I over-simplified when I said:
It already does use both paren-matches and quote-matches from the #lang to make an Emacs "char syntax table".
Actually (from racket--hash-lang-on-new-lang
):
;; If the lang uses racket-grouping-position, i.e. it uses
;; s-expressions, then use racket-mode-syntax-table. That way
;; other Emacs features and packages are more likely to work.
;; Otherwise, assume nothing about the lang and set a "plain"
;; syntax table where no characters are assumed to delimit
;; parens, comments, or strings.
(set-syntax-table (if (plist-get plist 'racket-grouping)
racket-mode-syntax-table
(racket--make-non-sexp-syntax-table
(plist-get plist 'paren-matches)
(plist-get plist 'quote-matches))))
The first sentence is what matters here. We use drracket:grouping-position
as a signal for sexp langs. #lang racket
racket-hash-lang-mode
uses the classic racket-mode
char syntax table. It gets the behavior where |
doesn't electric-pair.
[The last sentence of that comment needs to be updated. Better: "Otherwise, make a 'plain' syntax-table assuming nothing but what the lang reports for parens and quotes."]
p.s. My brain is overflowing with #669 at the moment so I'm just describing how it's intended to work. If you think it could/should work differently, I'd be happy to discuss more, I might just need more time... 😄
No worries! Take your time :)
I've been looking at this again.
I'm having trouble figuring out how to make electric-pairs-mode
work well in all cases.
- electric-pairs-mode relies primarily on the buffer's char-syntax table, with an
electric-pair-pairs
variable as a fallback, which is a list of pairs of chars. Note the word "char", singular. Langs like rhombus that include multi-char parens like'(
and)'
are awkward. - Despite me marking comment tokens with syntax-table text-properties, sometimes electric-pairs-mode gets confused about whether it should act inside comments. e.g. typing "don't" in a comment shouldn't result in "don't'", but sometimes it does.
- rhombus says paren-matches are
(("(" . ")") ("[" . "]") ("{" . "}") ("'(" . ")'") ("«" . "»"))
and quote-matches are("\"" "'")
. - although rhombus includes
'
in quote-matches meta-data it actually lexes/tokenizes it as'parenthesis
. Is its quote-matches wrong?? - For purposes of auto-matching when you type, should typing
'
go ahead and insert''
then when you do(
add the()
inside to get'()'
? That makes sense but that would probably need its parens-matches list to be(
and)
and'
and'
-- but not'(
and)'
. - Maybe the above just means that rhombus' meta-data needs to be changed ... but maybe DrR needs the status quo data.
- Regardless, I wonder if
racket-hash-lang-mode
needs to adds its own simple delimiter-matching feature, as an alternative toelectric-pairs-mode
and similar modes. Maybe the square peg just won't ever fit in the round Emacs ecosystem? (Similar to how we have our own expression navigation commands using the lang's supplied notion of "grouping-position", instead of trying to makeforward-exp-function
work in all cases well enough to use the normal Emacs commands.)
I guess one unresolved issue is whether Racket Mode should support smartparens as an alternative to electric-pair. I'm perfectly OK if there's no support, but the fact that the Racket Mode documentation does mention smartparens led me to believe that it was supported.
Oh, and thank you for your work!!!
Good point.
The section about paredit
starts with this note:
Note: If you use
racket-hash-lang-mode
, you can useracket-hash-lang-mode-hook
to enable/disable paredit based on the specific #lang.
So:
- The note is wrong. It should talk about using the
racket-hash-lang-module-language-hook
. And add, hey look at the helpful example there. - The example there should probably explain that any paren-matching mode -- smartparens, paredit, electric-pair-mode, whatever -- is unlikely to work well unless the module language is "rackety".
- The
smartparens
section should get an equivalent (improved) note.
Although documentation is almost as hard as naming things, commit 5d3288b tries to do what I just described.