JD2022-TU1/main/tools/framework/JD.Kernel/Structs/FileLocation.cs

292 lines
8.2 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using JD.Kernel.StaticHelpers;
namespace JD.Kernel.Structs
{
/// <summary>
/// A simple file location.
/// </summary>
[Serializable]
public struct FileLocation
{
#region Constants
/// <summary>
/// String that is used in canonical strings when the fileName is empty.
/// </summary>
internal const string UnknownFileName = "<Unknown FileName>";
#endregion
#region Variables
private string m_fileName;
private int m_lineNumber;
private int m_columnNumber;
private int m_endLineNumber;
private int m_endColumnNumber;
private AdditionalInfo m_additionalInfo;
#endregion
#region Constructor
/// <summary>
/// Constructor.
/// </summary>
/// <param name="fileName"></param>
public FileLocation(string fileName)
: this(fileName, 0, 0)
{
}
/// <summary>
/// Constructor.
/// </summary>
/// <param name="fileName"></param>
/// <param name="additionalInfo"></param>
public FileLocation(string fileName, object additionalInfo)
: this(fileName, 0, 0)
{
AddInfo(additionalInfo);
}
/// <summary>
/// Constructor.
/// </summary>
/// <param name="fileName"></param>
/// <param name="line"></param>
/// <param name="column"></param>
public FileLocation(string fileName, int line, int column)
: this(fileName, line, column, line, column)
{
}
/// <summary>
/// Constructor.
/// </summary>
/// <param name="fileName"></param>
/// <param name="line"></param>
/// <param name="column"></param>
/// <param name="endLine"></param>
/// <param name="endColumn"></param>
public FileLocation(string fileName, int line, int column, int endLine, int endColumn)
{
m_fileName = fileName;
m_lineNumber = line;
m_columnNumber = column;
m_endLineNumber = endLine;
m_endColumnNumber = endColumn;
m_additionalInfo = null;
}
/// <summary>
/// Copy constructor.
/// </summary>
/// <param name="src"></param>
public FileLocation(FileLocation src)
{
m_fileName = src.m_fileName;
m_lineNumber = src.m_lineNumber;
m_columnNumber = src.m_columnNumber;
m_endLineNumber = src.m_endLineNumber;
m_endColumnNumber = src.m_endColumnNumber;
m_additionalInfo = src.m_additionalInfo;
}
#endregion
#region Properties
/// <summary>
/// Default, empty, file location
/// </summary>
public static FileLocation Empty
{
get
{
return new FileLocation(string.Empty);
}
}
/// <summary>
/// FileName.
/// </summary>
public string FileName
{
get { return m_fileName; }
set { m_fileName = value; }
}
/// <summary>
/// Line number.
/// </summary>
public int LineNumber
{
get { return m_lineNumber; }
set
{
m_lineNumber = value;
if (EndLineNumber == 0)
{
EndLineNumber = value;
}
}
}
/// <summary>
/// Column number.
/// </summary>
public int ColumnNumber
{
get { return m_columnNumber; }
set
{
m_columnNumber = value;
if (EndColumnNumber == 0)
{
EndColumnNumber = value;
}
}
}
/// <summary>
/// End line number.
/// </summary>
public int EndLineNumber
{
get { return m_endLineNumber; }
set { m_endLineNumber = value; }
}
/// <summary>
/// End column number.
/// </summary>
public int EndColumnNumber
{
get { return m_endColumnNumber; }
set { m_endColumnNumber = value; }
}
public bool IsEmpty
{
get { return string.IsNullOrEmpty(m_fileName); }
}
public string AdditionalInfoDisplayString
{
get { return string.Join(", ", EnumerateAdditionalInfo()); }
}
#endregion
#region Methods
#region Additional Info
/// <summary>
/// Retrieves additional info about this file location. <see cref="AddInfo"/>.
/// </summary>
/// <returns>The first info found of the given type, or null if no info is found of that type.</returns>
public TInfo GetInfo<TInfo>()
{
return EnumerateAdditionalInfo().OfType<TInfo>().FirstOrDefault();
}
/// <summary>
/// Adds additional info that can be interpreted by views to provide more context to a file location.
/// </summary>
/// <remarks>
/// The info must be serializable.
/// </remarks>
/// <example>An actual item in a file, the position of the camera, etc...</example>
/// <param name="info"></param>
public void AddInfo(object info)
{
var newInfo = new AdditionalInfo(m_additionalInfo, info);
m_additionalInfo = newInfo;
}
private IEnumerable<object> EnumerateAdditionalInfo()
{
for (var node = m_additionalInfo; node != null; node = node.Next)
{
yield return node.Info;
}
}
#endregion
/// <summary>
/// Overriden.
/// </summary>
/// <returns></returns>
public override string ToString()
{
StringBuilder builder = new StringBuilder();
if (!string.IsNullOrEmpty(FileName) || LineNumber != 0)
{
builder.AppendFormat("{0}", string.IsNullOrEmpty(FileName) ? UnknownFileName : FileName);
if (LineNumber != 0)
{
if (ColumnNumber == 0)
{
if (EndLineNumber == LineNumber)
{
builder.AppendFormat("({0})", LineNumber);
}
else
{
builder.AppendFormat("({0}-{1})", LineNumber, EndLineNumber);
}
}
else if (EndLineNumber == LineNumber)
{
if (EndColumnNumber == ColumnNumber)
{
builder.AppendFormat("({0},{1})", LineNumber, ColumnNumber);
}
else
{
builder.AppendFormat("({0},{1}-{2})", LineNumber, ColumnNumber, EndColumnNumber);
}
}
else if (EndColumnNumber == ColumnNumber)
{
builder.AppendFormat("({0}-{1},{2})", LineNumber, EndLineNumber, ColumnNumber);
}
else
{
builder.AppendFormat("({0},{1},{2},{3})", LineNumber, ColumnNumber, EndLineNumber, EndColumnNumber);
}
}
}
return builder.ToString();
}
#endregion
#region Inner Types
[Serializable]
private class AdditionalInfo
{
public readonly AdditionalInfo Next;
public readonly object Info;
public AdditionalInfo(AdditionalInfo next, object info)
{
Throw.IfNull(info, "info");
Next = next;
Info = info;
}
}
#endregion
}
}