Skip to content

Commit f7aca77

Browse files
committed
Fixed stackoverflow issue in libvt100
1 parent 86e0bcd commit f7aca77

21 files changed

+7809
-89
lines changed

src/WinPrint.Console/WinPrint.Console.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
<AssemblyName>winprint</AssemblyName>
1010
<StartupObject></StartupObject>
1111

12-
<Version>2.0.3.76</Version>
12+
<Version>2.0.3.82</Version>
1313
<Company>Kindel Systems</Company>
1414
<Product>winprint</Product>
1515
<Authors>Charlie Kindel</Authors>

src/WinPrint.Core/ContentTypeEngines/AnsiCte.cs

Lines changed: 8 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,14 @@
11
// Copyright Kindel Systems, LLC - http://www.kindel.com
22
// Published under the MIT License at https://github.com/tig/winprint
33

4+
/// <summary>
5+
/// Define this to use the DyanmicScreen class. Otherwise, use Screen
6+
/// </summary>
7+
48
using System;
59
using System.Drawing;
610
using System.IO;
11+
using System.Linq;
712
using System.Runtime.InteropServices;
813
using System.Text;
914
using System.Threading.Tasks;
@@ -28,13 +33,12 @@ public class AnsiCte : ContentTypeEngineBase, IDisposable {
2833
public static AnsiCte Create() {
2934
var engine = new AnsiCte();
3035
// Populate it with the common settings
31-
engine.CopyPropertiesFrom(ModelLocator.Current.Settings.TextContentTypeEngineSettings);
36+
engine.CopyPropertiesFrom(ModelLocator.Current.Settings.AnsiContentTypeEngineSettings);
3237
return engine;
3338
}
3439

3540
// All of the lines of the text file, after reflow/line-wrap
3641
private DynamicScreen _screen;
37-
3842
public IAnsiDecoderClient DecoderClient { get => (IAnsiDecoderClient)_screen; }
3943

4044
private float _lineHeight;
@@ -144,46 +148,7 @@ public override async Task<int> RenderAsync(System.Drawing.Printing.PrinterResol
144148
vt100.Input(bytes);
145149
}
146150

147-
#if TESTVT100
148-
_screen[_screen.Lines.Count][0] = new Character('0') { Attributes = new GraphicAttributes() { ForegroundColor = Color.Red } };
149-
150-
for (var x = 0; x < _screen.Width; x++) {
151-
var c = _screen[x, x];
152-
if (c == null) c = new Character('*');
153-
_screen[x,x] = new Character(c.Char) { Attributes = new GraphicAttributes() { ForegroundColor = Color.Red } };
154-
}
155-
156-
for (var x = 0; x < 20; x++) {
157-
_screen[11][x] = new Character((char)((int)'0' + x)) { Attributes = new GraphicAttributes() {
158-
Bold = true,
159-
ForegroundColor = Color.Red } };
160-
}
161-
162-
for (var x = 0; x < _screen.Width; x++) {
163-
var c = _screen[x,20];
164-
if (c == null) c = new Character(' ');
165-
_screen[20][x] = new Character(c.Char) {
166-
Attributes = new GraphicAttributes() {
167-
Bold = true,
168-
ForegroundColor = Color.Green
169-
}
170-
};
171-
}
172-
173-
_screen[8][0] = new Character('_') { Attributes = new GraphicAttributes() { ForegroundColor = Color.Red } };
174-
_screen[23][31] = new Character('>') { Attributes = new GraphicAttributes() { ForegroundColor = Color.Red } };
175-
_screen[57][0] = new Character('{') { Attributes = new GraphicAttributes() { ForegroundColor = Color.Red } };
176-
177-
_screen.CursorPosition = new Point(0, 0);
178-
179-
var w = new StreamWriter("PygmentsCte.txt");
180-
w.Write(_screen);
181-
w.Close();
182-
#endif
183-
184-
185151
var n = (int)Math.Ceiling(_screen.Lines.Count / (double)_linesPerPage);
186-
187152
Log.Debug("Rendered {pages} pages of {linesperpage} lines per page, for a total of {lines} lines.", n, _linesPerPage, _screen.Lines.Count);
188153
return await Task.FromResult(n);
189154
}
@@ -289,6 +254,7 @@ public override void PaintPage(Graphics g, int pageNum) {
289254
g.DrawRectangle(Pens.Red, lineNumberWidth, yPos, PageSize.Width - lineNumberWidth, _lineHeight);
290255
}
291256
}
257+
292258
#if CURSOR
293259
if (_screen.CursorPosition.Y >= firstLineOnPage && _screen.CursorPosition.Y < firstLineOnPage + _linesPerPage) {
294260
var text = $"{(char)219}";
@@ -299,7 +265,7 @@ public override void PaintPage(Graphics g, int pageNum) {
299265
//g.DrawString(text, _cachedFont, new SolidBrush(Color.Blue), rect, StringFormat);
300266
g.DrawRectangle(Pens.Black, x + _screen.CursorPosition.X * width, _screen.CursorPosition.Y * _lineHeight, width, _lineHeight);
301267
}
302-
#endif
268+
#endif
303269
Log.Debug("Painted {lineOnPage} lines.", i - 1);
304270
}
305271
}

