Home > Essentials > DXCore – source code and source tree elements coordinate inside source files

DXCore – source code and source tree elements coordinate inside source files

May 27th, 2011

Inside Visual Studio IDE, the source code text has its coordinates: the line number and the column:

Source code coordinates

These coordinates are 1-based, and the first line has an index equal to 1. These values can be seen in the right bottom corner of the IDE:

Visual Studio right bottom corner

  • “Ln” is the line number
  • “Col” is the column number (offset position)
  • “Ch” is the character position (for example, a single ‘Tab’ character can take several columns)

After DXCore automatically parses a source file, the abstract source tree is built for the entire file. Language elements have the same coordinates that correspond to the text coordinates inside of the source file. The coordinates of the language element are accessible through its properties, e.g.:

  • StartLine – the starting line of a language element
  • StartOffset – the starting offset (column) of a language element
  • EndLine – the end line of a language element
  • EndOffset – the end offset (column) of a language element

For example, this line of CSharp code:

using System;

Has the following coordinates in Visual Studio:

SourceRange.Start point

and

SourceRange.End point

The language element can be located on several lines, e.g. a Class element most likely will have different starting and ending lines. These four numbers are encapsulated into a single property of the LanguageElement called Range, which has a type of the SourceRange structure. The SourceRange may consist of four coordinates: starting line, starting offset, ending line, ending offset, or may consist of two others of the SourcePoint type, which represent the starting point (1,1) and the end point (1,14). So, the SourcePoint contains a single pair of a line/offset values:

SourceRange(int startLine, int startOffset, int endLine, int endOffset)

is the equivalent of:

SourceRange(new SourcePoint (startLine, startOffset), new SourcePoint(endLine, endOffset))

The range and the stating/ending point properties are useful to manipulate the text of the source file. You can replace the piece of code using the SourceRange value of the element, or insert some new code before or after an element using the Start or End SourcePoint values available thought the Range property:

SourceRange elementRange = LanguageElement.Range;
SourcePoint elementStartPoint = LanguageElement.Range.Start;
SourcePoint elementEndPoint = LanguageElement.Range.End;

For example, let’s use these properties to remove, and then insert some text:

TextDocument activeTextDocument = CodeRush.Documents.ActiveTextDocument;
if (activeTextDocument != null)
{
  activeTextDocument.DeleteText(elementRange);
  activeTextDocument.InsertText(elementStartPoint, "/* LanguageElement was here. */");
}

Now, let’s observe useful APIs dealing with the source ranges and source point properties. On the LanguageElement instance there are the following properties and methods:

Name

Description

Range The source range of this language element.
NameRange The source range of the name  of this language element.
GetCutRange() Gets a SourceRange that includes leading and trailing white spaces. This method is useful for cutting, deleting or moving this LanguageElement, as this expanded SourceRange tends to produce a clean break in the code when removed.
GetFullBlockCoordinates() Gets the full block coordinates for this language element. “Full block” is defined as this element and any partnering elements that complete this block (or that this block completes), including attributes, XML Doc Comments, and regions that tightly enclose this block. The coordinates may extend beyond the bounds of this particular language element.
GetFullBlockCutRange() Gets a SourceRange that includes partnering elements, leading and trailing white spaces. Partnering elements are neighboring elements that complete this block (or that this element completes), and include attributes, XML Doc Comments, and regions that tightly enclose this block. This method is useful for cutting, deleting or moving this LanguageElement, as this expanded SourceRange tends to produce a clean break in the code when removed.
GetFullBlockRange() Gets the full block range for this language element. “Full block” is defined as this element and any partnering elements that complete this block (or that this block completes), including attributes, XML Doc Comments, and regions that tightly enclose this block. The coordinates may extend beyond the bounds of this particular language element.

The three similar methods: GetFullBlockRange, GetFullBlockCutRange and GetFullBlockCoordinates can take a parameter of type BlockElements, which specify what elements should be included into the resulting range. The BlockElement is a flagged enumeration, containing these elements:

