11using System ;
22using System . Collections . Generic ;
33using System . Diagnostics ;
4+ using System . IO ;
45using System . Linq ;
56using System . Text ;
7+ using System . Threading . Tasks ;
68using IronPython . Hosting ;
9+ using LiteHtmlSharp ;
10+ using Microsoft . VisualBasic ;
11+ using Serilog ;
712
813namespace WinPrint . Core . Services {
914 /// <summary>
@@ -19,28 +24,80 @@ public PygmentsConverterService() {
1924
2025 }
2126
22- public static string Convert ( string document ) {
27+ private Process _proc ;
28+ private TaskCompletionSource < bool > _eventHandled ;
2329
24- var engine = Python . CreateEngine ( ) ;
30+ public async Task < string > ConvertAsync ( string document , string style , string language ) {
31+ if ( _proc != null ) {
32+ throw new InvalidOperationException ( "ConvertAsync already in progress." ) ;
33+ }
34+ if ( _eventHandled != null ) {
35+ throw new InvalidOperationException ( "ConvertAsync already in progress." ) ;
36+ }
2537
26- dynamic builtin = engine . GetBuiltinModule ( ) ;
27- // you can store variables if you want
28- dynamic list = builtin . list ;
29- dynamic itertools = engine . ImportModule ( "itertools" ) ;
30- var numbers = new [ ] { 1 , 1 , 2 , 3 , 6 , 2 , 2 } ;
31- //Debug.WriteLine(builtin.str(list(itertools.chain(numbers, "foobar"))));
32- // prints `[1, 1, 2, 3, 6, 2, 2, 'f', 'o', 'o', 'b', 'a', 'r']`
38+ string file = Path . GetTempFileName ( ) ;
39+ _proc = new Process ( ) ;
40+ _proc . StartInfo . FileName = @"pygmentize.exe" ;
41+ _proc . StartInfo . Arguments = $ "-P outencoding=utf-8 -f 16m -O style={ ( string . IsNullOrEmpty ( style ) ? "default" : style ) } -l { language } -o { file } .an { file } ";
42+ _proc . StartInfo . RedirectStandardInput = true ;
43+ _proc . StartInfo . RedirectStandardOutput = true ;
44+ _proc . StartInfo . RedirectStandardError = true ;
45+ _proc . StartInfo . UseShellExecute = false ;
46+ _proc . StartInfo . CreateNoWindow = true ;
47+ _proc . EnableRaisingEvents = true ;
48+ _proc . Exited += Proc_Exited ;
3349
34- // to add to the search paths
35- //var searchPaths = engine.GetSearchPaths();
36- //searchPaths.Add(@"modules");
37- //engine.SetSearchPaths(searchPaths);
50+ _eventHandled = new TaskCompletionSource < bool > ( ) ;
3851
39- //// import the module
40- //dynamic myModule = engine.ImportModule("mymodule");
52+ try {
53+ Log . Debug ( "Writing temp file {file}" , _proc . StartInfo . FileName ) ;
54+ await File . WriteAllTextAsync ( file , document , Encoding . UTF8 ) . ConfigureAwait ( true ) ;
55+ Log . Debug ( "Starting {pyg} {args}" , _proc . StartInfo . FileName , _proc . StartInfo . Arguments ) ;
56+ _proc . Start ( ) ;
57+ }
58+ catch ( Exception e ) {
59+ // TODO: Better error message (output of stderr?)
60+ Log . Information ( "Failed to pygmentize: {Message}" , e . Message ) ;
61+ document = $ "{ _proc . StartInfo . FileName } { _proc . StartInfo . Arguments } failed:\n { e . Message } :\n ";
62+ }
63+ finally {
64+ Log . Debug ( "Waiting for pygments to exit" ) ;
65+ await Task . WhenAny ( _eventHandled . Task , Task . Delay ( 10000 ) ) . ConfigureAwait ( true ) ;
4166
42- return string . Join ( "," , engine . GetModuleFilenames ( ) ) ;
67+ if ( _proc . ExitCode != 0 ) {
68+ var stdErr = _proc . StandardError . ReadToEnd ( ) ;
69+ Log . Information ( "Failed to pygmentize: {Message}" , stdErr ) ;
70+ // TODO: This should really throw an exception
71+ document = $ "Failed to pygmentize: { stdErr } ";
72+ }
73+ else {
74+
75+ if ( ! string . IsNullOrEmpty ( $ "{ file } .an") && File . Exists ( $ "{ file } .an") ) {
76+ Log . Debug ( "Reading {file}" , $ "{ file } .an") ;
77+ document = await File . ReadAllTextAsync ( $ "{ file } .an", Encoding . UTF8 ) . ConfigureAwait ( true ) ;
78+ }
79+ }
80+
81+ // Clean up
82+ if ( ! string . IsNullOrEmpty ( file ) && File . Exists ( file ) ) {
83+ File . Delete ( file ) ;
84+ }
85+ if ( ! string . IsNullOrEmpty ( $ "{ file } .an") && File . Exists ( $ "{ file } .an") ) {
86+ File . Delete ( $ "{ file } .an") ;
87+ }
88+ _proc . Exited -= Proc_Exited ;
89+ _proc ? . Dispose ( ) ;
90+ _proc = null ;
91+ _eventHandled = null ;
92+ }
93+
94+ return document ;
4395 }
4496
97+ private void Proc_Exited ( object sender , EventArgs e ) {
98+ Log . Debug ( "pygmatize exited: Time: {exitTime}, ExitCode: {exitCode}, ElapsedTime: {elapsedTime}ms" , _proc . ExitTime , _proc . ExitCode , Math . Round ( ( _proc . ExitTime - _proc . StartTime ) . TotalMilliseconds ) ) ;
99+
100+ _eventHandled . TrySetResult ( true ) ;
101+ }
45102 }
46103}
0 commit comments