using System; using System.Collections.Generic; using System.Linq; using System.Text; using JD.Kernel.StaticHelpers; namespace JD.Kernel.Structs { /// /// A simple file location. /// [Serializable] public struct FileLocation { #region Constants /// /// String that is used in canonical strings when the fileName is empty. /// internal const string UnknownFileName = ""; #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 /// /// Constructor. /// /// public FileLocation(string fileName) : this(fileName, 0, 0) { } /// /// Constructor. /// /// /// public FileLocation(string fileName, object additionalInfo) : this(fileName, 0, 0) { AddInfo(additionalInfo); } /// /// Constructor. /// /// /// /// public FileLocation(string fileName, int line, int column) : this(fileName, line, column, line, column) { } /// /// Constructor. /// /// /// /// /// /// 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; } /// /// Copy constructor. /// /// 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 /// /// Default, empty, file location /// public static FileLocation Empty { get { return new FileLocation(string.Empty); } } /// /// FileName. /// public string FileName { get { return m_fileName; } set { m_fileName = value; } } /// /// Line number. /// public int LineNumber { get { return m_lineNumber; } set { m_lineNumber = value; if (EndLineNumber == 0) { EndLineNumber = value; } } } /// /// Column number. /// public int ColumnNumber { get { return m_columnNumber; } set { m_columnNumber = value; if (EndColumnNumber == 0) { EndColumnNumber = value; } } } /// /// End line number. /// public int EndLineNumber { get { return m_endLineNumber; } set { m_endLineNumber = value; } } /// /// End column number. /// 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 /// /// Retrieves additional info about this file location. . /// /// The first info found of the given type, or null if no info is found of that type. public TInfo GetInfo() { return EnumerateAdditionalInfo().OfType().FirstOrDefault(); } /// /// Adds additional info that can be interpreted by views to provide more context to a file location. /// /// /// The info must be serializable. /// /// An actual item in a file, the position of the camera, etc... /// public void AddInfo(object info) { var newInfo = new AdditionalInfo(m_additionalInfo, info); m_additionalInfo = newInfo; } private IEnumerable EnumerateAdditionalInfo() { for (var node = m_additionalInfo; node != null; node = node.Next) { yield return node.Info; } } #endregion /// /// Overriden. /// /// 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 } }