Posted 5 years ago by Rob Smiley
Version: 14.1.0601
Avatar

Is it possible to setup the editor to auto complete vb methods & functions? e.g. when I enter 'Public Sub Test()' and press enter, i'd like the editor to automatically enter 'End Sub' below the caret.

I've been looking at interface IDelimiterAutoCompleter but this only supports a limited set of characters

Comments (2)

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

Hi Rob,

We don't currently have that feature in place, but I will log your request.  You could possibly add that sort of thing yourself in the meantime by watching for Enter key presses and then doing some token scanning (via the snapshot reader) back on the same line to see if there is a method start. If there is, then scan forward to see if there is a related end and if not, insert one.


Actipro Software Support

Posted 5 years ago by Rob Smiley
Avatar

Thanks - would be great if you could add this functionality in future. Anyone else whos interested, this is what i've come up with - should be pretty easy to extend to handle For/Next Do/While blocks etc. Just register a new instance of the class with VBSyntaxLanguage using RegisterService.

namespace MyApp
{
    using System.Windows.Input;
    using ActiproSoftware.Text;
    using ActiproSoftware.Text.Languages.VB.Implementation;
    using ActiproSoftware.Text.Utility;
    using ActiproSoftware.Windows.Controls.SyntaxEditor;

    internal sealed class VBCloseBlockProvider : ActiproSoftware.Text.Utility.IKeyedObject, IEditorViewKeyInputEventSink
    {
        string IKeyedObject.Key
        {
            get { return "VBCloseBlockProvider"; }
        }

        private bool GoToNextTokenChain(ITextSnapshotReader reader, params int[] tokens)
        {
            if (tokens == null || tokens.Length < 1) return false;

            if (!reader.GoToNextTokenWithId(tokens[0])) return false;

            int firstOffset = reader.Offset;
            reader.GoToCurrentWordEnd();

            for (int i = 1; i < tokens.Length; i++)
            {
                var spaceTok = reader.ReadToken();
                if (spaceTok == null || spaceTok.Id != VBTokenId.Whitespace) return false;

                var tok = reader.ReadToken();
                if (tok == null || tok.Id != tokens[i]) return false;
            }

            reader.Offset = firstOffset;

            return true;
        }

        private bool GoToPreviousTokenOnCurrentLine(ITextSnapshotReader reader, params int[] token)
        {
            int currentLine = reader.Position.Line;
            return reader.GoToPreviousTokenWithId(token) && reader.Position.Line == currentLine;
        }

        void IEditorViewKeyInputEventSink.NotifyKeyDown(IEditorView view, KeyEventArgs e)
        {
            // NOTE: process when user hits Enter/Return key
            if (e.Key != Key.Return && e.Key != Key.Enter) return;

            var reader = view.GetReader();
            int offset = reader.Offset;

            // NOTE: find previous sub/function keyword on the current line
            if (!this.GoToPreviousTokenOnCurrentLine(reader, VBTokenId.KeywordSub, VBTokenId.KeywordFunction)) return;

            // NOTE: note the type of token potentially marking the block start (sub or function), so corresponding close block can be entered later
            var blockStartToken = reader.PeekToken();

            // NOTE: ensure matched sub/func is not part of existing close block
            if (this.GoToPreviousTokenOnCurrentLine(reader, VBTokenId.KeywordEnd)) return;

            // NOTE: from original offset, find next sub or function statement
            reader.Offset = offset;
            int nextSubFuncOffset = reader.GoToNextTokenWithId(VBTokenId.KeywordSub, VBTokenId.KeywordFunction) ? reader.Offset : -1;

            // NOTE: from original offset, find next 'end sub|func' statement
            reader.Offset = offset;
            int endSubFuncOffset = this.GoToNextTokenChain(reader, VBTokenId.KeywordEnd, blockStartToken.Id) ? reader.Offset : -1;

            // NOTE: enter 'end sub|func' if none exists for the current block
            if (endSubFuncOffset < 0 || nextSubFuncOffset < 0 || nextSubFuncOffset < endSubFuncOffset)
            {
                switch(blockStartToken.Id)
                {
                    case VBTokenId.KeywordSub:
                        view.InsertSurroundingText("\n\t", "\nEnd Sub");
                        break;

                    case VBTokenId.KeywordFunction:
                        view.InsertSurroundingText("\n\t", "\nEnd Function");
                        break;
                }

                e.Handled = true;
            }
        }

        void IEditorViewKeyInputEventSink.NotifyKeyUp(IEditorView view, KeyEventArgs e) { }
    }
}
The latest build of this product (v2018.1 build 0675) 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.