diff --git a/src/core/Statiq.Common/Execution/EmptyExecutionContext.cs b/src/core/Statiq.Common/Execution/EmptyExecutionContext.cs index 0a256ae44..f3a22ccef 100644 --- a/src/core/Statiq.Common/Execution/EmptyExecutionContext.cs +++ b/src/core/Statiq.Common/Execution/EmptyExecutionContext.cs @@ -90,8 +90,8 @@ public Task> ExecuteModulesAsync(IEnumerable public Stream GetContentStream(string content = null) => ExecutionState.GetContentStream(content); - public IJavaScriptEnginePool GetJavaScriptEnginePool(Action initializer = null, int startEngines = 10, int maxEngines = 25, int maxUsagesPerEngine = 100, TimeSpan? engineTimeout = null) => - ExecutionState.GetJavaScriptEnginePool(initializer, startEngines, maxEngines, maxUsagesPerEngine, engineTimeout); + public IJavaScriptEngine GetJavaScriptEngine(Action configureEngine = null) => + ExecutionState.GetJavaScriptEngine(configureEngine); public Task SendHttpRequestWithRetryAsync(Func requestFactory) => ExecutionState.SendHttpRequestWithRetryAsync(requestFactory); diff --git a/src/core/Statiq.Common/Execution/IExecutionState.cs b/src/core/Statiq.Common/Execution/IExecutionState.cs index 99f1ea99d..34bacebd7 100644 --- a/src/core/Statiq.Common/Execution/IExecutionState.cs +++ b/src/core/Statiq.Common/Execution/IExecutionState.cs @@ -182,26 +182,10 @@ internal set Task SendHttpRequestWithRetryAsync(Func requestFactory, int retryCount); /// - /// Gets a new . The returned engine pool should be disposed - /// when no longer needed. - /// - /// - /// The code to run when a new engine is created. This should configure - /// the environment and set up any required JavaScript libraries. - /// - /// The number of engines to initially start when a pool is created. - /// The maximum number of engines that will be created in the pool. - /// The maximum number of times an engine can be reused before it is disposed. - /// - /// The default timeout to use when acquiring an engine from the pool (defaults to 5 seconds). - /// If an engine can not be acquired in this time frame, an exception will be thrown. - /// - /// A new JavaScript engine pool. - IJavaScriptEnginePool GetJavaScriptEnginePool( - Action initializer = null, - int startEngines = 10, - int maxEngines = 25, - int maxUsagesPerEngine = 100, - TimeSpan? engineTimeout = null); + /// Gets a new . + /// + /// Optional delegate to configure the engine. + /// A new JavaScript engine. + IJavaScriptEngine GetJavaScriptEngine(Action configureEngine = null); } } \ No newline at end of file diff --git a/src/core/Statiq.Common/JavaScript/IJavaScriptEngine.cs b/src/core/Statiq.Common/JavaScript/IJavaScriptEngine.cs index 69b48aa04..af3f91102 100644 --- a/src/core/Statiq.Common/JavaScript/IJavaScriptEngine.cs +++ b/src/core/Statiq.Common/JavaScript/IJavaScriptEngine.cs @@ -5,10 +5,7 @@ namespace Statiq.Common { /// - /// A common interface to a JavaScript engine. Every JavaScript engine is - /// obtained from a and will be returned to the - /// pool when it is disposed. Therefore, you must dispose the engine when - /// you are done with it. + /// A common interface to a JavaScript engine. /// public interface IJavaScriptEngine : IDisposable { diff --git a/src/core/Statiq.Common/JavaScript/IJavaScriptEnginePool.cs b/src/core/Statiq.Common/JavaScript/IJavaScriptEnginePool.cs deleted file mode 100644 index a1244dd80..000000000 --- a/src/core/Statiq.Common/JavaScript/IJavaScriptEnginePool.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System; - -namespace Statiq.Common -{ - /// - /// Provides a shared pool of JavaScript engine instances. You should dispose the pool when - /// no longer needed to properly dispose of any allocated engines. - /// - public interface IJavaScriptEnginePool : IDisposable - { - /// - /// Gets an engine from the pool. This engine should be disposed when you are finished with it. - /// If an engine is free, this method returns immediately with the engine. - /// If no engines are available but we have not reached the maximum number of engines - /// yet, creates a new engine. If the maximum number of engines has been reached, blocks until an engine is - /// available again. - /// - /// - /// Maximum time to wait for a free engine. If not specified, defaults to the timeout - /// specified when creating the pool. - /// - /// A JavaScript engine. - IJavaScriptEngine GetEngine(TimeSpan? timeout = null); - - /// - /// Disposes the specified engine and removes it from the pool. A new engine will be created in it's place. - /// - /// The JavaScript engine. - void RecycleEngine(IJavaScriptEngine engine); - - /// - /// Disposes all engines in this pool, and creates new engines in their place. - /// - void RecycleAllEngines(); - } -} diff --git a/src/core/Statiq.Core/Execution/Engine.cs b/src/core/Statiq.Core/Execution/Engine.cs index e8cf12d21..fb08a9e06 100644 --- a/src/core/Statiq.Core/Execution/Engine.cs +++ b/src/core/Statiq.Core/Execution/Engine.cs @@ -10,6 +10,8 @@ using System.Text; using System.Threading; using System.Threading.Tasks; +using JavaScriptEngineSwitcher.Core; +using JavaScriptEngineSwitcher.Jint; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; @@ -36,6 +38,8 @@ public class Engine : IEngine, IDisposable // Gets initialized on first execute and reset when the pipeline collection changes private PipelinePhase[] _phases; + private static readonly object JsEngineSwitcherLock = new object(); + private bool _disposed; /// @@ -1057,18 +1061,25 @@ public async Task SendHttpRequestWithRetryAsync(Func - public IJavaScriptEnginePool GetJavaScriptEnginePool( - Action initializer = null, - int startEngines = 10, - int maxEngines = 25, - int maxUsagesPerEngine = 100, - TimeSpan? engineTimeout = null) => - new JavaScriptEnginePool( - initializer, - startEngines, - maxEngines, - maxUsagesPerEngine, - engineTimeout ?? TimeSpan.FromSeconds(5)); + public IJavaScriptEngine GetJavaScriptEngine(Action configureEngine = null) + { + // First we need to check if the JsEngineSwitcher has been configured. We'll do this + // by checking the DefaultEngineName being set. If that's there we can safely assume + // its been configured somehow (maybe via a configuration file). If not we'll wire up + // Jint as the default engine. + lock (JsEngineSwitcherLock) + { + if (string.IsNullOrWhiteSpace(JsEngineSwitcher.Current.DefaultEngineName)) + { + JsEngineSwitcher.Current.EngineFactories.Add(new JintJsEngineFactory()); + JsEngineSwitcher.Current.DefaultEngineName = JintJsEngine.EngineName; + } + } + + IJavaScriptEngine engine = new JavaScriptEngine(JsEngineSwitcher.Current.CreateDefaultEngine()); + configureEngine?.Invoke(engine); + return engine; + } /// /// Applies settings for analyzers and log levels as "[analyzer]=[log level]" (log level is optional, "All" to set all analyzers). diff --git a/src/core/Statiq.Core/Execution/ExecutionContext.cs b/src/core/Statiq.Core/Execution/ExecutionContext.cs index 2da0ef04c..9efdce3af 100644 --- a/src/core/Statiq.Core/Execution/ExecutionContext.cs +++ b/src/core/Statiq.Core/Execution/ExecutionContext.cs @@ -162,13 +162,8 @@ public async Task> ExecuteModulesAsync(IEnumerable _contextData.Engine.GetContentStream(content); /// - public IJavaScriptEnginePool GetJavaScriptEnginePool( - Action initializer = null, - int startEngines = 10, - int maxEngines = 25, - int maxUsagesPerEngine = 100, - TimeSpan? engineTimeout = null) => - _contextData.Engine.GetJavaScriptEnginePool(initializer, startEngines, maxEngines, maxUsagesPerEngine, engineTimeout); + public IJavaScriptEngine GetJavaScriptEngine(Action configureEngine = null) => + _contextData.Engine.GetJavaScriptEngine(configureEngine); // IDocumentFactory diff --git a/src/core/Statiq.Core/JavaScript/JavaScriptEnginePool.cs b/src/core/Statiq.Core/JavaScript/JavaScriptEnginePool.cs deleted file mode 100644 index 44525bdf9..000000000 --- a/src/core/Statiq.Core/JavaScript/JavaScriptEnginePool.cs +++ /dev/null @@ -1,81 +0,0 @@ -using System; -using Statiq.Common; -using JavaScriptEngineSwitcher.Core; -using JavaScriptEngineSwitcher.Jint; -using JSPool; -using IJavaScriptEngine = Statiq.Common.IJavaScriptEngine; - -namespace Statiq.Core -{ - internal class JavaScriptEnginePool : IJavaScriptEnginePool - { - private static readonly object EngineSwitcherLock = new object(); - - private readonly JsPool _pool; - private bool _disposed = false; - - public JavaScriptEnginePool( - Action initializer, - int startEngines, - int maxEngines, - int maxUsagesPerEngine, - in TimeSpan engineTimeout) - { - // First we need to check if the JsEngineSwitcher has been configured. We'll do this - // by checking the DefaultEngineName being set. If that's there we can safely assume - // its been configured somehow (maybe via a configuration file). If not we'll wire up - // Jint as the default engine. - lock (EngineSwitcherLock) - { - if (string.IsNullOrWhiteSpace(JsEngineSwitcher.Current.DefaultEngineName)) - { - JsEngineSwitcher.Current.EngineFactories.Add(new JintJsEngineFactory()); - JsEngineSwitcher.Current.DefaultEngineName = JintJsEngine.EngineName; - } - } - - _pool = new JsPool(new JsPoolConfig - { - EngineFactory = () => new JavaScriptEngine(JsEngineSwitcher.Current.CreateDefaultEngine()), - Initializer = x => initializer?.Invoke(x), - StartEngines = startEngines, - MaxEngines = maxEngines, - MaxUsagesPerEngine = maxUsagesPerEngine, - GetEngineTimeout = engineTimeout - }); - } - - public void Dispose() - { - CheckDisposed(); - _pool.Dispose(); - _disposed = true; - } - - public IJavaScriptEngine GetEngine(TimeSpan? timeout = null) => new PooledJavaScriptEngine(_pool.GetEngine(timeout), _pool); - - public void RecycleEngine(IJavaScriptEngine engine) - { - engine.ThrowIfNull(nameof(engine)); - if (!(engine is PooledJavaScriptEngine pooledEngine)) - { - throw new ArgumentException("The specified engine was not from a pool"); - } - if (pooledEngine.Pool != _pool) - { - throw new ArgumentException("The specified engine is from a different pool"); - } - _pool.DisposeEngine(pooledEngine.Engine); - } - - public void RecycleAllEngines() => _pool.Recycle(); - - private void CheckDisposed() - { - if (_disposed) - { - throw new ObjectDisposedException(nameof(JsPool)); - } - } - } -} \ No newline at end of file diff --git a/src/core/Statiq.Core/JavaScript/PooledJavaScriptEngine.cs b/src/core/Statiq.Core/JavaScript/PooledJavaScriptEngine.cs deleted file mode 100644 index c79a9a9b3..000000000 --- a/src/core/Statiq.Core/JavaScript/PooledJavaScriptEngine.cs +++ /dev/null @@ -1,151 +0,0 @@ -using System; -using System.Reflection; -using System.Text; -using JSPool; -using Statiq.Common; - -namespace Statiq.Core -{ - /// - /// Wraps a but overrides the - /// dispose behavior so that instead of disposing the - /// underlying engine, it returns the engine to the pool. - /// - internal class PooledJavaScriptEngine : IJavaScriptEngine - { - private bool _disposed = false; - - public PooledJavaScriptEngine(JavaScriptEngine engine, JsPool pool) - { - Engine = engine; - Pool = pool; - } - - internal JavaScriptEngine Engine { get; } - - internal JsPool Pool { get; } - - public void Dispose() - { - CheckDisposed(); - Pool.ReturnEngineToPool(Engine); - _disposed = true; - } - - public string Name - { - get - { - CheckDisposed(); - return Engine.Name; - } - } - - public string Version - { - get - { - CheckDisposed(); - return Engine.Version; - } - } - - public object Evaluate(string expression) - { - CheckDisposed(); - return Engine.Evaluate(expression); - } - - public T Evaluate(string expression) - { - CheckDisposed(); - return Engine.Evaluate(expression); - } - - public void Execute(string code) - { - CheckDisposed(); - Engine.Execute(code); - } - - public void ExecuteFile(string path, Encoding encoding = null) - { - CheckDisposed(); - Engine.ExecuteFile(path, encoding); - } - - public void ExecuteResource(string resourceName, Type type) - { - CheckDisposed(); - Engine.ExecuteResource(resourceName, type); - } - - public void ExecuteResource(string resourceName, Assembly assembly) - { - CheckDisposed(); - Engine.ExecuteResource(resourceName, assembly); - } - - public object CallFunction(string functionName, params object[] args) - { - CheckDisposed(); - return Engine.CallFunction(functionName, args); - } - - public T CallFunction(string functionName, params object[] args) - { - CheckDisposed(); - return Engine.CallFunction(functionName, args); - } - - public bool HasVariable(string variableName) - { - CheckDisposed(); - return Engine.HasVariable(variableName); - } - - public object GetVariableValue(string variableName) - { - CheckDisposed(); - return Engine.GetVariableValue(variableName); - } - - public T GetVariableValue(string variableName) - { - CheckDisposed(); - return Engine.GetVariableValue(variableName); - } - - public void SetVariableValue(string variableName, object value) - { - CheckDisposed(); - Engine.SetVariableValue(variableName, value); - } - - public void RemoveVariable(string variableName) - { - CheckDisposed(); - Engine.RemoveVariable(variableName); - } - - public void EmbedHostObject(string itemName, object value) - { - CheckDisposed(); - Engine.EmbedHostObject(itemName, value); - } - - public void EmbedHostType(string itemName, Type type) - { - CheckDisposed(); - Engine.EmbedHostType(itemName, type); - } - - private void CheckDisposed() - { - if (_disposed) - { - throw new ObjectDisposedException(nameof(PooledJavaScriptEngine)); - } - } - } -} \ No newline at end of file diff --git a/src/core/Statiq.Core/Statiq.Core.csproj b/src/core/Statiq.Core/Statiq.Core.csproj index f5834e7d5..0f7917b91 100644 --- a/src/core/Statiq.Core/Statiq.Core.csproj +++ b/src/core/Statiq.Core/Statiq.Core.csproj @@ -5,8 +5,7 @@ - - + diff --git a/src/core/Statiq.Testing.JavaScript/Statiq.Testing.JavaScript.csproj b/src/core/Statiq.Testing.JavaScript/Statiq.Testing.JavaScript.csproj index f7a724490..b9bbb6c5a 100644 --- a/src/core/Statiq.Testing.JavaScript/Statiq.Testing.JavaScript.csproj +++ b/src/core/Statiq.Testing.JavaScript/Statiq.Testing.JavaScript.csproj @@ -4,8 +4,8 @@ Statiq Static StaticContent StaticSite Blog BlogEngine - - + + diff --git a/src/core/Statiq.Testing/Execution/TestEngine.cs b/src/core/Statiq.Testing/Execution/TestEngine.cs index 71fd12bb2..b8f5e670a 100644 --- a/src/core/Statiq.Testing/Execution/TestEngine.cs +++ b/src/core/Statiq.Testing/Execution/TestEngine.cs @@ -195,13 +195,12 @@ public async Task SendHttpRequestWithRetryAsync(Func - public IJavaScriptEnginePool GetJavaScriptEnginePool( - Action initializer = null, - int startEngines = 10, - int maxEngines = 25, - int maxUsagesPerEngine = 100, - TimeSpan? engineTimeout = null) => - new TestJsEnginePool(JsEngineFunc, initializer); + public IJavaScriptEngine GetJavaScriptEngine(Action configureEngine = null) + { + IJavaScriptEngine engine = JsEngineFunc(); + configureEngine?.Invoke(engine); + return engine; + } public Func JsEngineFunc { get; set; } = () => throw new NotImplementedException("JavaScript test engine not initialized. Statiq.Testing.JavaScript can be used to return a working JavaScript engine"); diff --git a/src/core/Statiq.Testing/Execution/TestExecutionContext.cs b/src/core/Statiq.Testing/Execution/TestExecutionContext.cs index 6ae43f445..5272f3568 100644 --- a/src/core/Statiq.Testing/Execution/TestExecutionContext.cs +++ b/src/core/Statiq.Testing/Execution/TestExecutionContext.cs @@ -305,13 +305,8 @@ public async Task> ExecuteModulesAsync(IEnumerable - public IJavaScriptEnginePool GetJavaScriptEnginePool( - Action initializer = null, - int startEngines = 10, - int maxEngines = 25, - int maxUsagesPerEngine = 100, - TimeSpan? engineTimeout = null) => - Engine.GetJavaScriptEnginePool(initializer, startEngines, maxEngines, maxUsagesPerEngine, engineTimeout); + public IJavaScriptEngine GetJavaScriptEngine(Action configureEngine = null) => + Engine.GetJavaScriptEngine(configureEngine); public Func JsEngineFunc { diff --git a/src/core/Statiq.Testing/Execution/TestJsEnginePool.cs b/src/core/Statiq.Testing/Execution/TestJsEnginePool.cs deleted file mode 100644 index 47829c7e1..000000000 --- a/src/core/Statiq.Testing/Execution/TestJsEnginePool.cs +++ /dev/null @@ -1,53 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.Collections.Immutable; -using System.IO; -using System.Linq; -using System.Net; -using System.Net.Http; -using System.Text; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Logging.Abstractions; -using Statiq.Common; - -namespace Statiq.Testing -{ - public class TestJsEnginePool : IJavaScriptEnginePool - { - private readonly Func _engineFunc; - private readonly Action _initializer; - - public TestJsEnginePool(Func engineFunc, Action initializer) - { - _engineFunc = engineFunc; - _initializer = initializer; - } - - public IJavaScriptEngine GetEngine(TimeSpan? timeout = null) - { - IJavaScriptEngine engine = _engineFunc(); - _initializer?.Invoke(engine); - return engine; - } - - public void Dispose() - { - } - - public void RecycleEngine(IJavaScriptEngine engine) - { - throw new NotImplementedException(); - } - - public void RecycleAllEngines() - { - throw new NotImplementedException(); - } - } -} diff --git a/src/extensions/Statiq.Highlight/HighlightCode.cs b/src/extensions/Statiq.Highlight/HighlightCode.cs index bb712c51c..62bdc08e9 100644 --- a/src/extensions/Statiq.Highlight/HighlightCode.cs +++ b/src/extensions/Statiq.Highlight/HighlightCode.cs @@ -90,99 +90,99 @@ public HighlightCode WithAutoHighlightUnspecifiedLanguage(bool autoHighlight) /// protected override async Task> ExecuteContextAsync(IExecutionContext context) { - IJavaScriptEnginePool enginePool = context.GetJavaScriptEnginePool(x => + Func engineFunc = () => { - if (string.IsNullOrWhiteSpace(_highlightJsFile)) + return context.GetJavaScriptEngine(x => { - x.ExecuteResource("highlight.js", typeof(HighlightCode)); - } - else - { - x.ExecuteFile(_highlightJsFile); - } - }); - using (enginePool) + if (string.IsNullOrWhiteSpace(_highlightJsFile)) + { + x.ExecuteResource("highlight.js", typeof(HighlightCode)); + } + else + { + x.ExecuteFile(_highlightJsFile); + } + }); + }; + + IEnumerable results = await context.Inputs.ParallelSelectAsync(async input => { - IEnumerable results = await context.Inputs.ParallelSelectAsync(async input => + try { - try + IHtmlDocument htmlDocument = await input.ParseHtmlAsync(); + bool highlighted = false; + foreach (AngleSharp.Dom.IElement element in htmlDocument.QuerySelectorAll(_codeQuerySelector)) { - IHtmlDocument htmlDocument = await input.ParseHtmlAsync(); - bool highlighted = false; - foreach (AngleSharp.Dom.IElement element in htmlDocument.QuerySelectorAll(_codeQuerySelector)) + // Don't highlight anything that potentially is already highlighted + if (element.ClassList.Contains("hljs")) { - // Don't highlight anything that potentially is already highlighted - if (element.ClassList.Contains("hljs")) - { - continue; - } + continue; + } - // Skip highlighting if there is no language detected and auto highlight is disabled for unspecified languages - if (!element.ClassList.Any(c => c.StartsWith("language")) && !_autoHighlightUnspecifiedLanguage) - { - continue; - } + // Skip highlighting if there is no language detected and auto highlight is disabled for unspecified languages + if (!element.ClassList.Any(c => c.StartsWith("language")) && !_autoHighlightUnspecifiedLanguage) + { + continue; + } - try + try + { + HighlightElement(engineFunc, element); + highlighted = true; + } + catch (Exception innerEx) + { + if (innerEx.Message.Contains("Unknown language: ") && _warnOnMissingLanguage) { - HighlightElement(enginePool, element); - highlighted = true; + context.LogWarning($"Exception while highlighting source code: {innerEx.Message}"); } - catch (Exception innerEx) + else { - if (innerEx.Message.Contains("Unknown language: ") && _warnOnMissingLanguage) - { - context.LogWarning($"Exception while highlighting source code: {innerEx.Message}"); - } - else - { - context.LogInformation($"Exception while highlighting source code: {innerEx.Message}"); - } + context.LogInformation($"Exception while highlighting source code: {innerEx.Message}"); } } - - return highlighted ? input.Clone(context.GetContentProvider(htmlDocument)) : input; } - catch (Exception ex) - { - context.LogWarning("Exception while highlighting source code for {0}: {1}", input.ToSafeDisplayString(), ex.Message); - return input; - } - }); - // Materialize the results before disposing the JS engine - return results.ToList(); - } + return highlighted ? input.Clone(context.GetContentProvider(htmlDocument)) : input; + } + catch (Exception ex) + { + context.LogWarning("Exception while highlighting source code for {0}: {1}", input.ToSafeDisplayString(), ex.Message); + return input; + } + }); + + // Materialize the results before disposing the JS engine + return results.ToList(); } - internal static void HighlightElement(IJavaScriptEnginePool enginePool, AngleSharp.Dom.IElement element) + internal static void HighlightElement(Func engineFunc, AngleSharp.Dom.IElement element) { - using (IJavaScriptEngine engine = enginePool.GetEngine()) - { - // Make sure to use TextContent, otherwise you'll get escaped html which highlight.js won't parse - engine.SetVariableValue("input", element.TextContent); + using IJavaScriptEngine engine = engineFunc(); - // Check if they specified a language in their code block - string language = element.ClassList.FirstOrDefault(i => i.StartsWith("language")); - if (language is object) - { - engine.SetVariableValue("language", language.Replace("language-", string.Empty)); - engine.Execute("result = hljs.highlight(language, input)"); - } - else + // Make sure to use TextContent, otherwise you'll get escaped html which highlight.js won't parse + engine.SetVariableValue("input", element.TextContent); + + // Check if they specified a language in their code block + string language = element.ClassList.FirstOrDefault(i => i.StartsWith("language")); + if (language is object) + { + engine.SetVariableValue("language", language.Replace("language-", string.Empty)); + engine.Execute("result = hljs.highlight(language, input)"); + } + else + { + language = "(auto)"; // set this to auto in case there is an exception below + engine.Execute("result = hljs.highlightAuto(input)"); + string detectedLanguage = engine.Evaluate("result.language"); + if (!string.IsNullOrWhiteSpace(detectedLanguage)) { - language = "(auto)"; // set this to auto in case there is an exception below - engine.Execute("result = hljs.highlightAuto(input)"); - string detectedLanguage = engine.Evaluate("result.language"); - if (!string.IsNullOrWhiteSpace(detectedLanguage)) - { - element.ClassList.Add("language-" + detectedLanguage); - } + element.ClassList.Add("language-" + detectedLanguage); } - - element.ClassList.Add("hljs"); - element.InnerHtml = engine.Evaluate("result.value"); } + + element.ClassList.Add("hljs"); + element.InnerHtml = engine.Evaluate("result.value"); } } } \ No newline at end of file diff --git a/src/extensions/Statiq.Highlight/HighlightShortcode.cs b/src/extensions/Statiq.Highlight/HighlightShortcode.cs index 8b7f37a25..404dde948 100644 --- a/src/extensions/Statiq.Highlight/HighlightShortcode.cs +++ b/src/extensions/Statiq.Highlight/HighlightShortcode.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using AngleSharp.Html.Parser; @@ -58,32 +59,34 @@ public override ShortcodeResult Execute(KeyValuePair[] args, str HighlightJsFile, AddPre); - using (IJavaScriptEnginePool enginePool = context.GetJavaScriptEnginePool(x => + IJavaScriptEngine EngineFunc() { - if (dictionary.ContainsKey(HighlightJsFile)) + return context.GetJavaScriptEngine(x => { - x.ExecuteFile(dictionary.GetString(HighlightJsFile)); - } - else - { - x.ExecuteResource("highlight.js", typeof(Statiq.Highlight.HighlightCode)); - } - })) + if (dictionary.ContainsKey(HighlightJsFile)) + { + x.ExecuteFile(dictionary.GetString(HighlightJsFile)); + } + else + { + x.ExecuteResource("highlight.js", typeof(Statiq.Highlight.HighlightCode)); + } + }); + } + + AngleSharp.Dom.IDocument htmlDocument = HtmlHelper.DefaultHtmlParser.ParseDocument(string.Empty); + AngleSharp.Dom.IElement element = htmlDocument.CreateElement(dictionary.GetString(Element, "code")); + element.InnerHtml = content.Trim(); + if (dictionary.ContainsKey(Language)) { - AngleSharp.Dom.IDocument htmlDocument = HtmlHelper.DefaultHtmlParser.ParseDocument(string.Empty); - AngleSharp.Dom.IElement element = htmlDocument.CreateElement(dictionary.GetString(Element, "code")); - element.InnerHtml = content.Trim(); - if (dictionary.ContainsKey(Language)) - { - element.SetAttribute("class", $"language-{dictionary.GetString("Language")}"); - } - HighlightCode.HighlightElement(enginePool, element); - if (dictionary.GetBool(AddPre) || (!dictionary.ContainsKey(AddPre) && content.Contains('\n'))) - { - return $"
{element.OuterHtml}
"; - } - return element.OuterHtml; + element.SetAttribute("class", $"language-{dictionary.GetString("Language")}"); + } + HighlightCode.HighlightElement(EngineFunc, element); + if (dictionary.GetBool(AddPre) || (!dictionary.ContainsKey(AddPre) && content.Contains('\n'))) + { + return $"
{element.OuterHtml}
"; } + return element.OuterHtml; } } } \ No newline at end of file