Skip to content

Conversation

@Yunuuuu
Copy link

@Yunuuuu Yunuuuu commented Mar 8, 2022

This PR extend current single-level fold-section (#163) by implementing multiple-levels fold section for r documents.

Current sub-sections just provide a symbol in outline. Now, we can use one of these c("*", "-", "+", "=") to implement sub-fold, sub-sub-fold, sub-sub-sub-fold and more.

These characters work just like "#" in markdown file, where one indicates first-level, both indicates second-level, three indicates third-level and more ... And we can fold-unfold them based on their section-levels

Just put one of these characters next to the comment character "#" in a R file.

Moreoever, this PR also prunes section names by removing %% which is indicative of markdown chunk in R files implemented by REditorSupport/vscode-R#662.

Here is some examples (see the outline panel):

# fisrt level -----

# ** second level ----

a <- 1:10
b <- 2:3

# %% *** third level ----
b <- 2:3
# %%

# the next section ----
 # with space at the beginning is the same of `previous sub-section`   ----
 # which provides just a symbol ----

 # with space at the beginning and without suffix fold indication
 # will fold comment
d <- letters

image

An example outline:
image

if (length(comments) == 0) {
if (identical(length(comments), 0L)) {
return(NULL)
}
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Continous comment lines will break the multiple levels fold, so we cancel comment fold when observing a r document section signatures - at least 4 of one of c("#", "+", "-", "=", "*")

R/utils.R Outdated
}

# indent can be indicative of symbol object in vscode outline
get_r_document_label_sections <- function(line_seq, doc_content) {
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I rename previous called subsection into label_section for it only provides a label without fold support

R/utils.R Outdated
# define suffix labels and prefix labels for section
# enable adding further labels easily
section_suffix <- c("#", "+", "-", "=", "*") # at least 4
sub_section_prefix <- c("*", "-", "+", "=")
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the prefix used to indicate the title levels

@renkun-ken
Copy link
Member

Thanks for working on this. I'll take a closer look later today.

@Yunuuuu
Copy link
Author

Yunuuuu commented Mar 14, 2022

Now, more than two blank lines out of function (block ranges) can indicate the end of section

@Yunuuuu
Copy link
Author

Yunuuuu commented Mar 14, 2022

  1. use one of section_mark_suffix <- c("#", "+", "-", "=", "*") to indicate section beginning. specifics in function get_r_document_sections and get_r_document_one_line_symbols
  • numbers over 2 is indicative of section name (section range with one line)
  • numbers over 4 is indicative of section range
  1. use one of section_level_prefix <- c("*", "-", "+", "=") to indicate section levels. The more prefix current section has, the lower level it is. Just like character # in markdown syntax.
  2. more than two blank lines out of block ranges (which is defined in (), [], {}) can indicate the end of section.

@renkun-ken
Copy link
Member

I was wondering if RStudio has multi-level foldable regions. I took a look at https://support.rstudio.com/hc/en-us/articles/200484568-Code-Folding-and-Sections-in-the-RStudio-IDE, and it seems that it only defined top-level section.

@renkun-ken
Copy link
Member

  1. use one of section_mark_suffix <- c("#", "+", "-", "=", "*") to indicate section beginning. specifics in function get_r_document_sections and get_r_document_one_line_symbols

    • numbers over 2 is indicative of section name (section range with one line)

    • numbers over 4 is indicative of section range

    1. use one of section_level_prefix <- c("*", "-", "+", "=") to indicate section levels. The more prefix current section has, the lower level it is. Just like character # in markdown syntax.

    2. more than two blank lines out of block ranges (which is defined in (), [], {}) can indicate the end of section.

Would you like to provide an example for each of these?

Also, look like the syntax might add too much complexity. I don't figure out how I can create a third level section without creating a code chunk.

and for the following code chunk I expected that folding only applies to the chunk since the syntax of both code chunk # %% and sections are mixed.

# %% *** third level ----
b <- 2:3
# %%

I feel quite a bit confused with the proposed syntax at the moment.

@Yunuuuu
Copy link
Author

Yunuuuu commented Mar 15, 2022

Sorry for the poor explanation, I remember RStudio can only define top-level sections before, but it can define multi-level sections now see below picture from this link.
image

we can also define section using one of suffix c("#", "+", "-", "=", "*"), see example below which has been implemented by you before.

# sections 1 -----
section1 <- 1:10
# section 2 ####
section2 <- letters
# section 3 ++++
section3 <- 3

I see vscode-r define fold region in r file using function get_r_document_sections or rmarkdown file using function get_rmd_document_sections. To add sub-sections, sub-sub sections or more, function get_r_document_sections should be re-defined in the similar way of get_rmd_document_sections. Though current get_r_document_sections also define sub-section, it is just a one-line section range and provides just a symbol in the outline viewer of vscode (we cannot fold section region) using indentation to implement (referred in here #163 (comment)) ; the implement code for current sub-section one-line range is linked here.

If we choose to use the same way of RStudio to implement multi-level sections we'll break code chunk in R files (using %%). So I choose to use one of prefix c("*", "-", "+", "=") to indicate section-levels no matter whether there is one %% at the beginning of current line, (the prefix was defined by a variable section_level_prefix so we can add more or omit some easily), I don't know if this is a good choice?

Sorry, I cannot make my vscode screen recorder (like screen-recorder and Chronicler) work, please install via pak::pkg_install("Yunuuuu/languageserver") and check the folding and outline for following code in vscode

see blow example:

# fisrt level -----
# ** second level ----
a <- 1:10
b <- 2:3
# %% *** third level ----
b <- 2:3
# %%
# the next section ----
section_two <- letters
# ** the next section - second level----
d <- letters

image
image

Further, more than one blank lines out of block ranges could indicate the end of current section, see blow code:

# section one -----
a <- 1:10
fn <- function(x){




}


# ** section two ----
# though this section has two `**` but it still out of above section with zero `*` as two blank lines indicate the end of above section
a <- 1:10
b <- 2:3

image
image

And the current one-line range (referred here #163 (comment)) which provides just a symbol in outline is also kept by combining one of suffix c("#", "+", "-", "=", "*") and indentation (this is useful to set outline symbol in a function) :

# the section ----
 # with space at the beginning is the same of `previous sub-section` --
 # which provides just a symbol --
d <- letters

image

@Yunuuuu
Copy link
Author

Yunuuuu commented Mar 15, 2022

I find I only implement section breaks for folding (more than one blank lines out of block ranges could indicate the end of current section). But I didn't implement it for symbol in the vscode outline viewer , it would require us to re-construct this code too as we should include get_block_folding_ranges to check if the blank lines are in this type of ranges. I'll try to fix this.

@Yunuuuu
Copy link
Author

Yunuuuu commented Mar 15, 2022

I have tested all of these, it seems no error occur and more than one blank lines (break sections) could also work in vscode outline viewer

@Yunuuuu
Copy link
Author

Yunuuuu commented Mar 15, 2022

# section one -----
a <- 1:10
fn <- function(x) {




}


# ** section two ----
# though this section has two `**` but it still out of above section with zero `*` as two blank lines indicate the end of above section
a <- 1:10


b <- 2:3

image

@Yunuuuu
Copy link
Author

Yunuuuu commented Mar 15, 2022

If we add # to section_level_prefix, this will work the same with RStudio, and we can combine it with %%.

@Yunuuuu
Copy link
Author

Yunuuuu commented Mar 15, 2022

for the following code chunk I expected that folding only applies to the chunk since the syntax of both code chunk # %% and sections are mixed.

The code chunk doesn’t matter, we can define any levels of section no matter if the beginning has a code chunk indication %%

@Yunuuuu
Copy link
Author

Yunuuuu commented Mar 15, 2022

Now, # can work too, like RStudio.
image

@Yunuuuu
Copy link
Author

Yunuuuu commented Mar 15, 2022

image

@Yunuuuu
Copy link
Author

Yunuuuu commented Mar 15, 2022

if vscode-r extension can let code chunk token %% ignore this regex: \\s*[\\*\\-\\#\\=\\+]*\\s*, we can regulate the order of %% token and section level token [*-+=#], and put %% behind these prefix, more like RStudio or markdown. And should we only provide # to indicate section level ? In this way, vscode-r has ignored multiple # character for %%.

# section one ----
a <- 1:10

## %% sub-section ----
b <- letters
# %%

## %% sub-section ----
d <- LETTERS
# %%

### sub-sub-section ----
e <- 1:3

#### sub-sub-sub-section ----
f <- 1:20

image

For other section level token [*-+=] we now must put them after %% to let %% work well, like this:

# section one ----
a <- 1:10

# %% * sub-section ----
b <- letters
# %%

# %% * sub-section ----
d <- LETTERS
# %%

# ** sub-sub-section ----
e <- 1:3

# *** sub-sub-sub-section ----
f <- 1:20

image

@renkun-ken
Copy link
Member

Thanks for the updates. Should we just keep the RStudio syntax like markdown titles for sections so that users won't get confused?

@Yunuuuu
Copy link
Author

Yunuuuu commented Mar 23, 2022

Thanks for your suggestions @renkun-ken, I have omitted other section level indicative token and added more comment for this.

@Yunuuuu
Copy link
Author

Yunuuuu commented Mar 23, 2022

Now this behave consistently with RStudio. See following example:

# section one ----
a <- 1:10

## %% first sub-section ----
b <- letters
# %%

### first sub-sub-section ----
d <- 1:2

## %% second sub-section ----
e <- LETTERS
# %%

### sub-sub-section ----
f <- 1:3

#### sub-sub-sub-section ----
g <- 1:20

image

# *** numbers over 2 is indicative of section name (section range with one line)
# *** see `get_r_document_one_line_symbols`
section_symbol_regex <- paste0(
"\\", section_mark_suffix, "{2,}",
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi, @renkun-ken, another change I have made is this section symbols which were implemented by 95803b2, which used at least four tokens (c("#", "+", "-", "=", "*")) and indention to execute code subsection. I have decreased this into only two, as much nested function will easily exceed 80 characters. Is this a good choice ?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess we better be aligned with RStudio syntax when there is no significant benefit. Maybe we could revisit this until there is much complaint about this.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for your suggestions @renkun-ken, it'll be really better if this can be consistent with RStudio completely. The implements of internal sub-sections of function need some works for me, but I should prepare for my graduation now, I'll back for this sometime this year.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would you mind if I do some modification to the PR? I'll do some style modification and add some test cases, and then I'll merge it for now.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And good luck with your graduation :)

Copy link
Author

@Yunuuuu Yunuuuu Mar 23, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Of course, it won't be better and thanks, renkun

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

😷Poor english, Sorry. Last expression can be wrong, I meant that It would be great if you could help me😷this may be what I want.

@Yunuuuu
Copy link
Author

Yunuuuu commented Mar 24, 2022

@renkun-ken , I have re-designed the framework of implementing folding ranges by using recursive function. and now, we can make sub-section everywhere in r document no matter whether the codes are in blocks. And I feel this is much faster than last push (a subjective feeling as I felt the display of outline views is much faster😁). there's not enough time for me to tidy code. It may be a little mess.

Here is some example code and picture:

# section one ----
a <- 1:10

## %% first sub-section ----
b <- letters
# %%

### first sub-sub-section ----
d <- 1:2

## %% second sub-section ----
e <- LETTERS
# %%

### sub-sub-section ----
f <- 1:3

#### sub-sub-sub-section ----
g <- 1:20


# b ------


a <- function(x) {

    # section one ----
    a <- 1:10

    ## %% first sub-section ----
    b <- letters
    # %%



    ### first sub-sub-section ----
    d <- 1:2

    ## %% second sub-section ----
    e <- LETTERS
    # %%

    ### sub-sub-section ----
    f <- 1:3

    #### sub-sub-sub-section ----
    g <- 1:20


    c(a, b, d, e, f, g)
}

# a ----
setdiff(1, 1)

image

@Yunuuuu
Copy link
Author

Yunuuuu commented Mar 24, 2022

But the code chunk cannot work in functions blocks, maybe it's due to the prefix space, but I have no time to work for this (a bit anxiety for graduation).
image

@Yunuuuu
Copy link
Author

Yunuuuu commented Mar 25, 2022

more complex nested blocks can work

a <- function(x) {b <- function() {

        # section for function b ------
        x <- 1:2
        x
    }

    # section one ----
    a <- 1:10

    ## first sub-section ----
    b <- letters


    ### section two - two blank lines will break previous section one ----
    d <- 1:2

    x <- function() {
    # section for function x -----
    c(a, b, d)

}}

image

@Yunuuuu Yunuuuu closed this May 31, 2022
@Yunuuuu
Copy link
Author

Yunuuuu commented May 31, 2022

Sorry, I found I pulled the merge process from branch 'upstream/master' into this. I'll close this in case of messing code. I'm not famaliar with Git operation. Sorry.

@petrbouchal
Copy link

This looked good and would have been very useful - any chance the PR can be revived and merged?

@Yunuuuu
Copy link
Author

Yunuuuu commented Aug 2, 2022

I'll pull these for the developer to review when they have time.

@kylebutts
Copy link
Contributor

I agree! Would be awesome to have this :-)

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

Successfully merging this pull request may close these issues.

4 participants