Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions ChangeLog
Original file line number Diff line number Diff line change
@@ -1,3 +1,17 @@
2025-12-23 Christophe Gouel <[email protected]>

* lisp/ess-custom.el (ess-r-outline-style) (ess-r-outline-regexp):
New user option to pick an outline convention (RStudio rulers vs.
stars). Remove option ess-r-outline-regexp.
* lisp/ess-r-mode.el (ess-r-outline-style-alist)
(ess-r--outline-style-definition)
(ess-r--outline-style-value)
(ess-r-outline-level)
(ess-r-set-outline-style): Drive outline-minor-mode via the selected
style and make the choice hack-local-variable aware.
* doc/ess.texi (Outline navigation): Document `ess-r-outline-style`
and the available styles.

2025-10-27 Christophe Gouel <[email protected]>

* lisp/ess-custom.el: Support for outline-minor-mode
Expand Down
40 changes: 28 additions & 12 deletions doc/ess.texi
Original file line number Diff line number Diff line change
Expand Up @@ -433,7 +433,7 @@ processes. This is a good command to consider binding to a global key.
ESS works with processes on remote computers as easily as with processes
on the local machine. The recommended way to access a statistical
program on remote computer is to start it with @xref{Top,,, tramp, TRAMP
User Manual}.
User Manual}.

Start an ssh session using TRAMP with @samp{C-x C-f /ssh:user@@host:
RET}. Tramp should open a dired buffer in your remote home directory.
Expand Down Expand Up @@ -1328,7 +1328,7 @@ effect of aborting the current command.
@kindex C-c C-z
@kbd{C-c C-z} When in process buffer, return to the most recent script
buffer. When in a script buffer pop to the associated process buffer.
Consecutive presses of @kbd{C-z} switch between the script and process buffers.
Consecutive presses of @kbd{C-z} switch between the script and process buffers.

