Posted 19 years ago by Jeff Bridges
Avatar
Hi,

I'm trying to implement the Highlighter into my .Text based blog, however, it doesn't seem to work with the control, so therefore I tried using the CodeHighLighterEngine class like in the code below.

However, I get the following error message:
"System.NullReferenceException: Object reference not set to an instance of an object."
which occurs on the GenerateHtmlInline method.

Is it even possible to use the code highlighting w/o the web control? If yes, how?

Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
'Put user code to initialize the page here
Dim engine As New ActiproSoftware.CodeHighlighter.CodeHighlighterEngine
Dim language As New ActiproSoftware.SyntaxEditor.SyntaxLanguage("VB.NET", False)
Dim code As String = "'Test" & System.Environment.NewLine & "Dim code As String"
Dim output As String = engine.GenerateHtmlInline("1", code, language)
Label1.Text = output
End Sub


Greetings

Comments (10)

Posted 19 years ago by Joe
Avatar
After many, many hours, I was able to extract the interface to be able to generate just the Html markup, without using the control. The HTML markup still has the Actipro Software name and website address, so I'm sure they won't mind me posting how I did it. ;] (If you view the source on any website that uses the control, that's all you see anyways)

To have this work, you still need a few things.
1. The Settings in the web.config file
2. ActiproSoftware.CodeHighlighter.dll, ActiproSoftware.Shard.dll referenced
3. A dll of the semantic parsers for outlining
4. Two methods to work with the GenerateHtmlInline() method

1. Just copy/paste the settings from the web.config file that came with the example into your own web.config file

2. Make sure you copy/paste the ActiproSoftware.CodeHighlighter.dll and ActiproSoftware.Shard.dll into your "bin" directory, then set a reference to it in Visual Studio by right-clicking "References" -> "Add Reference..."

3. This can be the confusing one. If you look in the example, you'll see a folder named "Parsers". These are the parsers that are used for "semantic parsing". If you have no clue what I'm talking about, don't worry. Just know that you need these files for your outlining to work. The easy way to use this is to just compile the example, and copy/paste the "CodeHighlighterTest.dll" into your "bin"directory.
You can also just compile those few files into a dll, though then you also have to change the files/classes referenced in your web.config file. The command to compile the single files into a dll is (all one line):
vbc /reference:ActiproSoftware.Shared.dll /reference:ActiproSoftware.CodeHighlighter.dll /target:library /out:Parsers.dll *.vb
Save that into a .bat file in the same directory as the vb parser files and run it from the command line.

4. I created two methods to be able to make the code work:

        private string SyntaxHighlight(string input, string language, bool outline, System.Web.UI.Page page)
        {
            CodeHighlighterConfiguration configuration1 = 
                         (CodeHighlighterConfiguration) ConfigurationSettings.GetConfig("codeHighlighter");
            string text1 = input;
            if (text1 == null)
            {
                return HttpUtility.HtmlEncode(text1);
            }
            else
            {
                if (configuration1.LanguageConfigs[language] == null)
                {
                    throw new ApplicationException("Error: language \"" +language+"\" not a valid language.");
                }
                SyntaxLanguage language1 = this.GetLanguage(language, configuration1);
                CodeHighlighterEngine engine1 = new CodeHighlighterEngine();
                engine1.OutliningEnabled = outline;
                engine1.OutliningImagesPath = page.ResolveUrl(configuration1.OutliningImagesPath);
                engine1.SpacesInTabs = configuration1.SpacesInTabs;
                return engine1.GenerateHtmlInline(page.UniqueID, text1, language1);
            }
        }
and

        private SyntaxLanguage GetLanguage(string language, CodeHighlighterConfiguration configuration2)
        {
            SyntaxLanguageConfiguration configuration1 = 
                               (SyntaxLanguageConfiguration) configuration2.LanguageConfigs[language];
            string text1 = configuration1.DefinitionPath;

            SyntaxLanguage language1 = SyntaxLanguage.LoadFromXml(configuration1.DefinitionPath, 0);
            if (configuration1.SemanticParserType != null)
            {
                char[] chArray1 = new char[1] { ',' } ;
                string[] textArray1 = configuration1.SemanticParserType.Split(chArray1);
                ObjectHandle handle1 = Activator.CreateInstance(textArray1[1].Trim(), textArray1[0].Trim());
                language1.SemanticParser = (SemanticParser) handle1.Unwrap();
            }
            return language1;
        }
Then it's as simple as calling the method as such: SyntaxHighlight(codeBlock, language, true, this)

Enjoy!

- <A HREF="http://blog.xamlcoder.com" TARGET=_blank>Joe</A>

[ 02-13-2005: Message edited by: Joe ]

[ 02-13-2005: Message edited by: Joe ]
Posted 19 years ago by Actipro Software Support - Cleveland, OH, USA
Avatar
My apologies for not replying sooner. We set up our forums to e-mail us when posts are made however the e-mails for this forum were never wired up so we never noticed new posts. <IMG SRC="smile.gif" border="0"> This is fixed now.

The CodeHighlighterEngine should be able to be called without use of the ASP.NET control. The ASP.NET control calls it behind the scenes to generate the HTML. If you are still getting the exception when you try generating the HTML, please send us the stack trace of the exception and we can help figure out what the issue is.


Actipro Software Support

Posted 19 years ago by Joe
Avatar
Yes - you can use it without the control, but only with those two methods I posted. Trying to use something like:

ActiproSoftware.CodeHighlighter.CodeHighlighterEngine engine = new CodeHighlighterEngine();
            ActiproSoftware.SyntaxEditor.SyntaxLanguage lang = new SyntaxLanguage(this.LanguageKey, false);
            TextBox2.Text = engine.GenerateHtmlInline(this.UniqueID, TextBox1.Text, lang);
You get:
(Line 172 as the error line)
Line 170:            ActiproSoftware.CodeHighlighter.CodeHighlighterEngine engine = new CodeHighlighterEngine();
Line 171:            ActiproSoftware.SyntaxEditor.SyntaxLanguage lang = new SyntaxLanguage(this.LanguageKey, false);
Line 172:            TextBox2.Text = engine.GenerateHtmlInline(this.UniqueID, TextBox1.Text, lang);
Stack Trace:

[NullReferenceException: Object reference not set to an instance of an object.]
   ActiproSoftware.CodeHighlighter.CodeHighlighterEngine.GenerateHtmlInline(String uniqueID, String code, SyntaxLanguage language) +1285
   blog.Components.Test.Button1_Click(Object sender, EventArgs e) in c:\code\asp.net\website\blog\components\test.aspx.cs:172
   System.Web.UI.WebControls.Button.OnClick(EventArgs e) +108
   System.Web.UI.WebControls.Button.System.Web.UI.IPostBackEventHandler.RaisePostBackEvent(String eventArgument) +57
   System.Web.UI.Page.RaisePostBackEvent(IPostBackEventHandler sourceControl, String eventArgument) +18
   System.Web.UI.Page.RaisePostBackEvent(NameValueCollection postData) +33
   System.Web.UI.Page.ProcessRequestMain() +1292
The control uses *late binding* to bind the correct Sematic Parser to the Language. So you can't just create a new instance of the SyntaxLanguage - you have to load the DLL of the sematic parser. Vai:
SyntaxLanguageConfiguration configuration1 =                                (SyntaxLanguageConfiguration) configuration2.LanguageConfigs[language];
// Load the Syntax Definitions
SyntaxLanguage language1 = SyntaxLanguage.LoadFromXml(configuration1.DefinitionPath, 0);
char[] chArray1 = new char[1] { ',' } ;
string[] textArray1 = configuration1.SemanticParserType.Split(chArray1);
ObjectHandle handle1 = Activator.CreateInstance(textArray1[1].Trim(), textArray1[0].Trim());
// Unwrap the DLL containing the Sematic Parser
language1.SemanticParser = (SemanticParser) handle1.Unwrap();
So you CAN use the GenerateHtmlInline() method without the control, but you HAVE to bind the correct Sematic Parser to the Syntax Language for this to work. A GetLanguage(string language, CodeHighlighterConfiguration configuration) type method is required for it to work.

If you look in your control, you have these EXACT methods. One is void(), one returns a type of SyntaxLanguage. (Thank you Lutz)
private void &#5121;()
{
      CodeHighlighterConfiguration configuration1 = this.&#5121;();
      string text1 = this.Text;
      if (this.&#5121; == null)
      {
            this.&#5122; = HttpUtility.HtmlEncode(text1);
      }
      else
      {
            if (configuration1.LanguageConfigs[this.&#5121;] == null)
            {
                  throw new ApplicationException(string.Format(&#5161;.&#5121;("\x000e2?z6;4=/;=?z1?#z}!j'}z-   <IMG SRC="wink.gif" border="0">z45.z659;.?&gt;z34z.2?z-?8z;**639;.354})z\r?8t954&lt;3=z&lt;36?tWP"), this.&#5121;   <IMG SRC="wink.gif" border="0">);
            }
            SyntaxLanguage language1 = this.&#5121;(configuration1);
            CodeHighlighterEngine engine1 = new CodeHighlighterEngine();
            engine1.OutliningEnabled = this.&#5121;();
            engine1.OutliningImagesPath = this.Page.ResolveUrl(configuration1.OutliningImagesPath);
            engine1.SpacesInTabs = configuration1.SpacesInTabs;
            this.&#5122; = engine1.GenerateHtmlInline(this.UniqueID, text1, language1);
      }
}
and
private SyntaxLanguage &#5121;(CodeHighlighterConfiguration configuration2)
{
      SyntaxLanguageConfiguration configuration1 = (SyntaxLanguageConfiguration) configuration2.LanguageConfigs[this.&#5121;];
      string text1 = &#5161;.&#5121;("\x00195&gt;?\x00123=263=2.?(`\x0016;4=/;=?`\n;.2g") + configuration1.DefinitionPath;
      if ((configuration2.SpacesInTabs &gt; 0) && (HttpContext.Current.Cache[text1] != null))
      {
            return (SyntaxLanguage) HttpContext.Current.Cache[text1];
      }
      if (HttpContext.Current.Items[text1] == null)
      {
            SyntaxLanguage language1 = SyntaxLanguage.LoadFromXml(configuration1.DefinitionPath, 0);
            if (configuration1.SemanticParserType != null)
            {
                  char[] chArray1 = new char[1] { ',' } ;
                  string[] textArray1 = configuration1.SemanticParserType.Split(chArray1);
                  ObjectHandle handle1 = Activator.CreateInstance(textArray1[1].Trim(), textArray1[0].Trim());
                  language1.SemanticParser = (SemanticParser) handle1.Unwrap();
            }
            HttpContext.Current.Items[text1] = language1;
      }
      if (((configuration2.SpacesInTabs &gt; 0) && (HttpContext.Current.Cache[text1] == null)) && (HttpContext.Current.Items[text1] != null))
      {
            HttpContext.Current.Cache.Insert(text1, HttpContext.Current.Items[text1], new CacheDependency(configuration1.DefinitionPath), DateTime.Now.AddMinutes((double) configuration2.CacheLanguageTimeout), TimeSpan.Zero);
      }
      return (SyntaxLanguage) HttpContext.Current.Items[text1];
}
The void() gets called in the "protected override void Render(HtmlTextWriter writer)" method, and it calls the method returning the SyntaxLanguage, and the last line, sets the Output property of the control to the HTML generated.

If you didn't want the outlining, it might be possible to not unwrap the DLL and use use the .LoadFromXML() methods, though then you loose that feature.

The control is wonderful nevertheless - just have this one issue.

If I'm wrong ... please let me know how else you are suppose to do it? ;]

- <A HREF="http://blog.xamlcoder.com" TARGET=_blank>Joe</A>

[ 02-14-2005: Message edited by: Joe ]
Posted 19 years ago by Actipro Software Support - Cleveland, OH, USA
Avatar
I just did a test myself and it worked ok here. Check this code out:

CodeHighlighterEngine engine = new CodeHighlighterEngine();
SyntaxLanguage language = SyntaxLanguage.LoadFromXml(@"C:\CodeHighlighter\Languages\ActiproSoftware.VBDotNet.xml", 0);
Console.WriteLine(engine.GenerateHtmlInline("1", "Dim b as Integer 'Comment", language));
With that code I had made a simple Windows Forms application and executed it. The HTML that was output went to the Console window and looked fine. No exceptions or anything.


Actipro Software Support

Posted 19 years ago by Joe
Avatar
<BLOCKQUOTE><font size="1" face="Verdana, Arial">quote:</font><HR>Originally posted by Actipro Software Support:
<STRONG>I just did a test myself and it worked ok here. Check this code out:

CodeHighlighterEngine engine = new CodeHighlighterEngine();
SyntaxLanguage language = SyntaxLanguage.LoadFromXml(@"C:\CodeHighlighter\Languages\ActiproSoftware.VBDotNet.xml", 0);
Console.WriteLine(engine.GenerateHtmlInline("1", "Dim b as Integer 'Comment", language));
With that code I had made a simple Windows Forms application and executed it. The HTML that was output went to the Console window and looked fine. No exceptions or anything.</STRONG><HR></BLOCKQUOTE>

I tried it as well, and it does work. ;] I'm sure most people don't really use the outlining much anyway - it's just a slick feature (I love it though). The way that the control was programmed originally was to be dynamic with what language was picked, so there's another reason why the other fuctions seem a little complex. I think that the confusion stemmed from the constructor of the SyntaxLanguage - it seemed like you could create an instance of the class with just that, whereas this doesn't seem to be the case.

I haven't messed around too much with late-binding programming (I'm sure there's another name for it), but it's a really nice feature; you can keep your implimentation code the same and just update the library's that it works with. A good practice. Anyhow - glad to see some replys! Happy coding!

- <A HREF="http://blog.xamlcoder.com" TARGET=_blank>Joe</A>
Posted 19 years ago by Actipro Software Support - Cleveland, OH, USA
Avatar
The languages are the same as with our SyntaxEditor product. So really you can construct a complete language definition from scratch by using the contructor and then adding the appropriate objects to the language's collections. But most people will just want to use the XML definitions and load them using the code I posted.

If you want to add outlining, you need to assign a SemanticParser to the language. That is set via the SyntaxLanguage.SemanticParser property. We provide several samples for those classes. In addition, you'd need to set the engine's OutliningEnabled property to true and you'd need to set the OutliningImagesPath property to the path where the images are for outlining indicators.

So really, you can can complete syntax-highlighting with outlining output in 6 lines of code. Not bad! <IMG SRC="smile.gif" border="0">


Actipro Software Support

Posted 17 years ago by Pablo Viale
Avatar
Ok this is exactly what I want to do, but I use VB.
I tried to translate the code, like this:
        Dim engine As New ActiproSoftware.CodeHighlighter.CodeHighlighterEngine
        Dim language As ActiproSoftware.SyntaxEditor.Addons.Dynamic.DynamicSyntaxLanguage.LoadFromXml(@"C:\CodeHighlighter\Languages\ActiproSoftware.VBDotNet.xml", 0)
        Console.WriteLine(engine.GenerateHtmlInline("1", "Dim b as Integer 'Comment", language))
But in the second line the "@" is causing problems, it says: "Character is not valid".

Of course I thought the @ was a typo, but if I delete it, then I get another error: "Array bounds cannot appear in type specifiers". The error shows at "C:\CodeHighlighter\Languages\ActiproSoftware.VBDotNet.xml"

Any ideas?

[Modified at 12/23/2006 08:31 PM]
Posted 17 years ago by Pablo Viale
Avatar
YOOOOOOOOOHOOOOOOOOOOO I got it working.

        Dim engine As New ActiproSoftware.CodeHighlighter.CodeHighlighterEngine
        Dim language As ActiproSoftware.SyntaxEditor.Addons.Dynamic.DynamicSyntaxLanguage
        language = ActiproSoftware.SyntaxEditor.Addons.Dynamic.DynamicSyntaxLanguage.LoadFromXml(Server.MapPath("Languages/Lexers/ActiproSoftware.VBDotNet.xml"), 0)
        'Console.WriteLine(engine.GenerateHtmlInline("1", "Dim b as Integer 'Comment", language))
        TextBox1.Text = engine.GenerateHtmlInline("1", "Dim b as Integer 'Comment", language)
        Label1.Text = engine.GenerateHtmlInline("1", "Dim b as Integer 'Comment", language)

Posted 17 years ago by Pablo Viale
Avatar
I have a lot of more work to do, though.
I have to open the database, open the posted text, then search for the tag code language="vb.net"
and then search for /code, get the in-between code, pass it through the code hightlighter,
then look for some more, because in the same post I can have several code tags.

And then I have to put all together.

I think I need to use regular expressions.

I know some of you have had the same problem and you already have a solution for it.

Is someone willing to share some code?? As a Christmas gift maybe??

=)

[Modified at 12/23/2006 08:44 PM]
Posted 17 years ago by Actipro Software Support - Cleveland, OH, USA
Avatar
Our code uses a regex to parse out the language code sections. This is the regex:
&lt;code (\\s+ language=&quot; (?<Language>.*) &quot;)? \\s* &gt; (?<Code>(.|\\n)*?) &lt;/code&gt;
Then while parsing each code section we call this method:
private static string HighlightCode(string languageKey, string code) {
    CodeHighlighterEngine engine = new CodeHighlighterEngine();
    engine.LineNumberMarginVisible = false;
    engine.OutliningEnabled = false;
    return engine.GenerateHtmlInline("1", code, 
        CodeHighlighter.CodeHighlighter.GetLanguage(
            (CodeHighlighterConfiguration)ConfigurationManager.GetSection("codeHighlighter"),
            languageKey));    
}
That code returns the HTML marked up code for the specified code in the post. Hope that helps.


Actipro Software Support

The latest build of this product (v4.0.59) was released 13 years ago, which was after the last post in this thread.