SharpDevelop Community

Get your problems solved!
Welcome to SharpDevelop Community Sign in | Join | Help
in Search

xshd files for ANSI colors

Last post 10-02-2011 12:00 AM by tooslow. 5 replies.
Page 1 of 1 (6 items)
Sort Posts: Previous Next
  • 09-30-2011 4:05 AM

    xshd files for ANSI colors

    I love the performance of AvalonEditor vs RichText in WPF, but I have run into a bit of a snag.

    I am writing a terminal that receives ANSI escape sequences for color, and I cannot figure out the best way to approach this in AE.

    My terminal only needs to support (most) of the Display Attributes for ANSI, as documented here:

    http://www.termsys.demon.co.uk/vtansi.htm

    The problem that I am running into is that once a display attribute is recieved, it affects all of the following text until another attribute comes in.

    Anyway, I have looked at the xshds and the LineTransformers, but can't see a way to make either of these work.  Any advice would be appreciated.

     

  • 09-30-2011 5:19 PM In reply to

    Re: xshd files for ANSI colors

    I would do this in two steps:

    1. A VisualLineElementGenerator converts escape sequences into invisible elements.
    2. A line transformer applies the effects caused by the escape sequences.

                textEditor.TextArea.TextView.ElementGenerators.Add(new EscapeSequenceElementGenerator());
                textEditor.TextArea.TextView.LineTransformers.Add(new EscapeSequenceLineTransformer());
                textEditor.Text = @"This is red and \bblue!";

        public class EscapeSequenceElementGenerator : VisualLineElementGenerator
        {
            public override int GetFirstInterestedOffset(int startOffset)
            {
                DocumentLine endLine = CurrentContext.VisualLine.LastDocumentLine;
                StringSegment relevantText = CurrentContext.GetText(startOffset, endLine.EndOffset - startOffset);
                
                for (int i = 0; i < relevantText.Count; i++) {
                    if (relevantText.Text[relevantText.Offset + i] == '\\')
                        return startOffset + i;
                }
                return -1;
            }
            
            public override VisualLineElement ConstructElement(int offset)
            {
                TextDocument document = CurrentContext.Document;
                if (document.GetCharAt(offset) == '\\' && offset + 1 < document.TextLength) {
                    char c = document.GetCharAt(offset + 1);
                    switch (c) {
                        case 'r':
                            return new EscapeSequenceElement(Brushes.Red, 2);
                        case 'b':
                            return new EscapeSequenceElement(Brushes.Blue, 2);
                    }
                }
                return null;
            }
        }
        
        public class EscapeSequenceElement : VisualLineElement
        {
            public readonly Brush ForegroundBrush;
            
            public EscapeSequenceElement(Brush foregroundBrush, int documentLength) : base(1, documentLength)
            {
                this.ForegroundBrush = foregroundBrush;
            }
            
            public override TextRun CreateTextRun(int startVisualColumn, ITextRunConstructionContext context)
            {
                return new TextHidden(1);
            }
        }
        
        public class EscapeSequenceLineTransformer : IVisualLineTransformer
        {
            public void Transform(ITextRunConstructionContext context, IList<VisualLineElement> elements)
            {
                EscapeSequenceElement currentEscapeSequence = null;
                foreach (VisualLineElement element in elements) {
                    if (element is EscapeSequenceElement) {
                        currentEscapeSequence = (EscapeSequenceElement)element;
                    } else if (currentEscapeSequence != null) {
                        element.TextRunProperties.SetForegroundBrush(currentEscapeSequence.ForegroundBrush);
                    }
                }
            }
        }

  • 10-01-2011 5:44 PM In reply to

    Re: xshd files for ANSI colors

    Thanks for the help, I appreciate it.

    One thing I'm noticing is that even though GetFirstInterestedOffset is returning something other than -1, ConstructElement is never being called.

    Also, in your example, 'CreateTextRun' returns a TextHidden of 1 length.  Should this be returning the length of the escape sequence?

    ie: In my case, an escape sequence might be 01b[1;37m, so would I return a length of 7 here?  Sorry - I've not been able to test this yet since ConstructElement is not called.

    Here is the code I'm using for GetFirstInterestedOffset

    public override int GetFirstInterestedOffset(int startOffset)

    {

      DocumentLine endLine = CurrentContext.VisualLine.LastDocumentLine;

      StringSegment relevantText = CurrentContext.GetText(startOffset, endLine.EndOffset - startOffset);

     

      for (int i = 0; i < relevantText.Count; i++)

      {

        char c = relevantText.Text[relevantText.Offset + i];

     

        if ((int)c == 27) // ESC

          return startOffset + i;

      }

     

      return -1;

    }

    and some example data...  "01b

    [0;37;44mNormal, White on Blue"

    (where the '01b' is actually ANSI char #27, the escape character)

     

  • 10-01-2011 5:57 PM In reply to

    Re: xshd files for ANSI colors

    I found the problem...

    The SingleCharacterElementGenerator was getting in the way, since it was also looking for (any) control key.  Turning off that option fixed things.  I seem to have it working now.  Thanks for the tip.

     

  • 10-01-2011 7:35 PM In reply to

    Re: xshd files for ANSI colors

    The EscapeSequenceElement is calling the base constructor with base(1, documentLength).

    This tells AvalonEdit to combine documentLength characters into 1 virtual character. It is this virtual character that is then hidden by the TextHidden element.

  • 10-02-2011 12:00 AM In reply to

    Re: xshd files for ANSI colors

    Well - I thought I had it working... it works, as long as their is only one esc sequence on the line. :(

Page 1 of 1 (6 items)
Powered by Community Server (Commercial Edition), by Telligent Systems
Don't contact us via this (fleischfalle@alphasierrapapa.com) email address.