If @var{toggle-eob} is given, the value of
@code{ess-switch-to-end-of-proc-buffer} is toggled.
Expand Down Expand Up @@ -3089,13 +3089,14 @@ by various ESS variables such as @code{ess-imenu-S-generic-expression}.
@cindex code folding
@findex outline-minor-mode
@findex ess-r-outline-level
@vindex ess-r-outline-regexp
@vindex ess-r-outline-style
R editing buffers integrate with @code{outline-minor-mode}. When you
toggle the minor mode (for example via @kbd{M-x outline-minor-mode} or
by adding it to @code{ess-r-mode-hook}), ESS assigns
@code{ess-r-outline-level} to @code{outline-level} and installs
@code{ess-r-outline-regexp} so that comment headings drive folding.
Lines that begin with one or more @samp{#}, followed by text and a
@code{ess-r-outline-level} to @code{outline-level} and configures
@code{outline-regexp} according to @code{ess-r-outline-style} so that
comment headings drive folding. With the default @code{RStudio} style,
lines that begin with one or more @samp{#}, followed by text and a
trailing marker of @samp{----}, @samp{====}, or @samp{####}, are treated
as outline headings. This matches the section markers convention adopted by
RStudio.
Expand All @@ -3107,19 +3108,34 @@ RStudio.
#### Helpers ####
@end example

The number of leading @samp{#} characters sets the outline depth. Use
standard Outline commands (such as @kbd{C-c @ C-t}) to cycle visibility once
The number of leading @samp{#} characters sets the outline depth. When using
this outline style, it is recommended to use
@code{setq ess-indent-with-fancy-comments nil} or
@code{setq ess-style 'RStudio}. Otherwise, single-hash comments are treated as
right-margin comments with comment-column 40.

Use standard Outline commands (such as @kbd{C-c @ C-t}) to cycle visibility once
the minor mode is active. To enable Outlining automatically, add it to the R
mode hook:

@example
(add-hook 'ess-r-mode-hook #'outline-minor-mode)
@end example

@defvr {User Option} ess-r-outline-regexp
Regular expression used by ESS to recognise outline headings in R
buffers. The default matches the RStudio-style sections shown above,
but you can customise it if you prefer a different comment convention.
@defvr {User Option} ess-r-outline-style
Select which outline convention @code{ess-r-mode} should use. The
default @code{RStudio} style recognises the comment rulers shown above.
Choose @code{stars} to match the @samp{### * Section} pattern:

@example
### * Setup
### ** Data
### *** Models
### **** Helpers
@end example

You can switch styles via
@code{M-x ess-r-set-outline-style} or by customizing this option.
@end defvr

@node Toolbar
Expand Down
16 changes: 12 additions & 4 deletions lisp/ess-custom.el
Original file line number Diff line number Diff line change
Expand Up @@ -1571,11 +1571,19 @@ by `ess-function-template'."
:group 'ess
:type 'regexp)

(defcustom ess-r-outline-regexp
"^[ \t]*#+ +.*\\(?:----\\|====\\|####\\)\\s-*$"
"Regexp used to detect the beginning of R headings."
(defcustom ess-r-outline-style 'RStudio
"Outline convention used by `ess-r-mode'.
Choose between comment rulers like RStudio (\"### Section title ----\")
and \"stars\" headings \(\"### *** Section title\").

When using the RStudio outline style, it is recommended to use \(setq
ess-indent-with-fancy-comments nil) or \(setq ess-style 'RStudio).
Otherwise, single-hash comments are treated as right-margin comments
with `comment-column' 40."
:group 'ess-R
:type 'regexp)
:type '(choice (const :tag "RStudio comment rulers" RStudio)
(const :tag "Stars (### *** headings)" stars))
:safe #'symbolp)


; ess-inf: variables for inferior-ess.
Expand Down
65 changes: 60 additions & 5 deletions lisp/ess-r-mode.el
Original file line number Diff line number Diff line change
Expand Up @@ -299,14 +299,68 @@ When t, loading a file into a namespaced will output information
about which objects are exported and which stay hidden in the
namespace.")

(defun ess-r-outline-level ()
"R mode `outline-level` function."
(defconst ess-r--outline-rstudio-regexp
"^[ \t]*#+ +.*\\(?:----\\|====\\|####\\)\\s-*$"
"R outline Regexp when `ess-r-outline-style' is `RStudio'.")

(defconst ess-r--outline-stars-regexp
"^\\(?:> \\)?###\\s-+\\(\\*+\\)\\s-+.*$"
"R outline regexp used when `ess-r-outline-style' is `stars'.")

(defun ess-r--outline-style-definition (&optional style)
"Return the style definition for STYLE, defaulting to `ess-r-outline-style'."
(let ((style (or style ess-r-outline-style)))
(or (assq style ess-r-outline-style-alist)
(error "Unknown ESS outline style: %s" style))))

(defun ess-r--outline-style-value (key &optional style)
"Return value for KEY in STYLE's definition."
(cdr (assq key (cdr (ess-r--outline-style-definition style)))))

(defun ess-r--outline-level-rstudio ()
"Compute outline level for `RStudio` style headings."
(save-excursion
(beginning-of-line)
(if (looking-at "^[ \t]*\\(#+\\)\\s-")
(length (match-string 1))
(length (match-string 1))
1000)))

(defun ess-r--outline-level-stars ()
"Compute outline level for `stars` style headings."
(save-excursion
(beginning-of-line)
(if (looking-at "^\\(?:> \\)?###\\s-+\\(\\*+\\)\\s-+")
(length (match-string 1))
1000)))

(defconst ess-r-outline-style-alist
`((RStudio
(outline-regexp . ,ess-r--outline-rstudio-regexp)
(outline-level . ,#'ess-r--outline-level-rstudio))
(stars
(outline-regexp . ,ess-r--outline-stars-regexp)
(outline-level . ,#'ess-r--outline-level-stars)))
"Mapping between outline styles and their regexp/level helpers.")

(defun ess-r-outline-level ()
"R mode `outline-level` dispatcher for the current outline style."
(funcall (ess-r--outline-style-value 'outline-level)))

(defun ess-r-set-outline-style (&optional style)
"Apply STYLE (or `ess-r-outline-style') to the current buffer."
(interactive
(list (intern (completing-read
"Outline style"
(mapcar (lambda (entry) (symbol-name (car entry)))
ess-r-outline-style-alist)
nil t nil nil
(symbol-name (or ess-r-outline-style 'RStudio))))))
(let* ((style (or style ess-r-outline-style))
(entry (ess-r--outline-style-definition style)))
(setq-local ess-r-outline-style (car entry))
(setq-local outline-regexp (ess-r--outline-style-value 'outline-regexp style))
(setq-local outline-level #'ess-r-outline-level)))

;; The syntax class for '\' is punctuation character to handle R 4.1
;; lambdas. Inside strings it should be treated as an escape
;; character which we ensure here.
Expand Down Expand Up @@ -843,6 +897,8 @@ top level functions only."
(setq-local electric-layout-rules '((?{ . after)))
;; indentation
(add-hook 'hack-local-variables-hook #'ess-set-style nil t)
;; outline
(add-hook 'hack-local-variables-hook #'ess-r-set-outline-style nil t)
;; eldoc
(ess--setup-eldoc #'ess-r-eldoc-function)
;; auto-complete
Expand All @@ -864,8 +920,7 @@ top level functions only."
(when ess-imenu-use-S
(imenu-add-to-menubar "Imenu-R"))
;; outline
(setq-local outline-level #'ess-r-outline-level)
(setq-local outline-regexp ess-r-outline-regexp)
(ess-r-set-outline-style)
(setq-local beginning-of-defun-function #'ess-r-beginning-of-defun)
(setq-local end-of-defun-function #'ess-r-end-of-defun)
(ess-roxy-mode))
Expand Down