Skip to content

gilch/parinfer-rust-mode

 
 

Repository files navigation

https://circleci.com/gh/justinbarclay/parinfer-rust-mode.svg?style=svg https://melpa.org/packages/parinfer-rust-mode-badge.svg https://stable.melpa.org/packages/parinfer-rust-mode-badge.svg

Parinfer

Parinfer is a plugin that aims to make writing lisp simple. This library is a minimalistic wrapper around eraserhd/parinfer-rust to provide an Emacs minor mode. parinfer-rust-mode aims to be a simpler adaptation of Parinfer that only offers “smart mode”, leveraging the parinfer-rust plugin to do most of the heavy lifting.

Capabilities:

  • Making code auto-adhere to formatting conventions
  • Influencing expression-nesting with indentation
  • Maintaining indentation when expressions shift
  • Allowing Paredit-like features without hot keys

Requirements

  1. Emacs (26+) compiled with Dynamic Module support.
  2. Running on MacOS/Linux, with Windows support coming soon.
  3. (Optional) Curl - to download the library for you

Installation

parinfer-rust-mode

From source

You can install parinfer-rust-mode from source (this github repo)

cd /path/for/elisp-packages
git clone [email protected]:justinbarclay/parinfer-rust-mode.git

After that add it to your load path and go wild.

