Example #1
0
        //TODO: Copied from VsVimHost
        public FSharpOption <int> GetNewLineIndent(ITextView textView, ITextSnapshotLine contextLine, ITextSnapshotLine newLine, IVimLocalSettings localSettings)
        {
            //if (_vimApplicationSettings.UseEditorIndent)
            //{
            var indent = _smartIndentationService.GetDesiredIndentation(textView, newLine);

            if (indent.HasValue)
            {
                return(FSharpOption.Create(indent.Value));
            }
            else
            {
                // If the user wanted editor indentation but the editor doesn't support indentation
                // even though it proffers an indentation service then fall back to what auto
                // indent would do if it were enabled (don't care if it actually is)
                //
                // Several editors like XAML offer the indentation service but don't actually
                // provide information.  User clearly wants indent there since the editor indent
                // is enabled.  Do a best effort and use Vim style indenting
                return(FSharpOption.Create(EditUtil.GetAutoIndent(contextLine, localSettings.TabStop)));
            }
            //}

            //return FSharpOption<int>.None;
        }
Example #2
0
        public override string GetIndentationString(int lineNumber)
        {
            if (lineNumber < 1 || lineNumber > editor.LineCount)
            {
                return("");
            }
            var doc = context.AnalysisDocument;

            if (doc == null)
            {
                return(editor.GetLineIndent(lineNumber));
            }
            var snapshot    = editor.TextView.TextBuffer.CurrentSnapshot;
            var caretLine   = snapshot.GetLineFromLineNumber(lineNumber - 1);
            int?indentation = smartIndentationService.GetDesiredIndentation(editor.TextView, caretLine);

            if (indentation.HasValue && indentation.Value > 0)
            {
                return(CalculateIndentationString(indentation.Value));
            }

            var line = editor.GetLine(lineNumber);

            if (line == null)
            {
                return(editor.GetLineIndent(lineNumber));
            }
            try {
                if (line.Contains(editor.CaretOffset))
                {
                    var syntaxRoot = doc.GetSyntaxRootSynchronously(default);
Example #3
0
        /// <summary>
        /// Remaps a given x-coordinate to a valid point. If the provided x-coordinate is past the right end of the line, it will
        /// be clipped to the correct position depending on the virtual space settings. If the ISmartIndent is providing indentation
        /// settings, the x-coordinate will be changed based on that.
        /// </summary>
        private double MapXCoordinate(ITextViewLine textLine, double xCoordinate, bool userSpecifiedXCoordinate)
        {
            // if the clicked point is to the right of the text and virtual space is disabled, the coordinate
            // needs to be fixed
            if ((xCoordinate > textLine.TextRight) && !this.IsVirtualSpaceOrBoxSelectionEnabled)
            {
                double indentationWidth = 0.0;

                // ask the ISmartIndent to see if any indentation is necessary for empty lines
                if (textLine.End == textLine.Start)
                {
                    int?indentation = _smartIndentationService.GetDesiredIndentation(_wpfTextView, textLine.Start.GetContainingLine());
                    if (indentation.HasValue)
                    {
                        //The indentation specified by the smart indent service is desired column position of the caret. Find out how much virtual space
                        //need to be at the end of the line to satisfy that.
                        //TOOD:  _wpfTextView.FormattedLineSource.ColumnWidth instead of 16
                        indentationWidth = Math.Max(0.0, (((double)indentation.Value) * 16 - textLine.TextWidth));

                        // if the coordinate is specified by the user and the user has selected a coordinate to the left
                        // of the indentation suggested by ISmartIndent, overrule the ISmartIndent provided value and
                        // do not use any indentation.
                        if (userSpecifiedXCoordinate && (xCoordinate < (textLine.TextRight + indentationWidth)))
                        {
                            indentationWidth = 0.0;
                        }
                    }
                }

                xCoordinate = textLine.TextRight + indentationWidth;
            }

            return(xCoordinate);
        }
Example #4
0
        /// <summary>
        /// Gets the desired indentation
        /// </summary>
        /// <param name="textView">Text view</param>
        /// <param name="smartIndentationService">Smart indentation service</param>
        /// <param name="line">Line</param>
        /// <returns></returns>
        public static int?GetDesiredIndentation(ITextView textView, ISmartIndentationService smartIndentationService, ITextSnapshotLine line)
        {
            if (textView == null)
            {
                throw new ArgumentNullException(nameof(textView));
            }
            if (smartIndentationService == null)
            {
                throw new ArgumentNullException(nameof(smartIndentationService));
            }
            if (line == null)
            {
                throw new ArgumentNullException(nameof(line));
            }

            var indentStyle = textView.Options.GetIndentStyle();

            switch (indentStyle)
            {
            case IndentStyle.None:
                return(0);

            case IndentStyle.Block:
                return(GetDesiredBlockIndentation(textView, line));

            case IndentStyle.Smart:
                var indentSize = smartIndentationService.GetDesiredIndentation(textView, line);
                Debug.Assert(indentSize == null || indentSize.Value >= 0);
                return(indentSize);

            default:
                Debug.Fail($"Invalid {nameof(IndentStyle)}: {indentStyle}");
                return(null);
            }
        }
Example #5
0
		/// <summary>
		/// Gets the desired indentation
		/// </summary>
		/// <param name="textView">Text view</param>
		/// <param name="smartIndentationService">Smart indentation service</param>
		/// <param name="line">Line</param>
		/// <returns></returns>
		public static int? GetDesiredIndentation(ITextView textView, ISmartIndentationService smartIndentationService, ITextSnapshotLine line) {
			if (textView == null)
				throw new ArgumentNullException(nameof(textView));
			if (smartIndentationService == null)
				throw new ArgumentNullException(nameof(smartIndentationService));
			if (line == null)
				throw new ArgumentNullException(nameof(line));

			var indentStyle = textView.Options.GetIndentStyle();
			switch (indentStyle) {
			case IndentStyle.None:
				return 0;

			case IndentStyle.Block:
				return GetDesiredBlockIndentation(textView, line);

			case IndentStyle.Smart:
				var indentSize = smartIndentationService.GetDesiredIndentation(textView, line);
				Debug.Assert(indentSize == null || indentSize.Value >= 0);
				return indentSize;

			default:
				Debug.Fail($"Invalid {nameof(IndentStyle)}: {indentStyle}");
				return null;
			}
		}
Example #6
0
        // From https://github.com/dotnet/roslyn/blob/e39a3aeb1185ef0b349cad96a105969423065eac/src/EditorFeatures/Core/Shared/Extensions/ITextViewExtensions.cs#L278
        public static int? GetDesiredIndentation(this ITextView textView, ISmartIndentationService smartIndentService, ITextSnapshotLine line)
        {
            var pointInView = textView.BufferGraph.MapUpToSnapshot(line.Start, PointTrackingMode.Positive, PositionAffinity.Successor, textView.TextSnapshot);

            if (!pointInView.HasValue)
                return null;

            var lineInView = textView.TextSnapshot.GetLineFromPosition(pointInView.Value.Position);
            return smartIndentService.GetDesiredIndentation(textView, lineInView);
        }
Example #7
0
        // From https://github.com/dotnet/roslyn/blob/e39a3aeb1185ef0b349cad96a105969423065eac/src/EditorFeatures/Core/Shared/Extensions/ITextViewExtensions.cs#L278
        public static int?GetDesiredIndentation(this ITextView textView, ISmartIndentationService smartIndentService, ITextSnapshotLine line)
        {
            var pointInView = textView.BufferGraph.MapUpToSnapshot(line.Start, PointTrackingMode.Positive, PositionAffinity.Successor, textView.TextSnapshot);

            if (!pointInView.HasValue)
            {
                return(null);
            }

            var lineInView = textView.TextSnapshot.GetLineFromPosition(pointInView.Value.Position);

            return(smartIndentService.GetDesiredIndentation(textView, lineInView));
        }
        /// <summary>
        /// Remaps a given x-coordinate to a valid point. If the provided x-coordinate is past the right end of the line, it will
        /// be clipped to the correct position depending on the virtual space settings. If the ISmartIndent is providing indentation
        /// settings, the x-coordinate will be changed based on that.
        /// </summary>
        public static double MapXCoordinate(this ITextViewLine textLine, ITextView textView,
                                            double xCoordinate, ISmartIndentationService smartIndentationService, bool userSpecifiedXCoordinate)
        {
            if (textLine == null)
            {
                throw new ArgumentNullException(nameof(textLine));
            }

            if (textView == null)
            {
                throw new ArgumentNullException(nameof(textView));
            }

            // if the clicked point is to the right of the text and virtual space is disabled, the coordinate
            // needs to be fixed
            if ((xCoordinate > textLine.TextRight) && !textView.IsVirtualSpaceOrBoxSelectionEnabled())
            {
                double indentationWidth = 0.0;

                // ask the ISmartIndent to see if any indentation is necessary for empty lines
                if (textLine.End == textLine.Start)
                {
                    int?indentation = smartIndentationService?.GetDesiredIndentation(textView, textLine.Start.GetContainingLine());
                    if (indentation.HasValue)
                    {
                        //The indentation specified by the smart indent service is desired column position of the caret. Find out how much virtual space
                        //need to be at the end of the line to satisfy that.
                        // TODO: need a way to determine column width in xplat scenarios, bug https://devdiv.visualstudio.com/DevDiv/_workitems/edit/637741
                        double columnWidth = (textView is ITextView3 textView3) ? textView3.FormattedLineSource.ColumnWidth : throw new NotSupportedException();
                        indentationWidth = Math.Max(0.0, (((double)indentation.Value) * columnWidth - textLine.TextWidth));

                        // if the coordinate is specified by the user and the user has selected a coordinate to the left
                        // of the indentation suggested by ISmartIndent, overrule the ISmartIndent provided value and
                        // do not use any indentation.
                        if (userSpecifiedXCoordinate && (xCoordinate < (textLine.TextRight + indentationWidth)))
                        {
                            indentationWidth = 0.0;
                        }
                    }
                }

                xCoordinate = textLine.TextRight + indentationWidth;
            }

            return(xCoordinate);
        }
Example #9
0
        /// <summary>
        /// Remaps a given x-coordinate to a valid point. If the provided x-coordinate is past the right end of the line, it will
        /// be clipped to the correct position depending on the virtual space settings. If the ISmartIndent is providing indentation
        /// settings, the x-coordinate will be changed based on that.
        /// </summary>
        public static double MapXCoordinate(this ITextViewLine textLine, ITextView textView,
                                            double xCoordinate, ISmartIndentationService smartIndentationService, bool userSpecifiedXCoordinate)
        {
            if (textLine == null)
            {
                throw new ArgumentNullException(nameof(textLine));
            }

            if (textView == null)
            {
                throw new ArgumentNullException(nameof(textView));
            }

            // if the clicked point is to the right of the text and virtual space is disabled, the coordinate
            // needs to be fixed
            if ((xCoordinate > textLine.TextRight) && !textView.IsVirtualSpaceOrBoxSelectionEnabled())
            {
                double indentationWidth = 0.0;

                // ask the ISmartIndent to see if any indentation is necessary for empty lines
                if (textLine.End == textLine.Start)
                {
                    int?indentation = smartIndentationService?.GetDesiredIndentation(textView, textLine.Start.GetContainingLine());
                    if (indentation.HasValue)
                    {
                        //The indentation specified by the smart indent service is desired column position of the caret. Find out how much virtual space
                        //need to be at the end of the line to satisfy that.
                        double columnWidth = (textView.ViewScroller is IViewScroller2 viewScroller) ? viewScroller.ColumnWidth : 7;
                        indentationWidth = Math.Max(0.0, (((double)indentation.Value) * columnWidth - textLine.TextWidth));

                        // if the coordinate is specified by the user and the user has selected a coordinate to the left
                        // of the indentation suggested by ISmartIndent, overrule the ISmartIndent provided value and
                        // do not use any indentation.
                        if (userSpecifiedXCoordinate && (xCoordinate < (textLine.TextRight + indentationWidth)))
                        {
                            indentationWidth = 0.0;
                        }
                    }
                }

                xCoordinate = textLine.TextRight + indentationWidth;
            }

            return(xCoordinate);
        }
        /// <summary>
        /// Indents the line where the caret is currently located.
        /// </summary>
        /// <remarks>
        /// We don't send this command to the editor since smart indentation doesn't work along with
        /// BufferChanged event. Instead, we need to implement indentation ourselves. We still use
        /// ISmartIndentProvider provided by the language.
        /// </remarks>
        private void IndentCurrentLine(SnapshotPoint caretPosition)
        {
            Debug.Assert(_currentLanguageBuffer != null);

            var caretLine   = caretPosition.GetContainingLine();
            var indentation = _smartIndenterService.GetDesiredIndentation(_textView, caretLine);

            // When the user submits via ctrl-enter, the indenter service sometimes
            // gets confused and maps the subject position after the last newline in
            // a language buffer to the location *before* the next prompt in the
            // surface buffer.  When this happens, indentation will be 0.  Fortunately,
            // no indentation is required in such cases, so we can just do nothing.
            if (indentation != null && indentation != 0)
            {
                var sourceSpans = GetSourceSpans(caretPosition.Snapshot);
                var promptIndex = GetPromptIndexForPoint(sourceSpans, caretPosition);
                var promptSpan  = sourceSpans[promptIndex];
                Debug.Assert(IsPrompt(promptSpan));
                int promptLength = promptSpan.Length;
                Debug.Assert(promptLength == 2 || promptLength == 0); // Not required, just expected.
                var adjustedIndentationValue = indentation.GetValueOrDefault() - promptLength;

                if (caretPosition == caretLine.End)
                {
                    // create virtual space:
                    _textView.Caret.MoveTo(new VirtualSnapshotPoint(caretPosition, adjustedIndentationValue));
                }
                else
                {
                    var langCaret = GetPositionInLanguageBuffer(caretPosition);
                    if (langCaret == null)
                    {
                        return;
                    }

                    // insert whitespace indentation:
                    var    options    = _textView.Options;
                    string whitespace = GetWhiteSpaceForVirtualSpace(adjustedIndentationValue, options.IsConvertTabsToSpacesEnabled() ? default(int?) : options.GetTabSize());
                    _currentLanguageBuffer.Insert(langCaret.Value, whitespace);
                }
            }
        }
Example #11
0
        public override string GetIndentationString(int lineNumber)
        {
            if (lineNumber < 1 || lineNumber > editor.LineCount)
            {
                return("");
            }
            var doc = context.AnalysisDocument;

            if (doc == null)
            {
                return(editor.GetLineIndent(lineNumber));
            }
            var snapshot    = editor.TextView.TextBuffer.CurrentSnapshot;
            var caretLine   = snapshot.GetLineFromLineNumber(lineNumber - 1);
            int?indentation = smartIndentationService.GetDesiredIndentation(editor.TextView, caretLine);

            if (indentation.HasValue && indentation.Value > 0)
            {
                return(CalculateIndentationString(indentation.Value));
            }
            return(editor.GetLineIndent(lineNumber) + CalculateIndentationString(editor.Options.IndentationSize));
        }