Question

I'm trying to define some custom highlighting rules for AvalonEdit. There doesn't seem to be any documentation for this -- there's some documentation on the file format, but nothing on how to actually load and use the definition once you've created it.

The "Syntax highlighting" wiki page (for the old WinForms TextEditor) documents how to load highlighting definitions from a .xshd file on disk, but I'd rather embed it as a resource, the same way AvalonEdit does with its built-in definitions.

I've looked at the code in the ICSharpCode.AvalonEdit project that loads its built-in highlighters, but the actual "load from resource" code is done in DefaultHighlightingManager.LoadHighlighting, which is private -- and which, to make things weirder, is apparently only called in release builds.

I can keep fumbling around, copy/paste some of the code from the private methods, and try to cobble something together that might or might not work, but it seems worthwhile to ask: what is the standard way to do this? Is there a recommended way for third-party code to load a highlighting definition from a resource?


Daniel's answer gave me a good start, but you need to include the namespace name in the string you pass to GetManifestResourceStream -- if you don't, you'll get a NullReferenceException (because it returns a null stream).

I wound up adding a static class called ResourceLoader to the same project folder as the .xshd file, with this method:

public static IHighlightingDefinition LoadHighlightingDefinition(
    string resourceName)
{
    var type = typeof(ResourceLoader);
    var fullName = type.Namespace + "." + resourceName;
    using (var stream = type.Assembly.GetManifestResourceStream(fullName))
    using (var reader = new XmlTextReader(stream))
        return HighlightingLoader.Load(reader, HighlightingManager.Instance);
}

Then I can just call ResourceLoader.LoadHighlightingDefinition("Name.xshd").

For anyone following along at home, the .xshd file needs to have its Build Action set to Embedded Resource.

Was it helpful?

Solution

You can use the static methods in the class ICSharpCode.AvalonEdit.Highlighting.Xshd.HighlightingLoader to load .xshd files. For example:

using (Stream s = myAssembly.GetManifestResourceStream("MyHighlighting.xshd")) {
    using (XmlTextReader reader = new XmlTextReader(s)) {
        textEditor.SyntaxHighlighting = HighlightingLoader.Load(reader, HighlightingManager.Instance);
    }
}

The loading code in AvalonEdit itself is weird because it eagerly loads the xshds in debug builds (so that errors in them are noticed immediately), but delay-loads them in release builds.

OTHER TIPS

For what it's worth, if you're using F#, this is a code snippet that works to register the xshd file.

let registerHighlighting() =
    try
        // Load our custom highlighting definition
        match System.Reflection.Assembly.GetExecutingAssembly().GetManifestResourceStream("GSLhighlighting.xshd") with
            | null -> failwithf "ERROR: could not find embedded resource"
            | s ->
                use reader = new XmlTextReader(s)
                let gslHighlighting = ICSharpCode.AvalonEdit.Highlighting.Xshd.HighlightingLoader.Load(reader, HighlightingManager.Instance)
                // and register it in the HighlightingManager
                HighlightingManager.Instance.RegisterHighlighting("GSL", [| ".gsl" |], gslHighlighting)
                editor.SyntaxHighlighting <- gslHighlighting
    with _ as exn ->
        printfn "ERROR: %s" exn.Message

I personally prefer Darren's way of registering your highlighting definition using RegisterHighlighting, then you can use it in your XAML like other built-in definitions.

C#

public partial class App : Application
{
    public App()
    {
        using (var stream = new System.IO.MemoryStream(WpfApp15.Properties.Resources.sql))
        {
            using (var reader = new System.Xml.XmlTextReader(stream))
            {
                ICSharpCode.AvalonEdit.Highlighting.HighlightingManager.Instance.RegisterHighlighting("SQL", new string[0],
                    ICSharpCode.AvalonEdit.Highlighting.Xshd.HighlightingLoader.Load(reader,
                        ICSharpCode.AvalonEdit.Highlighting.HighlightingManager.Instance));
            }
        }
    } 
}

XAML

<avalon:TextEditor SyntaxHighlighting="SQL"/>

When I used GetManifestResourceStream for an xshd file I got null. I used StreamReader instead:

using (StreamReader s = 
            new StreamReader(@"C:\Users\Smadar.Tsdaka\Documents\ServoStudio\Scripts\ServoStudioSyntax.xshd"))
        {
            using (XmlTextReader reader = new XmlTextReader(s))
            {
                scriptBody.SyntaxHighlighting =
                    ICSharpCode.AvalonEdit.Highlighting.Xshd.HighlightingLoader.Load(
                    reader,
                    HighlightingManager.Instance);
            }
        }

Create a resource string and call it "xshd" and in the content write what you want. Next use this simple code:

XmlReader xshdres = XmlReader.Create(new MemoryStream(Encoding.Unicode.GetBytes(Properties.Resources.xshd)));
textEditor.SyntaxHighlighting = HighlightingLoader.Load(xshdres, HighlightingManager.Instance);

textEditor it's the name of the avalonedit texteditor in the XAML.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top