This class is the main class of the text model. Basically, it is a System.Text.StringBuilder with events.
Thread safety:

However, there is a single method that is thread-safe: CreateSnapshot() (and its overloads).

Inheritance: IDocument, INotifyPropertyChanged
		internal DocumentLine(TextDocument document)
		{
#if DEBUG
			Debug.Assert(document != null);
			this.document = document;
#endif
		}
		/// <summary>
		///     Creates a new TextDocumentAccessor that indents only a part of the document.
		/// </summary>
		public TextDocumentAccessor(TextDocument document, int minLine, int maxLine)
		{
			if (document == null)
				throw new ArgumentNullException("document");
			doc = document;
			this.minLine = minLine;
			this.maxLine = maxLine;
		}
		/// <summary>
		///     Creates a new TextDocumentAccessor.
		/// </summary>
		public TextDocumentAccessor(TextDocument document)
		{
			if (document == null)
				throw new ArgumentNullException("document");
			doc = document;
			minLine = 1;
			maxLine = doc.LineCount;
		}
		/// <summary>
		///     Registers the <paramref name="targetTracker" /> as line tracker for the <paramref name="textDocument" />.
		///     A weak reference to the target tracker will be used, and the WeakLineTracker will deregister itself
		///     when the target tracker is garbage collected.
		/// </summary>
		public static WeakLineTracker Register(TextDocument textDocument, ILineTracker targetTracker)
		{
			if (textDocument == null)
				throw new ArgumentNullException("textDocument");
			if (targetTracker == null)
				throw new ArgumentNullException("targetTracker");
			var wlt = new WeakLineTracker(textDocument, targetTracker);
			textDocument.LineTrackers.Add(wlt);
			return wlt;
		}
        public TextColoringTransformer(TextDocument document)
        {
            this.document = document;

            TextTransformations = new TextSegmentCollection<TextTransformation>(document);

            CommentBrush = Brush.Parse("#559A3F");
            CallExpressionBrush = Brush.Parse("Pink");
            IdentifierBrush = Brush.Parse("#D4D4D4");
            KeywordBrush = Brush.Parse("#569CD6");
            LiteralBrush = Brush.Parse("#D69D85");
            PunctuationBrush = Brush.Parse("#D4D4D4");
            UserTypeBrush = Brush.Parse("#4BB289");
        }
		/// <inheritdoc cref="IIndentationStrategy.IndentLine" />
		public override int IndentLine(TextDocument document, DocumentLine line, int caretOffset)
		{
			var lineNr = line.LineNumber;
			var acc = new TextDocumentAccessor(document, lineNr, lineNr);
			var result = Indent(acc, false, caretOffset);

			var t = acc.Text;
			if (t.Length == 0)
			{
				// use AutoIndentation for new lines in comments / verbatim strings.
				return base.IndentLine(document, line, caretOffset);
			}

			return result;
		}
        public EditorModel()
        {
            shell = IoC.Get<IShell>();

            codeAnalysisRunner = new JobRunner();
            TextDocument = new TextDocument();

            AnalysisTriggerEvents.Select(_ => Observable.Timer(TimeSpan.FromMilliseconds(500))
            .SelectMany(o => DoCodeAnalysisAsync())).Switch().Subscribe(_ => { });

            //AnalysisTriggerEvents.Throttle(TimeSpan.FromMilliseconds(500)).Subscribe(async _ =>
            //{
            //    await DoCodeAnalysisAsync();
            //});
        }
		public TextColoringTransformer(TextDocument document)
		{
			this.document = document;

			TextTransformations = new TextSegmentCollection<TextTransformation>(document);

			CommentBrush = Brush.Parse("#559A3F");
			CallExpressionBrush = Brush.Parse("#DCDCAA");
			IdentifierBrush = Brush.Parse("#C8C8C8");
			KeywordBrush = Brush.Parse("#569CD6");
			LiteralBrush = Brush.Parse("#D69D85");
            NumericLiteralBrush = Brush.Parse("#B5CEA8");
            EnumConstantBrush = Brush.Parse("#B5CEA8");
            EnumTypeNameBrush = Brush.Parse("#B5CEA8");
            InterfaceBrush = Brush.Parse("#B5CEA8");

            PunctuationBrush = Brush.Parse("#C8C8C8");
			UserTypeBrush = Brush.Parse("#4EC9B0");
		}
		/// <inheritdoc />
		public virtual int IndentLine(TextDocument document, DocumentLine line, int caretOffset)
		{
			if (document == null)
				throw new ArgumentNullException("document");
			if (line == null)
				throw new ArgumentNullException("line");

			var previousLine = line.PreviousLine;
			if (previousLine != null)
			{
				var indentationSegment = TextUtilities.GetWhitespaceAfter(document, previousLine.Offset);
				var indentation = document.GetText(indentationSegment);
				// copy indentation to line
				indentationSegment = TextUtilities.GetWhitespaceAfter(document, line.Offset);
				document.Replace(indentationSegment, indentation);
			}

			return caretOffset;
		}
        /// <inheritdoc cref="IIndentationStrategy.IndentLine" />
        public override int IndentLine(TextDocument document, DocumentLine line, int caretIndex)
        {
            if (line == null)
            {
                return caretIndex;
            }

            var lineNr = line.LineNumber;
            var acc = new TextDocumentAccessor(document, lineNr, lineNr);

            var leadingWhiteSpaceBefore = TextUtilities.GetLeadingWhitespace(document, line).Length;
            var result = Indent(acc, false, caretIndex);
            var t = acc.Text;

            result = caretIndex + TextUtilities.GetLeadingWhitespace(document, line).Length - leadingWhiteSpaceBefore;

            if (t.Length == 0)
            {
                // use AutoIndentation for new lines in comments / verbatim strings.
                return base.IndentLine(document, line, caretIndex);
            }

            return result;
        }
        public int Format(TextDocument textDocument, uint offset, uint length, int cursor)
        {
            bool replaceCursor = cursor >= 0 ? true : false;

            if (!replaceCursor)
            {
                cursor = 0;
            }

            var replacements = ClangFormat.FormatXml(textDocument.Text, offset, length, (uint)cursor,
                ClangFormatSettings.Default);

            return ApplyReplacements(textDocument, cursor, replacements, replaceCursor);
        }
        public void RegisterSourceFile(IIntellisenseControl intellisense, ICompletionAssistant completionAssistant,
            TextEditor.TextEditor editor, ISourceFile file, TextDocument doc)
        {
            CPlusPlusDataAssociation association = null;

            if (dataAssociations.TryGetValue(file, out association))
            {
                throw new Exception("Source file already registered with language service.");
            }

            association = new CPlusPlusDataAssociation(doc);
            dataAssociations.Add(file, association);

            association.KeyUpHandler = (sender, e) =>
            {
                if (editor.TextDocument == doc)
                {
                    switch (e.Key)
                    {
                        case Key.Return:
                            {
                                if (editor.CaretIndex >= 0 && editor.CaretIndex < editor.TextDocument.TextLength)
                                {
                                    if (editor.TextDocument.GetCharAt(editor.CaretIndex) == '}')
                                    {
                                        editor.TextDocument.Insert(editor.CaretIndex, Environment.NewLine);
                                        editor.CaretIndex--;

                                        var currentLine = editor.TextDocument.GetLineByOffset(editor.CaretIndex);

                                        editor.CaretIndex = IndentationStrategy.IndentLine(editor.TextDocument, currentLine, editor.CaretIndex);
                                        editor.CaretIndex = IndentationStrategy.IndentLine(editor.TextDocument, currentLine.NextLine.NextLine,
                                            editor.CaretIndex);
                                        editor.CaretIndex = IndentationStrategy.IndentLine(editor.TextDocument, currentLine.NextLine, editor.CaretIndex);
                                    }

                                    var newCaret = IndentationStrategy.IndentLine(editor.TextDocument,
                                        editor.TextDocument.GetLineByOffset(editor.CaretIndex), editor.CaretIndex);

                                    editor.CaretIndex = newCaret;
                                }
                            }
                            break;
                    }
                }
            };

            association.TextInputHandler = (sender, e) =>
            {
                if (editor.TextDocument == doc)
                {
                    OpenBracket(editor, editor.TextDocument, e.Text);
                    CloseBracket(editor, editor.TextDocument, e.Text);

                    switch (e.Text)
                    {
                        case "}":
                        case ";":
                            editor.CaretIndex = Format(editor.TextDocument, 0, (uint)editor.TextDocument.TextLength, editor.CaretIndex);
                            break;

                        case "{":
                            var lineCount = editor.TextDocument.LineCount;
                            var offset = Format(editor.TextDocument, 0, (uint)editor.TextDocument.TextLength, editor.CaretIndex);

                            // suggests clang format didnt do anything, so we can assume not moving to new line.
                            if (lineCount != editor.TextDocument.LineCount)
                            {
                                if (offset <= editor.TextDocument.TextLength)
                                {
                                    var newLine = editor.TextDocument.GetLineByOffset(offset);
                                    editor.CaretIndex = newLine.PreviousLine.EndOffset;
                                }
                            }
                            else
                            {
                                editor.CaretIndex = offset;
                            }
                            break;
                    }
                }
            };

            editor.AddHandler(InputElement.KeyUpEvent, association.KeyUpHandler, RoutingStrategies.Tunnel);

            editor.TextInput += association.TextInputHandler;
        }
        public CPlusPlusDataAssociation(TextDocument textDocument)
        {
            BackgroundRenderers = new List<IBackgroundRenderer>();
            DocumentLineTransformers = new List<IDocumentLineTransformer>();

            TextColorizer = new TextColoringTransformer(textDocument);
            TextMarkerService = new TextMarkerService(textDocument);

            BackgroundRenderers.Add(new BracketMatchingBackgroundRenderer());
            BackgroundRenderers.Add(TextMarkerService);

            DocumentLineTransformers.Add(TextColorizer);
            DocumentLineTransformers.Add(new DefineTextLineTransformer());
            DocumentLineTransformers.Add(new PragmaMarkTextLineTransformer());
            DocumentLineTransformers.Add(new IncludeTextLineTransformer());
        }
