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

Code Folding should be based on syntax, not on indentation level #101

Closed
iamntz opened this issue Jul 15, 2013 · 63 comments
Closed

Code Folding should be based on syntax, not on indentation level #101

iamntz opened this issue Jul 15, 2013 · 63 comments

Comments

@iamntz
Copy link
Contributor

iamntz commented Jul 15, 2013

Just to prevent things like #100

@OliverJAsh
Copy link

👍 I see this as quite important.

@FichteFoll
Copy link
Collaborator

It's, by the way, the highest voted feature on userecho.

@andrewchen5678
Copy link

This makes me want to use another text editor instead because it is important for me to fold not based on indentation just like all other editors

@RonnyPfannschmidt
Copy link

as a partial hopefully more easy solution to this, how about making folding aware of basic syntax groups

for example :

  • in xml, a multiline attribute declaration should not killl the possibliity to fold in the tree below
  • in python using parens should not kill the ability to fold a class/function body after a multiline base/argument declaration

@iamntz
Copy link
Contributor Author

iamntz commented Feb 14, 2015

Hi guys. I was digging into default packages and it seems that there is a fold.py file, that deal with (almost?) everything related to folding.

Although I'm not sure how, I think this can be fixed by overwriting this default package.

What do you think?

@FichteFoll
Copy link
Collaborator

I think that the folding arrows are decoupled from fold.py and call the internal api directly.

@iamntz
Copy link
Contributor Author

iamntz commented Feb 14, 2015

Hmm, yeah, i guess you're right. I was too excited about my great discovery and I didn't looked further 👎

@TWiStErRob
Copy link

Here's another example of this:

<inventory>
    <item name="Convector Heater">
        <description>Sencor 750W + 1250W = 2000W
Dial temperature setting
Fan heat distribution</description>
    </item>
</inventory>

If I fold this at <inventory> I get:

<inventory>...
Dial temperature setting
Fan heat distribution</description>
    </item>
</inventory>

Note that I can't change the format of the xml because then the description would have weird whitespaces in it when read by applications (unlike HTML whitespace collapsing). I tried CDATA blocks and the result is the same.

Another thing to note is that I can't even fold at <item> for some reason.

These two issues essentially render xml/html folding useless (dare to say IE does a better job ;). I think severity needs a little bump on this 2-year-old bug.

@FichteFoll
Copy link
Collaborator

Sublime Text does not offer folding arrows for single further-indented lines.

@wiktor-obrebski
Copy link

it would be very nice to have it. it's quite a shame that such good editor have problems with so basic thing.

@jnwatts
Copy link

jnwatts commented Dec 29, 2015

I just spent a few hours digging into this, and for my own needs I've arrived at a plugin+keymap work-around that provides a keyboard shortcut that folds based on scope rather than indent. Using the Chain of Command plugin:

    {
        "keys": ["ctrl+shift+["],
        "command": "chain", "args": {
            "commands": [
                ["expand_selection", {"to": "scope"}],
                ["fold"],
                ["move", {"by": "lines", "forward": true}]
            ]
        },
    },
    {
        "keys": ["ctrl+shift+]"],
        "command": "chain", "args": {
            "commands": [
                ["unfold"],
                ["move", {"by": "lines", "forward": true}]
            ]
        },
    },

With a real plugin or modification of Sublime itself, additional logic could be added to search specific types of scope, as the above will happily collapse a single word if it has its own scope.

For those who are interested in going deeper/further, the built in folding logic can be found in default.sublime-package's fold.py (Not sure where the official source for this is).

@FichteFoll
Copy link
Collaborator

There is no official source online because it's a "core" package. You can technically only refer to the bundled version.

The other packages have been released here: https://github.com/sublimehq/Packages

@ghost
Copy link

ghost commented Apr 19, 2016

If implemented, please make sure Plain Text is included in the syntax definition because I use code folding for text files a lot.

I organize my lists in .txt files like outined info, and indent sections for better navigation because of no Go To Symbol support.

@juanitogan
Copy link

At the moment, I would be happy to just fold a block of data that has no indent. No syntax folding required. Would be useful for folding comments as well like some editors do. Basic logic: If three or more sequential lines have no indent (before a blank or indented line, or EOF), allow the leading block of lines to be folded, leaving the last line unfolded to allow current folding (required, logically, whether the last line is currently foldable or not).

