├── .gitignore ├── LICENSE ├── README.org └── tutorial ├── ess-customization.org ├── ess-customization.pdf ├── ess-customization.tex ├── ess-init.el ├── images ├── company-quickhelp.png ├── company.png ├── highlight_custom.png ├── highlight_default.png ├── lintr.png ├── rdired.png └── window_config.png └── slides-ess-customization.pdf /.gitignore: -------------------------------------------------------------------------------- 1 | tutorial/auto 2 | tutorial/_minted-ess-customization 3 | tutorial/ess_customization.R 4 | tutorial/speaker_notes.org 5 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 ess-intro 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.org: -------------------------------------------------------------------------------- 1 | #+TITLE: Customizing and extending Emacs Speaks Statistics 2 | #+AUTHOR: Frédéric Santos 3 | 4 | ** Goals 5 | - Showing how to customize Emacs and ESS as an advanced R IDE 6 | - Helping newcomers and beginners to have a more friendly and efficient setup 7 | - Helping users migrating from other IDEs to keep behaviours and habits they are used to 8 | - Showcasing some other Emacs packages that play well with ESS and may improve your coding experience 9 | 10 | ** Ressources 11 | *** Tutorial 12 | - [[https://github.com/ess-intro/presentation-ess-customization/blob/main/tutorial/ess-customization.org][Raw org file]] 13 | - [[https://github.com/ess-intro/presentation-ess-customization/blob/main/tutorial/ess-customization.pdf][Tutorial in PDF format]] 14 | - [[https://github.com/ess-intro/presentation-ess-customization/blob/main/tutorial/slides-ess-customization.pdf][Tutorial as beamer slides]] (superceded by the above PDF tutorial) 15 | - [[https://www.youtube.com/watch?v=Lf8qrLuvYp8][Video tutorial]] 16 | 17 | *** Emacs initialization file 18 | [[https://github.com/ess-intro/presentation-ess-customization/blob/main/tutorial/ess-init.el][A minimal init file]] for some possible customization of ESS is also provided. It should be adapted [[https://github.com/ess-intro/presentation-ess-customization/blob/4b4e388ce0b496b396d090f0121e3fb4785d640a/tutorial/ess-init.el#L127][(in particular for ~yasnippet~)]] according to your own setup and habits. 19 | -------------------------------------------------------------------------------- /tutorial/ess-customization.org: -------------------------------------------------------------------------------- 1 | #+TITLE: Customizing and extending Emacs Speaks Statistics 2 | #+SUBTITLE: Part of the ESS-Intro series 3 | #+AUTHOR: Frédéric Santos 4 | #+EMAIL: frederic.santos@u-bordeaux.fr 5 | #+DATE: \today 6 | #+LANGUAGE: en 7 | #+STARTUP: showall 8 | #+OPTIONS: email:t toc:t ^:nil 9 | #+LATEX_HEADER: \usepackage[english]{babel} 10 | #+LATEX_HEADER: \usepackage{a4wide} 11 | #+LATEX_HEADER: \usepackage{mathpazo} 12 | #+LATEX_HEADER: \usepackage{amsmath} 13 | #+LATEX_HEADER: \usepackage{titlesec} 14 | #+LATEX_HEADER: \titlelabel{\thetitle.\quad} 15 | #+LATEX_HEADER: \usepackage[usenames,dvipsnames]{xcolor} % For colors with friendly names 16 | #+LATEX_HEADER: \usepackage{minted} 17 | #+LATEX_HEADER: \usepackage{mdframed} % Companion of minted for code blocks 18 | #+LATEX_HEADER: \usepackage{fancyvrb} % For verbatim R outputs 19 | #+LATEX_HEADER: \usemintedstyle{friendly} % set style if needed, see https://frama.link/jfRr8Lpj 20 | #+LATEX_HEADER: \mdfdefinestyle{mystyle}{linecolor=gray!30,backgroundcolor=gray!30} 21 | #+LATEX_HEADER: \BeforeBeginEnvironment{minted}{% 22 | #+LATEX_HEADER: \begin{mdframed}[style=mystyle]} 23 | #+LATEX_HEADER: \AfterEndEnvironment{minted}{% 24 | #+LATEX_HEADER: \end{mdframed}} 25 | #+LATEX_HEADER: %% Formatting of verbatim outputs (i.e., outputs of R results): 26 | #+LATEX_HEADER: \DefineVerbatimEnvironment{verbatim}{Verbatim}{% 27 | #+LATEX_HEADER: fontsize = \small, 28 | #+LATEX_HEADER: frame = leftline, 29 | #+LATEX_HEADER: formatcom = {\color{gray!97}} 30 | #+LATEX_HEADER: } 31 | #+LATEX_HEADER: \usepackage{float} 32 | #+LATEX_HEADER: \usepackage{url} 33 | #+LATEX_HEADER: %% Decalre new unicode characters for displaying trees: 34 | #+LATEX_HEADER: \DeclareUnicodeCharacter{2514}{\mbox{\kern.23em \vrule height2.2exdepth-1.8ptwidth.4pt\vrule height2.2ptdepth-1.8ptwidth.23em}} 35 | #+LATEX_HEADER: \DeclareUnicodeCharacter{2500}{\mbox{\vrule height2.2ptdepth-1.8ptwidth.5em}} 36 | #+PROPERTY: header-args:emacs-lisp :tangle ess-init.el 37 | 38 | * Introductory words 39 | ** A short tutorial for customizing ESS 40 | This document is a part of the ESS-Intro tutorial series. A full list of tutorials is available online at https://github.com/ess-intro. 41 | 42 | If you are are totally new to Emacs, you should probably begin with the tutorial "[[https://github.com/ess-intro/presentation-first-steps][First steps with Emacs]]" by Dirk Eddelbuettel. 43 | 44 | *** Target audience 45 | This tutorial is for R-users beginning to use Emacs Speaks Statistics (ESS). We only assume that you have mild familiarity with Emacs, and that you know how to customize Emacs by filling your ~.emacs~ or ~init.el~ file. 46 | 47 | *** Goals 48 | - Helping newcomers and beginners to have a more friendly and efficient setup 49 | - Helping users migrating from other IDEs to keep behaviours and habits they are used to 50 | - Showcasing some other Emacs packages that play well with ESS and may improve your coding experience 51 | 52 | *** Video tutorial 53 | This document is a written companion for the video tutorial available at: 54 | 55 | #+begin_center 56 | https://www.youtube.com/watch?v=Lf8qrLuvYp8 57 | #+end_center 58 | 59 | 60 | *** An opinionated tutorial? 61 | Some parts of this tutorial (e.g., replacing ~Flymake~ by ~Flycheck~ for syntax checking, or using ~company~ instead of other solutions for auto-completion) might be seen as quite opinionated. However, when several options or approaches were available for a given task, the most widespread and efficient (I hope!) was presented. 62 | 63 | If you prefer other approaches, or simply want to give a try to some other ones, the ESS manual remains the canonical and exhaustive documentation: http://ess.r-project.org/Manual/ess.html 64 | 65 | Feedbacks, fixes and contributions are welcome, and can be addressed [[https://github.com/ess-intro/presentation-ess-customization/issues][through the Github repository]]. 66 | 67 | ** A word about ~use-package~ 68 | In this document, several pieces of Emacs Lisp code will be proposed so that you can use them in your init file. Because it will provide a more reproducible setup in the following steps, it is assumed that you use [[https://jwiegley.github.io/use-package/][~use-package~]] for your init file. The Emacs Lisp code can be adapted in a straightforward manner if you do not use it. 69 | 70 | As a reminder, this is the minimal code to add in your init file so as to use ~use-package~, once it has been installed: 71 | 72 | #+begin_src emacs-lisp :eval no 73 | ;; Make sure that use-package is installed: 74 | (unless (package-installed-p 'use-package) 75 | (package-refresh-contents) 76 | (package-install 'use-package)) 77 | ;; Load use-package: 78 | (eval-when-compile 79 | (require 'use-package)) 80 | #+end_src 81 | 82 | * ESS customization 83 | ** Visibility of code evaluation 84 | From an R source file (i.e., an ESS[R] buffer), you can send code to the underlying R process with shortcuts like ~C-c C-b~ (~ess-eval-buffer~), ~C-RET~ (~ess-eval-region-or-line-and-step~), etc. 85 | 86 | In the inferior R process buffer, ESS can display either both the commands sent and their results, or only the results. The choice between the two can be made through the variable ~ess-eval-visibly~. 87 | 88 | This variable can be ~t~ (eval visibly and wait for process) or ~nil~ (eval invisibly); but by default it is set to ~‘nowait’~, which means that ESS shows input commands in the process buffer, but allows for further editing in the source buffer even while the previous instructions sent are still running. This way, ESS is never freezing while evaluating code. 89 | 90 | If you prefer to eval R code invisibly, add in your init file: 91 | 92 | #+begin_src emacs-lisp :eval no 93 | (setq ess-eval-visibly nil) 94 | #+end_src 95 | 96 | ** Syntactic highlighting in ESS R source buffers 97 | By default, ESS highlights literals, assignments, source functions and reserved words. An example of default syntactic highlighting is as follows: 98 | 99 | #+NAME: fig-default-highlight 100 | #+CAPTION: Default patterns for syntactic highlighting. 101 | #+ATTR_LATEX: :width 0.5 \textwidth 102 | [[./images/highlight_default.png]] 103 | 104 | You can add more patterns to be highlighted, or remove some of them, by customizing the variable ~ess-R-font-lock-keywords~. 105 | 106 | For instance, if you also want the numbers and the function calls to be highlighted: 107 | 108 | #+begin_src emacs-lisp :eval no 109 | ;; Font lock keywords for syntactic highlighting: 110 | (setq ess-R-font-lock-keywords 111 | '((ess-R-fl-keyword:keywords . t) 112 | (ess-R-fl-keyword:constants . t) 113 | (ess-R-fl-keyword:modifiers . t) 114 | (ess-R-fl-keyword:fun-defs . t) 115 | (ess-R-fl-keyword:assign-ops . t) 116 | (ess-R-fl-keyword:%op% . t) 117 | (ess-fl-keyword:fun-calls . t) 118 | (ess-fl-keyword:numbers . t) 119 | (ess-fl-keyword:operators) 120 | (ess-fl-keyword:delimiters) 121 | (ess-fl-keyword:=) 122 | (ess-R-fl-keyword:F&T . t))) 123 | #+end_src 124 | 125 | The same code is now highlighted differently, and maybe somewhat more clearly: 126 | 127 | #+NAME: fig-default-highlight 128 | #+CAPTION: More custom patterns for syntactic highlighting. 129 | #+ATTR_LATEX: :width 0.55 \textwidth 130 | [[./images/highlight_custom.png]] 131 | 132 | ** Parenthesis matching 133 | *** Seeing matching parentheses 134 | Directly taken from the ESS manual (http://ess.r-project.org/Manual/ess.html#Parens): 135 | 136 | #+begin_quote 137 | "Emacs has facilities for highlighting the parenthesis matching the parenthesis at point. This feature is very useful when trying to examine which parentheses match each other. This highlighting also indicates when parentheses are not matching." 138 | #+end_quote 139 | 140 | To activate parenthesis matching in ESS[R] (source) buffers, add this to your init file: 141 | 142 | #+begin_src emacs-lisp :results output 143 | ;; Activate global mode for parenthesis matching: 144 | (show-paren-mode) 145 | #+end_src 146 | 147 | *** Navigating through matching parentheses 148 | Here are some convenient tricks for navigating through parenthetical groups (this can be useful when dealing with large paren groups, e.g. when developing a shiny UI): 149 | 150 | #+CAPTION: Some useful shortcuts for dealing with parenthetical groups. 151 | |-----------+-----------------------------------------------------------------| 152 | | Shortcut | ~Elisp function~ (Docstring) | 153 | |-----------+-----------------------------------------------------------------| 154 | | ~C-M-p~ | ~backward-list~ (Move backward across one balanced paren group) | 155 | | ~C-M-n~ | ~forward-list~ (Move forward across one balanced paren group) | 156 | | ~C-M-SPC~ | ~mark-sexp~ (Set mark at the end of the paren group) | 157 | | ~C-M-k~ | ~kill-sexp~ (Kill from point to end of paren group) | 158 | |-----------+-----------------------------------------------------------------| 159 | 160 | For instance, when the point is over a closing parenthesis, ~C-M-p~ brings you to the matching opening parenthesis. Then, ~C-M-k~ kills to whole paren group. 161 | 162 | ** Syntax checker 163 | *** Syntax checking: ~Flycheck~ vs. ~Flymake~ 164 | ESS has facilities for on-the-fly syntax checking. Instead of using ~Flymake~, which is the default choice, using [[https://www.flycheck.org/en/latest/][~Flycheck~]] appears to be a better and more stable option. The ~Flycheck~ documentation allows for a comparison between those two packages: 165 | https://www.flycheck.org/en/latest/user/flycheck-versus-flymake.html 166 | 167 | To switch from ~Flymake~ to ~Flycheck~, you can add the following in your init file: 168 | 169 | #+begin_src emacs-lisp :results output 170 | ;; Remove Flymake support: 171 | (setq ess-use-flymake nil) 172 | ;; Replace it (globally) by Flycheck: 173 | (use-package flycheck 174 | :ensure t 175 | :init 176 | (global-flycheck-mode t)) 177 | #+end_src 178 | 179 | *** On-the-fly syntax checking with ~Flycheck~ 180 | Using ~Flycheck~ with ESS first requires you to install the R package ~lintr~: 181 | 182 | #+begin_src R :eval no 183 | ## Install stable CRAN version: 184 | install.packages("lintr", dep = TRUE) 185 | ## OR 186 | ## Install latest Github devel version: 187 | devtools::install_github("jimhester/lintr") 188 | #+end_src 189 | 190 | ([[https://emacs.stackexchange.com/questions/53018/flycheck-r-lintr-doesnt-find-anything][Some users reported]] that you might also have to create manually a folder =~/.R/lintr_cache= on your computer, if it was not created after the previous step.) 191 | 192 | ~lintr~ is an R package that offers facilities for static code analysis. It integrates with the main IDEs and text editors (Emacs, Rstudio, vim, etc.). In particular, it has native support for ESS + ~Flycheck~. 193 | 194 | Once both ~Flycheck~ and ~lintr~ are installed, your R code is analyzed "on-the-fly" while your are typing. Several checks are performed, including: 195 | - R code style: correct use of ~snake_case~, convenient spacing around all operators, etc. 196 | - undeclared variables in function body 197 | - bad use of ~=~ for variable assignment 198 | - unmatched parentheses 199 | 200 | The following screenshot (Fig. [[fig-lintr]]) gives some examples of such checks. To display all syntax error in a dedicated buffer, use =M-x flycheck-list-errors= (bound to =C-c ! l= by default). 201 | 202 | #+NAME: fig-lintr 203 | #+CAPTION: An example of syntax errors detected by ~lintr~ and displayed in a dedicated ~Flycheck~ buffer. 204 | #+ATTR_LATEX: :width \textwidth 205 | [[./images/lintr.png]] 206 | 207 | ** Some more steps towards an R IDE 208 | *** Rdired buffer 209 | [[http://ess.r-project.org/Manual/ess.html#Rdired][From the ESS manual:]] 210 | 211 | #+begin_quote 212 | "Ess-rdired provides a dired-like buffer for viewing, editing and plotting objects in your current R session. If you are used to using the dired (directory editor) facility in Emacs, this mode gives you similar functionality for R objects." 213 | #+end_quote 214 | 215 | All the R objects of the current R sessions are thus listed in the Rdired buffer, and it is possible to interact with them easily. For instance, type ~p~ for plotting an object, ~d~ for deleting it, etc. 216 | 217 | The screenshot in Figure [[fig-rdired]] shows the contents of an Rdired buffer for the R session associated to a small piece of code. 218 | 219 | #+NAME: fig-rdired 220 | #+CAPTION: An example of Rdired buffer (bottom window). 221 | #+ATTR_LATEX: :width 0.75 \textwidth 222 | [[./images/rdired.png]] 223 | 224 | Rdired buffers can be triggered manually with =M-x ess-rdired=, which might not be really convenient in practice. With the following piece of Emacs Lisp code, you will be able to use ~F9~ for both opening and closing the Rdired buffer, so that you can consult and display it only when necessary: 225 | 226 | #+begin_src emacs-lisp :results output 227 | ;; Open Rdired buffer with F9: 228 | (add-hook 'ess-r-mode-hook 229 | '(lambda () 230 | (local-set-key (kbd "") #'ess-rdired))) 231 | ;; Close Rdired buffer with F9 as well: 232 | (add-hook 'ess-rdired-mode-hook 233 | '(lambda () 234 | (local-set-key (kbd "") #'kill-buffer-and-window))) 235 | #+end_src 236 | 237 | *** Window management 238 | Users coming from other R IDEs may be used to a given window (or /pane/) configuration, e.g.: 239 | - R source code window at the top left 240 | - R console (i.e., inferior R process) at the top right 241 | - Rdired environment window at the bottom left 242 | - R help window at the bottom right 243 | 244 | This is only an arbitrary example, but quite a reasonable one. You will find in Figure [[fig-window-config]] a screenshot of such a window configuration. The corresponding Emacs Lisp code to add in your init file follows. 245 | 246 | #+NAME: fig-window-config 247 | #+CAPTION: An example of window configuration: ESS as an R IDE. 248 | #+ATTR_LATEX: :width \textwidth 249 | [[./images/window_config.png]] 250 | 251 | 252 | #+begin_src emacs-lisp :eval no 253 | ;; An example of window configuration: 254 | (setq display-buffer-alist 255 | '(("*R Dired" 256 | (display-buffer-reuse-window display-buffer-at-bottom) 257 | (window-width . 0.5) 258 | (window-height . 0.25) 259 | (reusable-frames . nil)) 260 | ("*R" 261 | (display-buffer-reuse-window display-buffer-in-side-window) 262 | (side . right) 263 | (slot . -1) 264 | (window-width . 0.5) 265 | (reusable-frames . nil)) 266 | ("*Help" 267 | (display-buffer-reuse-window display-buffer-in-side-window) 268 | (side . right) 269 | (slot . 1) 270 | (window-width . 0.5) 271 | (reusable-frames . nil)))) 272 | #+end_src 273 | 274 | #+begin_export latex 275 | \pagebreak 276 | #+end_export 277 | 278 | * Some useful Emacs packages 279 | ** Completion with company 280 | As mentioned [[https://ess.r-project.org/Manual/ess.html#Completion][in the ESS manual]], there are several completion frameworks for writing R code with ESS. The Emacs package [[https://company-mode.github.io/][~company~]] is an elegant solution, which also supports many other programming languages. Here is a minimal piece of Elisp code to add in your init file to install and load ~company~: 281 | 282 | #+begin_src emacs-lisp :eval no 283 | (use-package company 284 | :ensure t 285 | :config 286 | ;; Turn on company-mode globally: 287 | (add-hook 'after-init-hook 'global-company-mode) 288 | ;; Only activate company in R scripts, not in R console: 289 | (setq ess-use-company 'script-only)) 290 | #+end_src 291 | 292 | #+NAME: fig-company 293 | #+CAPTION: An example of code completion with ~company~: various candidates are proposed for the arguments of the function ~car::Anova()~. 294 | #+ATTR_LATEX: :width 0.64 \textwidth 295 | [[./images/company.png]] 296 | 297 | ~company~ offers completion candidates in various contexts: function name, argument name within a function call (as in Fig. [[fig-company]]), object name. It may seem preferable to adopt a non-intrusive workflow. For functions or objects names, completion starts automatically after you type a few letters. For arguments names within a function call, it is suggested that you trigger manually the completion only when you need it. This can be done with ~M-x company-complete~, or more conveniently, by binding this function to a convenient shortcut. For example, to bind it to ~F12~, add the following to your init file: 298 | 299 | #+begin_src emacs-lisp :eval no 300 | ;; Use F12 to trigger manually completion on R function args: 301 | (add-hook 'ess-r-mode-hook 302 | '(lambda () 303 | (local-set-key (kbd "") #'company-R-args))) 304 | #+end_src 305 | 306 | #+begin_export latex 307 | \pagebreak 308 | #+end_export 309 | 310 | Of course, further customization of ~company~ can be done in your init file. For instance: 311 | 312 | #+begin_src emacs-lisp :eval no 313 | ;; More customization options for company: 314 | (setq company-selection-wrap-around t 315 | ;; Align annotations to the right tooltip border: 316 | company-tooltip-align-annotations t 317 | ;; Idle delay in seconds until completion starts automatically: 318 | company-idle-delay 0.45 319 | ;; Completion will start after typing two letters: 320 | company-minimum-prefix-length 2 321 | ;; Maximum number of candidates in the tooltip: 322 | company-tooltip-limit 10) 323 | #+end_src 324 | 325 | ** Documentation popups with company-quickhelp 326 | [[https://github.com/company-mode/company-quickhelp][~company-quickhelp~]] allows for documentation popups, e.g. to further describe function arguments. 327 | 328 | #+CAPTION: Documentation popups with ~company-quickhelp~. 329 | #+ATTR_LATEX: :width \textwidth 330 | [[./images/company-quickhelp.png]] 331 | 332 | The minimal elisp code to add to your init file is straightforward: 333 | 334 | #+begin_src emacs-lisp :eval no 335 | (use-package company-quickhelp 336 | :ensure t 337 | :config 338 | ;; Load company-quickhelp globally: 339 | (company-quickhelp-mode) 340 | ;; Time before display of documentation popup: 341 | (setq company-quickhelp-delay 0.3)) 342 | #+end_src 343 | 344 | By default, the documentation popup is shown automatically. You can adjust the time before the popup shows up by customizing the variable ~company-quickhelp-delay~. 345 | 346 | ** Code snippets with yasnippet 347 | *** Key features 348 | [[https://github.com/joaotavora/yasnippet][~yasnippet~]] is an Emacs package allowing for the expansion of whole pieces of code you often use (/snippets/) from one given abbreviation. 349 | 350 | - All code snippets are stored as plain-text files in one given directory, so that they are easy to share with other people, and can be easily version controlled. 351 | - As a corollary, it is also easy to retrieve and use large collection of snippets already available online. For instance, Andrea Crotti maintains a great collection available at https://github.com/AndreaCrotti/yasnippet-snippets. 352 | - Although we only demonstrate its use within ESS and R here, note that ~yasnippet~ is not an R-specific solution, and that you can use it for any other programming language. 353 | 354 | *** Setting up ~yasnippet~ 355 | To set up ~yasnippet~, proceed through the following steps: 356 | 357 | 1. Create a directory ~snippets/~ at some convenient location, and add a subfolder ~ess-r-mode/~ in this directory. 358 | 2. Add the minimal following code in your init file: 359 | #+begin_src emacs-lisp :eval no 360 | (use-package yasnippet 361 | :ensure t 362 | :config 363 | ;; Indicate the directory containing your snippets: 364 | (setq yas-snippet-dirs '("path/to/your/snippets")) 365 | ;; Load your snippets on startup: 366 | (yas-reload-all) 367 | ;; Turn on yasnippet (minor) mode when editing R files: 368 | (add-hook 'ess-r-mode-hook #'yas-minor-mode)) 369 | #+end_src 370 | 3. You can now fill your ~snippets/ess-r-mode/~ directory with your own snippets. For instance, create a file ~function~ (without any extension) in this directory, with the following contents: 371 | #+begin_example 372 | #name : function 373 | #key : fun 374 | # -- 375 | ${1:name} <- function(${2:args}) { 376 | ${3:body} 377 | } 378 | #+end_example 379 | Each snippet has a unique ~name~, and can be triggered by typing a given ~key~ (followed by ~TAB~). As we will see later on, the present snippet allows for the expansion of a template for defining new R functions more easily. The ~yasnippet~ manual gives more details about the expected syntax to define your own code snippets: http://joaotavora.github.io/yasnippet/. 380 | 381 | 4. Now your ~snippets~ directory should look like: 382 | #+begin_example 383 | └── snippets 384 | └── ess-r-mode 385 | └── function 386 | #+end_example 387 | 388 | Feel free to add or retrieve (a lot!) more snippets, i.e. to add more template files within the ~ess-r-mode~ sub-directory. 389 | 390 | *** Using ~yasnippet~ in an ESS[R] buffer 391 | While you are editing an R source file with ESS, each snippet can be triggered by typing its ~key~ and then pressing ~TAB~. You can then navigate through the placeholders of the expanded template by pressing ~TAB~ again. 392 | 393 | For instance, with our previously defined snippet, typing ~fun~ followed by ~TAB~ will expand the full ~function~ template; you will then be able to specify easily a value for each of the three placeholders (the function's ~name~, its ~args~ and ~body~). 394 | 395 | Note that ~yasnippet~ has a short video tutorial, available at https://www.youtube.com/watch?v=ZCGmZK4V7Sg. 396 | -------------------------------------------------------------------------------- /tutorial/ess-customization.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ess-intro/presentation-ess-customization/2a4d87fe09186047f411bfa653648bbb4c4e8991/tutorial/ess-customization.pdf -------------------------------------------------------------------------------- /tutorial/ess-customization.tex: -------------------------------------------------------------------------------- 1 | % Created 2021-03-31 mer. 09:27 2 | % Intended LaTeX compiler: pdflatex 3 | \documentclass[11pt]{article} 4 | \usepackage[utf8]{inputenc} 5 | \usepackage[T1]{fontenc} 6 | \usepackage{graphicx} 7 | \usepackage{grffile} 8 | \usepackage{longtable} 9 | \usepackage{wrapfig} 10 | \usepackage{rotating} 11 | \usepackage[normalem]{ulem} 12 | \usepackage{amsmath} 13 | \usepackage{textcomp} 14 | \usepackage{amssymb} 15 | \usepackage{capt-of} 16 | \usepackage{hyperref} 17 | \usepackage{color} 18 | \usepackage[english]{babel} 19 | \usepackage{a4wide} 20 | \usepackage{mathpazo} 21 | \usepackage{amsmath} 22 | \usepackage{titlesec} 23 | \titlelabel{\thetitle.\quad} 24 | \usepackage[usenames,dvipsnames]{xcolor} % For colors with friendly names 25 | \usepackage{minted} 26 | \usepackage{mdframed} % Companion of minted for code blocks 27 | \usepackage{fancyvrb} % For verbatim R outputs 28 | \usemintedstyle{friendly} % set style if needed, see https://frama.link/jfRr8Lpj 29 | \mdfdefinestyle{mystyle}{linecolor=gray!30,backgroundcolor=gray!30} 30 | \BeforeBeginEnvironment{minted}{% 31 | \begin{mdframed}[style=mystyle]} 32 | \AfterEndEnvironment{minted}{% 33 | \end{mdframed}} 34 | %% Formatting of verbatim outputs (i.e., outputs of R results): 35 | \DefineVerbatimEnvironment{verbatim}{Verbatim}{% 36 | fontsize = \small, 37 | frame = leftline, 38 | formatcom = {\color{gray!97}} 39 | } 40 | \usepackage{float} 41 | \usepackage{url} 42 | %% Decalre new unicode characters for displaying trees: 43 | \DeclareUnicodeCharacter{2514}{\mbox{\kern.23em \vrule height2.2exdepth-1.8ptwidth.4pt\vrule height2.2ptdepth-1.8ptwidth.23em}} 44 | \DeclareUnicodeCharacter{2500}{\mbox{\vrule height2.2ptdepth-1.8ptwidth.5em}} 45 | \author{Frédéric Santos\thanks{frederic.santos@u-bordeaux.fr}} 46 | \date{\today} 47 | \title{Customizing and extending Emacs Speaks Statistics\\\medskip 48 | \large Part of the ESS-Intro series} 49 | \hypersetup{ 50 | pdfauthor={Frédéric Santos}, 51 | pdftitle={Customizing and extending Emacs Speaks Statistics}, 52 | pdfkeywords={}, 53 | pdfsubject={}, 54 | pdfcreator={Emacs 27.1 (Org mode 9.4.5)}, 55 | pdflang={English}} 56 | \begin{document} 57 | 58 | \maketitle 59 | \tableofcontents 60 | 61 | 62 | \section{Introductory words} 63 | \label{sec:org795d064} 64 | \subsection{A short tutorial for customizing ESS} 65 | \label{sec:orgf7080c5} 66 | This document is a part of the ESS-Intro tutorial series. A full list of tutorials is available online at \url{https://github.com/ess-intro}. 67 | 68 | If you are are totally new to Emacs, you should probably begin with the tutorial ``\href{https://github.com/ess-intro/presentation-first-steps}{First steps with Emacs}'' by Dirk Eddelbuettel. 69 | 70 | \subsubsection{Target audience} 71 | \label{sec:org45650b4} 72 | This tutorial is for R-users beginning to use Emacs Speaks Statistics (ESS). We only assume that you have mild familiarity with Emacs, and that you know how to customize Emacs by filling your \texttt{.emacs} or \texttt{init.el} file. 73 | 74 | \subsubsection{Goals} 75 | \label{sec:orgec96ced} 76 | \begin{itemize} 77 | \item Helping newcomers and beginners to have a more friendly and efficient setup 78 | \item Helping users migrating from other IDEs to keep behaviours and habits they are used to 79 | \item Showcasing some other Emacs packages that play well with ESS and may improve your coding experience 80 | \end{itemize} 81 | 82 | \subsubsection{Video tutorial} 83 | \label{sec:org7d8cb0c} 84 | This document is a written companion for the video tutorial available at: 85 | 86 | \begin{center} 87 | \url{https://www.youtube.com/watch?v=Lf8qrLuvYp8} 88 | \end{center} 89 | 90 | 91 | \subsubsection{An opinionated tutorial?} 92 | \label{sec:orgaedb8ab} 93 | Some parts of this tutorial (e.g., replacing \texttt{Flymake} by \texttt{Flycheck} for syntax checking, or using \texttt{company} instead of other solutions for auto-completion) might be seen as quite opinionated. However, when several options or approaches were available for a given task, the most widespread and efficient (I hope!) was presented. 94 | 95 | If you prefer other approaches, or simply want to give a try to some other ones, the ESS manual remains the canonical and exhaustive documentation: \url{http://ess.r-project.org/Manual/ess.html} 96 | 97 | Feedbacks, fixes and contributions are welcome, and can be addressed \href{https://github.com/ess-intro/presentation-ess-customization/issues}{through the Github repository}. 98 | 99 | \subsection{A word about \texttt{use-package}} 100 | \label{sec:org1e31867} 101 | In this document, several pieces of Emacs Lisp code will be proposed so that you can use them in your init file. Because it will provide a more reproducible setup in the following steps, it is assumed that you use \href{https://jwiegley.github.io/use-package/}{\texttt{use-package}} for your init file. The Emacs Lisp code can be adapted in a straightforward manner if you do not use it. 102 | 103 | As a reminder, this is the minimal code to add in your init file so as to use \texttt{use-package}, once it has been installed: 104 | 105 | \begin{minted}[]{common-lisp} 106 | ;; Make sure that use-package is installed: 107 | (unless (package-installed-p 'use-package) 108 | (package-refresh-contents) 109 | (package-install 'use-package)) 110 | ;; Load use-package: 111 | (eval-when-compile 112 | (require 'use-package)) 113 | \end{minted} 114 | 115 | \section{ESS customization} 116 | \label{sec:org5c6aa43} 117 | \subsection{Visibility of code evaluation} 118 | \label{sec:org0cde447} 119 | From an R source file (i.e., an ESS[R] buffer), you can send code to the underlying R process with shortcuts like \texttt{C-c C-b} (\texttt{ess-eval-buffer}), \texttt{C-RET} (\texttt{ess-eval-region-or-line-and-step}), etc. 120 | 121 | In the inferior R process buffer, ESS can display either both the commands sent and their results, or only the results. The choice between the two can be made through the variable \texttt{ess-eval-visibly}. 122 | 123 | This variable can be \texttt{t} (eval visibly and wait for process) or \texttt{nil} (eval invisibly); but by default it is set to \texttt{‘nowait’}, which means that ESS shows input commands in the process buffer, but allows for further editing in the source buffer even while the previous instructions sent are still running. This way, ESS is never freezing while evaluating code. 124 | 125 | If you prefer to eval R code invisibly, add in your init file: 126 | 127 | \begin{minted}[]{common-lisp} 128 | (setq ess-eval-visibly nil) 129 | \end{minted} 130 | 131 | \subsection{Syntactic highlighting in ESS R source buffers} 132 | \label{sec:org8fa3961} 133 | By default, ESS highlights literals, assignments, source functions and reserved words. An example of default syntactic highlighting is as follows: 134 | 135 | \begin{figure}[htbp] 136 | \centering 137 | \includegraphics[width=0.5 \textwidth]{./images/highlight_default.png} 138 | \caption{\label{fig:orgdc616d0}Default patterns for syntactic highlighting.} 139 | \end{figure} 140 | 141 | You can add more patterns to be highlighted, or remove some of them, by customizing the variable \texttt{ess-R-font-lock-keywords}. 142 | 143 | For instance, if you also want the numbers and the function calls to be highlighted: 144 | 145 | \begin{minted}[]{common-lisp} 146 | ;; Font lock keywords for syntactic highlighting: 147 | (setq ess-R-font-lock-keywords 148 | '((ess-R-fl-keyword:keywords . t) 149 | (ess-R-fl-keyword:constants . t) 150 | (ess-R-fl-keyword:modifiers . t) 151 | (ess-R-fl-keyword:fun-defs . t) 152 | (ess-R-fl-keyword:assign-ops . t) 153 | (ess-R-fl-keyword:%op% . t) 154 | (ess-fl-keyword:fun-calls . t) 155 | (ess-fl-keyword:numbers . t) 156 | (ess-fl-keyword:operators) 157 | (ess-fl-keyword:delimiters) 158 | (ess-fl-keyword:=) 159 | (ess-R-fl-keyword:F&T . t))) 160 | \end{minted} 161 | 162 | The same code is now highlighted differently, and maybe somewhat more clearly: 163 | 164 | \begin{figure}[htbp] 165 | \centering 166 | \includegraphics[width=0.55 \textwidth]{./images/highlight_custom.png} 167 | \caption{\label{fig:orgc94beae}More custom patterns for syntactic highlighting.} 168 | \end{figure} 169 | 170 | \subsection{Parenthesis matching} 171 | \label{sec:org8ef6990} 172 | \subsubsection{Seeing matching parentheses} 173 | \label{sec:org0c63349} 174 | Directly taken from the ESS manual (\url{http://ess.r-project.org/Manual/ess.html\#Parens}): 175 | 176 | \begin{quote} 177 | ``Emacs has facilities for highlighting the parenthesis matching the parenthesis at point. This feature is very useful when trying to examine which parentheses match each other. This highlighting also indicates when parentheses are not matching.'' 178 | \end{quote} 179 | 180 | To activate parenthesis matching in ESS[R] (source) buffers, add this to your init file: 181 | 182 | \begin{minted}[]{common-lisp} 183 | ;; Activate global mode for parenthesis matching: 184 | (show-paren-mode) 185 | \end{minted} 186 | 187 | \subsubsection{Navigating through matching parentheses} 188 | \label{sec:org6b91289} 189 | Here are some convenient tricks for navigating through parenthetical groups (this can be useful when dealing with large paren groups, e.g. when developing a shiny UI): 190 | 191 | \begin{table}[htbp] 192 | \centering 193 | \begin{tabular}{ll} 194 | \hline 195 | Shortcut & \texttt{Elisp function} (Docstring)\\ 196 | \hline 197 | \texttt{C-M-p} & \texttt{backward-list} (Move backward across one balanced paren group)\\ 198 | \texttt{C-M-n} & \texttt{forward-list} (Move forward across one balanced paren group)\\ 199 | \texttt{C-M-SPC} & \texttt{mark-sexp} (Set mark at the end of the paren group)\\ 200 | \texttt{C-M-k} & \texttt{kill-sexp} (Kill from point to end of paren group)\\ 201 | \hline 202 | \end{tabular} 203 | \caption{Some useful shortcuts for dealing with parenthetical groups.} 204 | 205 | \end{table} 206 | 207 | For instance, when the point is over a closing parenthesis, \texttt{C-M-p} brings you to the matching opening parenthesis. Then, \texttt{C-M-k} kills to whole paren group. 208 | 209 | \subsection{Syntax checker} 210 | \label{sec:org1595182} 211 | \subsubsection{Syntax checking: \texttt{Flycheck} vs. \texttt{Flymake}} 212 | \label{sec:org20eddbe} 213 | ESS has facilities for on-the-fly syntax checking. Instead of using \texttt{Flymake}, which is the default choice, using \href{https://www.flycheck.org/en/latest/}{\texttt{Flycheck}} appears to be a better and more stable option. The \texttt{Flycheck} documentation allows for a comparison between those two packages: 214 | \url{https://www.flycheck.org/en/latest/user/flycheck-versus-flymake.html} 215 | 216 | To switch from \texttt{Flymake} to \texttt{Flycheck}, you can add the following in your init file: 217 | 218 | \begin{minted}[]{common-lisp} 219 | ;; Remove Flymake support: 220 | (setq ess-use-flymake nil) 221 | ;; Replace it (globally) by Flycheck: 222 | (use-package flycheck 223 | :ensure t 224 | :init 225 | (global-flycheck-mode t)) 226 | \end{minted} 227 | 228 | \subsubsection{On-the-fly syntax checking with \texttt{Flycheck}} 229 | \label{sec:orge85a15b} 230 | Using \texttt{Flycheck} with ESS first requires you to install the R package \texttt{lintr}: 231 | 232 | \begin{minted}[]{r} 233 | ## Install stable CRAN version: 234 | install.packages("lintr", dep = TRUE) 235 | ## OR 236 | ## Install latest Github devel version: 237 | devtools::install_github("jimhester/lintr") 238 | \end{minted} 239 | 240 | (\href{https://emacs.stackexchange.com/questions/53018/flycheck-r-lintr-doesnt-find-anything}{Some users reported} that you might also have to create manually a folder \texttt{\textasciitilde{}/.R/lintr\_cache} on your computer, if it was not created after the previous step.) 241 | 242 | \texttt{lintr} is an R package that offers facilities for static code analysis. It integrates with the main IDEs and text editors (Emacs, Rstudio, vim, etc.). In particular, it has native support for ESS + \texttt{Flycheck}. 243 | 244 | Once both \texttt{Flycheck} and \texttt{lintr} are installed, your R code is analyzed ``on-the-fly'' while your are typing. Several checks are performed, including: 245 | \begin{itemize} 246 | \item R code style: correct use of \texttt{snake\_case}, convenient spacing around all operators, etc. 247 | \item undeclared variables in function body 248 | \item bad use of \texttt{=} for variable assignment 249 | \item unmatched parentheses 250 | \end{itemize} 251 | 252 | The following screenshot (Fig. \ref{fig:org50cdeac}) gives some examples of such checks. To display all syntax error in a dedicated buffer, use \texttt{M-x flycheck-list-errors} (bound to \texttt{C-c ! l} by default). 253 | 254 | \begin{figure}[htbp] 255 | \centering 256 | \includegraphics[width=\textwidth]{./images/lintr.png} 257 | \caption{\label{fig:org50cdeac}An example of syntax errors detected by \texttt{lintr} and displayed in a dedicated \texttt{Flycheck} buffer.} 258 | \end{figure} 259 | 260 | \subsection{Some more steps towards an R IDE} 261 | \label{sec:org1fe77c0} 262 | \subsubsection{Rdired buffer} 263 | \label{sec:org7c0a814} 264 | \href{http://ess.r-project.org/Manual/ess.html\#Rdired}{From the ESS manual:} 265 | 266 | \begin{quote} 267 | ``Ess-rdired provides a dired-like buffer for viewing, editing and plotting objects in your current R session. If you are used to using the dired (directory editor) facility in Emacs, this mode gives you similar functionality for R objects.'' 268 | \end{quote} 269 | 270 | All the R objects of the current R sessions are thus listed in the Rdired buffer, and it is possible to interact with them easily. For instance, type \texttt{p} for plotting an object, \texttt{d} for deleting it, etc. 271 | 272 | The screenshot in Figure \ref{fig:org065fea9} shows the contents of an Rdired buffer for the R session associated to a small piece of code. 273 | 274 | \begin{figure}[htbp] 275 | \centering 276 | \includegraphics[width=0.75 \textwidth]{./images/rdired.png} 277 | \caption{\label{fig:org065fea9}An example of Rdired buffer (bottom window).} 278 | \end{figure} 279 | 280 | Rdired buffers can be triggered manually with \texttt{M-x ess-rdired}, which might not be really convenient in practice. With the following piece of Emacs Lisp code, you will be able to use \texttt{F9} for both opening and closing the Rdired buffer, so that you can consult and display it only when necessary: 281 | 282 | \begin{minted}[]{common-lisp} 283 | ;; Open Rdired buffer with F9: 284 | (add-hook 'ess-r-mode-hook 285 | '(lambda () 286 | (local-set-key (kbd "") #'ess-rdired))) 287 | ;; Close Rdired buffer with F9 as well: 288 | (add-hook 'ess-rdired-mode-hook 289 | '(lambda () 290 | (local-set-key (kbd "") #'kill-buffer-and-window))) 291 | \end{minted} 292 | 293 | \subsubsection{Window management} 294 | \label{sec:orgb6fd085} 295 | Users coming from other R IDEs may be used to a given window (or \emph{pane}) configuration, e.g.: 296 | \begin{itemize} 297 | \item R source code window at the top left 298 | \item R console (i.e., inferior R process) at the top right 299 | \item Rdired environment window at the bottom left 300 | \item R help window at the bottom right 301 | \end{itemize} 302 | 303 | This is only an arbitrary example, but quite a reasonable one. You will find in Figure \ref{fig:orgf85260e} a screenshot of such a window configuration. The corresponding Emacs Lisp code to add in your init file follows. 304 | 305 | \begin{figure}[htbp] 306 | \centering 307 | \includegraphics[width=\textwidth]{./images/window_config.png} 308 | \caption{\label{fig:orgf85260e}An example of window configuration: ESS as an R IDE.} 309 | \end{figure} 310 | 311 | 312 | \begin{minted}[]{common-lisp} 313 | ;; An example of window configuration: 314 | (setq display-buffer-alist 315 | '(("*R Dired" 316 | (display-buffer-reuse-window display-buffer-at-bottom) 317 | (window-width . 0.5) 318 | (window-height . 0.25) 319 | (reusable-frames . nil)) 320 | ("*R" 321 | (display-buffer-reuse-window display-buffer-in-side-window) 322 | (side . right) 323 | (slot . -1) 324 | (window-width . 0.5) 325 | (reusable-frames . nil)) 326 | ("*Help" 327 | (display-buffer-reuse-window display-buffer-in-side-window) 328 | (side . right) 329 | (slot . 1) 330 | (window-width . 0.5) 331 | (reusable-frames . nil)))) 332 | \end{minted} 333 | 334 | \pagebreak 335 | 336 | \section{Some useful Emacs packages} 337 | \label{sec:orgfdb4589} 338 | \subsection{Completion with company} 339 | \label{sec:org22a5943} 340 | As mentioned \href{https://ess.r-project.org/Manual/ess.html\#Completion}{in the ESS manual}, there are several completion frameworks for writing R code with ESS. The Emacs package \href{https://company-mode.github.io/}{\texttt{company}} is an elegant solution, which also supports many other programming languages. Here is a minimal piece of Elisp code to add in your init file to install and load \texttt{company}: 341 | 342 | \begin{minted}[]{common-lisp} 343 | (use-package company 344 | :ensure t 345 | :config 346 | ;; Turn on company-mode globally: 347 | (add-hook 'after-init-hook 'global-company-mode) 348 | ;; Only activate company in R scripts, not in R console: 349 | (setq ess-use-company 'script-only)) 350 | \end{minted} 351 | 352 | \begin{figure}[htbp] 353 | \centering 354 | \includegraphics[width=0.64 \textwidth]{./images/company.png} 355 | \caption{\label{fig:org7bf7e39}An example of code completion with \texttt{company}: various candidates are proposed for the arguments of the function \texttt{car::Anova()}.} 356 | \end{figure} 357 | 358 | \texttt{company} offers completion candidates in various contexts: function name, argument name within a function call (as in Fig. \ref{fig:org7bf7e39}), object name. It may seem preferable to adopt a non-intrusive workflow. For functions or objects names, completion starts automatically after you type a few letters. For arguments names within a function call, it is suggested that you trigger manually the completion only when you need it. This can be done with \texttt{M-x company-complete}, or more conveniently, by binding this function to a convenient shortcut. For example, to bind it to \texttt{F12}, add the following to your init file: 359 | 360 | \begin{minted}[]{common-lisp} 361 | ;; Use F12 to trigger manually completion on R function args: 362 | (add-hook 'ess-r-mode-hook 363 | '(lambda () 364 | (local-set-key (kbd "") #'company-R-args))) 365 | \end{minted} 366 | 367 | \pagebreak 368 | 369 | Of course, further customization of \texttt{company} can be done in your init file. For instance: 370 | 371 | \begin{minted}[]{common-lisp} 372 | ;; More customization options for company: 373 | (setq company-selection-wrap-around t 374 | ;; Align annotations to the right tooltip border: 375 | company-tooltip-align-annotations t 376 | ;; Idle delay in seconds until completion starts automatically: 377 | company-idle-delay 0.45 378 | ;; Completion will start after typing two letters: 379 | company-minimum-prefix-length 2 380 | ;; Maximum number of candidates in the tooltip: 381 | company-tooltip-limit 10) 382 | \end{minted} 383 | 384 | \subsection{Documentation popups with company-quickhelp} 385 | \label{sec:org1fac874} 386 | \href{https://github.com/company-mode/company-quickhelp}{\texttt{company-quickhelp}} allows for documentation popups, e.g. to further describe function arguments. 387 | 388 | \begin{figure}[htbp] 389 | \centering 390 | \includegraphics[width=\textwidth]{./images/company-quickhelp.png} 391 | \caption{Documentation popups with \texttt{company-quickhelp}.} 392 | \end{figure} 393 | 394 | The minimal elisp code to add to your init file is straightforward: 395 | 396 | \begin{minted}[]{common-lisp} 397 | (use-package company-quickhelp 398 | :ensure t 399 | :config 400 | ;; Load company-quickhelp globally: 401 | (company-quickhelp-mode) 402 | ;; Time before display of documentation popup: 403 | (setq company-quickhelp-delay 0.3)) 404 | \end{minted} 405 | 406 | By default, the documentation popup is shown automatically. You can adjust the time before the popup shows up by customizing the variable \texttt{company-quickhelp-delay}. 407 | 408 | \subsection{Code snippets with yasnippet} 409 | \label{sec:org261b148} 410 | \subsubsection{Key features} 411 | \label{sec:org94d8013} 412 | \href{https://github.com/joaotavora/yasnippet}{\texttt{yasnippet}} is an Emacs package allowing for the expansion of whole pieces of code you often use (\emph{snippets}) from one given abbreviation. 413 | 414 | \begin{itemize} 415 | \item All code snippets are stored as plain-text files in one given directory, so that they are easy to share with other people, and can be easily version controlled. 416 | \item As a corollary, it is also easy to retrieve and use large collection of snippets already available online. For instance, Andrea Crotti maintains a great collection available at \url{https://github.com/AndreaCrotti/yasnippet-snippets}. 417 | \item Although we only demonstrate its use within ESS and R here, note that \texttt{yasnippet} is not an R-specific solution, and that you can use it for any other programming language. 418 | \end{itemize} 419 | 420 | \subsubsection{Setting up \texttt{yasnippet}} 421 | \label{sec:orgfe8386b} 422 | To set up \texttt{yasnippet}, proceed through the following steps: 423 | 424 | \begin{enumerate} 425 | \item Create a directory \texttt{snippets/} at some convenient location, and add a subfolder \texttt{ess-r-mode/} in this directory. 426 | \item Add the minimal following code in your init file: 427 | \begin{minted}[]{common-lisp} 428 | (use-package yasnippet 429 | :ensure t 430 | :config 431 | ;; Indicate the directory containing your snippets: 432 | (setq yas-snippet-dirs '("path/to/your/snippets")) 433 | ;; Load your snippets on startup: 434 | (yas-reload-all) 435 | ;; Turn on yasnippet (minor) mode when editing R files: 436 | (add-hook 'ess-r-mode-hook #'yas-minor-mode)) 437 | \end{minted} 438 | \item You can now fill your \texttt{snippets/ess-r-mode/} directory with your own snippets. For instance, create a file \texttt{function} (without any extension) in this directory, with the following contents: 439 | \begin{verbatim} 440 | #name : function 441 | #key : fun 442 | # -- 443 | ${1:name} <- function(${2:args}) { 444 | ${3:body} 445 | } 446 | \end{verbatim} 447 | Each snippet has a unique \texttt{name}, and can be triggered by typing a given \texttt{key} (followed by \texttt{TAB}). As we will see later on, the present snippet allows for the expansion of a template for defining new R functions more easily. The \texttt{yasnippet} manual gives more details about the expected syntax to define your own code snippets: \url{http://joaotavora.github.io/yasnippet/}. 448 | 449 | \item Now your \texttt{snippets} directory should look like: 450 | \begin{verbatim} 451 | └── snippets 452 | └── ess-r-mode 453 | └── function 454 | \end{verbatim} 455 | 456 | Feel free to add or retrieve (a lot!) more snippets, i.e. to add more template files within the \texttt{ess-r-mode} sub-directory. 457 | \end{enumerate} 458 | 459 | \subsubsection{Using \texttt{yasnippet} in an ESS[R] buffer} 460 | \label{sec:orgcb772f3} 461 | While you are editing an R source file with ESS, each snippet can be triggered by typing its \texttt{key} and then pressing \texttt{TAB}. You can then navigate through the placeholders of the expanded template by pressing \texttt{TAB} again. 462 | 463 | For instance, with our previously defined snippet, typing \texttt{fun} followed by \texttt{TAB} will expand the full \texttt{function} template; you will then be able to specify easily a value for each of the three placeholders (the function's \texttt{name}, its \texttt{args} and \texttt{body}). 464 | 465 | Note that \texttt{yasnippet} has a short video tutorial, available at \url{https://www.youtube.com/watch?v=ZCGmZK4V7Sg}. 466 | \end{document} -------------------------------------------------------------------------------- /tutorial/ess-init.el: -------------------------------------------------------------------------------- 1 | ;;; ess-init.el --- A minimal init file with ESS customization. 2 | ;; 3 | ;; Copyleft, 2021. 4 | ;; Author: Frédéric Santos 5 | ;; URL: https://github.com/ess-intro/presentation-ess-customization 6 | ;; 7 | ;;; Commentary: 8 | ;; Provides possible inspiration for customizing ESS (without any warranty). 9 | ;; Should be adapted according to your own setup, in particular for yasnippet (l. 127). 10 | ;; 11 | ;;; Code: 12 | 13 | ;; Early birds: 14 | (package-initialize) 15 | (setq inhibit-splash-screen t) 16 | (global-display-line-numbers-mode) 17 | 18 | ;; Make sure that use-package is installed: 19 | (unless (package-installed-p 'use-package) 20 | (package-refresh-contents) 21 | (package-install 'use-package)) 22 | ;; Load use-package: 23 | (eval-when-compile 24 | (require 'use-package)) 25 | 26 | ;; Example of theme: 27 | (use-package solarized-theme 28 | :ensure t 29 | :config 30 | (setq solarized-distinct-fringe-background t) 31 | (load-theme 'solarized-light t)) 32 | 33 | ;; Code visibility: 34 | (setq ess-eval-visibly 'nowait) 35 | 36 | ;; Font lock keywords for syntactic highlighting: 37 | (setq ess-R-font-lock-keywords 38 | '((ess-R-fl-keyword:keywords . t) 39 | (ess-R-fl-keyword:constants . t) 40 | (ess-R-fl-keyword:modifiers . t) 41 | (ess-R-fl-keyword:fun-defs . t) 42 | (ess-R-fl-keyword:assign-ops . t) 43 | (ess-R-fl-keyword:%op% . t) 44 | (ess-fl-keyword:fun-calls . t) 45 | (ess-fl-keyword:numbers . t) 46 | (ess-fl-keyword:operators) 47 | (ess-fl-keyword:delimiters) 48 | (ess-fl-keyword:=) 49 | (ess-R-fl-keyword:F&T . t))) 50 | 51 | ;; Activate global mode for parenthesis matching: 52 | (show-paren-mode) 53 | 54 | ;; Remove Flymake support: 55 | (setq ess-use-flymake nil) 56 | ;; Replace it (globally) by Flycheck: 57 | (use-package flycheck 58 | :ensure t 59 | :init 60 | (global-flycheck-mode t)) 61 | 62 | ;; Open Rdired buffer with F9: 63 | (add-hook 'ess-r-mode-hook 64 | '(lambda () 65 | (local-set-key (kbd "") #'ess-rdired))) 66 | ;; Close Rdired buffer with F9 as well: 67 | (add-hook 'ess-rdired-mode-hook 68 | '(lambda () 69 | (local-set-key (kbd "") #'kill-buffer-and-window))) 70 | 71 | ;; An example of window configuration: 72 | (setq display-buffer-alist 73 | '(("*R Dired" 74 | (display-buffer-reuse-window display-buffer-at-bottom) 75 | (window-width . 0.5) 76 | (window-height . 0.25) 77 | (reusable-frames . nil)) 78 | ("*R" 79 | (display-buffer-reuse-window display-buffer-in-side-window) 80 | (side . right) 81 | (slot . -1) 82 | (window-width . 0.5) 83 | (reusable-frames . nil)) 84 | ("*Help" 85 | (display-buffer-reuse-window display-buffer-in-side-window) 86 | (side . right) 87 | (slot . 1) 88 | (window-width . 0.5) 89 | (reusable-frames . nil)))) 90 | 91 | (use-package company 92 | :ensure t 93 | :config 94 | ;; Turn on company-mode globally: 95 | (add-hook 'after-init-hook 'global-company-mode) 96 | ;; Only activate company in R scripts, not in R console: 97 | (setq ess-use-company 'script-only)) 98 | 99 | ;; Use F12 to trigger manually completion on R function args: 100 | (add-hook 'ess-r-mode-hook 101 | '(lambda () 102 | (local-set-key (kbd "") #'company-R-args))) 103 | 104 | ;; More customization options for company: 105 | (setq company-selection-wrap-around t 106 | ;; Align annotations to the right tooltip border: 107 | company-tooltip-align-annotations t 108 | ;; Idle delay in seconds until completion starts automatically: 109 | company-idle-delay 0.45 110 | ;; Completion will start after typing two letters: 111 | company-minimum-prefix-length 2 112 | ;; Maximum number of candidates in the tooltip: 113 | company-tooltip-limit 10) 114 | 115 | (use-package company-quickhelp 116 | :ensure t 117 | :config 118 | ;; Load company-quickhelp globally: 119 | (company-quickhelp-mode) 120 | ;; Time before display of documentation popup: 121 | (setq company-quickhelp-delay 0.3)) 122 | 123 | (use-package yasnippet 124 | :ensure t 125 | :config 126 | ;; Indicate the directory containing your snippets: 127 | ;; (setq yas-snippet-dirs '("path/to/your/snippets")) 128 | ;; Load your snippets on startup: 129 | (yas-reload-all) 130 | ;; Turn on yasnippet (minor) mode when editing R files: 131 | (add-hook 'ess-r-mode-hook #'yas-minor-mode)) 132 | -------------------------------------------------------------------------------- /tutorial/images/company-quickhelp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ess-intro/presentation-ess-customization/2a4d87fe09186047f411bfa653648bbb4c4e8991/tutorial/images/company-quickhelp.png -------------------------------------------------------------------------------- /tutorial/images/company.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ess-intro/presentation-ess-customization/2a4d87fe09186047f411bfa653648bbb4c4e8991/tutorial/images/company.png -------------------------------------------------------------------------------- /tutorial/images/highlight_custom.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ess-intro/presentation-ess-customization/2a4d87fe09186047f411bfa653648bbb4c4e8991/tutorial/images/highlight_custom.png -------------------------------------------------------------------------------- /tutorial/images/highlight_default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ess-intro/presentation-ess-customization/2a4d87fe09186047f411bfa653648bbb4c4e8991/tutorial/images/highlight_default.png -------------------------------------------------------------------------------- /tutorial/images/lintr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ess-intro/presentation-ess-customization/2a4d87fe09186047f411bfa653648bbb4c4e8991/tutorial/images/lintr.png -------------------------------------------------------------------------------- /tutorial/images/rdired.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ess-intro/presentation-ess-customization/2a4d87fe09186047f411bfa653648bbb4c4e8991/tutorial/images/rdired.png -------------------------------------------------------------------------------- /tutorial/images/window_config.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ess-intro/presentation-ess-customization/2a4d87fe09186047f411bfa653648bbb4c4e8991/tutorial/images/window_config.png -------------------------------------------------------------------------------- /tutorial/slides-ess-customization.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ess-intro/presentation-ess-customization/2a4d87fe09186047f411bfa653648bbb4c4e8991/tutorial/slides-ess-customization.pdf --------------------------------------------------------------------------------