From 2ff3ea6f01fae46af28ee9a52a2bd648c0258ee9 Mon Sep 17 00:00:00 2001 From: Justin Barclay Date: Sat, 18 May 2024 22:07:59 -0700 Subject: [PATCH 1/7] doc: Update docs on how to support guile scheme --- parinfer-rust-mode.el | 26 ++++++++++++++------------ readme.org | 39 +++++++++++++++++++++++---------------- 2 files changed, 37 insertions(+), 28 deletions(-) diff --git a/parinfer-rust-mode.el b/parinfer-rust-mode.el index b64d9fd..a1aae1b 100644 --- a/parinfer-rust-mode.el +++ b/parinfer-rust-mode.el @@ -385,18 +385,20 @@ See `parinfer-rust--option-type' for a more complete explanation of the options. :group 'parinfer-rust-mode) (defvar parinfer-rust-major-mode-options - (list - 'clojure-mode parinfer-rust-clojure-options - 'clojurec-mode parinfer-rust-clojure-options - 'clojurescript-mode parinfer-rust-clojure-options - 'janet-mode parinfer-rust-janet-options - 'common-lisp-mode parinfer-rust-lisp-options - 'racket-mode parinfer-rust-racket-options - 'scheme-mode parinfer-rust-scheme-options - ;; This doesn't work - there is no guile mode but I am not sure what we can - ;; use to set guile specific options - 'guile-mode parinfer-rust-guile-options) - "Major mode specific options for that controls how the parinfer-rust library behaves.") + (list 'clojure-mode parinfer-rust-clojure-options + 'clojurec-mode parinfer-rust-clojure-options + 'clojurescript-mode parinfer-rust-clojure-options + 'clojure-ts-mode parinfer-rust-clojure-options + 'clojure-ts-clojurescript-mode parinfer-rust-clojure-options + 'janet-mode parinfer-rust-janet-options + 'common-lisp-mode parinfer-rust-lisp-options + 'racket-mode parinfer-rust-racket-options + 'scheme-mode parinfer-rust-scheme-options) + ;; Rewrite this string to be more readable + "A plist that controls how parinfer-rust behaves for a given major mode. + +For more information see `parinfer-rust--option-type'") + ;;;;;;;;;;;;;;;;;;;;;;;;; ;; Setup ;;;;;;;;;;;;;;;;;;;;;;;;; diff --git a/readme.org b/readme.org index f96a422..277ce87 100644 --- a/readme.org +++ b/readme.org @@ -102,6 +102,20 @@ For the more adventurous, you can also download and compile the ~parinfer-rust~ (setq parinfer-rust-library "/path/to/parinfer-rust-library.so") #+END_SRC +** Modes +Parinfer can operate under three different modes when writing lisp. +*** Paren + Paren Mode gives you full control of parens, while Parinfer corrects indentation. You can still adjust indentation, but you won't be able to indent/dedent past certain boundaries set by parens on previous lines. + + [[./videos/paren-mode.gif]] +*** Indent + Indent Mode gives you full control of indentation, while Parinfer corrects or inserts close-parens where appropriate. Specifically, it only touches the groups of close-parens at the end of each line. + + [[./videos/indent-mode.gif]] +*** Smart + Smart Mode is like Indent Mode, but it tries to preserve the structure too. + + [[./videos/smart-mode.gif]] ** Commands | Command | Description | |----------------------------+-------------------------------------------------------| @@ -118,20 +132,6 @@ For the more adventurous, you can also download and compile the ~parinfer-rust~ (define-key parinfer-rust-mode-map (kbd "C-c C-p d") #'parinfer-rust-toggle-disable) #+end_src -** Modes - Parinfer can operate under three different modes when writing lisp. -*** Paren - Paren Mode gives you full control of parens, while Parinfer corrects indentation. You can still adjust indentation, but you won't be able to indent/dedent past certain boundaries set by parens on previous lines. - - [[./videos/paren-mode.gif]] -*** Indent - Indent Mode gives you full control of indentation, while Parinfer corrects or inserts close-parens where appropriate. Specifically, it only touches the groups of close-parens at the end of each line. - - [[./videos/indent-mode.gif]] -*** Smart - Smart Mode is like Indent Mode, but it tries to preserve the structure too. - - [[./videos/smart-mode.gif]] ** Customizations parinfer-rust-mode is purposefully light on option, but it does give a few options to tweak behavior. @@ -214,12 +214,19 @@ Options: node `(elisp)Replacing' Options: - * safe - * fast + + safe + + fast #+begin_quote default: safe #+end_quote + +*** Guile Support +If guile is your flavour of scheme you can override the scheme option in the ~parinfer-rust-major-mode-options~ plist with ~parinfer-rust-guile-options~. + +#+begin_src elisp + (setopt parinfer-rust-major-mode-options (plist-put parinfer-rust-major-mode-options 'scheme-mode 'parinfer-rust-guile-options)) +#+end_src ** parinfer-mode There is an alternate implementation of Parinfer for Emacs called [[https://github.com/DogLooksGood/parinfer-mode][parinfer-mode]]. It currently has support for Parinfer's "paren" and "indent". Additionally, it has had experimental support for "smart" mode, however, this has remained hidden on a branch and not accessible from MELPA for over a year. parinfer-smart-mode aims to be a simpler adaptation of Parinfer that just offers "smart mode", leveraging the parinfer-rust plugin to do most of the heavy lifting. From 5e97712facf0024f0eb9fd635bea625c4c834c8c Mon Sep 17 00:00:00 2001 From: Justin Barclay Date: Sat, 18 May 2024 22:34:00 -0700 Subject: [PATCH 2/7] fix: remove default hook to auto apply fast mode --- parinfer-rust-mode.el | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/parinfer-rust-mode.el b/parinfer-rust-mode.el index a1aae1b..29ee484 100644 --- a/parinfer-rust-mode.el +++ b/parinfer-rust-mode.el @@ -815,7 +815,7 @@ not available." (t (parinfer-rust-mode-enable)))) -(setq-default parinfer-rust-mode-hook '(parinfer-rust--auto-apply-fast-mode)) + (provide 'parinfer-rust-mode) ;;; parinfer-rust-mode.el ends here From c9a2f5c406bbf351552b59124ca9e344eb6c08df Mon Sep 17 00:00:00 2001 From: Justin Barclay Date: Sat, 18 May 2024 23:09:11 -0700 Subject: [PATCH 3/7] fix: parinfer-rust--disable should be turned off when mode is disabled --- parinfer-rust-mode.el | 1 + 1 file changed, 1 insertion(+) diff --git a/parinfer-rust-mode.el b/parinfer-rust-mode.el index 29ee484..a4526a8 100644 --- a/parinfer-rust-mode.el +++ b/parinfer-rust-mode.el @@ -719,6 +719,7 @@ Checks if MODE is a valid Parinfer mode, and uses (track-changes-unregister parinfer-rust--change-tracker) (setq-local parinfer-rust--change-tracker nil)) (remove-hook 'first-change-hook #'parinfer-rust--check-for-issues t) + (setq-local parinfer-rust--disable nil) (parinfer-rust--dim-parens)) (defun parinfer-rust-toggle-disable () From 6656912037303df9f7b954ab994be1d6756ac5ca Mon Sep 17 00:00:00 2001 From: Justin Barclay Date: Tue, 21 May 2024 20:58:54 -0700 Subject: [PATCH 4/7] fix: prevent buffer jumping around during fast strategy When using `delete-region` and `insert-buffer-substring` this sometimes causes the buffer to recenter the text edited area to the middle or the bottom of the buffer. By tracking the window position this allows parinfer-rust to make sure the jumping around isn't minimized. Jumping now only occurs if the user has `pixel-scroll-precision-mode` enabled and the buffer's start position is halfway between a line. --- parinfer-rust-mode.el | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/parinfer-rust-mode.el b/parinfer-rust-mode.el index a4526a8..bd34b13 100644 --- a/parinfer-rust-mode.el +++ b/parinfer-rust-mode.el @@ -614,10 +614,17 @@ CHANGES." (switch-to-buffer current) (if (eq parinfer-rust-buffer-replace-strategy 'fast) - (progn + (let ((window-start-pos (window-start))) (delete-region (point-min) (point-max)) - (insert-buffer-substring new-buf)) + (insert-buffer-substring new-buf) + (when (not (= window-start-pos + (window-start))) + ;; If the buffer is not pixel aligned, this will cause a slight jump. But + ;; if we want speed and not to jump around too much, this is the best we + ;; can do for now. I wish there was a way to maintain buffer height with + ;; pixel precision. + (set-window-start (selected-window) window-start-pos))) (replace-buffer-contents new-buf 1)) (kill-buffer new-buf) (undo-amalgamate-change-group change-group))))) From f2c6394930dbca46b8bdcaa6191b4eee8584b541 Mon Sep 17 00:00:00 2001 From: Justin Barclay Date: Wed, 22 May 2024 09:36:59 -0700 Subject: [PATCH 5/7] chore: lint fixes --- parinfer-rust-changes.el | 4 ++-- parinfer-rust-helper.el | 2 ++ parinfer-rust-mode.el | 25 ++++++++++++------------- 3 files changed, 16 insertions(+), 15 deletions(-) diff --git a/parinfer-rust-changes.el b/parinfer-rust-changes.el index 0157c29..fc7dcee 100644 --- a/parinfer-rust-changes.el +++ b/parinfer-rust-changes.el @@ -87,7 +87,7 @@ changes)) (defun parinfer-rust--fetch-changes (id) - "Fetch changes for current buffer using signal ID." + "Fetch change for current buffer using signal ID." (track-changes-fetch id (lambda (start end before) (if parinfer-rust--disable @@ -111,7 +111,7 @@ parinfer-rust--changes)))))) (defun parinfer-rust--changes-signal (id &optional distance) - "Signal changes for ID with optional DISTANCE." + "Signal change for ID with optional DISTANCE." (parinfer-rust--fetch-changes id) (if distance ;; We're still in the middle of changes, but they're "far", diff --git a/parinfer-rust-helper.el b/parinfer-rust-helper.el index bff20dc..c4936cb 100644 --- a/parinfer-rust-helper.el +++ b/parinfer-rust-helper.el @@ -242,6 +242,7 @@ mode to better emulate users." (cond ((< num 0) 0) ((> num max) max) (t num)))) + (defun parinfer-rust--defer-loading (&rest _) "Defer loading of `parinfer-rust-mode' until the buffer is in focus." ;; This is a parinfer enabled buffer that started in the background and has now been moved to the foreground @@ -250,6 +251,7 @@ mode to better emulate users." (window-buffer (selected-window)))) (remove-hook 'window-selection-change-functions #'parinfer-rust--defer-loading t) (parinfer-rust-mode-enable))) + ;; Disable fill column warning only for this buffer to enable long strings of text without ;; having to do a weird mapconcat. ;; Local Variables: diff --git a/parinfer-rust-mode.el b/parinfer-rust-mode.el index bd34b13..ba6f1ad 100644 --- a/parinfer-rust-mode.el +++ b/parinfer-rust-mode.el @@ -384,6 +384,18 @@ See `parinfer-rust--option-type' for a more complete explanation of the options. :type parinfer-rust--option-type :group 'parinfer-rust-mode) +;;;;;;;;;;;;;;;;;;;;;;;;; +;; Setup +;;;;;;;;;;;;;;;;;;;;;;;;; +(require 'parinfer-rust parinfer-rust-library t) +(require 'parinfer-rust-changes) + +(require 'subr-x) +(require 'font-lock) + +(defconst parinfer-rust--mode-types '("indent" "smart" "paren") + "The different modes that parinfer can operate on.") + (defvar parinfer-rust-major-mode-options (list 'clojure-mode parinfer-rust-clojure-options 'clojurec-mode parinfer-rust-clojure-options @@ -399,19 +411,6 @@ See `parinfer-rust--option-type' for a more complete explanation of the options. For more information see `parinfer-rust--option-type'") -;;;;;;;;;;;;;;;;;;;;;;;;; -;; Setup -;;;;;;;;;;;;;;;;;;;;;;;;; - -(defconst parinfer-rust--mode-types '("indent" "smart" "paren") - "The different modes that parinfer can operate on.") - -(require 'parinfer-rust parinfer-rust-library t) -(require 'parinfer-rust-changes) - -(require 'subr-x) -(require 'font-lock) - ;; Check version and prompt to download latest version if out of date ;; Problem: Emacs can't reload dynamic libraries, which means that if we ;; download a new library the user has to restart Emacs for changes to take effect. From ae3a3e966b68415eec355211f9378b8f68920c93 Mon Sep 17 00:00:00 2001 From: Justin Barclay Date: Wed, 22 May 2024 14:03:34 -0700 Subject: [PATCH 6/7] fix: when started in a modified state parinfer-rust will not work When buffer is in a modified state and `parinfer-rust-check-before-enable` is set to `'defer` then first-change-hook won't fire while parinfer-rust-mode is enabled. We can use pre-command-hook to defer running parinfer-rust-mode until the user interacts with the buffer. This has the issue where, if a user is just navigating a buffer, parinfer-rust will still need to run. As a TODO for a future work we can optimize this by looking for changes in the buffer and only progressing through check for issue just before a change is going to be made. Switch to precommand hook --- parinfer-rust-mode.el | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/parinfer-rust-mode.el b/parinfer-rust-mode.el index ba6f1ad..7cb2271 100644 --- a/parinfer-rust-mode.el +++ b/parinfer-rust-mode.el @@ -671,6 +671,8 @@ If a change is detected in the buffer, prompt the user to see if they still want Disable `parinfer-rust-mode' if the user does not want to have parinfer autofix them, or if there is no reasonable way for `parinfer-rust-mode' to automatically fix them." + ;; TODO: this should only run the first time the buffer is actually changed. + ;; buffer searching or navigating should not trigger this. (setq-local parinfer-rust--disable nil) ;; Disable change tracker for now because we are about to make changes in an change hook. (track-changes-unregister parinfer-rust--change-tracker) @@ -682,7 +684,7 @@ parinfer autofix them, or if there is no reasonable way for (setq-local parinfer-rust--change-tracker (track-changes-register #'parinfer-rust--changes-signal :disjoint t))) - (remove-hook 'first-change-hook #'parinfer-rust--check-for-issues t)) + (remove-hook 'pre-command-hook #'parinfer-rust--check-for-issues t)) (defun parinfer-rust--switch-mode (&optional mode) "Switch to a different Parinfer MODE. @@ -724,7 +726,7 @@ Checks if MODE is a valid Parinfer mode, and uses (when parinfer-rust--change-tracker (track-changes-unregister parinfer-rust--change-tracker) (setq-local parinfer-rust--change-tracker nil)) - (remove-hook 'first-change-hook #'parinfer-rust--check-for-issues t) + (remove-hook 'pre-command-hook #'parinfer-rust--check-for-issues t) (setq-local parinfer-rust--disable nil) (parinfer-rust--dim-parens)) @@ -764,8 +766,7 @@ This includes stopping tracking of all changes." buffer-read-only) ;; Defer checking for changes until a user changes the buffer (setq-local parinfer-rust--disable t) - (add-hook 'first-change-hook #'parinfer-rust--check-for-issues nil t)) - + (add-hook 'pre-command-hook #'parinfer-rust--check-for-issues nil t)) ((eq 'immediate parinfer-rust-check-before-enable) (setq-local parinfer-rust--disable t) (parinfer-rust--check-for-issues)) From 7ec909ebded27a616fdbe1ed256b566d31b6d3db Mon Sep 17 00:00:00 2001 From: Justin Barclay Date: Thu, 23 May 2024 00:02:56 -0700 Subject: [PATCH 7/7] chore: add flyspell to troublesome modes and minor code cleanup Flyspell and parinfer-rust-mode don't play well together. Flyspell moves the cursor around the buffer when spell checking the buffer and, for some unknown reason, when `parinfer-rust--execute` is executed it can detect the cursor position as it was being moved around by flyspell. In safe mode Emacs is smart enough to handle this and put the cursor in the right place. However, fast mode will just let the cursor jump around. So, in order to avoid this flyspell-mode should be disabled if parinfer-rust is to behave properly --- parinfer-rust-changes.el | 5 +---- parinfer-rust-helper.el | 6 +++++- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/parinfer-rust-changes.el b/parinfer-rust-changes.el index fc7dcee..b0b2ddf 100644 --- a/parinfer-rust-changes.el +++ b/parinfer-rust-changes.el @@ -102,12 +102,9 @@ (parinfer-rust--get-cursor-x))))) (push (list 'lineNo lineNo 'x x - 'start start - 'end end 'length (length before) 'before-text before - 'after-text (buffer-substring-no-properties start end) - 'group nil) + 'after-text (buffer-substring-no-properties start end)) parinfer-rust--changes)))))) (defun parinfer-rust--changes-signal (id &optional distance) diff --git a/parinfer-rust-helper.el b/parinfer-rust-helper.el index c4936cb..b78f10e 100644 --- a/parinfer-rust-helper.el +++ b/parinfer-rust-helper.el @@ -28,6 +28,7 @@ (declare-function parinfer-rust-mode-enable "parinfer-rust-mode") (defvar parinfer-rust--mode) (defvar parinfer-rust-dim-parens) + (defvar parinfer-rust-buffer-replace-strategy) (defvar parinfer-rust-mode)) (require 'url) @@ -139,7 +140,10 @@ Uses PARINFER-RUST-VERSION to download a compatible version of the library." If the user does not disable these modes then it may cause bugs or crashes" (let ((warning-list)) - (dolist (mode parinfer-rust-troublesome-modes) + (dolist (mode (if (eq parinfer-rust-buffer-replace-strategy + 'fast) + (cons 'flyspell-mode parinfer-rust-troublesome-modes) + parinfer-rust-troublesome-modes)) (when (parinfer-rust--is-active-minor-mode mode) (push mode warning-list))) (if (and