Esempio n. 1
0
 /// <summary>
 /// Initializes a new instance of the <see cref="ValueChangedEventArgs"/> class.
 /// </summary>
 /// <param name="rawValue">The raw analog sensor reading</param>
 /// <param name="value">The analog sensor reading, converted to voltage.</param>
 /// <param name="pinNumber">The pin number that triggered the event.</param>
 /// <param name="triggerReason">The reason for the event</param>
 public ValueChangedEventArgs(uint rawValue, ElectricPotential value, int pinNumber, TriggerReason triggerReason)
 {
     RawValue      = rawValue;
     Value         = value;
     PinNumber     = pinNumber;
     TriggerReason = triggerReason;
 }
 public static TriggerState GetTriggerState(
     string expression, TriggerReason reason, char typedChar, bool isCondition,
     out int triggerLength, out ExpressionNode triggerExpression, out ListKind listKind,
     out IReadOnlyList <ExpressionNode> comparandVariables)
 {
     comparandVariables = null;
     if (isCondition)
     {
         listKind = ListKind.None;
         return(GetConditionTriggerState(expression, reason, typedChar, out triggerLength, out triggerExpression, out comparandVariables));
     }
     return(GetTriggerState(expression, reason, typedChar, out triggerLength, out triggerExpression, out listKind));
 }
Esempio n. 3
0
        public static TriggerState GetTriggerState(
            string expression, TriggerReason reason, char typedChar, bool isCondition,
            out int triggerLength, out ExpressionNode triggerExpression, out ListKind listKind,
            out IReadOnlyList <ExpressionNode> comparandVariables)
        {
            comparandVariables = null;

            var state = GetTriggerState(expression, reason, typedChar, isCondition, out triggerLength, out triggerExpression, out var triggerNode, out listKind);

            if (state != TriggerState.None && isCondition)
            {
                comparandVariables = GetComparandVariables(triggerNode).ToList();
            }

            return(state);
        }
Esempio n. 4
0
        static TriggerState GetTriggerState(
            string expression, TriggerReason reason, char typedChar, bool isCondition,
            out int triggerLength, out ExpressionNode triggerExpression, out ExpressionNode triggerNode, out ListKind listKind)
        {
            triggerLength = 0;
            listKind      = ListKind.None;

            var isNewline   = typedChar == '\n';
            var isTypedChar = reason == TriggerReason.TypedChar;

            if (isTypedChar && !isNewline && expression.Length > 0 && expression[expression.Length - 1] != typedChar)
            {
                triggerExpression = null;
                triggerNode       = null;
                LoggingService.LogWarning($"Expression text '{expression}' is not consistent with typed character '{typedChar}'");
                return(TriggerState.None);
            }

            if (expression.Length == 0)
            {
                //automatically trigger at the start of an expression regardless
                triggerExpression = new ExpressionText(0, expression, true);
                triggerNode       = triggerExpression;
                return(TriggerState.Value);
            }

            if (isCondition)
            {
                triggerExpression = ExpressionParser.ParseCondition(expression);
            }
            else
            {
                const ExpressionOptions options = ExpressionOptions.ItemsMetadataAndLists | ExpressionOptions.CommaLists;
                triggerExpression = ExpressionParser.Parse(expression, options);
            }

            return(GetTriggerState(triggerExpression, reason, typedChar, out triggerLength, out triggerNode, out listKind));
        }