src/WinPrint.Core/ContentTypeEngines/ContentTypeEngineBase.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ namespace WinPrint.Core.ContentTypeEngines {
2424
public abstract class ContentTypeEngineBase : ModelBase, INotifyPropertyChanged {
2525
public static string DefaultContentType = "text/plain";
2626
public static string DefaultCteClassName = "AnsiCte";
27-
public static string DefaultSyntaxHighlighterCteNameClassName = "PrismCte";
27+
public static string DefaultSyntaxHighlighterCteNameClassName = "AnsiCte";
2828

2929
public new event PropertyChangedEventHandler PropertyChanged;
3030
protected new void OnPropertyChanged([CallerMemberName] string propertyName = null) {

src/WinPrint.Core/Models/ContentSettings.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,13 @@ public class ContentSettings : ModelBase {
3434
public int Darkness { get => _darkness; set => SetField(ref _darkness, value); }
3535
private int _darkness = 0;
3636

37+
/// <summary>
38+
/// Style to use for formatting. Dependent on Content Engine. For AnsiCte, represents a Pygments.org style name.
39+
/// </summary>
40+
[SafeForTelemetry]
41+
public string Style { get => _style; set => SetField(ref _style, value); }
42+
private string _style = string.Empty;
43+
3744
/// <summary>
3845
/// If true, content will be drawn with line numbers (if supported)
3946
/// </summary>

src/WinPrint.Core/Models/Macros.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,12 @@ sealed public class Macros {
6060
/// </summary>
6161
public string CteName => svm.ContentEngine == null ? "" : svm.ContentEngine.GetType().Name;
6262

63+
/// <summary>
64+
/// The style used for formatting (e.g. "default" or "colorful"; from Pygments.org).
65+
/// </summary>
66+
public string Style => svm.ContentEngine == null || svm.ContentEngine.ContentSettings == null ? "" : svm.ContentEngine.ContentSettings.Style;
67+
68+
6369
/// <summary>
6470
/// The current sheet number.
6571
/// </summary>

src/WinPrint.Core/Models/Settings.cs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ public int NumSheets {
9797
/// Content type handlers
9898
/// </summary>
9999
// public Dictionary<string, ContentBase> ContentTypes { get; set; }
100+
public AnsiCte AnsiContentTypeEngineSettings { get; set; }
100101
public TextCte TextContentTypeEngineSettings { get; set; }
101102
public HtmlCte HtmlContentTypeEngineSettings { get; set; }
102103
public PrismCte PrismContentTypeEngineSettings { get; set; }
@@ -232,6 +233,12 @@ public static Settings CreateDefaultSettings() {
232233
//settings.size = new WindowSize(1024, 800);
233234
//settings.location = new WindowLocation(100, 100);
234235

236+
AnsiContentTypeEngineSettings = new AnsiCte() {
237+
ContentSettings = new ContentSettings() {
238+
Style = "pastie",
239+
}
240+
},
241+
235242
TextContentTypeEngineSettings = new TextCte() {
236243
// This font will be overriddent by Sheet defined fonts (if any)
237244
//ContentSettings = new ContentSettings() {
@@ -283,6 +290,7 @@ public static Settings CreateDefaultSettings() {
283290
PageSeparator = false,
284291
ContentSettings = new ContentSettings() {
285292
Font = new Font() { Family = defaultContentFontFamily, Size = defaultContentFontSize, Style = defaultContentFontStyle },
293+
Style = "pastie",
286294
Darkness = 100,
287295
Grayscale = false,
288296
PrintBackground = true
@@ -313,6 +321,7 @@ public static Settings CreateDefaultSettings() {
313321
PageSeparator = false,
314322
ContentSettings = new ContentSettings() {
315323
Font = new Font() { Family = defaultContentFontFamily, Size = defaultContentFontSize, Style = defaultContentFontStyle },
324+
Style = "pastie",
316325
Darkness = 100,
317326
Grayscale = false,
318327
PrintBackground = true,
Lines changed: 73 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,14 @@
11
using System;
22
using System.Collections.Generic;
33
using System.Diagnostics;
4+
using System.IO;
45
using System.Linq;
56
using System.Text;
7+
using System.Threading.Tasks;
68
using IronPython.Hosting;
9+
using LiteHtmlSharp;
10+
using Microsoft.VisualBasic;
11+
using Serilog;
712

813
namespace 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
}

src/WinPrint.Core/ViewModels/SheetViewModel.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -379,6 +379,12 @@ public async Task<bool> LoadStringAsync(string document, string contentType) {
379379
ContentEngine.ContentSettings.CopyPropertiesFrom(ContentSettings);
380380
}
381381

382+
if (!string.IsNullOrEmpty(Language) && ContentEngine.SupportedContentTypes.Contains("text/ansi")) {
383+
// Syntax highlight
384+
// TODO: Spin up a thread
385+
document = await ServiceLocator.Current.PygmentsConverterService.ConvertAsync(document, ContentEngine.ContentSettings.Style, Language).ConfigureAwait(true);
386+
}
387+
382388
ContentEngine.Encoding = Encoding;
383389
retval = await ContentEngine.SetDocumentAsync(document).ConfigureAwait(false);
384390
}
@@ -691,6 +697,11 @@ private System.ComponentModel.PropertyChangedEventHandler OnContentSettingsPrope
691697
reflow = true;
692698
break;
693699

700+
case "Style":
701+
ContentSettings.Style = _sheet.ContentSettings.Style;
702+
reflow = true;
703+
break;
704+
694705
default:
695706
throw new InvalidOperationException($"Property change not handled: {e.PropertyName}");
696707
}

src/WinPrint.Core/WinPrint.Core.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
<PropertyGroup>
55
<TargetFramework>netcoreapp3.1</TargetFramework>
66
<Platforms>AnyCPU;x64;x86</Platforms>
7-
<Version>2.0.3.465</Version>
7+
<Version>2.0.3.550</Version>
88
<Company>Kindel Systems</Company>
99
<Product>winprint</Product>
1010
<Authors>Charlie Kindel</Authors>

0 commit comments

Comments
 (0)