Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Request: include support for R package magrittr #96

Closed
uhkeller opened this issue May 27, 2014 · 11 comments
Closed

Request: include support for R package magrittr #96

uhkeller opened this issue May 27, 2014 · 11 comments

Comments

@uhkeller
Copy link

The R package magrittr defines the pipe-forwarding binary operator %>% that makes for much more readable code in my experience. It would be nice if ESS could provide support for this operator by a) providing a key binding for it and b) highlighting it as it does other operators.

@mmaechler
Copy link
Member

Sorry, dear UH, but I pretty strongly disagree that ESS itself should start providing support for such things... There won't be an end if we start here...
OTOH, we may think of providing hooks for ESS extensions.. that you could provide and would be responsible for maintaining.

@gaborcsardi
Copy link

Here is some code for

  1. providing a key binding for %>%,
  2. highlighting it, and
  3. writing it as a nice unicode triple arrow character.

This is how it looks:
https://raw.githubusercontent.com/gaborcsardi/dot-emacs/master/screenshot-2.png

;; Pretty arrows and magrittr pipes in R
(defvar pretty-alist
  (cl-pairlis '() '()))
(add-to-list 'pretty-alist '("%>%" . "⇛"))
(add-to-list 'pretty-alist '("<-" . "⇐"))
(defun pretty-things ()
  (mapc
   (lambda (x)
     (let ((word (car x))
           (char (cdr x)))
       (font-lock-add-keywords
        nil
        `((,(concat "\\(^\\|[^a-zA-Z0-9]\\)\\(" word "\\)[a-zA-Z]")
            (0 (progn
                 (decompose-region (match-beginning 2) (match-end 2))
                 nil)))))
       (font-lock-add-keywords
        nil
        `((,(concat "\\(^\\|[^a-zA-Z0-9]\\)\\(" word "\\)[^a-zA-Z]")
            (0 (progn
                 (compose-region (match-beginning 2) (match-end 2)
                  ,char)
                 nil)))))))
   pretty-alist))

(add-hook 'R-mode-hook
      (lambda ()
        (font-lock-add-keywords nil
                 '(("\\(%>%\\)" 1
                    font-lock-builtin-face t)))))

(define-key ess-mode-map [(super .)] "%>%")

@vspinu
Copy link
Member

vspinu commented Aug 10, 2014

I tend to agree with Martin. This seems like a good idea for a more general package "pretty-things". magrittr is used pretty marginally and I would not include such a general feature for its sake only. Your code is also not in the final production shape and more work need to be done to properly integrate into ESS smart operators, font-locking and customization system.

On the other hand I like the idea of lambda and composition that would make R even more functional than it is. I think you guys should try and push pipe and lambda to R core. It would make a great addition. I would also like to see threading macros (like -> and ->> in clojure).

To wrap up, we would prefer to wait and see. If magrittr takes off and gets some traction we would be happy to reconsider.

@vspinu vspinu closed this as completed Aug 10, 2014
@mmaechler
Copy link
Member

Actually, I have learned quite a bit more about the issue in the mean time, notably about the relative importance of magrittr notably in the "Hadleyverse". I'm reopening therefore (with an excuse to @Vitoshka ; I should have taken up the issue myself..)

@mmaechler mmaechler reopened this Aug 11, 2014
@gtuckerkellogg
Copy link

magrittr is important in the Hadleyverse in part because other packages like dplyr also adopt the pipe. While the highlighting @gaborcsardi showed above works, can anyone suggest some elisp to indent after %>% properly in ESS? Right now ESS indentation of a pipeline looks like

library(dplyr)
foo <-  filter(mtcars, gear > 3) %>%
        filter(cyl < 6) %>%
            filter(carb == 2)

That is, every use of %>% increases the indentation. The examples I've seen documenting %>% keep all the pipes at a single level, that is:

foo <-  filter(mtcars, gear > 3) %>%
        filter(cyl < 6) %>%
        filter(carb == 2)

