/// <inheritdoc /> /// <remarks> /// If the <paramref name="position"/> is negative, the engine will /// update to: document.TextLength + (offset % document.TextLength+1) /// Otherwise it will update to: offset % document.TextLength+1 /// </remarks> public void Update(int position) { const int BUFFER_SIZE = 2000; if (currentEngine.Offset == position) { //positions match, nothing to be done return; } else if (currentEngine.Offset > position) { //moving backwards, so reset from previous saved location ResetEngineToPosition(position); } // get the engine caught up int nextSave = (cachedEngines.Count == 0) ? BUFFER_SIZE : cachedEngines.Peek().Offset + BUFFER_SIZE; if (currentEngine.Offset + 1 == position) { char ch = currentEngine.Document.GetCharAt(currentEngine.Offset); currentEngine.Push(ch); if (currentEngine.Offset == nextSave) { cachedEngines.Push(currentEngine.Clone()); } } else { //bulk copy characters in case buffer is unmanaged //(faster if we reduce managed/unmanaged transitions) while (currentEngine.Offset < position) { int endCut = currentEngine.Offset + BUFFER_SIZE; if (endCut > position) { endCut = position; } string buffer = currentEngine.Document.GetText(currentEngine.Offset, endCut - currentEngine.Offset); foreach (char ch in buffer) { currentEngine.Push(ch); //ConsoleWrite ("pushing character '{0}'", ch); if (currentEngine.Offset == nextSave) { cachedEngines.Push(currentEngine.Clone()); nextSave += BUFFER_SIZE; } } } } }
string GetIndentationString(int offset, DocumentLocation loc) { stateTracker.Update(Math.Min(data.Length, offset)); DocumentLine line = data.Document.GetLine(loc.Line); if (line == null) { return(""); } // Get context to the end of the line w/o changing the main engine's state var ctx = stateTracker.Clone(); ctx.Update(line.Offset + line.Length); // int pos = line.Offset; string curIndent = line.GetIndentation(data.Document); int nlwsp = curIndent.Length; // int o = offset > pos + nlwsp ? offset - (pos + nlwsp) : 0; if (!stateTracker.LineBeganInsideMultiLineComment || (nlwsp < line.LengthIncludingDelimiter && data.Document.GetCharAt(line.Offset + nlwsp) == '*')) { return(ctx.ThisLineIndent); } return(curIndent); }
void DoReSmartIndent(int cursor) { if (stateTracker.LineBeganInsideVerbatimString || stateTracker.LineBeganInsideMultiLineComment) { return; } DocumentLine line = textEditorData.Document.GetLineByOffset(cursor); // stateTracker.UpdateEngine (line.Offset); // Get context to the end of the line w/o changing the main engine's state var ctx = stateTracker.Clone(); for (int max = cursor; max < line.EndOffset; max++) { ctx.Push(textEditorData.Document.GetCharAt(max)); } int pos = line.Offset; string curIndent = line.GetIndentation(textEditorData.Document); int nlwsp = curIndent.Length; int offset = cursor > pos + nlwsp ? cursor - (pos + nlwsp) : 0; if (!stateTracker.LineBeganInsideMultiLineComment || (nlwsp < line.LengthIncludingDelimiter && textEditorData.Document.GetCharAt(line.Offset + nlwsp) == '*')) { // Possibly replace the indent string newIndent = ctx.ThisLineIndent; int newIndentLength = newIndent.Length; if (newIndent != curIndent) { if (CompletionWindowManager.IsVisible) { if (pos < CompletionWindowManager.CodeCompletionContext.TriggerOffset) { CompletionWindowManager.CodeCompletionContext.TriggerOffset -= nlwsp; } } newIndentLength = textEditorData.Replace(pos, nlwsp, newIndent); textEditorData.Document.CommitLineUpdate(textEditorData.Caret.Line); // Engine state is now invalid stateTracker.Update(pos); CompletionWindowManager.HideWindow(); } pos += newIndentLength; } else { pos += curIndent.Length; } pos += offset; textEditorData.FixVirtualIndentation(); }
/// <inheritdoc /> string ITextPasteHandler.FormatPlainText(int offset, string text, byte[] copyData) { if (copyData != null && copyData.Length == 1) { var strategy = TextPasteUtils.Strategies[(PasteStrategy)copyData[0]]; text = strategy.Decode(text); } engine.Update(offset); if (engine.IsInsideStringLiteral) { int idx = text.IndexOf('"'); if (idx > 0) { var o = offset; while (o < engine.Document.TextLength) { char ch = engine.Document.GetCharAt(o); engine.Push(ch); if (NewLine.IsNewLine(ch)) { break; } o++; if (!engine.IsInsideStringLiteral) { return(TextPasteUtils.StringLiteralStrategy.Encode(text)); } } return(TextPasteUtils.StringLiteralStrategy.Encode(text.Substring(0, idx)) + text.Substring(idx)); } return(TextPasteUtils.StringLiteralStrategy.Encode(text)); } else if (engine.IsInsideVerbatimString) { int idx = text.IndexOf('"'); if (idx > 0) { var o = offset; while (o < engine.Document.TextLength) { char ch = engine.Document.GetCharAt(o); engine.Push(ch); o++; if (!engine.IsInsideVerbatimString) { return(TextPasteUtils.VerbatimStringStrategy.Encode(text)); } } return(TextPasteUtils.VerbatimStringStrategy.Encode(text.Substring(0, idx)) + text.Substring(idx)); } return(TextPasteUtils.VerbatimStringStrategy.Encode(text)); } var line = engine.Document.GetLineByOffset(offset); var pasteAtLineStart = line.Offset == offset; var indentedText = new StringBuilder(); var curLine = new StringBuilder(); var clonedEngine = engine.Clone(); bool isNewLine = false, gotNewLine = false; for (int i = 0; i < text.Length; i++) { var ch = text[i]; if (clonedEngine.IsInsideVerbatimString || clonedEngine.IsInsideMultiLineComment) { clonedEngine.Push(ch); curLine.Append(ch); continue; } var delimiterLength = NewLine.GetDelimiterLength(ch, i + 1 < text.Length ? text[i + 1] : ' '); if (delimiterLength > 0) { isNewLine = true; if (gotNewLine || pasteAtLineStart) { if (curLine.Length > 0 || formattingOptions.EmptyLineFormatting == EmptyLineFormatting.Indent) { indentedText.Append(clonedEngine.ThisLineIndent); } } indentedText.Append(curLine); indentedText.Append(textEditorOptions.EolMarker); curLine.Length = 0; gotNewLine = true; i += delimiterLength - 1; // textEditorOptions.EolMarker[0] is the newLineChar used by the indentation engine. clonedEngine.Push(textEditorOptions.EolMarker[0]); } else { if (isNewLine) { if (ch == '\t' || ch == ' ') { clonedEngine.Push(ch); continue; } isNewLine = false; } curLine.Append(ch); clonedEngine.Push(ch); } if (clonedEngine.IsInsideVerbatimString || clonedEngine.IsInsideMultiLineComment && !(clonedEngine.LineBeganInsideVerbatimString || clonedEngine.LineBeganInsideMultiLineComment)) { if (gotNewLine) { if (curLine.Length > 0 || formattingOptions.EmptyLineFormatting == EmptyLineFormatting.Indent) { indentedText.Append(clonedEngine.ThisLineIndent); } } pasteAtLineStart = false; indentedText.Append(curLine); curLine.Length = 0; gotNewLine = false; continue; } } if (gotNewLine && (!pasteAtLineStart || curLine.Length > 0)) { indentedText.Append(clonedEngine.ThisLineIndent); } if (curLine.Length > 0) { indentedText.Append(curLine); } return(indentedText.ToString()); }
/// <inheritdoc /> string ITextPasteHandler.FormatPlainText(SourceText sourceText, int offset, string text, byte [] copyData) { if (copyData != null && copyData.Length == 1) { var strategy = TextPasteUtils.Strategies [(PasteStrategy)copyData [0]]; text = strategy.Decode(text); } engine.Update(sourceText, offset); if (engine.IsInsideStringLiteral) { int idx = text.IndexOf('"'); if (idx > 0) { var o = offset; while (o < sourceText.Length) { char ch = sourceText [o]; engine.Push(ch); if (NewLine.IsNewLine(ch)) { break; } o++; if (!engine.IsInsideStringLiteral) { return(TextPasteUtils.StringLiteralStrategy.Encode(text)); } } return(TextPasteUtils.StringLiteralStrategy.Encode(text.Substring(0, idx)) + text.Substring(idx)); } return(TextPasteUtils.StringLiteralStrategy.Encode(text)); } else if (engine.IsInsideVerbatimString) { int idx = text.IndexOf('"'); if (idx > 0) { var o = offset; while (o < sourceText.Length) { char ch = sourceText [o]; engine.Push(ch); o++; if (!engine.IsInsideVerbatimString) { return(TextPasteUtils.VerbatimStringStrategy.Encode(text)); } } return(TextPasteUtils.VerbatimStringStrategy.Encode(text.Substring(0, idx)) + text.Substring(idx)); } return(TextPasteUtils.VerbatimStringStrategy.Encode(text)); } // on the fly formatting is done in post formatting, if turned off just correct indenting. if (!InUnitTestMode && DefaultSourceEditorOptions.Instance.OnTheFlyFormatting) { return(text); } var line = sourceText.Lines.GetLineFromPosition(offset); var pasteAtLineStart = line.Start == offset; var indentedText = StringBuilderCache.Allocate(); var curLine = StringBuilderCache.Allocate(); var clonedEngine = engine.Clone(); bool isNewLine = false, gotNewLine = false; for (int i = 0; i < text.Length; i++) { var ch = text [i]; if (clonedEngine.IsInsideVerbatimString || clonedEngine.IsInsideMultiLineComment || clonedEngine.IsInsidePreprocessorComment) { clonedEngine.Push(ch); curLine.Append(ch); continue; } var delimiterLength = NewLine.GetDelimiterLength(ch, i + 1 < text.Length ? text [i + 1] : ' '); if (delimiterLength > 0) { isNewLine = true; if (gotNewLine || pasteAtLineStart) { if (curLine.Length > 0 /*|| formattingOptions.EmptyLineFormatting == EmptyLineFormatting.Indent*/) { indentedText.Append(clonedEngine.ThisLineIndent); } } indentedText.Append(curLine); var newLine = options.GetOption(FormattingOptions.NewLine, LanguageNames.CSharp); indentedText.Append(newLine); curLine.Length = 0; gotNewLine = true; i += delimiterLength - 1; // textEditorOptions.EolMarker[0] is the newLineChar used by the indentation engine. clonedEngine.Push(newLine [0]); } else { if (isNewLine) { if (ch == '\t' || ch == ' ') { clonedEngine.Push(ch); continue; } isNewLine = false; } curLine.Append(ch); clonedEngine.Push(ch); } if (clonedEngine.IsInsideVerbatimString || clonedEngine.IsInsideMultiLineComment && !(clonedEngine.LineBeganInsideVerbatimString || clonedEngine.LineBeganInsideMultiLineComment)) { if (gotNewLine) { if (curLine.Length > 0 /*|| formattingOptions.EmptyLineFormatting == EmptyLineFormatting.Indent*/) { indentedText.Append(clonedEngine.ThisLineIndent); } } pasteAtLineStart = false; indentedText.Append(curLine); curLine.Length = 0; gotNewLine = false; continue; } } if (gotNewLine && (!pasteAtLineStart || curLine.Length > 0)) { indentedText.Append(clonedEngine.ThisLineIndent); } if (curLine.Length > 0) { indentedText.Append(curLine); } StringBuilderCache.Free(curLine); return(StringBuilderCache.ReturnAndFree(indentedText)); }