// 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 length = (int)length_doc; int start = (int)start_pos; // allocate a buffer IntPtr buffer_ptr = Marshal.AllocHGlobal(length); if (buffer_ptr == IntPtr.Zero) { return; } IDocument idoc = (IDocument)Marshal.PtrToStructure(p_access, typeof(IDocument)); IDocumentVtable vtable = (IDocumentVtable)Marshal.PtrToStructure((IntPtr)idoc.VTable, typeof(IDocumentVtable)); // scintilla fills the allocated buffer vtable.GetCharRange(p_access, buffer_ptr, (IntPtr)start, (IntPtr)length); if (buffer_ptr == IntPtr.Zero) { return; } // convert the buffer into a managed string string content = Marshal.PtrToStringAnsi(buffer_ptr, length); int cur_level = (int)SciMsg.SC_FOLDLEVELBASE; int cur_line = (int)vtable.LineFromPosition(p_access, (IntPtr)start); if (cur_line > 0) { int prev_level = (int)vtable.GetLevel(p_access, (IntPtr)(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"]) { vtable.SetLevel(p_access, (IntPtr)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; } vtable.SetLevel(p_access, (IntPtr)cur_line, cur_level); cur_line++; cur_level = next_level; } // free allocated buffer Marshal.FreeHGlobal(buffer_ptr); }
// virtual void SCI_METHOD Lex(Sci_PositionU startPos, i64 lengthDoc, int initStyle, IDocument *pAccess) = 0; public static void Lex(IntPtr instance, UIntPtr start_pos, IntPtr length_doc, int init_style, IntPtr p_access) { /* main lexing method. * start_pos is always the startposition of a line * length_doc is NOT the total length of a document but the size of the text to be styled * init_style is the style of last styled byte * p_access is the pointer of the IDocument cpp class */ int length = (int)length_doc; int start = (int)start_pos; bool bHighlight = SupportedProperties["highlightnumeric"]; //bool bHighlight = true; // allocate a buffer IntPtr buffer_ptr = Marshal.AllocHGlobal(length); if (buffer_ptr == IntPtr.Zero) { return; } // create the IDocument interface (struct) from the provided p_access pointer IDocument idoc = (IDocument)Marshal.PtrToStructure(p_access, typeof(IDocument)); // create/simulate the vtable of the IDocument interface IDocumentVtable vtable = (IDocumentVtable)Marshal.PtrToStructure((IntPtr)idoc.VTable, typeof(IDocumentVtable)); // scintilla fills the allocated buffer vtable.GetCharRange(p_access, buffer_ptr, (IntPtr)start, (IntPtr)length); if (buffer_ptr == IntPtr.Zero) { return; } // convert the buffer into a managed string string content = Marshal.PtrToStringAnsi(buffer_ptr, length); for (int i = 0; i < length; i++) { int start_position = i; string tag = ""; int idx = 0; bool num = false; bool dot = false; int start_num = -1; if (i + 2 < length) { tag = content.Substring(i, 3); } if (Segs1.Contains(tag)) { idx = 1; } else if (Segs2.Contains(tag)) { idx = 2; } else if (Segs3.Contains(tag)) { idx = 3; } else if (Segs4.Contains(tag)) { idx = 4; } while (i < length) { // highlight numeric values if (bHighlight) { if (num && (content[i] == '.')) { dot = true; } else if (!num && (content[i] >= '0') && (content[i] <= '9')) { num = true; start_num = i; } else if ((content[i] < '0') || (content[i] > '9')) { if (num && dot) { // style up until numeric vtable.StartStyling(p_access, (IntPtr)(start + start_position)); vtable.SetStyleFor(p_access, (IntPtr)(start_num - start_position), (char)idx); // style numeric highlight vtable.StartStyling(p_access, (IntPtr)(start + start_num)); vtable.SetStyleFor(p_access, (IntPtr)(i - start_num), (char)9); // 9 = highlight numeric // new start position after numeric start_position = i; } // reset num = false; dot = false; } } // read rest of the line if (content[i] == '\n') { break; } i++; } // let scintilla style this line vtable.StartStyling(p_access, (IntPtr)(start + start_position)); vtable.SetStyleFor(p_access, (IntPtr)(i - start_position), (char)idx); } // free allocated buffer Marshal.FreeHGlobal(buffer_ptr); }