1 module nxt.line_column;
2 
3 @safe:
4 
5 void diagnoseGNUStyle(Args...)(scope const string tag,
6                                scope const string path,
7                                const LineColumn lc,
8                                Args args)
9 {
10     import std.stdio : writeln;
11     debug writeln(path,
12                   ":", lc.line + 1, // line offset starts at 1
13                   ":", lc.column,   // column counter starts at 0
14                   ": ", tag, ": ", args);
15 }
16 
17 @safe pure nothrow @nogc:
18 
19 struct LineColumn
20 {
21     uint line; ///< 32-bit should suffice for now.
22     uint column; ///< 32-bit should suffice for now.
23 }
24 
25 /** Convert `offset` at `haystack` to line and column. */
26 LineColumn offsetLineColumn(scope const char[] haystack,
27                             size_t offset)
28 {
29     // find 0-based column offset
30     size_t cursor = offset;      // cursor
31     while (cursor != 0) // TODO extend to support UTF-8
32     {
33         if (cursor >= 1)
34         {
35             if (haystack[cursor - 1] == '\n' || // TODO extend to support UTF-8
36                 haystack[cursor - 1] == '\r')   // TODO extend to support UTF-8
37             {
38                 break;
39             }
40         }
41         cursor -= 1;
42     }
43     // cursor is not at beginning of line
44 
45     const column = offset-cursor; // column byte offset
46 
47     // find 0-based line offset
48     size_t lineCounter = 0;
49     while (cursor != 0)
50     {
51         if (haystack[cursor - 1] == '\n' ||
52             haystack[cursor - 1] == '\r')
53         {
54             cursor -= 1;
55             if (cursor != 0 &&
56                 (haystack[cursor - 1] == '\r')) // DOS-style line ending "\r\n"
57             {
58                 cursor -= 1;
59             }
60             else            // UNIX-style line ending "\n"
61             {
62             }
63             lineCounter += 1;
64         }
65         else                // no line ending at cursor
66         {
67             cursor -= 1;
68         }
69     }
70 
71     return typeof(return)(cast(uint)lineCounter,
72                           cast(uint)column);
73 }
74 
75 @safe pure unittest
76 {
77     auto x = "\nx\n y";
78     assert(x.length == 5);
79     assert(x.offsetLineColumn(0) == LineColumn(0, 0));
80     assert(x.offsetLineColumn(1) == LineColumn(1, 0));
81     assert(x.offsetLineColumn(2) == LineColumn(1, 1));
82     assert(x.offsetLineColumn(3) == LineColumn(2, 0));
83     assert(x.offsetLineColumn(4) == LineColumn(2, 1));
84 }
85 
86 version(unittest)
87 {
88     import nxt.dbgio;
89 }