If support for %>% is under consideration for ESS, it would be great to address the indentation at the same time.

@vspinu
Copy link
Member

vspinu commented Jan 29, 2015

Have a look at ess-first-continued-statement-offset and ess-continued-statement-offset. I have

foo <-
    filter(mtcars, gear > 3) %>%
      filter(cyl < 6) %>%
      filter(carb == 2)

With the following style:

(add-to-list 'ess-style-alist
             '(my-style
               (ess-indent-level . 4)
               (ess-first-continued-statement-offset . 2)
               (ess-continued-statement-offset . 0)
               (ess-brace-offset . -4)
               (ess-expression-offset . 4)
               (ess-else-offset . 0)
               (ess-close-brace-offset . 0)
               (ess-brace-imaginary-offset . 0)
               (ess-continued-brace-offset . 0)
               (ess-arg-function-offset . 4)
           (ess-arg-function-offset-new-line . '(4))
               ))

(setq ess-default-style 'my-style)

@gtuckerkellogg
Copy link

Fantastic, thanks!

@kwstat
Copy link

kwstat commented Feb 24, 2015

For what it's worth...with key-chord-mode, I make it easier to type the pipe operator by using two quick ">" keystrokes:

(require 'key-chord)
(key-chord-mode 1)
(key-chord-define-global ">>" "%>%")

@vspinu vspinu closed this as completed in c92de55 Mar 12, 2015
@vspinu
Copy link
Member

vspinu commented Mar 12, 2015

I have added ess-R-fl-keyword:%op% to the ESS>font-lock menu and corresponding ess-%op%-face.

As to the binding, smart operators is not ESS's business. I am experimenting with key-combo now. It it implements ess-smart-underscore cycling idea on a much larger scale and looks very promisin . This is what I have right now:

(require 'key-combo)

(defvar key-combo-ess-default
  (append key-combo-common-default
      '((">"  . (" > " " %>% "))
        ("$"  . ("$" " %$% "))
        ("<>" . " %<>% ")
        ("*"  . ("*" " * "))
        ("^"  . ("^" " ^ "))
        ("/"  . ("/" " / "))
        ("~" . " ~ ")
        (":" . (":" "::" ":::"))
        (":="  . " := ") ; data.table
        ;; ("inn" . " %in% ") ; doesn't work
        ("->"  . " -> "))))

(key-combo-define-hook '(ess-mode-hook inferior-ess-mode-hook)
               'ess-key-combo-load-default
               key-combo-ess-default)

@dahtah
Copy link
Contributor

dahtah commented Mar 31, 2016

Using key-combo is a really good solution. The above didn't quite work on my setup, though (Emacs 24.4.1). Here's a working version:

(require 'key-combo)

(key-combo-mode 1)

(add-hook 'ess-mode-hook
        '(lambda()
           (key-combo-mode t)))

(add-hook 'inferior-ess-mode-hook
        '(lambda()
           (key-combo-mode t)))

(defvar key-combo-ess-default
      '((">"  . (" > " " %>% "))
        ("$"  . ("$" " %$% "))
        ("<>" . " %<>% ")
        ("*"  . ("*" " * "))
    ("%" . ("%" "%*%" "%%"))
        ("^"  . ("^" " ^ "))
        ("/"  . ("/" " / "))
        ("~" . " ~ ")
        (":" . (":" "::" ":::"))
        (":="  . " := ") ; data.table
        ("->"  . " -> ")))

(key-combo-define-hook '(ess-mode-hook inferior-ess-mode-hook)
               'ess-key-combo-load-default
               key-combo-ess-default)

@sumanstats
Copy link

Simple solution is to put this line in your init.el file:

(global-set-key (kbd "C-S-m") (lambda () (interactive) (insert "%>%")))

It will provide the same binding as rstudio for pipe operator of magrittr.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

8 participants