示例#1
0
        /// <summary>
        /// Try to parse as a sequence of columns and styles separated by commas.
        /// e.g. 40 1px solid red, 80 2px dashed blue
        /// The style part is optional but, if present, it must be well-formed.
        /// </summary>
        /// <param name="codingConvention">The coding convention.</param>
        /// <param name="fallbackStrokeParameters">Stroke parameters to use when the style is not specified.</param>
        /// <returns>The set of guidelines if successful, or null if not.</returns>
        private static HashSet <Guideline> ParseGuidelines(string codingConvention, StrokeParameters fallbackStrokeParameters)
        {
            var set = new HashSet <Guideline>();

            foreach (var token in GetTokens(codingConvention, s_comma))
            {
                var partEnumerator = GetTokens(token, s_space);
                if (!partEnumerator.MoveNext())
                {
                    // Empty token. Ignore and continue.
                    continue;
                }

                if (!TryParsePosition(partEnumerator.Current, out var column))
                {
                    return(null);
                }

                var strokeParameters = fallbackStrokeParameters;
                if (partEnumerator.MoveNext() && !TryParseStrokeParameters(partEnumerator, out strokeParameters))
                {
                    return(null);
                }

                set.Add(new Guideline(column, strokeParameters?.Freeze()));
            }

            return(set);
        }
示例#2
0
        /// <summary>
        /// Construct a new <see cref="Guideline"/>.
        /// </summary>
        /// <param name="column">The column number. Must be between 0 and 10,000.</param>
        /// <param name="strokeParameters">The stroke parameters for this guideline. If null, then
        /// the default brush from Fonts & Colors is used with default .</param>
        public Guideline(int column, StrokeParameters strokeParameters)
        {
            if (!IsValidColumn(column))
            {
                throw new ArgumentOutOfRangeException(nameof(column), Resources.AddGuidelineParameterOutOfRange);
            }

            Column           = column;
            StrokeParameters = strokeParameters;
        }
示例#3
0
        private static bool TryParseStrokeParameters(TokenEnumerator tokensEnumerator, out StrokeParameters strokeParameters)
        {
            strokeParameters = null;

            // Pixel width (stroke thickness)
            var token = tokensEnumerator.Current;

            if (!token.EndsWith("px", StringComparison.Ordinal))
            {
                return(false);
            }

            if (!double.TryParse(token.Substring(0, token.Length - 2), out var strokeThickness))
            {
                return(false);
            }

            if (strokeThickness < 0 || strokeThickness > 50)
            {
                return(false);
            }

            strokeParameters = new StrokeParameters
            {
                Brush           = new SolidColorBrush(Colors.Black),
                StrokeThickness = strokeThickness
            };

            if (!tokensEnumerator.MoveNext())
            {
                return(true);
            }

            // Line style
            token = tokensEnumerator.Current;
            if (Enum.TryParse <LineStyle>(token, ignoreCase: true, out var lineStyle))
            {
                strokeParameters.LineStyle = lineStyle;
            }

            if (!tokensEnumerator.MoveNext())
            {
                return(true);
            }

            // Color
            token = tokensEnumerator.Current;
            if (TryParseColor(token, out var color))
            {
                strokeParameters.Brush = new SolidColorBrush(color);
            }

            // Ignore trailing tokens.
            return(true);
        }
示例#4
0
        /// <summary>
        /// The guideline_style looks like this:
        /// guidelines_style = 1px dotted 80FF0000
        /// Meaning single pixel, dotted style, color red, 50% opaque
        ///
        /// 1px specifies the width in pixels.
        /// dotted specifies the line style.Simple to support: solid, dotted and dashed
        /// </summary>
        /// <param name="text">The value read from guidelines_style editorconfig.</param>
        /// <param name="strokeParameters">The parsed stroke parameters.</param>
        /// <returns>True if parameters were parsed. False otherwise.</returns>
        public static bool TryParseStrokeParametersFromCodingConvention(string text, out StrokeParameters strokeParameters)
        {
            var tokensEnumerator = GetTokens(text, s_separators).GetEnumerator();

            if (!tokensEnumerator.MoveNext())
            {
                strokeParameters = null;
                return(false);
            }

            return(TryParseStrokeParameters(tokensEnumerator, out strokeParameters));
        }
