DXCore – source code and source tree elements coordinate inside source files
Inside Visual Studio IDE, the source code text has its coordinates: the line number and the column:

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:

- “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:

and

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:

- NameRange:

- GetCutRange():

- GetFullBlockRange():

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

- GetFullBlockCutRange():

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
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…
@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.