Is parentheses matching supported?

SyntaxEditor for WPF Forum

Posted 10 years ago by Gustavo Guerra
Version: 9.1.0503
Avatar
If not, will it be in the near future?

Best Regards,
Gustavo Guerra

Comments (11)

Posted 10 years ago by Actipro Software Support - Cleveland, OH, USA
Avatar
Gustavo,

Sorry not yet, it is on our TODO list. I don't have a target date yet.


Actipro Software Support

Posted 9 years ago by Martin de Jong - Statistics Netherlands
Avatar
Hi

Still on your TODO list i guess? ;) Is it already in the top 10 ?
Posted 9 years ago by Actipro Software Support - Cleveland, OH, USA
Avatar
Hi Martin,

We just added auto-indent and text formatting capabilities in the most recent build. Samples showing how to use them are coming in the next build. Bracket highlighting is working its way up the list although working on the .NET Languages Add-on is about the top item next, especially since you can achieve bracket highlighting yourself right now if you wish via the use of our tagging and adornments framework.


Actipro Software Support

Posted 9 years ago by Chistopher Allen
Avatar
Hi,

Has brace matching been added yet? If not, would you be able to provide an example as to how this could be done using the adornments framework? (Also, I'm using the Silverlight version).

Thanks,
Chris

[Modified at 04/11/2011 02:01 PM]
Posted 9 years ago by Actipro Software Support - Cleveland, OH, USA
Avatar
Hi Chris,

Sorry not yet, we're still working on automated IntelliPrompt for the .NET Languages Add-on (it's a massive undertaking to do it "right").

We have bracket highlighting on the TODO list. You can implement it yourself in the meantime though. Our adornments framework is very flexible and the AdornmentsHighlightWord QuickStart shows a concept very similar to what you'd do for bracket highlighting.


Actipro Software Support

Posted 9 years ago by Martin de Jong - Statistics Netherlands
Avatar
Using the tagging framework and tokens i am trying this:

namespace StatNeth.Blaise.IDE.SourceEditorWPF.Language {

    /// <summary>
    /// Bracket Tagger tags matching brackets and IF/ENDIF tokens
    /// </summary>
    public class BracketTagger : TaggerBase<IClassificationTag> {

        private IToken selectedToken = null;    // token selected by user
        private int matchingTokenId = -1;       // matching token to look for
        private List<int> hoppingNodes = null;  // tokens part of the bracket combination (e.g ELSE for a IF token)
        private bool scanUpwards = true;

        private IEditorView view;

        private static List<int> IF_Nodes = new List<int>();   // hopping nodes for the IF token

        private static IClassificationType bracketClassificationType = new ClassificationType("BracketHighlight", "Bracket Highlight");

            
        /// <summary>
        /// Initializes the <c>BracketTagger</c> class.
        /// </summary>
        static BracketTagger() {
            SolidColorBrush brush = new SolidColorBrush(Color.FromArgb(0x70, 0xC0, 0xC0, 0xC0));
            AmbientHighlightingStyleRegistry.Instance.Register(bracketClassificationType, new HighlightingStyle(null, brush));
            IF_Nodes.Add(Mediator.K_ELSEIF);
            IF_Nodes.Add(Mediator.K_ELSE);
        }

        /// <summary>
        /// Initializes a new instance of the <c>WordHighlightTagger</c> class.
        /// </summary>
        /// <param name="view">The view to which this manager is attached.</param>
        public BracketTagger(IEditorView view)
            : base("CustomBracketTagger",
            new Ordering[] { new Ordering(TaggerKeys.Token, OrderPlacement.Before) }, view.SyntaxEditor.Document) {
            
            // Initialize
            this.view = view;
            this.view.SelectionChanged += new EventHandler<EditorViewSelectionEventArgs>(OnViewSelectionChanged);

            // Update current word
            this.UpdateCurrentBracket();
        }
        