Fold this:

0000
1111
2222
3333
  foo

to this:

0000 [...]
3333
  foo

@braver
Copy link

braver commented Aug 8, 2017

I'd say a lot of the strength of Sublime's folding actually comes from a complete lack of understanding or logic. Perhaps it's a bit weird if you're used to other systems, but it's super flexible and works the same way for any file.

Which results in problems for the default indentation action when indentation is missing, or indentation is broken as in the example xml's. However, you usually don't want to see indentation like that in pretty much any language.

Examples demonstrating what you're asking for:

foldit

Here I created a selection simply by holding shift, then moving the caret up. The selection can then be folded using the keyboard shortcut or the menu entry.

Another example demonstrating how to deal with the xml example:

foldit-xml

Here, a selection was created by hitting the keyboard shortcut for Expand Selection To Tag, and then folded by hitting the shortcut for that.

Sure, in each case creating the selection and then folding is more work that simply hitting the Fold shortcut, but that's the price you pay for being able to fold absolutely any range you want.

I'm not saying it couldn't be better. Some language hints might help the default fold action to guess the correct range to fold more often. Not because Sublime can't fold it right now, but because it would make folding more discoverable and a tiny bit more efficient. I'd wager Sublime's folding limitations are more serious when it comes to unfolding.

@aone2020
Copy link

aone2020 commented May 9, 2020

unbelievable, 2020, still NO

@troygilbert
Copy link

To be honest, I'd be thrilled to simply have the current code-folding but have it work on single-line blocks. Like, I've tried and I can't imagine a scenario where it makes sense to not give the user the option to fold a block that has a single line in it (but folding a block with 2 lines in it works perfectly!).

@sanyi0411
Copy link

First comment here is from 2013. Now it's 2021 and still no change. Please someone do something

@boycce
Copy link

boycce commented Mar 4, 2021

wadamygonnadooo!
image

@datainadequate
Copy link

This really rules out Sublime Text as a useful editor for XML. This is a shame because XML is horrible to edit and it would be much nicer to do it in Sublime Text than in Visual Studio. But you cannot work sensibly with XML unless you have folding based on XML syntax.

@santoshsrinivas
Copy link

santoshsrinivas commented Jan 31, 2022

I am not sure what incentive you guys need to prioritize this.
Help in coding? Please ask. I am sure there are extremely smart people in the community who can volunteer.
Money? I am happy to pay. I have already purchased a license, I don't mind a few extra bucks.

I am disappointed that I couldn't use the product I bought. I am currently using other editors due to lack of this feature.

