Homepage: https://github.com/genovese/ess-smart-equals
Author: Christopher R. Genovese
Updated:
Flexible, context-sensitive assignment key for R/S
Assignment in R is syntactically complicated by a few features: 1. the historical role of '_' (underscore) as an assignment character in the S language; 2. the somewhat inconvenient-to-type, if conceptually pure, '<-' operator as the preferred assignment operator; 3. the ability to use either an '=', '<-', and a variety of other operators for assignment; and 4. the multiple roles that '=' can play, including for setting named arguments in a function call. This package offers a flexible, context-sensitive assignment key for R and S that is, by default, tied to the '=' key. This key inserts or completes relevant, properly spaced operators (assignment, comparison, etc.) based on the syntactic context in the code. It allows very easy cycling through the possible operators in that context. The contexts, the operators, and their cycling order in each context are customizable. The package defines a minor mode `ess-smart-equals-mode', intended for S-language modes (e.g., ess-r-mode, inferior-ess-r-mode, and ess-r-transcript-mode), that when enabled in a buffer activates the '=' key to to handle context-sensitive completion and cycling of relevant operators. When the mode is active and an '=' is pressed: 1. With a prefix argument or in specified contexts (which for most major modes means in strings or comments), just insert '='. 2. If an operator relevant to the context lies before point (with optional whitespace), it is replaced, cyclically, by the next operator in the configured list for that context. 3. Otherwise, if a prefix of an operator relevant to the context lies before point, that operator is completed. 4. Otherwise, the highest priority relevant operator is inserted with surrounding whitespace (see `ess-smart-equals-no-spaces'). Consecutive presses of '=' cycle through the relevant operators. After an '=', a backspace (or other configurable keys) removes the last operator and tab offers a choice of operators by completion. (Shift-backspace will delete one character only and restore the usual maning of backspace.) See `ess-smart-equals-cancel-keys'. By default, the minor mode activates the '=' key, but this can be customized by setting the option `ess-smart-equals-key' before this package is loaded. The function `ess-smart-equals-activate' arranges for the minor mode to be activated by mode hooks for any given list of major modes, defaulting to ESS major modes associated with R (ess-r-mode, inferior-ess-r-mode, ess-r-transcript-mode, ess-roxy-mode). Examples -------- In the left column below, ^ marks the location at which an '=' key is pressed, the remaining columns show the result of consecutive presses of '=' using the package's default settings. position of point. Before '=' Press '=' Another '=' Another '=' ---------- --------- ----------- ----------- foo^ foo <- ^ foo <<- ^ foo = ^ foo ^ foo <- ^ foo <<- ^ foo = ^ foo<^ foo <- ^ foo <<- ^ foo = ^ foo=^ foo = ^ foo -> ^ foo ->> ^ foo(a^ foo(a = ^ foo( a == ^ foo( a != ^ if( foo=^ if( foo == ^ if( foo != ^ if( foo <= ^ if( foo<^ if( foo < ^ if( foo > ^ if( foo >= ^ "foo ^ "foo =^ "foo ==^ "foo ===^ #...foo ^ #...foo =^ #...foo ==^ #...foo ===^ As a bonus, the value of the variable `ess-smart-equals-extra-ops' when this package is loaded, determines some other smart operators that may prove useful. Currently, only `brace', `paren', and `percent' are supported, causing `ess-smart-equals-open-brace', `ess-smart-equals-open-paren', and `ess-smart-equals-percent' to be bound to '{', '(', and '%', respectively. The first two of these configurably places a properly indented and spaced matching pair at point or around the region if active. The paren pair also includes a magic space with a convenient keymap for managing parens. See the readme. See the customizable variable `ess-smart-equals-brace-newlines' for configuring the newlines in braces. The third operator (`ess-smart-equals-percent') performs matching of %-operators. Finally, the primary user facing functions are named with a prefix `ess-smart-equals-' to avoid conflicts with other packages. Because this is long, the internal functions and objects use a shorter (but still distinctive) prefix `essmeq-'. Installation and Initialization ------------------------------- The package can be loaded from MELPA using `package-install' or another Emacs package manager. Alternatively, you can clone or download the source directly from the github repository and put the file `ess-smart-equals.el' in your Emacs load path. A variety of activation options is described below, but tl;dr: the recommended way to activate the mode (e.g., in your init file) is either directly with (setq ess-smart-equals-extra-ops '(brace paren percent)) (with-eval-after-load 'ess-r-mode (require 'ess-smart-equals) (ess-smart-equals-activate)) or with use-package: (use-package ess-smart-equals :init (setq ess-smart-equals-extra-ops '(brace paren percent)) :after (:any ess-r-mode inferior-ess-r-mode ess-r-transcript-mode) :config (ess-smart-equals-activate)) A more detailed description follows, if you want to see variations. To activate, you need only do (with-eval-after-load 'ess-r-mode (require 'ess-smart-equals) (ess-smart-equals-activate)) somewhere in your init file, which will add `ess-smart-equals-mode' to a prespecified (but customizable) list of mode hooks. For those who use the outstanding `use-package', you can do (use-package ess-smart-equals :after (:any ess-r-mode inferior-ess-r-mode ess-r-transcript-mode) :config (ess-smart-equals-activate)) somewhere in your init file. An equivalent but less concise version of this is (use-package ess-smart-equals :after (:any ess-r-mode inferior-ess-r-mode ess-r-transcript-mode) :hook ((ess-r-mode . ess-smart-equals-mode) (inferior-ess-r-mode . ess-smart-equals-mode) (ess-r-transcript-mode . ess-smart-equals-mode) (ess-roxy-mode . ess-smart-equals-mode)) To also activate the extra smart operators and bind them automatically, you can replace this with (use-package ess-smart-equals :init (setq ess-smart-equals-extra-ops '(brace paren percent)) :after (:any ess-r-mode inferior-ess-r-mode ess-r-transcript-mode) :config (ess-smart-equals-activate)) Details on customization are provided in the README file. Testing ------- To run the tests, install cask and do `cask install' in the ess-smart-equals project directory. Then, at the command line, from the project root directory do cask exec ert-runner cask exec ecukes --reporter magnars and if manual testing is desired do cask emacs -Q -l test/manual-init.el --eval '(cd "~/")' & Additional test cases are welcome in pull requests.