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;
            }
        }
Beispiel #2
0
        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));
        }