        /// <summary>
        /// Occurs when the view's selection is changed.
        /// </summary>
        /// <param name="sender">The sender of the event.</param>
        /// <param name="e">The <see cref="EditorViewSelectionEventArgs"/> that contains data related to this event.</param>
        private void OnViewSelectionChanged(object sender, EditorViewSelectionEventArgs e) {
            if (view == null)
                return;
            
            // Update
            this.UpdateCurrentBracket();
        }

        private void UpdateCurrentBracket() {
            // reset
            selectedToken = null;
            matchingTokenId = -1;
            hoppingNodes = null;
            
            if ((view == null) || (view.Selection == null))
                return;

            TextRange tr = view.GetCurrentWordTextRange();
            if (tr.IsDeleted)
                return;
            selectedToken = view.CurrentSnapshot.GetReader(tr.StartOffset).Token;
            if (selectedToken == null || selectedToken.TextRange == null || selectedToken.TextRange.IsDeleted) {
                selectedToken = null;
                return;
            }
            switch (selectedToken.Id) {
                case Mediator.OpenParenthesis :
                    matchingTokenId = Mediator.CloseParenthesis;
                    scanUpwards = false;
                    break;
                case Mediator.CloseParenthesis:
                    matchingTokenId = Mediator.OpenParenthesis;
                    scanUpwards = true;
                    break;
                case Mediator.OpenSquareBrace:
                    matchingTokenId = Mediator.CloseSquareBrace;
                    scanUpwards = false;
                    break;
                case Mediator.CloseSquareBrace:
                    matchingTokenId = Mediator.OpenSquareBrace;
                    scanUpwards = true;
                    break;
                case Mediator.K_IF:
                    matchingTokenId = Mediator.K_ENDIF;
                    hoppingNodes = IF_Nodes;
                    scanUpwards = false;
                    break;
                case Mediator.K_ENDIF:
                    matchingTokenId = Mediator.K_IF;
                    hoppingNodes = IF_Nodes;
                    scanUpwards = true;
                    break;
                case Mediator.K_DO:
                    matchingTokenId = Mediator.K_ENDDO;
                    scanUpwards = false;
                    break;
                case Mediator.K_ENDDO:
                    matchingTokenId = Mediator.K_DO;
                    scanUpwards = true;
                    break;
                default:
                    selectedToken = null;
                    return;
            }
            // Notify that tags changed
            this.OnTagsChanged(new TagsChangedEventArgs(new TextSnapshotRange(view.SyntaxEditor.Document.CurrentSnapshot, view.SyntaxEditor.Document.CurrentSnapshot.TextRange)));
        }
    
        /////////////////////////////////////////////////////////////////////////////////////////////////////
        // PUBLIC PROCEDURES
        /////////////////////////////////////////////////////////////////////////////////////////////////////
        
        /// <summary>
        /// Returns the tag ranges that intersect with the specified normalized snapshot ranges.
        /// </summary>
        /// <param name="snapshotRanges">The collection of normalized snapshot ranges.</param>
        /// <param name="parameter">An optional parameter that provides contextual information about the tag request.</param>
        /// <returns>The tag ranges that intersect with the specified normalized snapshot ranges.</returns>
        public override IEnumerable<TagSnapshotRange<IClassificationTag>> GetTags(NormalizedTextSnapshotRangeCollection snapshotRanges, object parameter) {
            if (selectedToken == null)
                yield break;

            // Loop through the requested snapshot ranges...
            foreach (TextSnapshotRange snapshotRange in snapshotRanges) {
                // If the snapshot range is not zero-length...
                if (!snapshotRange.IsZeroLength) {
                    ITextSnapshotReader reader = null;
                    List<TextRange> hops = new List<TextRange>();
                    int stackSize = 0;
                    // get reader for search text
                    if (scanUpwards) {
                        reader = snapshotRange.Snapshot.GetReader(0);
                        if (reader != null) {
                            reader.Offset = selectedToken.StartOffset - 1;
                        }
                    } else {
                        reader = snapshotRange.Snapshot.GetReader(selectedToken.TextRange.LastOffset);
                    }
                    // start scanning 
                    while (reader != null && reader.Token != null &&
                        ( (scanUpwards && !reader.IsAtSnapshotStart) ||
                          (!scanUpwards && !reader.IsAtSnapshotEnd))) {
                        if (selectedToken.Id == reader.Token.Id) {
                            stackSize++;
                        } else if (stackSize == 0 && hoppingNodes != null && hoppingNodes.Contains(reader.Token.Id)) {
                            hops.Add(reader.Token.TextRange);
                        } else if (matchingTokenId == reader.Token.Id) {
                            if (stackSize > 0)
                                stackSize--;
                            else {
                                // mark selected token
                                yield return CreateTag(snapshotRange.Snapshot, selectedToken.TextRange);
                                // mark matching token
                                yield return CreateTag(snapshotRange.Snapshot, reader.Token.TextRange);
                                // mark hops
                                foreach (TextRange tr in hops) {
                                    yield return CreateTag(snapshotRange.Snapshot, tr);
                                }
                                yield break;
                            }
                        }
                        if (scanUpwards) {
                            reader.GoToPreviousToken();
                        } else {
                            reader.GoToNextToken();
                        }
                    } // while
                }
            }
        }

