### Enable and Highlight Indentation Guides Source: https://github.com/desjarlais/scintilla.net/wiki/Brace-Matching Configure Scintilla to display indentation guides using `IndentationGuides` and highlight a specific guide using `HighlightGuide`. The `GetColumn` method can determine the column number for a given document position. ```cs scintilla.IndentationGuides = IndentView.LookBoth; ``` ```cs int lastCaretPos = 0; private void form_Load(object sender, EventArgs e) { scintilla.IndentationGuides = IndentView.LookBoth; scintilla.Styles[Style.BraceLight].BackColor = Color.LightGray; ``` -------------------------------- ### Retrieve Text from ScintillaNET Control Source: https://github.com/desjarlais/scintilla.net/wiki/Basic-Text-Retrieval-and-Modification Use `Text` to get the entire document content, but prefer `GetTextRange` for specific portions to avoid performance issues with large documents. Reading lines into a list is also demonstrated. ```cs // Get the whole document var wholeDoc = scintilla.Text; // Get the first 256 characters of the document var text = scintilla.GetTextRange(0, Math.Min(256, scintilla.TextLength)); Console.WriteLine(text); // Sometimes it's nice to read the lines of a file to an array/list for processing var myListOfItems = new List(); foreach (var item in scintilla.Lines) myListOfItems.Add(item.Text); // or... List myListOfItems = scintilla.Lines.Select(x => x.Text).ToList(); ``` -------------------------------- ### Get Character Before and After Caret Source: https://github.com/desjarlais/scintilla.net/wiki/Character-Autocompletion Retrieves the characters immediately before and after the caret. Handles edge cases where the caret is at the beginning of the document. ```csharp // int; gets what's before the inserted character. Notice the ternary operator. // If the caret is at the beginning of the document, Scintilla will not check // what's behind it (because there's nothing) var charPrev = docStart ? scintilla.GetCharAt(caretPos) : scintilla.GetCharAt(caretPos - 2); // int; gets what's after the inserted character var charNext = scintilla.GetCharAt(caretPos); ``` -------------------------------- ### Handle CharAdded for Autocompletion Source: https://github.com/desjarlais/scintilla.net/wiki/Basic-Autocompletion This C# code snippet demonstrates how to handle the CharAdded event to trigger autocompletion. It finds the start of the current word and displays the autocompletion list if characters have been entered. ```csharp private void scintilla_CharAdded(object sender, CharAddedEventArgs e) { // Find the word start var currentPos = scintilla.CurrentPosition; var wordStartPos = scintilla.WordStartPosition(currentPos, true); // Display the autocompletion list var lenEntered = currentPos - wordStartPos; if (lenEntered > 0) { if (!scintilla.AutoCActive) scintilla.AutoCShow(lenEntered, "abstract as base break case catch checked continue default delegate do else event explicit extern false finally fixed for foreach goto if implicit in interface internal is lock namespace new null object operator out override params private protected public readonly ref return sealed sizeof stackalloc switch this throw true try typeof unchecked unsafe using virtual while"); } } ``` -------------------------------- ### Iterate Through Indicator Ranges Source: https://github.com/desjarlais/scintilla.net/wiki/Indicators Iterate through all filled and cleared ranges for a specific indicator, checking if a range is filled using a bitmap flag. This example demonstrates how to retrieve text ranges tagged with a specific indicator. ```cs var textLength = scintilla.TextLength; var indicator = scintilla.Indicators[8]; var bitmapFlag = (1 << indicator.Index); var startPos = 0; var endPos = 0; do { startPos = indicator.Start(endPos); endPos = indicator.End(startPos); // Is this range filled with our indicator (8)? var bitmap = scintilla.IndicatorAllOnFor(startPos); var filled = ((bitmapFlag & bitmap) == bitmapFlag); if (filled) { // Do stuff with indicator range Debug.WriteLine(scintilla.GetTextRange(startPos, (endPos - startPos))); } } while (endPos != 0 && endPos < textLength); ``` -------------------------------- ### Get Caret Position and Document Boundaries Source: https://github.com/desjarlais/scintilla.net/wiki/Character-Autocompletion Defines variables to determine the current caret position and whether it is at the beginning or end of the document. These are used to inform autocompletion logic. ```csharp // int; the current position of caret var caretPos = scintilla.CurrentPosition; // bool; the caret is at the very beginning of the document var docStart = caretPos == 1; // bool; the caret is at the very end of the document var docEnd = caretPos == scintilla.Text.Length; ``` -------------------------------- ### Update Custom Line Numbers (Hexadecimal Example) Source: https://github.com/desjarlais/scintilla.net/wiki/Displaying-Line-Numbers This function updates the margin text for each line to display its line number in hexadecimal format. It is called when lines are inserted or deleted to ensure the line numbers remain accurate. ```cs private void UpdateLineNumbers(int startingAtLine) { // Starting at the specified line index, update each // subsequent line margin text with a hex line number. for (int i = startingAtLine; i < scintilla.Lines.Count; i++) { scintilla.Lines[i].MarginStyle = Style.LineNumber; scintilla.Lines[i].MarginText = "0x" + i.ToString("X2"); } } ``` ```cs private void scintilla_Insert(object sender, ModificationEventArgs e) { // Only update line numbers if the number of lines changed if (e.LinesAdded != 0) UpdateLineNumbers(scintilla.LineFromPosition(e.Position)); } ``` ```cs private void scintilla_Delete(object sender, ModificationEventArgs e) { // Only update line numbers if the number of lines changed if (e.LinesAdded != 0) UpdateLineNumbers(scintilla.LineFromPosition(e.Position)); } ``` -------------------------------- ### Send SCI_PAGEDOWN Message Directly Source: https://github.com/desjarlais/scintilla.net/wiki/Direct-Messages Use this method to send a message directly to the Scintilla control. This example sends the SCI_PAGEDOWN message to scroll the view down one page. Avoid using DirectMessage unless you are certain of the implications, as ScintillaNET makes assumptions about the control's state. ```cs const int SCI_PAGEDOWN = 2322; scintilla.DirectMessage(SCI_PAGEDOWN, IntPtr.Zero, IntPtr.Zero); ``` -------------------------------- ### Manual Syntax Styling with StartStyling and SetStyling Source: https://github.com/desjarlais/scintilla.net/wiki/Custom-Syntax-Highlighting Use StartStyling to set the initial position and SetStyling to apply styles to character ranges. Ensure the lexer is set to Lexer.Null to prevent interference from built-in lexers. ```cs scintilla.LexerName = string.Empty; scintilla.Styles[1].ForeColor = Color.Red; scintilla.Styles[2].ForeColor = Color.Blue; scintilla.StartStyling(0); scintilla.SetStyling(5, 1); scintilla.SetStyling(2, 2); ``` -------------------------------- ### Bind AutoCompleteMenu to ScintillaNET Source: https://github.com/desjarlais/scintilla.net/wiki/Custom-Autocompletion Initialize the AutoCompleteMenu by setting the TargetControlWrapper. This should be done in your Form_Load event or a similar initialization point. ```csharp AutoCompleteMenu.TargetControlWrapper = New ScintillaWrapper(scintilla1); ``` -------------------------------- ### Define and Apply Indicators Source: https://github.com/desjarlais/scintilla.net/wiki/Indicators Configure an indicator's style and color, set it as the current indicator, and then fill specified text ranges with it. ```cs // Define an indicator scintilla.Indicators[8].Style = IndicatorStyle.Squiggle; scintilla.Indicators[8].ForeColor = Color.Red; // Get ready for fill scintilla.IndicatorCurrent = 8; // Fill ranges scintilla.IndicatorFillRange(2, 5); scintilla.IndicatorFillRange(25, 33); // etc... ``` -------------------------------- ### Describe Keyword Sets for C++ Lexer Source: https://github.com/desjarlais/scintilla.net/wiki/Automatic-Syntax-Highlighting Call DescribeKeywordSets to understand the available keyword sets for the current lexer. This helps in determining which sets to configure for syntax highlighting. ```cs scintilla.Lexer = Lexer.Cpp; Console.WriteLine(scintilla.DescribeKeywordSets()); ``` -------------------------------- ### Configure Default and Cpp Lexer Styles Efficiently Source: https://github.com/desjarlais/scintilla.net/wiki/Automatic-Syntax-Highlighting This approach first resets and configures the default style with common properties, then applies it to all styles using StyleClearAll. Finally, it sets specific foreground colors for various C++ lexer token types. ```cs // Configuring the default style with properties // we have common to every lexer style saves time. scintilla.StyleResetDefault(); scintilla.Styles[Style.Default].Font = "Consolas"; scintilla.Styles[Style.Default].Size = 10; scintilla.StyleClearAll(); // Configure the CPP (C#) lexer styles scintilla.Styles[Style.Cpp.Default].ForeColor = Color.Silver; scintilla.Styles[Style.Cpp.Comment].ForeColor = Color.FromArgb(0, 128, 0); // Green scintilla.Styles[Style.Cpp.CommentLine].ForeColor = Color.FromArgb(0, 128, 0); // Green scintilla.Styles[Style.Cpp.CommentLineDoc].ForeColor = Color.FromArgb(128, 128, 128); // Gray scintilla.Styles[Style.Cpp.Number].ForeColor = Color.Olive; scintilla.Styles[Style.Cpp.Word].ForeColor = Color.Blue; scintilla.Styles[Style.Cpp.Word2].ForeColor = Color.Blue; scintilla.Styles[Style.Cpp.String].ForeColor = Color.FromArgb(163, 21, 21); // Red scintilla.Styles[Style.Cpp.Character].ForeColor = Color.FromArgb(163, 21, 21); // Red scintilla.Styles[Style.Cpp.Verbatim].ForeColor = Color.FromArgb(163, 21, 21); // Red scintilla.Styles[Style.Cpp.StringEol].BackColor = Color.Pink; scintilla.Styles[Style.Cpp.Operator].ForeColor = Color.Purple; scintilla.Styles[Style.Cpp.Preprocessor].ForeColor = Color.Maroon; ``` -------------------------------- ### Set Brace Styles Source: https://github.com/desjarlais/scintilla.net/wiki/Brace-Matching Configure the appearance for highlighted matching braces and bad (unmatched) braces. Use `Style.BraceLight` for matching braces and `Style.BraceBad` for unmatched ones. ```cs scintilla.Styles[Style.BraceLight].BackColor = Color.LightGray; scintilla.Styles[Style.BraceLight].ForeColor = Color.BlueViolet; scintilla.Styles[Style.BraceBad].ForeColor = Color.Red; ``` -------------------------------- ### Configure Default and C++ Lexer Styles Source: https://github.com/desjarlais/scintilla.net/wiki/Automatic-Syntax-Highlighting Set default font and size, then configure specific styles for C++ lexer elements like comments, numbers, keywords, strings, and operators. This provides a base for C# syntax highlighting. ```cs // Configuring the default style with properties // we have common to every lexer style saves time. scintilla.StyleResetDefault(); scintilla.Styles[Style.Default].Font = "Consolas"; scintilla.Styles[Style.Default].Size = 10; scintilla.StyleClearAll(); // Configure the CPP (C#) lexer styles scintilla.Styles[Style.Cpp.Default].ForeColor = Color.Silver; scintilla.Styles[Style.Cpp.Comment].ForeColor = Color.FromArgb(0, 128, 0); // Green scintilla.Styles[Style.Cpp.CommentLine].ForeColor = Color.FromArgb(0, 128, 0); // Green scintilla.Styles[Style.Cpp.CommentLineDoc].ForeColor = Color.FromArgb(128, 128, 128); // Gray scintilla.Styles[Style.Cpp.Number].ForeColor = Color.Olive; scintilla.Styles[Style.Cpp.Word].ForeColor = Color.Blue; scintilla.Styles[Style.Cpp.Word2].ForeColor = Color.Blue; scintilla.Styles[Style.Cpp.String].ForeColor = Color.FromArgb(163, 21, 21); // Red scintilla.Styles[Style.Cpp.Character].ForeColor = Color.FromArgb(163, 21, 21); // Red scintilla.Styles[Style.Cpp.Verbatim].ForeColor = Color.FromArgb(163, 21, 21); // Red scintilla.Styles[Style.Cpp.StringEol].BackColor = Color.Pink; scintilla.Styles[Style.Cpp.Operator].ForeColor = Color.Purple; scintilla.Styles[Style.Cpp.Preprocessor].ForeColor = Color.Maroon; scintilla.LexerName = "cpp"; ``` -------------------------------- ### Initiate Background Document Loading in Scintilla.NET Source: https://github.com/desjarlais/scintilla.net/wiki/Documents This event handler demonstrates how to create an ILoader, asynchronously load a file using LoadFileAsync, and assign the resulting document to the Scintilla control. It includes error handling for cancellation and other exceptions, and manages the document's reference count. ```cs private async void button_Click(object sender, EventArgs e) { try { var loader = scintilla.CreateLoader(256); if (loader == null) throw new ApplicationException("Unable to create loader."); var cts = new CancellationTokenSource(); var document = await LoadFileAsync(loader, @"your_file_path.txt", cts.Token); scintilla.Document = document; // Every document starts with a reference count of 1. Assigning it to Scintilla increased that to 2. // To let Scintilla control the life of the document, we'll drop it back down to 1. scintilla.ReleaseDocument(document); } catch (OperationCanceledException) { } catch(Exception) { MessageBox.Show(this, "There was an error loading the file.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); } } ``` -------------------------------- ### Implement Dynamic Autocomplete Collection Source: https://github.com/desjarlais/scintilla.net/wiki/Custom-Autocompletion Create a dynamic collection that implements IEnumerable to provide autocomplete suggestions based on the current text content. This is useful when the list of keywords changes frequently. ```csharp internal class DynamicCollection : IEnumerable { public IEnumerator GetEnumerator() { return BuildList().GetEnumerator(); } private IEnumerable BuildList() { //find all words of the text var words = new Dictionary(); foreach (Match m in Regex.Matches(tb.Text, @"\b\w+\b")) words[m.Value] = m.Value; //return autocomplete items foreach(var word in words.Keys) yield return new AutocompleteItem(word); } } ... autocompleteMenu1.SetAutocompleteItems(new DynamicCollection(tb)); ``` -------------------------------- ### Set Primary and Secondary Keywords for C# Source: https://github.com/desjarlais/scintilla.net/wiki/Automatic-Syntax-Highlighting Configure the primary and secondary keyword sets for C# syntax highlighting. Primary keywords include language keywords, and secondary keywords include .NET types. Keywords can be separated by any whitespace. ```cs scintilla.SetKeywords(0, "abstract as base break case catch checked continue default delegate do else event explicit extern false finally fixed for foreach goto if implicit in interface internal is lock namespace new null object operator out override params private protected public readonly ref return sealed sizeof stackalloc switch this throw true try typeof unchecked unsafe using virtual while"); scintilla.SetKeywords(1, "bool byte char class const decimal double enum float int long sbyte short static string struct uint ulong ushort void"); ``` -------------------------------- ### Initialize Jolt XML Reader Source: https://github.com/desjarlais/scintilla.net/wiki/Basic-Intellisense Initialize Jolt's XML reader before passing it to extender functions. This is typically done during the Form's Load event. ```VB.NET Private reader As Jolt.XmlDocCommentReader reader = New Jolt.XmlDocCommentReader(Assembly.GetExecutingAssembly()) ``` -------------------------------- ### Highlight Matching Braces in Scintilla.NET Source: https://github.com/desjarlais/scintilla.net/wiki/Brace-Matching This code snippet demonstrates how to highlight matching braces and indicate invalid brace pairings. It requires the `scintilla` control and a `lastCaretPos` variable to track caret movement. Ensure `Style.BraceLight` and `Style.BraceBad` are configured. ```C# scintilla.Styles[Style.BraceLight].ForeColor = Color.BlueViolet; scintilla.Styles[Style.BraceBad].ForeColor = Color.Red; } ``` ```C# private static bool IsBrace(int c) { switch (c) { case '(': case ')': case '[': case ']': case '{': case '}': case '<': case '>': return true; } return false; } ``` ```C# private void scintilla_UpdateUI(object sender, UpdateUIEventArgs e) { // Has the caret changed position? var caretPos = scintilla.CurrentPosition; if (lastCaretPos != caretPos) { lastCaretPos = caretPos; var bracePos1 = -1; var bracePos2 = -1; // Is there a brace to the left or right? if (caretPos > 0 && IsBrace(scintilla.GetCharAt(caretPos - 1))) bracePos1 = (caretPos - 1); else if (IsBrace(scintilla.GetCharAt(caretPos))) bracePos1 = caretPos; if (bracePos1 >= 0) { // Find the matching brace bracePos2 = scintilla.BraceMatch(bracePos1); if (bracePos2 == Scintilla.InvalidPosition) { scintilla.BraceBadLight(bracePos1); scintilla.HighlightGuide = 0; } else { scintilla.BraceHighlight(bracePos1, bracePos2); scintilla.HighlightGuide = scintilla.GetColumn(bracePos1); } } else { // Turn off brace matching scintilla.BraceHighlight(Scintilla.InvalidPosition, Scintilla.InvalidPosition); scintilla.HighlightGuide = 0; } } } ``` -------------------------------- ### Handle Caret Movement for Brace Matching Source: https://github.com/desjarlais/scintilla.net/wiki/Brace-Matching Listen to the `UpdateUI` event to detect caret movement. If the caret is adjacent to a brace, find and highlight the matching brace using `BraceMatch` and `BraceHighlight`. Unmatched braces are indicated with `BraceBadLight`. ```cs int lastCaretPos = 0; private void scintilla_UpdateUI(object sender, UpdateUIEventArgs e) { // Has the caret changed position? var caretPos = scintilla.CurrentPosition; if (lastCaretPos != caretPos) { lastCaretPos = caretPos; var bracePos1 = -1; var bracePos2 = -1; // Is there a brace to the left or right? if (caretPos > 0 && IsBrace(scintilla.GetCharAt(caretPos - 1))) bracePos1 = (caretPos - 1); else if (IsBrace(scintilla.GetCharAt(caretPos))) bracePos1 = caretPos; if (bracePos1 >= 0) { // Find the matching brace bracePos2 = scintilla.BraceMatch(bracePos1); if (bracePos2 == Scintilla.InvalidPosition) scintilla.BraceBadLight(bracePos1); else scintilla.BraceHighlight(bracePos1, bracePos2); } else { // Turn off brace matching scintilla.BraceHighlight(Scintilla.InvalidPosition, Scintilla.InvalidPosition); } } } ``` -------------------------------- ### Switch to Existing Document in Scintilla Source: https://github.com/desjarlais/scintilla.net/wiki/Documents Increases the reference count of the previous document before switching to a new one. After switching, it releases the new document to make Scintilla the sole owner, ensuring proper reference counting. ```cs private void SwitchDocument(Document nextDocument) { var prevDocument = scintilla.Document; scintilla.AddRefDocument(prevDocument); // Replace the current document and make Scintilla the owner scintilla.Document = nextDocument; scintilla.ReleaseDocument(nextDocument); } ``` -------------------------------- ### Set Cpp Lexer String Style Source: https://github.com/desjarlais/scintilla.net/wiki/Automatic-Syntax-Highlighting Use the Style.Cpp.String constant to set the font, size, and foreground color for string literals in the C++ lexer. ```cs scintilla.Styles[Style.Cpp.String].Font = "Consolas"; scintilla.Styles[Style.Cpp.String].Size = 10; scintilla.Styles[Style.Cpp.String].ForeColor = Color.FromArgb(163, 21, 21); // Red ``` -------------------------------- ### Scintilla.NET Form Load and Style Needed Event Handlers Source: https://github.com/desjarlais/scintilla.net/wiki/Custom-Syntax-Highlighting These C# methods handle the initialization of Scintilla.NET styles and the `StyleNeeded` event, delegating the actual lexing to a `CSharpLexer` instance. Ensure the `CSharpLexer` class is properly defined and initialized. ```csharp private CSharpLexer cSharpLexer = new CSharpLexer("class const int namespace partial public static string using void"); private void form_Load(object sender, EventArgs e) { scintilla.StyleResetDefault(); scintilla.Styles[Style.Default].Font = "Consolas"; scintilla.Styles[Style.Default].Size = 10; scintilla.StyleClearAll(); scintilla.Styles[CSharpLexer.StyleDefault].ForeColor = Color.Black; scintilla.Styles[CSharpLexer.StyleKeyword].ForeColor = Color.Blue; scintilla.Styles[CSharpLexer.StyleIdentifier].ForeColor = Color.Teal; scintilla.Styles[CSharpLexer.StyleNumber].ForeColor = Color.Purple; scintilla.Styles[CSharpLexer.StyleString].ForeColor = Color.Red; scintilla.Lexer = Lexer.Container; } private void scintilla_StyleNeeded(object sender, StyleNeededEventArgs e) { var startPos = scintilla.GetEndStyled(); var endPos = e.Position; cSharpLexer.Style(scintilla, startPos, endPos); } ``` -------------------------------- ### Define and Apply Indicators Source: https://github.com/desjarlais/scintilla.net/blob/master/docs/sections/indicators.md Defines a custom indicator with a specific style and color, then sets it as the current indicator to fill ranges of text. Use this to visually mark specific text segments. ```cs scintilla.Indicators[8].Style = IndicatorStyle.Squiggle; scintilla.Indicators[8].ForeColor = Color.Red; // Get ready for fill scintilla.IndicatorCurrent = 8; // Fill ranges scintilla.IndicatorFillRange(2, 5); scintilla.IndicatorFillRange(25, 33); // etc... ``` -------------------------------- ### Add Static Keywords at Runtime Source: https://github.com/desjarlais/scintilla.net/wiki/Custom-Autocompletion Use this method to add static keywords to the autocomplete menu when you need to change them during runtime. For truly dynamic keywords, consider Method 4. ```csharp string[] snippets = { "Whatever", "Bla", "Another_bla", "HEY" }; private void BuildAutocompleteMenu() { var items = new List(); foreach (var item in snippets) items.Add(new SnippetAutocompleteItem(item) { ImageIndex = 1 }); //set as autocomplete source autocompleteMenu1.SetAutocompleteItems(items); } ``` -------------------------------- ### Handling StyleNeeded Event for Dynamic Styling Source: https://github.com/desjarlais/scintilla.net/wiki/Custom-Syntax-Highlighting Enable custom styling by setting the lexer to Lexer.Container and handling the StyleNeeded event. Determine the range to style using GetEndStyled and the event's Position property. ```cs private void scintilla_StyleNeeded(object sender, StyleNeededEventArgs e) { var startPos = scintilla.GetEndStyled(); var endPos = e.Position; // TODO style this range } ``` -------------------------------- ### Set C# Lexer in Scintilla.net Source: https://github.com/desjarlais/scintilla.net/wiki/Automatic-Syntax-Highlighting Set the LexerName property to "cpp" to enable C# syntax highlighting. This lexer also supports C, Java, JavaScript, and others due to shared lexical grammar. ```cs scintilla.LexerName = "cpp"; ``` -------------------------------- ### Create Custom Autocomplete Item with Tooltip Source: https://github.com/desjarlais/scintilla.net/wiki/Custom-Autocompletion Define a custom AutocompleteItem class to store additional information like tooltips alongside the completion text. Override the Compare method to customize visibility and selection logic. ```csharp internal class EmailSnippet : AutocompleteItem { public EmailSnippet(string email): base(email) { ImageIndex = 0; ToolTipTitle = "Insert email:"; ToolTipText = email; } public override CompareResult Compare(string fragmentText) { if (fragmentText == Text) return CompareResult.VisibleAndSelected; if (fragmentText.Contains("@")) return CompareResult.Visible; return CompareResult.Hidden; } } ``` -------------------------------- ### Asynchronously Load File Data into Scintilla Document Source: https://github.com/desjarlais/scintilla.net/wiki/Documents This method loads character data from a file asynchronously into a Scintilla document using an ILoader. Ensure proper error handling and cancellation to manage the document's reference count. ```cs private async Task LoadFileAsync(ILoader loader, string path, CancellationToken cancellationToken) { try { using (var file = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read, bufferSize: 4096, useAsync: true)) using (var reader = new StreamReader(file)) { var count = 0; var buffer = new char[4096]; while ((count = await reader.ReadAsync(buffer, 0, buffer.Length).ConfigureAwait(false)) > 0) { // Check for cancellation cancellationToken.ThrowIfCancellationRequested(); // Add the data to the document if (!loader.AddData(buffer, count)) throw new IOException("The data could not be added to the loader."); } return loader.ConvertToDocument(); } } catch { loader.Release(); throw; } } ``` -------------------------------- ### Complete CSharpLexer Class Source: https://github.com/desjarlais/scintilla.net/wiki/Custom-Syntax-Highlighting This C# class implements a lexer for C# code, identifying keywords, identifiers, numbers, and strings. It manages internal states and uses a `HashSet` for efficient keyword lookup. The `Style` method processes a given range of text. ```csharp public class CSharpLexer { public const int StyleDefault = 0; public const int StyleKeyword = 1; public const int StyleIdentifier = 2; public const int StyleNumber = 3; public const int StyleString = 4; private const int STATE_UNKNOWN = 0; private const int STATE_IDENTIFIER = 1; private const int STATE_NUMBER = 2; private const int STATE_STRING = 3; private HashSet keywords; public void Style(Scintilla scintilla, int startPos, int endPos) { // Back up to the line start var line = scintilla.LineFromPosition(startPos); startPos = scintilla.Lines[line].Position; var length = 0; var state = STATE_UNKNOWN; // Start styling scintilla.StartStyling(startPos); while (startPos < endPos) { ``` -------------------------------- ### Configure Automatic Code Folding in Scintilla.NET Source: https://github.com/desjarlais/scintilla.net/wiki/Automatic-Cold-Folding This snippet demonstrates the essential steps to enable and customize automatic code folding for a lexer in Scintilla.NET. It covers setting lexer properties, configuring a margin for folding symbols, customizing marker appearances, and enabling automatic folding behavior. ```cs // Set the lexer scintilla.LexerName = "cpp"; // Instruct the lexer to calculate folding scintilla.SetProperty("fold", "1"); scintilla.SetProperty("fold.compact", "1"); // Configure a margin to display folding symbols scintilla.Margins[2].Type = MarginType.Symbol; scintilla.Margins[2].Mask = Marker.MaskFolders; scintilla.Margins[2].Sensitive = true; scintilla.Margins[2].Width = 20; // Set colors for all folding markers for (int i = 25; i <= 31; i++) { scintilla.Markers[i].SetForeColor(SystemColors.ControlLightLight); scintilla.Markers[i].SetBackColor(SystemColors.ControlDark); } // Configure folding markers with respective symbols scintilla.Markers[Marker.Folder].Symbol = MarkerSymbol.BoxPlus; scintilla.Markers[Marker.FolderOpen].Symbol = MarkerSymbol.BoxMinus; scintilla.Markers[Marker.FolderEnd].Symbol = MarkerSymbol.BoxPlusConnected; scintilla.Markers[Marker.FolderMidTail].Symbol = MarkerSymbol.TCorner; scintilla.Markers[Marker.FolderOpenMid].Symbol = MarkerSymbol.BoxMinusConnected; scintilla.Markers[Marker.FolderSub].Symbol = MarkerSymbol.VLine; scintilla.Markers[Marker.FolderTail].Symbol = MarkerSymbol.LCorner; // Enable automatic folding scintilla.AutomaticFold = (AutomaticFold.Show | AutomaticFold.Click | AutomaticFold.Change); ``` -------------------------------- ### Set Cpp Lexer Comment Line Style Source: https://github.com/desjarlais/scintilla.net/wiki/Automatic-Syntax-Highlighting Use the Style.Cpp.CommentLine constant to set the font, size, and foreground color for single-line comments in the C++ lexer. ```cs scintilla.Styles[Style.Cpp.CommentLine].Font = "Consolas"; scintilla.Styles[Style.Cpp.CommentLine].Size = 10; scintilla.Styles[Style.Cpp.CommentLine].ForeColor = Color.FromArgb(0, 128, 0); // Green ``` -------------------------------- ### Increase Line Spacing in Scintilla.net Source: https://github.com/desjarlais/scintilla.net/wiki/Increase-Line-Spacing Use ExtraAscent and ExtraDescent properties to add extra space above and below lines, improving readability. This is useful when the default font spacing is too cramped. ```cs // Increase line spacing scintilla.ExtraAscent = 5; scintilla.ExtraDescent = 5; ``` -------------------------------- ### Insert, Append, and Delete Text in ScintillaNET Source: https://github.com/desjarlais/scintilla.net/wiki/Basic-Text-Retrieval-and-Modification Efficiently modify document content using `AppendText`, `DeleteRange`, and `InsertText`. For removing a specific line, set `TargetStart` and `TargetEnd` and use `ReplaceTarget` with an empty string. ```cs scintilla.Text = "Hello"; scintilla.AppendText(" World"); // 'Hello' -> 'Hello World' scintilla.DeleteRange(0, 5); // 'Hello World' -> ' World' scintilla.InsertText(0, "Goodbye"); // ' World' -> 'Goodbye World' // Remove line from Scintilla scintilla.TargetStart = scintilla.Lines[0].Position; scintilla.TargetEnd = scintilla.Lines[0].EndPosition; scintilla.ReplaceTarget(string.Empty); ``` -------------------------------- ### Configure Margin for Custom Line Numbers Source: https://github.com/desjarlais/scintilla.net/wiki/Displaying-Line-Numbers Configure margin 0 to be a right-aligned text margin to display custom line number formats. Set an initial width sufficient for the custom display. ```cs scintilla.Margins[0].Type = MarginType.RightText; scintilla.Margins[0].Width = 35; ``` -------------------------------- ### Highlight Word with Indicator Source: https://github.com/desjarlais/scintilla.net/wiki/Find-and-Highlight-Words Finds all case-insensitive occurrences of a specified string and highlights them with a light-green indicator. Uses indicator 8, clearing previous uses and setting its appearance before searching. ```cs private void HighlightWord(string text) { if (string.IsNullOrEmpty(text)) return; // Indicators 0-7 could be in use by a lexer // so we'll use indicator 8 to highlight words. const int NUM = 8; // Remove all uses of our indicator scintilla.IndicatorCurrent = NUM; scintilla.IndicatorClearRange(0, scintilla.TextLength); // Update indicator appearance scintilla.Indicators[NUM].Style = IndicatorStyle.StraightBox; scintilla.Indicators[NUM].Under = true; scintilla.Indicators[NUM].ForeColor = Color.Green; scintilla.Indicators[NUM].OutlineAlpha = 50; scintilla.Indicators[NUM].Alpha = 30; // Search the document scintilla.TargetStart = 0; scintilla.TargetEnd = scintilla.TextLength; scintilla.SearchFlags = SearchFlags.None; while (scintilla.SearchInTarget(text) != -1) { // Mark the search results with the current indicator scintilla.IndicatorFillRange(scintilla.TargetStart, scintilla.TargetEnd - scintilla.TargetStart); // Search the remainder of the document scintilla.TargetStart = scintilla.TargetEnd; scintilla.TargetEnd = scintilla.TextLength; } } ``` -------------------------------- ### Basic C# Lexer Loop Skeleton Source: https://github.com/desjarlais/scintilla.net/wiki/Custom-Syntax-Highlighting This is the skeleton of a C# lexer loop that iterates through characters, identifies strings, and applies styling. It manages lexer states to correctly parse different token types. ```csharp public const int StyleString = 4; private const int STATE_UNKNOWN = 0; private const int STATE_STRING = 3; public void Style(Scintilla scintilla, int startPos, int endPos) { var state = STATE_UNKNOWN; // Start styling scintilla.StartStyling(startPos); while (startPos < endPos) { var c = (char)scintilla.GetCharAt(startPos); REPROCESS: switch (state) { case STATE_UNKNOWN: if (c == '"') { // Start of "string" scintilla.SetStyling(1, StyleString); state = STATE_STRING; } break; case STATE_STRING: break; // etc... } startPos++; } } ``` -------------------------------- ### Basic Character Autocompletion Source: https://github.com/desjarlais/scintilla.net/wiki/Character-Autocompletion Handles autocompletion for '()', '{}', '[]', '""', and "''" by inserting the closing character immediately after the opening one. This basic implementation may incorrectly autocomplete quotes in words like "you're". ```csharp private void scintilla_CharAdded(object sender, CharAddedEventArgs e) { switch (e.Char) { case '(': scintilla.InsertText(scintilla.CurrentPosition, ")"); break; case '{': scintilla.InsertText(scintilla.CurrentPosition, "}"); break; case '[': scintilla.InsertText(scintilla.CurrentPosition, "]"); break; case '"': scintilla.InsertText(scintilla.CurrentPosition, "\""); break; case '\'': scintilla.InsertText(scintilla.CurrentPosition, "'"); break; } } ``` -------------------------------- ### Create New Document in Scintilla Source: https://github.com/desjarlais/scintilla.net/wiki/Documents Increases the reference count of the current document before replacing it with a new blank document. This prevents the current document from being deleted when it's unassociated. ```cs private void NewDocument() { var document = scintilla.Document; scintilla.AddRefDocument(document); // Replace the current document with a new one scintilla.Document = Document.Empty; } ``` -------------------------------- ### Share Document Between Scintilla Controls Source: https://github.com/desjarlais/scintilla.net/wiki/Documents Assign the same Document object to multiple Scintilla controls to enable them to display and edit the same content. This increases the document's reference count. ```cs scintilla2.Document = scintilla1.Document; ``` -------------------------------- ### Combine Autocompletion Flags Source: https://github.com/desjarlais/scintilla.net/wiki/Character-Autocompletion Combines the previously defined boolean flags to determine if autocompletion should proceed for characters or strings. This logic helps prevent incorrect autocompletion. ```csharp // bool; combination of all of the flags above var isCharOrString = (isCharPrevBlank && isCharNextBlank) || isEnclosed || isSpaceEnclosed; ``` -------------------------------- ### Insert Matched Brackets and Quotes in Scintilla.net Source: https://github.com/desjarlais/scintilla.net/wiki/Character-Autocompletion This method handles the insertion of closing brackets and quotes. It checks the surrounding characters to determine if the insertion is appropriate, preventing unwanted behavior when typing within existing pairs or in specific contexts. ```csharp private void InsertMatchedChars(CharAddedEventArgs e) { var caretPos = scintilla.CurrentPosition; var docStart = caretPos == 1; var docEnd = caretPos == scintilla.Text.Length; var charPrev = docStart ? scintilla.GetCharAt(caretPos) : scintilla.GetCharAt(caretPos - 2); var charNext = scintilla.GetCharAt(caretPos); var isCharPrevBlank = charPrev == ' ' || charPrev == '\t' || charPrev == '\n' || charPrev == '\r'; var isCharNextBlank = charNext == ' ' || charNext == '\t' || charNext == '\n' || charNext == '\r' || docEnd; var isEnclosed = (charPrev == '(' && charNext == ')') || (charPrev == '{' && charNext == '}') || (charPrev == '[' && charNext == ']'); var isSpaceEnclosed = (charPrev == '(' && isCharNextBlank) || (isCharPrevBlank && charNext == ')') || (charPrev == '{' && isCharNextBlank) || (isCharPrevBlank && charNext == '}') || (charPrev == '[' && isCharNextBlank) || (isCharPrevBlank && charNext == ']'); var isCharOrString = (isCharPrevBlank && isCharNextBlank) || isEnclosed || isSpaceEnclosed; var charNextIsCharOrString = charNext == '"' || charNext == '\''; switch (e.Char) { case '(': if (charNextIsCharOrString) return; scintilla.InsertText(caretPos, ")"); break; case '{': if (charNextIsCharOrString) return; scintilla.InsertText(caretPos, "}"); break; case '[': if (charNextIsCharOrString) return; scintilla.InsertText(caretPos, "]"); break; case '"': // 0x22 = " if (charPrev == 0x22 && charNext == 0x22) { scintilla.DeleteRange(caretPos, 1); scintilla.GotoPosition(caretPos); return; } if (isCharOrString) scintilla.InsertText(caretPos, "\""); break; case '\'': // 0x27 = ' if (charPrev == 0x27 && charNext == 0x27) { scintilla.DeleteRange(caretPos, 1); scintilla.GotoPosition(caretPos); return; } if (isCharOrString) scintilla.InsertText(caretPos, "'" ); break; } } ``` -------------------------------- ### Insert Matching Brackets and Quotes in Visual Basic Source: https://github.com/desjarlais/scintilla.net/wiki/Character-Autocompletion This subroutine inserts matching closing characters for parentheses, braces, brackets, and quotes. It checks the context, such as whether the cursor is at the beginning or end of the document, and if the surrounding characters are blank or part of an existing string. Use this to provide automatic code completion for delimiters. ```vb Private Sub InsertMatchedChars(charNew As Char) Dim caretPos As Integer = txtScript.CurrentPosition Dim docStart As Boolean = caretPos = 1 Dim docEnd As Boolean = caretPos = txtScript.Text.Length Dim charPrev As Char = If(docStart, ChrW(txtScript.GetCharAt(caretPos)), ChrW(txtScript.GetCharAt(caretPos - 2))) Dim charNext As Char = ChrW(txtScript.GetCharAt(caretPos)) Dim isCharPrevBlank As Boolean = charPrev = " " OrElse charPrev = "\t" OrElse charPrev = "\n" OrElse charPrev = "\r" Dim isCharNextBlank As Boolean = charNext = " " OrElse charNext = "\t" OrElse charNext = "\n" OrElse charNext = "\r" OrElse docEnd Dim isEnclosed As Boolean = (charPrev = "(" AndAlso charNext = ")") OrElse (charPrev = "{" AndAlso charNext = "}") OrElse (charPrev = "[" AndAlso charNext = "]") Dim isSpaceEnclosed As Boolean = (charPrev = "(" AndAlso isCharNextBlank) OrElse (isCharPrevBlank AndAlso charNext = ")") OrElse (charPrev = "{" AndAlso isCharNextBlank) OrElse (isCharPrevBlank AndAlso charNext = "}") OrElse (charPrev = "[" AndAlso isCharNextBlank) OrElse (isCharPrevBlank AndAlso charNext = "]") Dim isCharOrString As Boolean = (isCharPrevBlank AndAlso isCharNextBlank) OrElse isEnclosed OrElse isSpaceEnclosed Dim charNextIsCharOrString As Boolean = charNext = """" OrElse charNext = "'" Select Case charNew Case "(" If charNextIsCharOrString Then Exit Sub End If txtScript.InsertText(caretPos, ")") Case "{" If charNextIsCharOrString Then Exit Sub End If txtScript.InsertText(caretPos, "}") Case "[" If charNextIsCharOrString Then Exit Sub End If txtScript.InsertText(caretPos, "]") Case """" If charPrev = """" AndAlso charNext = """" Then txtScript.DeleteRange(caretPos, 1) txtScript.GotoPosition(caretPos) Exit Sub End If If isCharOrString Then txtScript.InsertText(caretPos, """") End If Case "'" If charPrev = "'" AndAlso charNext = "'" Then txtScript.DeleteRange(caretPos, 1) txtScript.GotoPosition(caretPos) End If If isCharOrString Then txtScript.InsertText(caretPos, "'") End If End Select End Sub ``` ```vb Private Sub txtScript_CharAdded(sender As Object, e As CharAddedEventArgs) Handles txtScript.CharAdded InsertMatchedChars(ChrW(e.Char)) End Sub ```