Community
    • Login

    Python Script - Fold levels/flags

    Scheduled Pinned Locked Moved Help wanted · · · – – – · · ·
    4 Posts 2 Posters 1.6k Views
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • Alguem MeuglaA
      Alguem Meugla
      last edited by

      I don’t understand what “editor.getFoldLevel(line)” with a line number as argument will return. With one line number it always returns 9218, with another line number it always changes between 9217<->1025 when I restart notepad++.
      I have searched about this, but I don’t understand it because:
      9218 (dec) = 0010 0100 0000 0010 (bin)
      9217 (dec) = 0010 0100 0000 0001 (bin)
      1025 (dec) = 0000 0100 0000 0001 (bin)
      and the table here only goes up to 128 power.
      I would like to know what those flags mean, how they are calculated/what defines them, specially about that only bit that changes between 9217 and 1025.

      Additionally, there is a FOLDLEVEL.HEADERFLAG that always seems to return “Npp.FOLDLEVEL.HEADERFLAG” when used directly in the console, or “HEADERFLAG” when used in the console as “str(FOLDLEVEL.HEADERFLAG)”.
      I also would like to know more about this function, what it is supposed to return, and what is a Headerflag. The only thing I found about it was this, which means nothing to me.

      Thank you anyone who would like to give a hand.

      1 Reply Last reply Reply Quote 0
      • dailD
        dail
        last edited by dail

        The folding of Scintilla can be a little difficult to understand at first, but luckily the documentation you pointed to on the Scintilla page is adequate.

        So some of this is pretty much repeating what the documentation says, but has some examples using LuaScript. I know you asked specifically about PythonScript but you seem to understand enough that translating between LuaScript and PythonScript shouldn’t be hard as most of the stuff is a one to one mapping. Plus the concepts are exactly the same.

        Fold Levels

        Let’s take for example this C++ code:

        int main(void) {
        	// comment
        
        	if (3 > 10) {
        		printf("nope")
        	}
        	return 0;
        }
        

        Within Notepad++ it looks like this as its fold levels.

        Using editor.getFoldLevel(line) provides information about the line’s folding which includes:

        • The fold level number (in the above example the printf() call is within the 2nd fold level)
        • The fold level header flag…which indicates if it is a fold point (i.e. the boxes that can be folded)
        • The fold level white flag…in all honesty I’m not sure what this does and think it is applicable to certain languages. For now this can be ignored.

        According to the documentation:

        The fold level is a number in the range 0 to SC_FOLDLEVELNUMBERMASK (0x0FFF).

        Which is easy to do, just take the returned value from editor.getFoldLevel(line) and bitwise AND it with SC_FOLDLEVELNUMBERMASK. In PythonScript it would look to be FOLDLEVEL.NUMBERMASK. The documentation also states:

        However, the initial fold level is set to SC_FOLDLEVELBASE (0x400) to allow unsigned arithmetic on folding levels.

        So you need to subtract SC_FOLDLEVELBASE from what you just “AND’ed” off. This will give you the fold number of the line.

        To get the header flag you need to take the fold level and bitwise AND it with SC_FOLDLEVELHEADERFLAG (which this is the highest bit you are seeing in your values you posted above).

        So…a bit of LuaScript to demonstrate what I’ve just described:

        -- Iterate over each line
        for i = 0, editor.LineCount - 1 do
        	-- Get the fold level of the line
        	local foldLevel = editor.FoldLevel[i]
        	
        	-- Calculate the fold number
        	local foldNumber = (foldLevel & SC_FOLDLEVELNUMBERMASK) - SC_FOLDLEVELBASE
        	
        	-- Get the header flag
        	local headerFlag = (foldLevel & SC_FOLDLEVELHEADERFLAG) == SC_FOLDLEVELHEADERFLAG
        
        	print(string.format("Line %d, has a fold level of %d", i + 1, foldNumber))
        	if headerFlag then
        		print("\tand it is a fold point")
        	end
        end
        

        Will output:

            Line 1, has a fold level of 0
            	and it is a fold point
            Line 2, has a fold level of 1
            Line 3, has a fold level of 1
            Line 4, has a fold level of 1
            	and it is a fold point
            Line 5, has a fold level of 2
            Line 6, has a fold level of 2
            Line 7, has a fold level of 1
            Line 8, has a fold level of 1
        

        Once you have this information you can do things like select all the words within the same fold level (great for renaming local variables) or select all the text of a fold level (great for extracting code within a if or for statement and creating a separate function from it).


        A couple of the things you specifically mentioned:

        it always changes between 9217<->1025 when I restart notepad++.

        If the text is the same, then these shouldn’t change at all. Maybe now you know a bit more how the fold level works, you can figure out why this might be different.

        Additionally, there is a FOLDLEVEL.HEADERFLAG that always seems to return “Npp.FOLDLEVEL.HEADERFLAG” when used directly in the console, or “HEADERFLAG” when used in the console as “str(FOLDLEVEL.HEADERFLAG)”.

        These values are all constants so they will always be the same.

        Fold flags

        This is separate from everything described above. This is how the folding is drawn and does not apply per line but rather the entire document. With N++ the default is to draw a line below the text when it is folded. Such as:

        You can do things like set the fold flags to draw above and below the folded lines (again using LuaScript):

        editor.FoldFlags = SC_FOLDFLAG_LINEAFTER_CONTRACTED | SC_FOLDFLAG_LINEBEFORE_CONTRACTED
        

        Then the folding will look like this:

        1 Reply Last reply Reply Quote 8
        • Alguem MeuglaA
          Alguem Meugla
          last edited by

          Nice post :), thank you, now I understand it!

          Looks like notepad sometimes thinks that the line has a folding box, and other times it thinks it doesn’t, thus the 9217<->1025 change in fold level. The script I’m looking at (from here, which bugs sometimes and I’m trying to debug) is set to run when the document loads and I think that the fold levels are loading yet or something, because I put a few debug lines there telling me the values of the variables

          print "FOLDLEVEL.HEADERFLAG: " + str(int(FOLDLEVEL.HEADERFLAG))
          print "editor.getFoldLevel(" + str(_line) + "): " + str(editor.getFoldLevel(_line))
          print "editor.getFoldLevel(" + str(_line) + ") & FOLDLEVEL.HEADERFLAG: " + str(editor.getFoldLevel(_line) & FOLDLEVEL.HEADERFLAG)
          

          and the output was like this:

          FOLDLEVEL.HEADERFLAG: 8192
          editor.getFoldLevel(54): 1025
          editor.getFoldLevel(54) & FOLDLEVEL.HEADERFLAG: 8192
          

          which should be

          >>> 8192 & 1025
          0
          

          Weird, maybe it had changed from 1025 to 9217 between the two script lines, or something. I will leave the debug code, and next time something doesn’t work I will look at it better. (somehow it is working fine now)

          Do line numbers and fold levels stay the same after hiding some code?

          About the FOLDLEVEL.HEADERFLAG now I know it’s just a constant and I can look at it in the console using “int(FOLDLEVEL.HEADERFLAG)” :)

          1 Reply Last reply Reply Quote 0
          • dailD
            dail
            last edited by

            Do line numbers and fold levels stay the same after hiding some code?

            Yes. There are other various API calls provided by Scintilla than can tell you things like if the line is actually folded, or to manually fold/unfold the line and children of that line.

            1 Reply Last reply Reply Quote 1
            • First post
              Last post
            The Community of users of the Notepad++ text editor.
            Powered by NodeBB | Contributors