        /// <summary>
        /// Create a standard BracketTag
        /// </summary>
        /// <param name="snapshot"></param>
        /// <param name="textRange"></param>
        /// <returns></returns>
        private static TagSnapshotRange<IClassificationTag> CreateTag(ITextSnapshot snapshot, TextRange textRange) {
            return new TagSnapshotRange<IClassificationTag>(
                                        new TextSnapshotRange(snapshot, textRange),
                                        new ClassificationTag(bracketClassificationType)
                                        );
        }
        
        /// <summary>
        /// Occurs when the manager is closed and detached from the view.
        /// </summary>
        /// <remarks>
        /// The default implementation of this method does nothing.
        /// Overrides should release any event handlers set up in the manager's constructor.
        /// </remarks>
        protected override void OnClosed() {
            // Detach from the view
            if (view != null) {
                view.SelectionChanged -= new EventHandler<EditorViewSelectionEventArgs>(OnViewSelectionChanged);
                view = null;
            }

            // Call the base method
            base.OnClosed();
        }
        
    }
}
Any comments on this?
Posted 9 years ago by Chistopher Allen
Avatar
Thanks, I'm trying it out. What assembly is Mediator in? I haven't been able to locate it and I'm wondering if it might be in a WPF specific assembly and if there is a Silverlight equivalent?
Posted 9 years ago by Martin de Jong - Statistics Netherlands
Avatar
My piece of code is token based. The Mediator class is actually the (Antlr)-lexer class which contains all the token ids. If you have a lexer you can retrieve the token ids from there. Token based scanning of the text seemed to me a bit more reliable then just scanning text for strings.

So references to the Mediator class should be replaced by your own class containing lexing ids. Please keep in mind that this sample is not (fully) tested, it is just my try. :)
Posted 9 years ago by Chistopher Allen
Avatar
Ah, got it. Thanks for you help, I was able to get your sample working!
Posted 9 years ago by Actipro Software Support - Cleveland, OH, USA
Avatar
Our only comment would be that in scenarios where you have very large documents, scanning back through all the tokens of the document could affect performance. You may want to cap how many tokens back you scan to ensure performance remains high while typing.


Actipro Software Support

Answer - Posted 7 years ago by Actipro Software Support - Cleveland, OH, USA
Avatar

We're happy to announce that delimiter highlighting has been added as a feature in the upcoming 2012.2 versions of SyntaxEditor. More detail is here:

http://blog.actiprosoftware.com/post.aspx?id=f0d37707-b41e-4f62-aca6-f92be80fba0e


Actipro Software Support

The latest build of this product (v2019.1 build 0683) was released 1 month ago, which was after the last post in this thread.

Add Comment

Please log in to a validated account to post comments.