Beispiel #14
0
		internal void Push(TextDocument document, DocumentChangeEventArgs e)
		{
			if (state == StatePlayback)
				throw new InvalidOperationException("Document changes during undo/redo operations are not allowed.");
			if (state == StatePlaybackModifyDocument)
				state = StatePlayback; // allow only 1 change per expected modification
			else
				Push(new DocumentChangeOperation(document, e));
		}
		public static ISegment GetTrailingWhitespace(TextDocument document, DocumentLine documentLine)
		{
			if (documentLine == null)
				throw new ArgumentNullException("documentLine");
			var segment = GetWhitespaceBefore(document, documentLine.EndOffset);
			// If the whole line consists of whitespace, we consider all of it as leading whitespace,
			// so return an empty segment as trailing whitespace.
			if (segment.Offset == documentLine.Offset)
				return new SimpleSegment(documentLine.EndOffset, 0);
			return segment;
		}
        public static int ApplyReplacements(TextDocument document, int cursor, XDocument replacements, bool replaceCursor = true)
        {
            var elements = replacements.Elements().First().Elements();

            document.BeginUpdate();

            var offsetChange = 0;
            foreach (var element in elements)
            {
                switch (element.Name.LocalName)
                {
                    case "cursor":
                        cursor = Convert.ToInt32(element.Value);
                        break;

                    case "replacement":
                        var offset = -1;
                        var replacementLength = -1;
                        var attributes = element.Attributes();

                        foreach (var attribute in attributes)
                        {
                            switch (attribute.Name.LocalName)
                            {
                                case "offset":
                                    offset = Convert.ToInt32(attribute.Value);
                                    break;

                                case "length":
                                    replacementLength = Convert.ToInt32(attribute.Value);
                                    break;
                            }
                        }

                        document.Replace(offsetChange + offset, replacementLength, element.Value);

                        offsetChange += element.Value.Length - replacementLength;
                        break;
                }
            }

            document.EndUpdate();

            return replaceCursor ? cursor : -1;
        }
        private void OpenBracket(TextEditor.TextEditor editor, TextDocument document, string text)
        {
            if (text[0].IsOpenBracketChar() && editor.CaretIndex <= document.TextLength && editor.CaretIndex > 0)
            {
                var nextChar = ' ';

                if (editor.CaretIndex != document.TextLength)
                {
                    document.GetCharAt(editor.CaretIndex);
                }

                if (char.IsWhiteSpace(nextChar) || nextChar.IsCloseBracketChar())
                {
                    document.Insert(editor.CaretIndex, text[0].GetCloseBracketChar().ToString());
                }
            }
        }
