Skip to content

Commit d60b249

Browse files
committed
Auto detect line endings
1 parent 8e170e2 commit d60b249

File tree

5 files changed

+127
-37
lines changed

5 files changed

+127
-37
lines changed

src/Generator/Driver.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,20 @@ void ValidateOptions()
4545
}
4646

4747
if (Options.NoGenIncludeDirs != null)
48+
{
4849
foreach (var incDir in Options.NoGenIncludeDirs)
4950
ParserOptions.AddIncludeDirs(incDir);
51+
}
52+
53+
NewLineType newLineType = Options.OutputNewLineType;
54+
if (Options.OutputNewLineType == NewLineType.Auto)
55+
{
56+
var sourceNewLineType = GeneratorHelpers.GetNewLineTypeFromGitConfig(Options.OutputDir);
57+
58+
newLineType = sourceNewLineType ?? NewLineType.Host;
59+
}
60+
61+
TextGenerator.SetLineEndingType(newLineType);
5062
}
5163

5264
public void Setup()

src/Generator/Options.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,15 @@ public enum GenerationOutputMode
1515
FilePerUnit
1616
}
1717

18+
public enum NewLineType
19+
{
20+
Auto, // Attempt to auto-detect the new line type using git repository settings of the output directory
21+
Host, // Same as Environment.NewLine on the source generator host
22+
LF,
23+
CR,
24+
CRLF,
25+
}
26+
1827
public class DriverOptions
1928
{
2029
public DriverOptions()
@@ -84,6 +93,8 @@ public bool DoAllModulesHaveLibraries() =>
8493

8594
public string OutputDir;
8695

96+
public NewLineType OutputNewLineType = NewLineType.Auto;
97+
8798
public bool OutputInteropIncludes;
8899
public bool GenerateFunctionTemplates;
89100
/// <summary>

src/Generator/Utils/ProcessHelper.cs

Lines changed: 40 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -7,46 +7,50 @@ public static class ProcessHelper
77
{
88
public static string Run(string path, string args, out int error, out string errorMessage)
99
{
10-
using (var process = new Process())
10+
return RunFrom(null, path, args, out error, out errorMessage);
11+
}
12+
13+
public static string RunFrom(string workingDir, string path, string args, out int error, out string errorMessage)
14+
{
15+
using var process = new Process();
16+
process.StartInfo.WorkingDirectory = workingDir;
17+
process.StartInfo.FileName = path;
18+
process.StartInfo.Arguments = args;
19+
process.StartInfo.UseShellExecute = false;
20+
process.StartInfo.RedirectStandardOutput = true;
21+
process.StartInfo.RedirectStandardError = true;
22+
23+
var reterror = new StringBuilder();
24+
var retout = new StringBuilder();
25+
process.OutputDataReceived += (sender, outargs) =>
26+
{
27+
if (string.IsNullOrEmpty(outargs.Data))
28+
return;
29+
30+
if (retout.Length > 0)
31+
retout.AppendLine();
32+
retout.Append(outargs.Data);
33+
};
34+
process.ErrorDataReceived += (sender, errargs) =>
1135
{
12-
process.StartInfo.FileName = path;
13-
process.StartInfo.Arguments = args;
14-
process.StartInfo.UseShellExecute = false;
15-
process.StartInfo.RedirectStandardOutput = true;
16-
process.StartInfo.RedirectStandardError = true;
36+
if (string.IsNullOrEmpty(errargs.Data))
37+
return;
1738

18-
var reterror = new StringBuilder();
19-
var retout = new StringBuilder();
20-
process.OutputDataReceived += (sender, outargs) =>
21-
{
22-
if (!string.IsNullOrEmpty(outargs.Data))
23-
{
24-
if (retout.Length > 0)
25-
retout.AppendLine();
26-
retout.Append(outargs.Data);
27-
}
28-
};
29-
process.ErrorDataReceived += (sender, errargs) =>
30-
{
31-
if (!string.IsNullOrEmpty(errargs.Data))
32-
{
33-
if (reterror.Length > 0)
34-
reterror.AppendLine();
35-
reterror.Append(errargs.Data);
36-
}
37-
};
39+
if (reterror.Length > 0)
40+
reterror.AppendLine();
41+
reterror.Append(errargs.Data);
42+
};
3843

39-
process.Start();
40-
process.BeginOutputReadLine();
41-
process.BeginErrorReadLine();
42-
process.WaitForExit();
43-
process.CancelOutputRead();
44-
process.CancelErrorRead();
44+
process.Start();
45+
process.BeginOutputReadLine();
46+
process.BeginErrorReadLine();
47+
process.WaitForExit();
48+
process.CancelOutputRead();
49+
process.CancelErrorRead();
4550

46-
error = process.ExitCode;
47-
errorMessage = reterror.ToString();
48-
return retout.ToString();
49-
}
51+
error = process.ExitCode;
52+
errorMessage = reterror.ToString();
53+
return retout.ToString();
5054
}
5155
}
5256
}

