diff --git a/parinfer-rust-changes.el b/parinfer-rust-changes.el index 0157c29..b0b2ddf 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 @@ -102,16 +102,13 @@ (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) - "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..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 @@ -242,6 +246,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 +255,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 b64d9fd..7cb2271 100644 --- a/parinfer-rust-mode.el +++ b/parinfer-rust-mode.el @@ -384,32 +384,33 @@ See `parinfer-rust--option-type' for a more complete explanation of the options. :type parinfer-rust--option-type :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.") ;;;;;;;;;;;;;;;;;;;;;;;;; ;; 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) +(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 + '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'") + ;; 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. @@ -612,10 +613,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))))) @@ -663,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) @@ -674,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. @@ -716,7 +726,8 @@ 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)) (defun parinfer-rust-toggle-disable () @@ -755,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)) @@ -813,7 +823,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 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.