Beispiel #18
0
 public TextAnchorTree(TextDocument document)
 {
     this.document = document;
 }
		public DocumentChangeOperation(TextDocument document, DocumentChangeEventArgs change)
		{
			this.document = document;
			this.change = change;
		}
        public void OpenFile(ISourceFile file, IIntellisenseControl intellisense,
            ICompletionAssistant completionAssistant)
        {
            if (ProjectFile != file)
            {
                if (System.IO.File.Exists(file.Location))
                {
                    using (var fs = System.IO.File.OpenText(file.Location))
                    {
                        TextDocument = new TextDocument(fs.ReadToEnd());
                        TextDocument.FileName = file.Location;
                    }

                    ProjectFile = file;

                    RegisterLanguageService(intellisense, completionAssistant);

                    DocumentLoaded?.Invoke(this, new EventArgs());
                }
            }
        }
		/// <summary>
		///     Does nothing: indenting multiple lines is useless without a smart indentation strategy.
		/// </summary>
		public virtual int IndentLines(TextDocument document, int beginLine, int endLine, int caretOffset)
		{
			return caretOffset;
		}
        public int Comment(TextDocument textDocument, ISegment segment, int caret = -1, bool format = true)
        {
            var result = caret;

            var lines = VisualLineGeometryBuilder.GetLinesForSegmentInDocument(textDocument, segment);

            textDocument.BeginUpdate();

            foreach (var line in lines)
            {
                textDocument.Insert(line.Offset, "//");
            }

            if (format)
            {
                result = Format(textDocument, (uint)segment.Offset, (uint)segment.Length, caret);
            }

            textDocument.EndUpdate();

            return result;
        }
		public TextAnchorTree(TextDocument document)
		{
			this.document = document;
		}
        public int UnComment(TextDocument textDocument, ISegment segment, int caret = -1, bool format = true)
        {
            var result = caret;

            var lines = VisualLineGeometryBuilder.GetLinesForSegmentInDocument(textDocument, segment);

            textDocument.BeginUpdate();

            foreach (var line in lines)
            {
                var index = textDocument.GetText(line).IndexOf("//");

                if (index >= 0)
                {
                    textDocument.Replace(line.Offset + index, 2, string.Empty);
                }
            }

            if (format)
            {
                result = Format(textDocument, (uint)segment.Offset, (uint)segment.Length, caret);
            }

            textDocument.EndUpdate();

            return result;
        }