Esempio n. 5
0
        static TriggerState GetTriggerState(
            ExpressionNode triggerExpression, TriggerReason reason, char typedChar,
            out int triggerLength, out ExpressionNode triggerNode, out ListKind listKind)
        {
            triggerLength = 0;
            listKind      = ListKind.None;

            var isExplicit  = reason == TriggerReason.Invocation;
            var isBackspace = reason == TriggerReason.Backspace;
            var isTypedChar = reason == TriggerReason.TypedChar;

            if (triggerExpression is ListExpression el)
            {
                //the last list entry is the thing that triggered it
                triggerExpression = el.Nodes.Last();
                listKind          = el.Separator == ',' ? ListKind.Comma : ListKind.Semicolon;
                if (triggerExpression is ExpressionError e && e.Kind == ExpressionErrorKind.EmptyListEntry)
                {
                    triggerLength = 0;
                    triggerNode   = triggerExpression;
                    return(TriggerState.Value);
                }
            }

            if (triggerExpression is ExpressionText text)
            {
                //automatically trigger at the start of an expression regardless
                if (text.Length == 0)
                {
                    triggerNode = triggerExpression;
                    return(TriggerState.Value);
                }

                if (typedChar == '\\' || (!isTypedChar && text.Value[text.Length - 1] == '\\'))
                {
                    triggerLength = 0;
                    triggerNode   = triggerExpression;
                    return(TriggerState.DirectorySeparator);
                }

                var val = text.Value;
                int leadingWhitespace = 0;
                for (int i = 0; i < val.Length; i++)
                {
                    if (char.IsWhiteSpace(val[i]))
                    {
                        leadingWhitespace++;
                    }
                    else
                    {
                        break;
                    }
                }

                var length = val.Length - leadingWhitespace;
                if (length == 0)
                {
                    triggerLength = 0;
                    triggerNode   = triggerExpression;
                    return(isExplicit ? TriggerState.Value : TriggerState.None);
                }

                //auto trigger on first char
                if (length == 1 && !isBackspace)
                {
                    triggerLength = 1;
                    triggerNode   = triggerExpression;
                    return(TriggerState.Value);
                }

                if (isExplicit)
                {
                    var lastSlash = text.Value.LastIndexOf('\\');
                    if (lastSlash != -1)
                    {
                        triggerLength = text.Length - lastSlash - 1;
                        triggerNode   = triggerExpression;
                        return(TriggerState.DirectorySeparator);
                    }
                    triggerLength = length;
                    triggerNode   = triggerExpression;
                    return(TriggerState.Value);
                }

                triggerLength = 0;
                triggerNode   = null;
                return(TriggerState.None);
            }

            //find the deepest node that touches the end
            triggerNode = triggerExpression.Find(triggerExpression.End);
            if (triggerNode == null)
            {
                return(TriggerState.None);
            }

            // if inside a quoted expression, scope down
            if (triggerNode != triggerExpression)
            {
                ExpressionNode p = triggerNode.Parent;
                while (p != null && p != triggerExpression)
                {
                    if (p is QuotedExpression quotedExpr)
                    {
                        return(GetTriggerState(
                                   quotedExpr.Expression, reason, typedChar,
                                   out triggerLength, out triggerNode, out _));
                    }
                    p = p.Parent;
                }
            }

            // path separator completion
            if (triggerNode is ExpressionText lit)
            {
                if (lit.Length > 0 && lit.Value[lit.Length - 1] == '\\')
                {
                    return(TriggerState.DirectorySeparator);
                }

                //explicit trigger grabs back to last slash, if any
                if (isExplicit)
                {
                    var lastSlash = lit.Value.LastIndexOf('\\');
                    if (lastSlash != -1)
                    {
                        triggerLength = lit.Length - lastSlash - 1;
                        return(TriggerState.DirectorySeparator);
                    }
                }

                //eager trigger on first char after /
                if (!isExplicit && lit.Length > 1 && lit.Value[lit.Value.Length - 2] == '\\' && IsPossiblePathSegmentStart(typedChar))
                {
                    triggerLength = 1;
                    return(TriggerState.DirectorySeparator);
                }
            }

            //find the deepest error
            var error = triggerNode as ExpressionError;

            if (error == null)
            {
                ExpressionNode p = triggerNode.Parent;
                while (p != null && error == null)
                {
                    error = p as IncompleteExpressionError;
                    if (p == triggerExpression)
                    {
                        break;
                    }
                    p = p.Parent;
                }
            }

            if (triggerNode == error && !(error is IncompleteExpressionError))
            {
                triggerNode = error.Parent;
            }

            if (error is ExpressionError ee && ee.WasEOF)
            {
                ExpressionNode parent = triggerNode.Parent is ExpressionError err ? err.Parent : triggerNode.Parent;
                switch (triggerNode)
                {
                case ExpressionItem _:
                    if (ee.Kind == ExpressionErrorKind.ExpectingMethodOrTransform)
                    {
                        return(TriggerState.ItemFunctionName);
                    }
                    break;

                case ExpressionItemName ein:
                    if (ee.Kind == ExpressionErrorKind.ExpectingRightParenOrDash)
                    {
                        if (ShouldTriggerName(ein.Name))
                        {
                            triggerLength = ein.Name.Length;
                            return(TriggerState.ItemName);
                        }
                        return(TriggerState.None);
                    }
                    break;

                case ExpressionPropertyName pn:
                    if (ee.Kind == ExpressionErrorKind.ExpectingRightParenOrPeriod)
                    {
                        if (ShouldTriggerName(pn.Name))
                        {
                            triggerLength = pn.Name.Length;
                            return(TriggerState.PropertyName);
                        }
                        return(TriggerState.None);
                    }
                    break;

                case ExpressionFunctionName fn:
                    if (ee.Kind == ExpressionErrorKind.IncompleteProperty)
                    {
                        if (ShouldTriggerName(fn.Name))
                        {
                            triggerLength = fn.Name.Length;
                            if (IsConditionFunctionError(ee))
                            {
                                return(TriggerState.ConditionFunctionName);
                            }
                            return(TriggerState.PropertyFunctionName);
                        }
                        return(TriggerState.None);
                    }
                    if (ee.Kind == ExpressionErrorKind.ExpectingLeftParen)
                    {
                        if (ShouldTriggerName(fn.Name))
                        {
                            triggerLength = fn.Name.Length;
                            if (IsConditionFunctionError(ee))
                            {
                                return(TriggerState.ConditionFunctionName);
                            }
                            return(TriggerState.ItemFunctionName);
                        }
                        return(TriggerState.None);
                    }
                    break;

                case ExpressionPropertyFunctionInvocation _:
                    if (ee.Kind == ExpressionErrorKind.ExpectingMethodName)
                    {
                        return(TriggerState.PropertyFunctionName);
                    }
                    if (ee.Kind == ExpressionErrorKind.ExpectingClassName)
                    {
                        return(TriggerState.PropertyFunctionClassName);
                    }
                    break;

                case ExpressionClassReference cr:
                    if (ee.Kind == ExpressionErrorKind.ExpectingBracketColonColon ||
                        ((ee.Kind == ExpressionErrorKind.ExpectingRightParenOrValue || ee.Kind == ExpressionErrorKind.ExpectingRightParenOrComma) && parent is ExpressionArgumentList)
                        )
                    {
                        if (ShouldTriggerName(cr.Name))
                        {
                            triggerLength = cr.Name.Length;
                            return(parent is ExpressionArgumentList? TriggerState.BareFunctionArgumentValue : TriggerState.PropertyFunctionClassName);
                        }
                        return(TriggerState.None);
                    }
                    break;

                case ExpressionMetadata m:
                    if (ee.Kind == ExpressionErrorKind.ExpectingMetadataName)
                    {
                        return(TriggerState.MetadataName);
                    }
                    if (ee.Kind == ExpressionErrorKind.ExpectingRightParenOrPeriod)
                    {
                        if (ShouldTriggerName(m.ItemName))
                        {
                            triggerLength = m.ItemName.Length;
                            return(TriggerState.MetadataOrItemName);
                        }
                        return(TriggerState.None);
                    }
                    if (ee.Kind == ExpressionErrorKind.ExpectingRightParen)
                    {
                        if (ShouldTriggerName(m.MetadataName))
                        {
                            triggerLength = m.MetadataName.Length;
                            return(TriggerState.MetadataName);
                        }
                        return(TriggerState.None);
                    }
                    break;

                case ExpressionText expressionText: {
                    if (
                        (error.Kind == ExpressionErrorKind.IncompleteString &&
                         (parent is ExpressionArgumentList || parent is ExpressionItemTransform || parent is ExpressionConditionOperator || parent is QuotedExpression)) ||
                        (error.Kind == ExpressionErrorKind.ExpectingRightParenOrValue && parent is ExpressionArgumentList)
                        )
                    {
                        var s = GetTriggerState(
                            expressionText.Value, reason, typedChar, false,
                            out triggerLength, out triggerExpression, out triggerNode, out _);
                        if (error.Kind != ExpressionErrorKind.IncompleteString && s == TriggerState.Value)
                        {
                            return(TriggerState.BareFunctionArgumentValue);
                        }
                        return(s);
                    }
                }
                break;

                case ExpressionArgumentList _: {
                    if (error.Kind == ExpressionErrorKind.ExpectingRightParenOrValue)
                    {
                        return(TriggerState.BareFunctionArgumentValue);
                    }
                }
                break;
                }
            }

            if (error != null)
            {
                switch (error.Kind)
                {
                case ExpressionErrorKind.ExpectingPropertyName:
                    return(TriggerState.PropertyName);

                case ExpressionErrorKind.ExpectingItemName:
                    return(TriggerState.ItemName);

                case ExpressionErrorKind.ExpectingMetadataOrItemName:
                    return(TriggerState.MetadataOrItemName);

                case ExpressionErrorKind.ExpectingClassName:
                    return(TriggerState.PropertyFunctionClassName);
                }
                return(TriggerState.None);
            }

            return(TriggerState.None);

            bool IsPossiblePathSegmentStart(char c) => c == '_' || char.IsLetterOrDigit(c) || c == '.';
            bool ShouldTriggerName(string n) =>
            isExplicit ||
            (isTypedChar && n.Length == 1) ||
            (isBackspace && n.Length == 0);

            bool IsConditionFunctionError(ExpressionError ee)
            => ee.Parent is ExpressionConditionOperator ||
            ee is IncompleteExpressionError iee && iee.IncompleteNode is ExpressionConditionFunction;
        }
        static TriggerState GetTriggerState(
            string expression, TriggerReason reason, char typedChar,
            out int triggerLength, out ExpressionNode triggerExpression, out ListKind listKind)
        {
            triggerLength = 0;
            listKind      = ListKind.None;

            var isExplicit  = reason == TriggerReason.Invocation;
            var isNewline   = typedChar == '\n';
            var isBackspace = reason == TriggerReason.Backspace;
            var isTypedChar = reason == TriggerReason.TypedChar;

            if (isTypedChar && !isNewline && expression.Length > 0 && expression[expression.Length - 1] != typedChar)
            {
                triggerExpression = null;
                LoggingService.LogWarning($"Expression text '{expression}' is not consistent with typed character '{typedChar}'");
                return(TriggerState.None);
            }

            if (expression.Length == 0)
            {
                //automatically trigger at the start of an expression regardless
                triggerExpression = new ExpressionText(0, expression, true);
                return(TriggerState.Value);
            }

            const ExpressionOptions options = ExpressionOptions.ItemsMetadataAndLists | ExpressionOptions.CommaLists;

            triggerExpression = ExpressionParser.Parse(expression, options);

            if (triggerExpression is ListExpression el)
            {
                //the last list entry is the thing that triggered it
                triggerExpression = el.Nodes.Last();
                if (triggerExpression is ExpressionError e && e.Kind == ExpressionErrorKind.EmptyListEntry)
                {
                    triggerLength = 0;
                    listKind      = LastChar() == ',' ? ListKind.Comma : ListKind.Semicolon;
                    return(TriggerState.Value);
                }
                var separator = expression[triggerExpression.Offset - 1];
                listKind = separator == ',' ? ListKind.Comma : ListKind.Semicolon;
            }

            if (triggerExpression is ExpressionText text)
            {
                if (typedChar == '\\' || (!isTypedChar && LastChar() == '\\'))
                {
                    triggerLength = 0;
                    return(TriggerState.DirectorySeparator);
                }

                var val = text.Value;
                int leadingWhitespace = 0;
                for (int i = 0; i < val.Length; i++)
                {
                    if (char.IsWhiteSpace(val[i]))
                    {
                        leadingWhitespace++;
                    }
                    else
                    {
                        break;
                    }
                }

                var length = val.Length - leadingWhitespace;
                if (length == 0)
                {
                    triggerLength = 0;
                    return(isExplicit ? TriggerState.Value : TriggerState.None);
                }

                //auto trigger on first char
                if (length == 1 && !isBackspace)
                {
                    triggerLength = 1;
                    return(TriggerState.Value);
                }

                if (isExplicit)
                {
                    var lastSlash = text.Value.LastIndexOf('\\');
                    if (lastSlash != -1)
                    {
                        triggerLength = text.Length - lastSlash - 1;
                        return(TriggerState.DirectorySeparator);
                    }
                    triggerLength = length;
                    return(TriggerState.Value);
                }

                triggerLength = 0;
                return(TriggerState.None);
            }

            //find the deepest node that touches the end
            var lastNode = triggerExpression.Find(expression.Length);

            if (lastNode == null)
            {
                return(TriggerState.None);
            }

            if (lastNode is ExpressionText lit)
            {
                if (LastChar() == '\\')
                {
                    return(TriggerState.DirectorySeparator);
                }

                //explicit trigger grabs back to last slash, if any
                if (isExplicit)
                {
                    var lastSlash = lit.Value.LastIndexOf('\\');
                    if (lastSlash != -1)
                    {
                        triggerLength = lit.Length - lastSlash - 1;
                        return(TriggerState.DirectorySeparator);
                    }
                }

                //eager trigger on first char after /
                if (!isExplicit && PenultimateChar() == '\\' && IsPossiblePathSegmentStart(typedChar))
                {
                    triggerLength = 1;
                    return(TriggerState.DirectorySeparator);
                }
            }

            //find the deepest error
            var            error  = lastNode as ExpressionError;
            ExpressionNode parent = lastNode.Parent;

            while (parent != null && error == null)
            {
                error  = parent as ExpressionError;
                parent = parent.Parent;
            }

            if (error is IncompleteExpressionError iee && iee.WasEOF)
            {
                switch (lastNode)
                {
                case ExpressionItem _:
                    if (iee.Kind == ExpressionErrorKind.ExpectingMethodOrTransform)
                    {
                        return(TriggerState.ItemFunctionName);
                    }
                    break;

                case ExpressionItemName ein:
                    if (iee.Kind == ExpressionErrorKind.ExpectingRightParenOrDash)
                    {
                        if (ShouldTriggerName(ein.Name))
                        {
                            triggerLength = ein.Name.Length;
                            return(TriggerState.ItemName);
                        }
                        return(TriggerState.None);
                    }
                    break;

                case ExpressionPropertyName pn:
                    if (iee.Kind == ExpressionErrorKind.ExpectingRightParenOrPeriod)
                    {
                        if (ShouldTriggerName(pn.Name))
                        {
                            triggerLength = pn.Name.Length;
                            return(TriggerState.PropertyName);
                        }
                        return(TriggerState.None);
                    }
                    break;

                case ExpressionFunctionName fn:
                    if (iee.Kind == ExpressionErrorKind.IncompleteProperty)
                    {
                        if (ShouldTriggerName(fn.Name))
                        {
                            triggerLength = fn.Name.Length;
                            return(TriggerState.PropertyFunctionName);
                        }
                        return(TriggerState.None);
                    }
                    if (iee.Kind == ExpressionErrorKind.ExpectingLeftParen)
                    {
                        if (ShouldTriggerName(fn.Name))
                        {
                            triggerLength = fn.Name.Length;
                            return(TriggerState.ItemFunctionName);
                        }
                        return(TriggerState.None);
                    }
                    break;

                case ExpressionPropertyFunctionInvocation _:
                    if (iee.Kind == ExpressionErrorKind.ExpectingMethodName)
                    {
                        return(TriggerState.PropertyFunctionName);
                    }
                    if (iee.Kind == ExpressionErrorKind.ExpectingClassName)
                    {
                        return(TriggerState.PropertyFunctionClassName);
                    }
                    break;

                case ExpressionClassReference cr:
                    if (iee.Kind == ExpressionErrorKind.ExpectingBracketColonColon ||
                        ((iee.Kind == ExpressionErrorKind.ExpectingRightParenOrValue || iee.Kind == ExpressionErrorKind.ExpectingRightParenOrComma) && cr.Parent is ExpressionArgumentList)
                        )
                    {
                        if (ShouldTriggerName(cr.Name))
                        {
                            triggerLength = cr.Name.Length;
                            return(cr.Parent is ExpressionArgumentList? TriggerState.BareFunctionArgumentValue : TriggerState.PropertyFunctionClassName);
                        }
                        return(TriggerState.None);
                    }
                    break;

                case ExpressionMetadata m:
                    if (iee.Kind == ExpressionErrorKind.ExpectingMetadataName)
                    {
                        return(TriggerState.MetadataName);
                    }
                    if (iee.Kind == ExpressionErrorKind.ExpectingRightParenOrPeriod)
                    {
                        if (ShouldTriggerName(m.ItemName))
                        {
                            triggerLength = m.ItemName.Length;
                            return(TriggerState.MetadataOrItemName);
                        }
                        return(TriggerState.None);
                    }
                    if (iee.Kind == ExpressionErrorKind.ExpectingRightParen)
                    {
                        if (ShouldTriggerName(m.MetadataName))
                        {
                            triggerLength = m.MetadataName.Length;
                            return(TriggerState.MetadataName);
                        }
                        return(TriggerState.None);
                    }
                    break;

                case ExpressionText expressionText: {
                    if (
                        (error.Kind == ExpressionErrorKind.IncompleteString && (expressionText.Parent is ExpressionArgumentList || expressionText.Parent is ExpressionItemTransform)) ||
                        (error.Kind == ExpressionErrorKind.ExpectingRightParenOrValue && expressionText.Parent is ExpressionArgumentList)
                        )
                    {
                        var s = GetTriggerState(
                            expressionText.Value, reason, typedChar,
                            out triggerLength, out triggerExpression, out _);
                        if (error.Kind != ExpressionErrorKind.IncompleteString && s == TriggerState.Value)
                        {
                            return(TriggerState.BareFunctionArgumentValue);
                        }
                        return(s);
                    }
                }
                break;

                case ExpressionArgumentList _: {
                    if (error.Kind == ExpressionErrorKind.ExpectingRightParenOrValue)
                    {
                        return(TriggerState.BareFunctionArgumentValue);
                    }
                }
                break;
                }
            }

            if (error != null)
            {
                switch (error.Kind)
                {
                case ExpressionErrorKind.ExpectingPropertyName:
                    return(TriggerState.PropertyName);

                case ExpressionErrorKind.ExpectingItemName:
                    return(TriggerState.ItemName);

                case ExpressionErrorKind.ExpectingMetadataOrItemName:
                    return(TriggerState.MetadataOrItemName);
                }
                return(TriggerState.None);
            }

            return(TriggerState.None);

            char LastChar() => expression[expression.Length - 1];
            char PenultimateChar() => expression[expression.Length - 2];
            bool IsPossiblePathSegmentStart(char c) => c == '_' || char.IsLetterOrDigit(c) || c == '.';
            bool ShouldTriggerName(string n) =>
            isExplicit ||
            (isTypedChar && n.Length == 1) ||
            (isBackspace && n.Length == 0);
        }
        public static TriggerState GetConditionTriggerState(
            string expression,
            TriggerReason reason, char typedChar,
            out int triggerLength, out ExpressionNode triggerExpression,
            out IReadOnlyList <ExpressionNode> comparandValues
            )
        {
            triggerLength   = 0;
            comparandValues = null;

            if (expression.Length == 0 || (expression.Length == 0 && expression[0] == '\''))
            {
                triggerExpression = new ExpressionText(0, "", true);
                return(TriggerState.Value);
            }

            if (expression.Length == 1)
            {
                triggerExpression = new ExpressionText(0, expression, true);
                triggerLength     = 1;
                return(TriggerState.Value);
            }

            var tokens = new List <Token> ();
            int lastExpressionStart = 0;

            try {
                var tokenizer = new ConditionTokenizer();
                tokenizer.Tokenize(expression);


                while (tokenizer.Token.Type != TokenType.EOF)
                {
                    switch (tokenizer.Token.Type)
                    {
                    case TokenType.And:
                    case TokenType.Or:
                        lastExpressionStart = tokenizer.Token.Position + tokenizer.Token.Value.Length;
                        break;
                    }
                    tokens.Add(tokenizer.Token);
                    tokenizer.GetNextToken();
                }

                int last = tokens.Count - 1;
                if (last >= 2 && TokenIsCondition(tokens[last - 1].Type))
                {
                    var lt = tokens[last];
                    if (lt.Type == TokenType.Apostrophe || (lt.Type == TokenType.String && (expression[lt.Position + lt.Value.Length] != '\'')))
                    {
                        lastExpressionStart = lt.Position;
                        comparandValues     = ReadPrecedingComparandVariables(tokens, last - 2);
                    }
                    else
                    {
                        triggerLength     = 0;
                        triggerExpression = null;
                        return(TriggerState.None);
                    }
                }
            } catch (Exception ex) {
                lastExpressionStart = 0;
                LoggingService.LogError("Error in condition tokenizer", ex);
            }

            var subexpr = expression.Substring(lastExpressionStart);

            return(GetTriggerState(subexpr, reason, typedChar, out triggerLength, out triggerExpression, out _));
        }