src/Generator/Utils/TextGenerator.cs

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ public interface ITextGenerator
2121

2222
public class TextGenerator : ITextGenerator
2323
{
24-
public static string NewLineChar = "\n";
24+
public static string NewLineChar;
2525

2626
public const uint DefaultIndentation = 4;
2727

@@ -47,6 +47,19 @@ public TextGenerator Clone()
4747
return new TextGenerator(this);
4848
}
4949

50+
public static void SetLineEndingType(NewLineType newLineType)
51+
{
52+
NewLineChar = newLineType switch
53+
{
54+
NewLineType.Host => Environment.NewLine,
55+
NewLineType.CR => @"\r",
56+
NewLineType.LF => @"\n",
57+
NewLineType.CRLF => @"\r\n",
58+
NewLineType.Auto => throw new ArgumentException("Don't use Auto here.", nameof(newLineType)),
59+
_ => throw new ArgumentOutOfRangeException(nameof(newLineType))
60+
};
61+
}
62+
5063
public void Write(string msg, params object[] args)
5164
{
5265
if (string.IsNullOrEmpty(msg))

src/Generator/Utils/Utils.cs

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
using System.Reflection;
55
using System.Text;
66
using System.Text.RegularExpressions;
7+
using CppSharp.Utils;
78

89
namespace CppSharp
910
{
@@ -130,4 +131,53 @@ public static string GetRelativePath(string fromPath, string toPath)
130131
return uri1.MakeRelativeUri(uri2).ToString();
131132
}
132133
}
134+
135+
public static class GeneratorHelpers
136+
{
137+
public static NewLineType? GetNewLineTypeFromGitConfig(string outputDir)
138+
{
139+
if (!bool.TryParse(
140+
ProcessHelper.RunFrom(outputDir,
141+
"git", "rev-parse --is-inside-work-tree",
142+
out _, out _
143+
),
144+
out bool isInsideWorkTree))
145+
{
146+
return null;
147+
}
148+
149+
if (!isInsideWorkTree)
150+
return null;
151+
152+
// Check git config core.eol setting
153+
var eolConfig = ProcessHelper.RunFrom(outputDir,
154+
"git", "config --get core.eol",
155+
out _, out _)
156+
.Trim().ToLowerInvariant();
157+
158+
switch (eolConfig)
159+
{
160+
case "lf":
161+
return NewLineType.LF;
162+
case "crlf":
163+
return NewLineType.CRLF;
164+
}
165+
166+
// Otherwise check git config core.autocrlf setting
167+
var autoCrLf = ProcessHelper.RunFrom(outputDir,
168+
"git", "config --get core.autocrlf",
169+
out _, out _)
170+
.Trim().ToLowerInvariant();
171+
172+
return autoCrLf switch
173+
{
174+
"input" => NewLineType.LF,
175+
"true" => NewLineType.CRLF,
176+
"false" => NewLineType.Host,
177+
178+
// If no specific settings found, fallback to host system default
179+
_ => NewLineType.Host
180+
};
181+
}
182+
}
133183
}

0 commit comments

Comments
 (0)