(add-to-list 'load-path "/path/to/parinfer-rust-mode")
(add-hook 'emacs-lisp-mode 'parinfer-rust-mode)

Use Package

Alternatively, you can tell something like use-package to manage it for you.

(use-package parinfer-rust-mode
  :hook emacs-lisp-mode)    

parinfer-rust library

You’ll also need to have the library installed on your system for you somewhere.

Option 1: Let Parinfer Rust install it for you

That’s it. There are no instructions here. When parinfer-rust-mode prompts you to download the library, say yes. parinfer-rust-mode will then use curl to download parinfer-rust and save it in ${EMACS_DIRECTORY}/parinfer-rust/.

If you’re curious, you can find the library files that parinfer-rust-mode downloads as release artifacts for parinfer-rust.

If you would always like parinfer-rust-mode to keep the library version in sync for you, automatically download it, then add the following line into your config:

(setq parinfer-rust-auto-download t)

If you are using the `use-package` snippet from above, that would look like:

(use-package parinfer-rust-mode
    :hook emacs-lisp-mode
    :init
    (setq parinfer-rust-auto-download t))

Option 2: Building library from sources

For the more adventurous of you, you can also download the parinfer-rust library from source and compile it.

Step 1: Build the Parinfer Rust library

When compiling manually the library name differs from platform to platform. Additionally, Emacs expects that these libraries have specific file extensions when first loading them up. This is a problem for MacOS because Rust compiles it as .dylib and we’ll need to give the file an .so extension when we copy it to it’s final location.

PlatformFile nameRequired extension
Linuxlibparinfer_rust.so.so
MacOSlibparinfer_rust.dylib.so
Windowsparinfer_rust.dll.dll
git clone https://github.com/eraserhd/parinfer-rust.git
cd parinfer-rust
cargo build --release
cp ./target/release/${library-name} ~/.emacs.d/parinfer-rust/${lib-name}
Step 2: Configure parinfer-rust-mode

Once you have compiled the libraries from source code you’ll need to tell parinfer-rust-mode how to find these libraries

(setq parinfer-rust-library "/path/to/parinfer-rust-library.so")

Commands

CommandDescription
parinfer-switch-modeQuickly switch between paren, indent, and smart modes
parinfer-rust-mode-disableToggle parinfer-rust-mode mode on or off
parinfer-rust-toggle-parenToggle between paren mode and current mode

These commands are no longer bound to the C-c C-p prefix keys by default. If you prefer to use the old bindings, add this to your configuration (keep in mind it may clash with some major mode bindings):

(define-key parinfer-rust-mode-map (kbd "C-c C-p t") #'parinfer-rust-toggle-paren-mode)
(define-key parinfer-rust-mode-map (kbd "C-c C-p s") #'parinfer-rust-switch-mode)
(define-key parinfer-rust-mode-map (kbd "C-c C-p d") #'parinfer-rust-toggle-disable)

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.

  • parinfer-rust-library

    The location to find or install the parinfer-rust library.

    default: ~/.emacs.d/parinfer-rust/parinfer-rust-*.so

  • parinfer-rust-library-dir

    The directory to store or to find the parinfer-rust library in. This allows a more fine grained approach to installing the parinfer library, if you don’t want to rename the library itself.

    default: ~/.emacs.d/parinfer-rust/parinfer-rust-*.so

  • parinfer-rust-preferred-mode

    The mode you want parinfer-rust-mode to start in. Options:

    • smart
    • indent
    • paren

    default: smart

  • parinfer-rust-check-before-enable

    Perform check on indentation before enabling `parinfer-rust-mode’

    If Parinfer detects that it needs to change the indentation in the before first running, it will prompt the user whether it is OK to adjust the indentation. If the user disagrees Parinfer will disable itself. The user may choose to get the prompt immediately whenever parinfer-rust-mode is enabled, defer it until the first change in the buffer, or disable it and never receive a prompt. When disabled, parinfer-rust-mode will run automatically balance the indentation for the user.

Options:

  • immediate
  • defer
  • nil

default: defer

  • parinfer-rust-auto-download

    Have parinfer-rust-mode download the latest version of the parinfer-rust library without prompting you. Generally used for automating your set-up.

    default: nil

  • parinfer-rust-dim-parens

    Dim parentheses that are inferred by Parinfer in indent and smart modes. Color can be configured via the parinfer-rust-dim-parens face.

    default: t

  • parinfer-rust-troublesome-modes

    A list of modes that may conflict when run alongside parinfer-rust-mode. parinfer-rust-mode will check for these modes when first enabled in a buffer and it will prompt to disable these modes for you. To disable parinfer-rust for checking for these modes, parinfer-rust-troublesome-modes to nil.

    default: (electric-pair-mode hungry-delete-mode global-hungry-delete-mode)

parinfer-mode

There is an alternate implementation of Parinfer for Emacs called 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.

Known Issues

  • Multiple cursors do not work as intended
  • Does not play well with other modes that insert parens or manage whitespace. If you have modes like electric-pair-mode or hungry-delete-mode enabled, you may want to disable them for any mode that has parinfer-rust-mode enabled. To help users work around this we offer to disable known troublesome modes if we detect them.

Out of Memory

This is still alpha software and parinfer-rust has been known to get Out of Memory warnings and cause Emacs to crash, so use at your own risk.

  • I’m maintaining a fork of parinfer-rust, that patches the libraries ability to cause an Out of Memory error.
  • In fairness to the maintainer of parinfer-rust, the reason that the library is crashing is due to the changes I am passing to the library. Which admittedly, can be non-sensical from parinfer’s perspective.

Reporting bugs

In some cases, parinfer-rust-mode can misbehave by making the wrong choices. When that happens I recommend you file a bug report. If you want to make my life easier, I recommend following these two as some pretty great examples on how to file a bug report.

Escape hatch

Is parinfer misbehaving in smart-mode? This could be due to a bug or because some commands are just plain weird. parinfer-rust-treat-command-as is an escape hatch for smart mode that allows you to tell parinfer-rust-mode what mode to run a specific command. parinfer-rust-treat-command-as is a list of pairs.The first item in the pair specifies the command and the second item in the pair specifies the mode the command should be run under. For example `(yank . "paren"), tells parinfer-rust-mode to override smart mode and run under paren mode when it detects that yank caused a change in the buffer.

You can extend to parinfer-rust-treat-command-as using add-to-list as shown below:

(add-to-list 'parinfer-rust-treat-command-as '(your-command . "paren")) 
;;or
(add-to-list 'parinfer-rust-treat-command-as '(your-command . "indent"))

Contributing

If you’d like to help contribute to the development of parinfer-rust-mode the only caveat interesting section of note is the testing framework.

parinfer-rust-mode relies on Cask to manage development libraries and to set-up the tests themselves.

Then after you have made some changes just run:

PARINFER_RUST_TEST=true make test

And you should get something like:

✦ ❯ PARINFER_RUST_TEST=true make test
emacs --version
GNU Emacs 28.0.50
Copyright (C) 2020 Free Software Foundation, Inc.
GNU Emacs comes with ABSOLUTELY NO WARRANTY.
You may redistribute copies of GNU Emacs
under the terms of the GNU General Public License.
For more information about these matters, see the file named COPYING.
cask build
Compiling /home/justin/dev/parinfer-rust-mode/parinfer-helper.el...
Compiling /home/justin/dev/parinfer-rust-mode/parinfer-rust-mode-autoloads.el...
Compiling /home/justin/dev/parinfer-rust-mode/parinfer-rust-mode.el...

In toplevel form:
parinfer-rust-mode.el:72:1: Error: Symbol’s value as variable is void: parinfer-rust-library
Compiling /home/justin/dev/parinfer-rust-mode/test-helper.el...
cask exec ert-runner test/**.el --quiet
...............................................................................................................................................

Ran 143 tests in 0.061 seconds

Thanks

  • Shaun Lebron for creating Parinfer
  • Jason Felice for creating and maintaining the parinfer-rust project
  • tianshu for helping me fall in love with parinfer-mode in Emacs.
  • Andrey Orst for his contributions to this project

About

Simplifying how you write Lisp

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages

  • Emacs Lisp 96.4%
  • Clojure 2.5%
  • Makefile 1.1%