40 changed files with 548 additions and 160 deletions
@ -0,0 +1,226 @@ |
|||||||
|
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
|
||||||
|
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
|
||||||
|
|
||||||
|
using System; |
||||||
|
using System.Collections.Generic; |
||||||
|
using System.Globalization; |
||||||
|
using System.IO; |
||||||
|
using System.Linq; |
||||||
|
using System.Windows.Documents; |
||||||
|
using ICSharpCode.AvalonEdit.Utils; |
||||||
|
|
||||||
|
namespace ICSharpCode.AvalonEdit.Highlighting |
||||||
|
{ |
||||||
|
/// <summary>
|
||||||
|
/// Represents a immutable piece text with highlighting information.
|
||||||
|
/// </summary>
|
||||||
|
public class RichText |
||||||
|
{ |
||||||
|
readonly string text; |
||||||
|
internal readonly int[] stateChangeOffsets; |
||||||
|
internal readonly HighlightingColor[] stateChanges; |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a RichText instance with the given text and RichTextModel.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="text">
|
||||||
|
/// The text to use in this RichText instance.
|
||||||
|
/// </param>
|
||||||
|
/// <param name="model">
|
||||||
|
/// The model that contains the formatting to use for this RichText instance.
|
||||||
|
/// <c>model.DocumentLength</c> should correspond to <c>text.Length</c>.
|
||||||
|
/// This parameter may be null, in which case the RichText instance just holds plain text.
|
||||||
|
/// </param>
|
||||||
|
public RichText(string text, RichTextModel model = null) |
||||||
|
{ |
||||||
|
if (text == null) |
||||||
|
throw new ArgumentNullException("text"); |
||||||
|
this.text = text; |
||||||
|
if (model != null) { |
||||||
|
var sections = model.GetHighlightedSections(0, text.Length).ToArray(); |
||||||
|
stateChangeOffsets = new int[sections.Length]; |
||||||
|
stateChanges = new HighlightingColor[sections.Length]; |
||||||
|
for (int i = 0; i < sections.Length; i++) { |
||||||
|
stateChangeOffsets[i] = sections[i].Offset; |
||||||
|
stateChanges[i] = sections[i].Color; |
||||||
|
} |
||||||
|
} else { |
||||||
|
stateChangeOffsets = new int[] { 0 }; |
||||||
|
stateChanges = new HighlightingColor[] { HighlightingColor.Empty }; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
internal RichText(string text, int[] offsets, HighlightingColor[] states) |
||||||
|
{ |
||||||
|
this.text = text; |
||||||
|
this.stateChangeOffsets = offsets; |
||||||
|
this.stateChanges = states; |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the text.
|
||||||
|
/// </summary>
|
||||||
|
public string Text { |
||||||
|
get { return text; } |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the text length.
|
||||||
|
/// </summary>
|
||||||
|
public int Length { |
||||||
|
get { return text.Length; } |
||||||
|
} |
||||||
|
|
||||||
|
int GetIndexForOffset(int offset) |
||||||
|
{ |
||||||
|
if (offset < 0 || offset > text.Length) |
||||||
|
throw new ArgumentOutOfRangeException("offset"); |
||||||
|
int index = Array.BinarySearch(stateChangeOffsets, offset); |
||||||
|
if (index < 0) { |
||||||
|
// If no color change exists directly at offset,
|
||||||
|
// return the index of the color segment that contains offset.
|
||||||
|
index = ~index - 1; |
||||||
|
} |
||||||
|
return index; |
||||||
|
} |
||||||
|
|
||||||
|
int GetEnd(int index) |
||||||
|
{ |
||||||
|
// Gets the end of the color segment no. index.
|
||||||
|
if (index + 1 < stateChangeOffsets.Length) |
||||||
|
return stateChangeOffsets[index + 1]; |
||||||
|
else |
||||||
|
return text.Length; |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the HighlightingColor for the specified offset.
|
||||||
|
/// </summary>
|
||||||
|
public HighlightingColor GetHighlightingAt(int offset) |
||||||
|
{ |
||||||
|
return stateChanges[GetIndexForOffset(offset)]; |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Retrieves the highlighted sections in the specified range.
|
||||||
|
/// The highlighted sections will be sorted by offset, and there will not be any nested or overlapping sections.
|
||||||
|
/// </summary>
|
||||||
|
public IEnumerable<HighlightedSection> GetHighlightedSections(int offset, int length) |
||||||
|
{ |
||||||
|
int index = GetIndexForOffset(offset); |
||||||
|
int pos = offset; |
||||||
|
int endOffset = offset + length; |
||||||
|
while (pos < endOffset) { |
||||||
|
int endPos = Math.Min(endOffset, GetEnd(index)); |
||||||
|
yield return new HighlightedSection { |
||||||
|
Offset = pos, |
||||||
|
Length = endPos - pos, |
||||||
|
Color = stateChanges[index] |
||||||
|
}; |
||||||
|
pos = endPos; |
||||||
|
index++; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new RichTextModel with the formatting from this RichText.
|
||||||
|
/// </summary>
|
||||||
|
public RichTextModel ToRichTextModel() |
||||||
|
{ |
||||||
|
return new RichTextModel(GetHighlightedSections(0, this.Length)); |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the text.
|
||||||
|
/// </summary>
|
||||||
|
public override string ToString() |
||||||
|
{ |
||||||
|
return text; |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates WPF Run instances that can be used for TextBlock.Inlines.
|
||||||
|
/// </summary>
|
||||||
|
public Run[] CreateRuns() |
||||||
|
{ |
||||||
|
Run[] runs = new Run[stateChanges.Length]; |
||||||
|
for (int i = 0; i < runs.Length; i++) { |
||||||
|
int startOffset = stateChangeOffsets[i]; |
||||||
|
int endOffset = i + 1 < stateChangeOffsets.Length ? stateChangeOffsets[i + 1] : text.Length; |
||||||
|
Run r = new Run(text.Substring(startOffset, endOffset - startOffset)); |
||||||
|
HighlightingColor state = stateChanges[i]; |
||||||
|
if (state.Foreground != null) |
||||||
|
r.Foreground = state.Foreground.GetBrush(null); |
||||||
|
if (state.Background != null) |
||||||
|
r.Background = state.Background.GetBrush(null); |
||||||
|
if (state.FontWeight != null) |
||||||
|
r.FontWeight = state.FontWeight.Value; |
||||||
|
if (state.FontStyle != null) |
||||||
|
r.FontStyle = state.FontStyle.Value; |
||||||
|
runs[i] = r; |
||||||
|
} |
||||||
|
return runs; |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Produces HTML code for the line, with <span style="..."> tags.
|
||||||
|
/// </summary>
|
||||||
|
public string ToHtml(HtmlOptions options = null) |
||||||
|
{ |
||||||
|
StringWriter stringWriter = new StringWriter(CultureInfo.InvariantCulture); |
||||||
|
using (var htmlWriter = new HtmlRichTextWriter(stringWriter, options)) { |
||||||
|
htmlWriter.Write(this); |
||||||
|
} |
||||||
|
return stringWriter.ToString(); |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Produces HTML code for a section of the line, with <span style="..."> tags.
|
||||||
|
/// </summary>
|
||||||
|
public string ToHtml(int offset, int length, HtmlOptions options = null) |
||||||
|
{ |
||||||
|
StringWriter stringWriter = new StringWriter(CultureInfo.InvariantCulture); |
||||||
|
using (var htmlWriter = new HtmlRichTextWriter(stringWriter, options)) { |
||||||
|
htmlWriter.Write(this, offset, length); |
||||||
|
} |
||||||
|
return stringWriter.ToString(); |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a substring of this rich text.
|
||||||
|
/// </summary>
|
||||||
|
public RichText Substring(int offset, int length) |
||||||
|
{ |
||||||
|
// if (offset == 0 && length == this.Length)
|
||||||
|
// return this;
|
||||||
|
throw new NotImplementedException(); |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Concatenates the specified rich texts.
|
||||||
|
/// </summary>
|
||||||
|
public static RichText Concat(params RichText[] texts) |
||||||
|
{ |
||||||
|
throw new NotImplementedException(); |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Concatenates the specified rich texts.
|
||||||
|
/// </summary>
|
||||||
|
public static RichText operator +(RichText a, RichText b) |
||||||
|
{ |
||||||
|
return RichText.Concat(a, b); |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Implicit conversion from string to RichText.
|
||||||
|
/// </summary>
|
||||||
|
public static implicit operator RichText(string text) |
||||||
|
{ |
||||||
|
if (text != null) |
||||||
|
return new RichText(text); |
||||||
|
else |
||||||
|
return null; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,69 @@ |
|||||||
|
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
|
||||||
|
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
|
||||||
|
|
||||||
|
using System; |
||||||
|
using ICSharpCode.AvalonEdit.Highlighting; |
||||||
|
|
||||||
|
namespace ICSharpCode.SharpDevelop.Workbench |
||||||
|
{ |
||||||
|
/// <summary>
|
||||||
|
/// The 'Output' pad.
|
||||||
|
/// Allows showing a text log to the user.
|
||||||
|
/// </summary>
|
||||||
|
public interface IOutputPad |
||||||
|
{ |
||||||
|
/// <summary>
|
||||||
|
/// Opens the pad.
|
||||||
|
/// </summary>
|
||||||
|
void BringToFront(); |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new output category.
|
||||||
|
/// </summary>
|
||||||
|
IOutputCategory CreateCategory(string displayName); |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Removes an existing output category.
|
||||||
|
/// </summary>
|
||||||
|
void RemoveCategory(IOutputCategory category); |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets/Sets the current category.
|
||||||
|
/// This property is thread-safe.
|
||||||
|
/// </summary>
|
||||||
|
IOutputCategory CurrentCategory { get; set; } |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The "Build" category.
|
||||||
|
/// </summary>
|
||||||
|
IOutputCategory BuildCategory { get; } |
||||||
|
} |
||||||
|
|
||||||
|
public interface IOutputCategory |
||||||
|
{ |
||||||
|
/// <summary>
|
||||||
|
/// Gets the display name of this category.
|
||||||
|
/// </summary>
|
||||||
|
string DisplayName { get; } |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Activates this output category in the UI.
|
||||||
|
/// </summary>
|
||||||
|
void Activate(bool bringPadToFront = false); |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Clears all text in the category.
|
||||||
|
/// </summary>
|
||||||
|
void Clear(); |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Appends text to this category.
|
||||||
|
/// </summary>
|
||||||
|
void AppendText(RichText text); |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Appends text to this category, followed by a newline.
|
||||||
|
/// </summary>
|
||||||
|
void AppendLine(RichText text); |
||||||
|
} |
||||||
|
} |
||||||
Loading…
Reference in new issue