Beispiel #25
0
		internal TextAnchor(TextDocument document)
		{
			Document = document;
		}
 private void CloseBracket(TextEditor.TextEditor editor, TextDocument document, string text)
 {
     if (text[0].IsCloseBracketChar() && editor.CaretIndex < document.TextLength && editor.CaretIndex > 0)
     {
         if (document.GetCharAt(editor.CaretIndex) == text[0])
         {
             document.Replace(editor.CaretIndex - 1, 1, string.Empty);
         }
     }
 }
		/// <summary>
		///     Deregisters the weak line tracker.
		/// </summary>
		public void Deregister()
		{
			if (textDocument != null)
			{
				textDocument.LineTrackers.Remove(this);
				textDocument = null;
			}
		}
		public static ISegment GetLeadingWhitespace(TextDocument document, DocumentLine documentLine)
		{
			if (documentLine == null)
				throw new ArgumentNullException("documentLine");
			return GetWhitespaceAfter(document, documentLine.Offset);
		}
		/// <inheritdoc cref="IIndentationStrategy.IndentLines" />
		public override int IndentLines(TextDocument document, int beginLine, int endLine, int caretOffset)
		{
			return Indent(new TextDocumentAccessor(document, beginLine, endLine), true, caretOffset);
		}
		private WeakLineTracker(TextDocument textDocument, ILineTracker targetTracker)
		{
			this.textDocument = textDocument;
			targetObject = new WeakReference(targetTracker);
		}
Beispiel #31
0
		internal void RegisterAffectedDocument(TextDocument document)
		{
			if (affectedDocuments == null)
				affectedDocuments = new List<TextDocument>();
			if (!affectedDocuments.Contains(document))
			{
				affectedDocuments.Add(document);
				document.BeginUpdate();
			}
		}