Please. Do something. :( :(

@jokoon
Copy link

jokoon commented Jan 31, 2022 via email

@idzikovsky
Copy link

@jokoon yeah, so they haven't touched that part of code for eight years now...
On the other hand, by looking at @wbond comments on this issue I assume that the more real reason is that developers simply don't find this problem important enough.

@TWiStErRob
Copy link

Issue is top 5, so it's hard to say it's not on their radar.

@jokoon
Copy link

jokoon commented Feb 1, 2022 via email

@BenjaminSchaaf
Copy link
Member

BenjaminSchaaf commented Mar 23, 2022

Build 4130 introduces a configuration for syntax definitions to base folding on scopes. When configured this extends to the gutter and all the folding shortcuts. Note that no default syntax have such a configuration yet.

See the following example:

<?xml version="1.0" encoding="UTF-8"?>
<plist version="1.0">
<dict>
    <key>scope</key>
    <string>source.c, source.c++, source.objc, source.objc++</string>
    <key>settings</key>
    <dict>
        <key>indentationFoldingEnabled</key>
        <false/>
        <key>scopeFoldingEnabled</key>
        <true/>
        <key>foldScopes</key>
        <array>
            <dict>
                <key>begin</key>
                <string>punctuation.section.block.begin</string>
                <key>end</key>
                <string>punctuation.section.block.end</string>
            </dict>
        </array>
    </dict>
</dict>
</plist>

@Sayayaya
Copy link

Sayayaya commented Jul 6, 2022

Is there somewhere the foldScopes syntax is documented... for example how would I get it to fold on //region //endregion etc. The example provided is not very clear to me.

@deathaxe
Copy link
Collaborator

deathaxe commented Jul 6, 2022

There's no "foldScopes syntax".

Folding is based on scopes.

The TextMate preference file above, shows how to define fold begin and end selectors.

All tokens scoped punctuation.section.block.begin are used as starting point and punctuation.section.block.end as termination of a folding region in C/C++/Obj-C/Obj-C++.

If you want to use //region as beginning and //endregion as termination, you'd want to either look for the scope they have assigned by desired syntax definition. The scope name is displayed via ctrl+shift+alt+P.

You may probably need to modify syntax definition to assign a proper scope.

Example

A Fold.sublime-syntax specifies scopes (e.g. keyword.other.region.[begin|end]).

%YAML 1.2
---
# See http://www.sublimetext.com/docs/syntax.html
scope: source.fold
file_extensions:
  - fold

contexts:
  main:
    - match: (\\)region\b
      scope: keyword.other.region.begin
      captures:
        1: punctuation.definition.region
    - match: (\\)endregion\b
      scope: keyword.other.region.end
      captures:
        1: punctuation.definition.region

A Fold.tmPreferences file declares those scopes as begin and end of a folding region.

<?xml version="1.0" encoding="UTF-8"?>
<plist version="1.0">
<dict>
    <key>scope</key>
    <string>source.fold</string>
    <key>settings</key>
    <dict>
        <key>scopeFoldingEnabled</key>
        <true/>
        <key>foldScopes</key>
        <array>
            <dict>
                <key>begin</key>
                <string>keyword.other.region.begin</string>
                <key>end</key>
                <string>keyword.other.region.end</string>
                <key>excludeTrailingNewlines</key>
                <true/>                
            </dict>
        </array>
    </dict>
</dict>
</plist>

ST has then learned to define fold regions beginning with //region and ending with //endregion.

@mnemnion
Copy link

mnemnion commented Aug 5, 2022

I'm having trouble getting this to work with telescoping scopes. I feel sure I'm doing something wrong, the indentation scopes fold.

The goal is to take this sort of todo:

** H2

...text

*** H3

**** H4

** H2

So that folding the first H2 folds everything between it and the next H2.

The dicts look like this:

            <dict>
                <key>begin</key>
                <string>markup.section.4.begin</string>
                <key>end</key>
                <string>markup.section.4.end</string>
                <key>excludeTrailingNewlines</key>
                <true/>
            </dict>
            <dict>
                <key>begin</key>
                <string>markup.section.3.begin</string>
                <key>end</key>
                <string>markup.section.3.end</string>
                <key>excludeTrailingNewlines</key>
                <true/>
            </dict>

Grammar has rules like

    - match: '{{h5}}'
      push:
      - meta_scope: markup.section.5.begin
      - match: '\s?(\*{5})'
        captures:
          1: markup.heading.section.level
        scope:
          markup.section.6.end
          markup.section.5.end
      - match: '(.*$)'
        captures:
          1: markup.entity.section.line
        pop: true


    - match: '{{h4}}'
      push:
      - meta_scope: markup.section.4.begin
      - match: '\s?(\*{4})'
        captures:
          1: markup.heading.section.level
        scope:
          markup.section.6.end
          markup.section.5.end
          markup.section.4.end
      - match: '(.*$)'
        captures:
          1: markup.entity.section.line
        pop: true

And so one: higher sections get a section close tag for every lower sort.

The problem is that: it works between peers (H3 won't gobble up H3), and an H3 won't fold an H2, but the sequence H3 H4 H2 gets the H2 and I can't for the life of me figure out why.

I know this is a work in progress, I'm exceedingly keen to see this feature, but I'm kinda stumped at this point.

@FichteFoll
Copy link
Collaborator

but the sequence H3 H4 H2 gets the H2 and I can't for the life of me figure out why.

What do you mean by that?

@mnemnion
Copy link

mnemnion commented Aug 6, 2022

It's the same behavior described in #5423.

If you have in markdown:

### H3

text

#### H4

text

## H2 

text

then folding H3 will fold the H2.

@jokoon
Copy link

jokoon commented Oct 26, 2023

scope source.c, source.c++, source.objc, source.objc++ settings indentationFoldingEnabled scopeFoldingEnabled foldScopes begin punctuation.section.block.begin end punctuation.section.block.end

Thanks, could you be more specific as to which file this should pasted into?

EDIT: I created a C++ folder in the Packages folder, and pasted this into the Fold.tmPreferences file... doesn't seem to fold curly braces in a single line.

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

No branches or pull requests