Example #1
0
        // virtual void SCI_METHOD Fold(Sci_PositionU startPos, i64 lengthDoc, int initStyle, IDocument *pAccess) = 0;
        public static void Fold(IntPtr instance, UIntPtr start_pos, IntPtr length_doc, int init_style, IntPtr p_access)
        {
            /*
             * is called with the exact range that needs folding.
             * Previously, lexers were called with a range that started one line
             * before the range that needs to be folded as this allowed fixing up
             * the last line from the previous folding.
             * The new approach allows the lexer to decide whether to backtrack
             * or to handle this more efficiently.
             *
             * Lessons I have learned so far are
             * - do not start with a base level of 0 to simplify the arithmetic int calculation
             * - scintilla recommends to use 0x400 as a base level
             * - when the value becomes smaller than the base value, set the base value
             * - create an additional margin in which you set the levels of the respective lines,
             *      so it is easy to see when something breaks.
             */

            int    start     = (int)start_pos;
            int    length    = (int)length_doc;
            IntPtr range_ptr = editor.GetRangePointer(start, length);
            string content   = Marshal.PtrToStringAnsi(range_ptr, length);


            int cur_level = (int)SciMsg.SC_FOLDLEVELBASE;
            int cur_line  = editor.LineFromPosition(start);

            if (cur_line > 0)
            {
                int  prev_level      = (int)editor.GetFoldLevel(cur_line - 1);
                bool header_flag_set = (prev_level & (int)SciMsg.SC_FOLDLEVELHEADERFLAG) == (int)SciMsg.SC_FOLDLEVELHEADERFLAG;

                if (header_flag_set)
                {
                    cur_level = (prev_level & (int)SciMsg.SC_FOLDLEVELNUMBERMASK) + 1;
                }
                else
                {
                    cur_level = (prev_level & (int)SciMsg.SC_FOLDLEVELNUMBERMASK);
                }
            }

            int next_level = cur_level;

            for (int i = 0; i < length; i++)
            {
                if (!SupportedProperties["fold"])
                {
                    editor.SetFoldLevel(cur_line, (int)SciMsg.SC_FOLDLEVELBASE);
                    while (i < length)
                    {
                        // read rest of the line
                        if (content[i] == '\n')
                        {
                            break;
                        }
                        i++;
                    }
                    cur_line++;
                    continue;
                }

                string tag = "";
                if (i + 2 < length)
                {
                    tag = content.Substring(i, 3);
                }


                if (FoldOpeningTags.Contains(tag))
                {
                    next_level++;
                    cur_level |= (int)SciMsg.SC_FOLDLEVELHEADERFLAG;
                }
                else if (FoldClosingTags.Contains(tag))
                {
                    next_level--;
                    if (SupportedProperties["fold.compact"])
                    {
                        cur_level--;
                    }
                    cur_level &= (int)SciMsg.SC_FOLDLEVELNUMBERMASK;
                }
                else
                {
                    cur_level &= (int)SciMsg.SC_FOLDLEVELNUMBERMASK;
                }

                while (i < length)
                {
                    // read rest of the line
                    if (content[i] == '\n')
                    {
                        break;
                    }
                    i++;
                }
                // set fold level
                if (cur_level < (int)SciMsg.SC_FOLDLEVELBASE)
                {
                    cur_level = (int)SciMsg.SC_FOLDLEVELBASE;
                }
                editor.SetFoldLevel(cur_line, cur_level);
                cur_line++;
                cur_level = next_level;
            }
        }