示例#5
0
        /// <summary>
        /// Creates editor column guidelines
        /// </summary>
        /// <param name="view">The <see cref="IWpfTextView"/> upon which the adornment will be drawn</param>
        /// <param name="settings">The guideline settings.</param>
        /// <param name="guidelineBrush">The guideline brush.</param>
        /// <param name="codingConventionsManager">The coding conventions manager for handling .editorconfig settings.</param>
        /// <param name="telemetry">Telemetry interface.</param>
        public ColumnGuideAdornment(IWpfTextView view, ITextEditorGuidesSettings settings, GuidelineBrush guidelineBrush, ICodingConventionsManager codingConventionsManager)
        {
            _view           = view;
            _guidelineBrush = guidelineBrush;
            _guidelineBrush.BrushChanged += GuidelineBrushChanged;
            _strokeParameters             = StrokeParameters.FromBrush(_guidelineBrush.Brush);

            if (codingConventionsManager != null && view.TryGetTextDocument(out var textDocument))
            {
                _codingConventionsCancellationTokenSource = new CancellationTokenSource();
                var fireAndForgetTask = LoadGuidelinesFromEditorConfigAsync(codingConventionsManager, textDocument.FilePath);
            }

            InitializeGuidelines(settings.GuideLinePositionsInChars);

            _view.LayoutChanged += OnViewLayoutChanged;
            _settingsChanged     = settings as INotifyPropertyChanged;
            if (_settingsChanged != null)
            {
                _settingsChanged.PropertyChanged += SettingsChanged;
            }

            _view.Closed += ViewClosed;
        }
示例#6
0
        private Task UpdateGuidelinesFromCodingConventionAsync(ICodingConventionContext codingConventionContext, CancellationToken cancellationToken)
        {
            if (cancellationToken.IsCancellationRequested)
            {
                return(Task.FromCanceled(cancellationToken));
            }

            StrokeParameters strokeParameters = null;

            if (codingConventionContext.CurrentConventions.TryGetConventionValue("guidelines_style", out string guidelines_style))
            {
                if (TryParseStrokeParametersFromCodingConvention(guidelines_style, out strokeParameters))
                {
                    _isUsingCodingConvention = true;
                    strokeParameters.Freeze();
                }
            }

            ICollection <Guideline> guidelines = null;

            if (codingConventionContext.CurrentConventions.TryGetConventionValue("guidelines", out string guidelinesConventionValue))
            {
                guidelines = ParseGuidelinesFromCodingConvention(guidelinesConventionValue, strokeParameters);
            }

            // Also support max_line_length: https://github.com/editorconfig/editorconfig/wiki/EditorConfig-Properties#max_line_length
            if (codingConventionContext.CurrentConventions.TryGetConventionValue("max_line_length", out string max_line_length) && TryParsePosition(max_line_length, out int maxLineLengthValue))
            {
                (guidelines ?? (guidelines = new List <Guideline>())).Add(new Guideline(maxLineLengthValue, strokeParameters));
            }

            if (guidelines != null)
            {
                // Override 'classic' settings.
                _isUsingCodingConvention = true;

                // TODO: await JoinableTaskFactory.SwitchToMainThreadAsync();
#pragma warning disable VSTHRD001 // Avoid legacy thread switching APIs
                _ = _view.VisualElement.Dispatcher.BeginInvoke(new Action <IEnumerable <Guideline> >(GuidelinesChanged), guidelines);
#pragma warning restore VSTHRD001 // Avoid legacy thread switching APIs
            }

            if (_isUsingCodingConvention && !s_sentEditorConfigTelemetry)
            {
                var eventTelemetry = new EventTelemetry("EditorConfig");
                if (!string.IsNullOrEmpty(guidelinesConventionValue))
                {
                    eventTelemetry.Properties.Add("Convention", guidelinesConventionValue);
                }

                if (!string.IsNullOrEmpty(max_line_length))
                {
                    eventTelemetry.Properties.Add(nameof(max_line_length), max_line_length);
                }

                if (!string.IsNullOrEmpty(guidelines_style))
                {
                    eventTelemetry.Properties.Add(nameof(guidelines_style), guidelines_style);
                }

                ColumnGuideAdornmentFactory.AddGuidelinesToTelemetry(eventTelemetry, guidelines);
                Telemetry.Client.TrackEvent(eventTelemetry);
                s_sentEditorConfigTelemetry = true;
            }

            return(Task.CompletedTask);
        }
示例#7
0
        public static HashSet <Guideline> ParseGuidelinesFromCodingConvention(string codingConvention, StrokeParameters fallbackStrokeParameters)
        {
            // First try parsing as a sequence of columns and styles separated by commas.
            var result = ParseGuidelines(codingConvention, fallbackStrokeParameters);

            if (result != null)
            {
                return(result);
            }

            // Fall back to parsing as just a set of column positions, ignoring any unparsable values.
            result = new HashSet <Guideline>();
            foreach (var position in GetTokens(codingConvention, s_separators))
            {
                if (TryParsePosition(position, out int column))
                {
                    result.Add(new Guideline(column, fallbackStrokeParameters));
                }
            }

            return(result);
        }