[Flags]
public enum BlockElements
{
  All,
  AllLeadingWhiteSpaces,
  AllSupportElements,
  AllTrailingWhiteSpaces,
  AllWhiteSpaces,
  Attributes,
  LeadingEmptyLines,
  LeadingWhiteSpace,
  None,
  Region,
  SupportComments,
  TrailingEmptyLines,
  TrailingWhiteSpace,
  WithoutUnsuitableRegions,
  XmlDocComments
}

Here’s a brief overview of this enumeration:

Name

Description

All Inlude everything: regions, comments, white space, etc.
AllLeadingWhiteSpaces Leading white space and leading empty lines
AllSupportElements Support elements are: attributes, comments, xml doc comments
AllTrailingWhiteSpaces Trailing white space and trailing empty lines
AllWhiteSpaces Leading and trailing white spaces
Attributes Attributes attached to an element (e.g. to a method or property)
LeadingEmptyLines Empty leading lines
LeadingWhiteSpace Leading white space
None Nothing except the language element itself
Region Region directives, e.g. #region … #end region
SupportComments Comments attached to a language element
TrailingEmptyLines Empty trailing lines
TrailingWhiteSpace Trailing white space
WithoutUnsuitableRegions Unsuitable regions are regions with a caption that is not equal to the element’s name
XmlDocComments Xml doc comments which describe a member or type declaration

Here are a few sample results of the above APIs for the following code:

class Program
{
  // private fields...

  #region Main
  /// <summary>
  /// The entry point.
  /// </summary>
  /// <param name="args">Arguments.</param>
  [ThreadStatic]
  static void Main(string[] args)
  {
    Args = args;
    if (args != null)
      ArgsLength = args.Length;
  }
  #endregion

  // public properties...
  public static int ArgsLength { get; set; }
  public static string[] Args { get; set; }
}

These are the results for the Main function:

  • Range:

DXCore LanguageElement.Range property

  • NameRange:

DXCore LanguageElement.NameRange property

  • GetCutRange():

DXCore LanguageElement.GetCutRange method

  • GetFullBlockRange():

DXCore LanguageElement.GetFullBlockRange method

  • GetFullBlockRange(BlockElements.Attributes | BlockElements.XmlDocComments):

DXCore LanguageElement.GetFullBlockRange(BlockElements) method

  • GetFullBlockCutRange():

DXCore LanguageElement.GetFullBlockCutRange method

Your feedback is much appreciated. Let me know if I can improve this article for better understanding of the source code coordinates.

—–
Products: DXCore
Versions: 10.2 and up
VS IDEs: any
Updated: May/30/2011
ID: D087

Similar Posts:

  1. Robert Leahey
    June 2nd, 2011 at 05:41 | #1

    Hey Alex,
    In one of my plug-ins, I want to be able to “normalize” spacing between regions in a source file. In other words, on-command, I want to specify that there be n number of lines between each region or element and the next element.
    Will I have to traverse node-by-node, examining SourceRanges and adding/removing empty lines between elements, or might there already be a provision for something like this?
    For instance:
    myNextElement.BumpDown(2); <– move myNextElement and everything following down two lines…
    or better yet:
    myCurrentElement.PadBottom(2); <– set two lines of space between myCurrentElement and start of next element…

  2. June 2nd, 2011 at 05:55 | #2

    @Robert Leahey
    This sounds similar to the upcoming ‘Code Formatting’ feature for the 11.1 release. There are hundreds of rules to format your code and, most likely, your idea could be a new formatting rule, where you can set a number of lines between regions in a source file. In addition, we have accepted the following suggestion – ‘Q323792 Code Formatting Engine – Provide API to define custom formatting rules’, so you’ll be able to ‘normalize’ spacing by adding a new formatting rule. If you still want to create a plug-in for doing this yourself, I think you have to iterate node-by-node, examine its SourceRange, and manually paste the number of empty lines according to your preference.