private void textBox_MouseMove(object sender, MouseEventArgs e) { int charIndex = textBox.GetCharIndexFromPosition(e.Location); int line = textBox.GetLineFromCharIndex(charIndex); if (textBox.Lines.Length <= line) { return; } if (mI18nTooltipLine == line) { return; } i18nTooltip.Hide(textBox); mI18nTooltipLine = line; string lineString = textBox.Lines[line]; Regex matcher = new Regex(@"i18n\(([^)]+)\)"); Match locMatch = matcher.Match(lineString); if (locMatch.Success) { mI18nLocKey = locMatch.Groups[1].Value; string translated = ModuleDataManager.GetInstance().LocalizeString(mI18nLocKey); translated = JsonHelper.WordWrap(translated, 100); i18nTooltip.Show(translated, textBox, e.Location); } else { i18nTooltip.Hide(textBox); mI18nLocKey = null; } }
private Tuple <string, int> GetTooltipAt(int x, int y) { // Translate mouse x,y to character position. var position = this.textBox.CharPositionFromPoint(x, y); var line = this.textBox.LineFromPosition(position); // Sometimes CharPositionFromPoint() returns out of range values (looks like when replacing few lines with many). if (position < 0 || position >= textBox.Text.Length) { return(new Tuple <string, int>(null, kAnchorNone)); } // Are we are hovering over an error icon in the margin? var isInErrorMargin = x > textBox.Margins[0].Width && x <= textBox.Margins[0].Width + textBox.Margins[kErrorMarginNumber].Width; if (isInErrorMargin && validationErrors != null && validationErrors.ContainsKey(line)) { return(new Tuple <string, int>(WordWrapString(validationErrors[line]), kAnchorError)); } // Are we hovering over an indicator? var currentAnchor = this.getIndicatorStartPosition(position); var hoveredIndicator = this.getIndicatorAt(position); if (hoveredIndicator == kFileIndicator) { return(new Tuple <string, int>("Ctrl-click to open file.", currentAnchor)); } else if (hoveredIndicator == kI18nIndicator) { var locKey = this.getLocKey(position); if (string.IsNullOrEmpty(locKey)) { return(new Tuple <string, int>("No such i18n entry found!", currentAnchor)); } mI18nLocKey = locKey; try { // Translate and display it as a tip. var translated = ModuleDataManager.GetInstance().LocalizeString(locKey); translated = JsonHelper.WordWrap(translated, 100).Trim(); return(new Tuple <string, int>(translated + "\n\nCtrl-click to edit.", currentAnchor)); } catch (Exception) { return(new Tuple <string, int>($"(Uncaught exception while trying to find i18n for {locKey})", currentAnchor)); } } // For JSON, display tips about the property or value being hovered over. if (jsonSuggester != null && !char.IsWhiteSpace(textBox.Text[position])) { var contextParsingPosition = position; // Find a following (or as a fallback, preceding) colon or open square bracket on the same line. // Could fail for colons/brackets embedded in strings, but that's good enough for now. while (contextParsingPosition < textBox.Lines[line].EndPosition && (textBox.Text[contextParsingPosition] != ':' && textBox.Text[contextParsingPosition] != '[')) { contextParsingPosition++; } if (contextParsingPosition == textBox.Lines[line].EndPosition) { contextParsingPosition = position; while (contextParsingPosition >= textBox.Lines[line].Position && (textBox.Text[contextParsingPosition] != ':' && textBox.Text[contextParsingPosition] != '[')) { contextParsingPosition--; } } if (contextParsingPosition >= 0 && (textBox.Text[contextParsingPosition] != ':' || textBox.Text[contextParsingPosition] != '[')) { var context = jsonSuggester.ParseOutContext(contextParsingPosition + 1, 0); if (context.IsValid) { var targetSchemas = JsonSchemaTools.GetSchemasForPath(jsonValidationSchema, context.Path, context.ObjectAroundCursor, context.ActivePropertyName); if (targetSchemas.Count > 0) { var schemaDescriptions = new HashSet <string>(targetSchemas.Select( annotated => JsonSchemaTools.DescribeSchema(annotated) + (annotated.Description != null ? "\n" + annotated.Description : ""))); var tipText = context.ActivePropertyName ?? context.Path.LastOrDefault() ?? "0"; if (schemaDescriptions.Count == 1) { tipText = (tipText == "0" ? "" : tipText + ": ") + schemaDescriptions.First(); } else { tipText = (tipText == "0" ? "One" : tipText + ", one") + " of:\n- " + string.Join("\n- ", schemaDescriptions.Select(s => s.Replace("\n", "\n "))); } return(new Tuple <string, int>(WordWrapString(tipText), contextParsingPosition)); } } } } return(new Tuple <string, int>(null, kAnchorNone)); }