/// <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)); }
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); }
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)); }
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 _)); }