View Source LogicalFile.Section (LogicalFile v1.0.4)
A Section
represents lines of text from a backing file that represent
a range of logical line numbers within a LogicalFile
.
Fields
source_path
the fully qualified file name of the backing file that theSection
represents.range
the range of logical line numbers theSection
representslines
a list of the lines in theSection
offset
a value that transforms a logical line number to a local line number within the backing file.
In the simple case a Section
represents the entire contents of a backing
file. However, a Section
can be split and moved (for example when another
Section
is inserted within its range). Here the offset
is adjusted to
allow the conversion of logical line numbers to local line numbers in the
backing file.
Link to this section Summary
Functions
first_line_number/1
returns the first logical line number of the specified
Section
.
last_line_number/1
returns the last logical line number of the specified
Section
.
line_matching/2
takes a Section
and either a predicate function or a
regular expression and returns a tuple {logical_line_no, line}
representing
the first line from the Section
that matches.
lines_matching/2
takes a Section
and either a predicate function or a
regular expression and returns a list of tuples of the form
{logical_lno, line}
for each line that matches.
new/1
creates a new Section
representing lines from the specified file.
resolve_line/2
takes a Section
and a logical line number line
that is
expected to be within the range of the Section
and returns a tuple
{file, line}
representing the file backing the Section
and the
corresponding local line number within the Section
set_offset/2
replaces the line number offset of the specified Section
.
set_range/2
replaces the logical line number range of the specified
Section
.
shift/2
takes a Section
and a number of lines to offset the section
by_lines
and returns a new Section
containing the same lines with the
logical line number range and offset shifted appropriately.
size/1
returns the number of lines in the specified Section
.
split/2
takes a Section
and a logical line number at_line
expected to be
within the Section
and returns a tuple {before_section, after_section}
derived by splitting the contents of the Section at the specified line.
splittable?/1
takes a Section
and determines whether it is splittable. In
general it's not splittable if it contains only one line.
total_size/1
returns the number of lines contained in the given list of
Section
s.
update_line/3
takes a Section
a logical number number expected to be
within the Section
and a function. It replaces that line with the result
of calling the function with the existing line.
Link to this section Functions
first_line_number/1
returns the first logical line number of the specified
Section
.
last_line_number/1
returns the last logical line number of the specified
Section
.
line/2
returns a String
containing the contents of logical line number
lno
which is expected to be within the range the Section
represents.
Examples
iex> alias LogicalFile.Section
iex> section = Section.new("test/support/main.source")
iex> assert "%(include.source)" = Section.line(section, 6)
line_matching/2
takes a Section
and either a predicate function or a
regular expression and returns a tuple {logical_line_no, line}
representing
the first line from the Section
that matches.
Examples
iex> alias LogicalFile.Section
iex> section = Section.new("test/support/main.source")
iex> include = ~r/%((?<file>.*))/
iex> assert {6, "%(include.source)"} = Section.line_matching(section, fn line -> String.length(line) > 5 end)
iex> assert {6, "%(include.source)"} = Section.line_matching(section, include)
lines_matching/2
takes a Section
and either a predicate function or a
regular expression and returns a list of tuples of the form
{logical_lno, line}
for each line that matches.
Examples
iex> alias LogicalFile.Section
iex> section = Section.new("test/support/commented.source")
iex> assert [{3, "%% nothing here"}, {6, "%% or here"}] = Section.lines_matching(section, fn line ->
...> String.starts_with?(line, "%%")
...> end)
iex> assert [{1, "one"}, {2, "two"}, {8, "six"}] = Section.lines_matching(section, fn line -> String.length(line) <4 end)
new/1
creates a new Section
representing lines from the specified file.
new/4
creates a new Section
representing the contents of the file specified
by source_path
and representing a particular range of logical line numbers
and their offset
new/4
for more information.
a range of lines with an offset. he offset determines how the line numbers in the range are converted into lines in the source file. For example if the offset is -5 then line 10 will correspond to line 5 of the source file.
Examples
iex> alias LogicalFile.Section
iex> section = Section.new("test/support/main.source")
iex> assert "test/support/main.source" = section.source_path
iex> assert 11 = Section.size(section)
iex> assert 1..11 = section.range
iex> assert 0 = section.offset
iex> alias LogicalFile.Section
iex> %Section{source_path: source_path, range: range, lines: lines} =
...> Section.new("foo.source", 1..6, ["one", "two", "three", "four", "five", "six"])
iex> assert "foo.source" = source_path
iex> assert 1..6 = range
iex> assert 6 = Enum.count(lines)
iex> alias LogicalFile.Section
iex> %Section{offset: offset} = Section.new("foo.source", 1..2, ["one", "two"], -7)
iex> assert -7 = offset
iex> alias LogicalFile.Section
iex> assert_raise(RuntimeError, fn ->
...> %Section{} =
...> Section.new("foo.source", 1..5, ["one", "two", "three", "four"])
...> end)
resolve_line/2
takes a Section
and a logical line number line
that is
expected to be within the range of the Section
and returns a tuple
{file, line}
representing the file backing the Section
and the
corresponding local line number within the Section
number Maps a line number coming from a source map that may include many sections into a line number relative to the section. For example a section may represent source included from another file.
E.g. File 1 contains 20 lines & File 2 contains 10 lines if we insert File 2 we get a structure like:
Lines 1..10 => File 1: Lines 1..10 Lines 11..20 => File 2: Lines 1..10 Lines 21..30 => File 1: Lines 11..20
If we ask for line 15 this maps to File 2, line 5. This means file 2 is offset from the map by -10. If we ask for line 25 this maps to file 1 line 15, again offset by -10.
Examples
iex> alias LogicalFile.Section
iex> section =
...> Section.new("test/support/main.source")
...> |> Section.set_range(21..30)
...> |> Section.set_offset(-10)
iex> assert {"test/support/main.source", 15} = Section.resolve_line(section, 25)
set_offset/2
replaces the line number offset of the specified Section
.
set_range/2
replaces the logical line number range of the specified
Section
.
shift/2
takes a Section
and a number of lines to offset the section
by_lines
and returns a new Section
containing the same lines with the
logical line number range and offset shifted appropriately.
Examples
iex> alias LogicalFile.Section
iex> section =
...> Section.new("foo.source", 1..4, ["one", "two", "three", "four"])
...> |> Section.shift(10)
iex> assert 11..14 = section.range
iex> assert -10 = section.offset
size/1
returns the number of lines in the specified Section
.
Examples
iex> alias LogicalFile.Section
iex> section = Section.new("foo.source", 1..4, ["one", "two", "three", "four"])
iex> assert 4 = Section.size(section)
split/2
takes a Section
and a logical line number at_line
expected to be
within the Section
and returns a tuple {before_section, after_section}
derived by splitting the contents of the Section at the specified line.
The before_section
contains all lines up to, but not including, the
specified line, the after_section
contains all lines from the specified
line to the end of the Section
.
Note: It is illegal to attempt to split a Section containing one line, or to set the split point on the first or last line of a Section. In any of these cases an exception is raised.
Examples
iex> alias LogicalFile.Section
iex> section = Section.new("foo.source", 1..6, ["one", "two", "three", "four", "five", "six"])
iex> {%Section{} = first, %Section{} = second} = Section.split(section, 4)
iex> assert "foo.source" = first.source_path
iex> assert 1..3 = first.range
iex> assert ["one", "two", "three"] = first.lines
iex> assert "foo.source" = second.source_path
iex> assert 4..6 = second.range
iex> assert ["four", "five", "six"] = second.lines
iex> alias LogicalFile.Section
iex> assert_raise(RuntimeError, fn ->
...> section = Section.new("foo.source", 1..4, ["one", "two", "three", "four"])
...> Section.split(section, 0)
...> end)
iex> alias LogicalFile.Section
iex> section = Section.new("foo.source", 1..3, ["alpha", "beta", "delta"]) |> Section.shift(36)
iex> {s1, s2} = Section.split(section, 38)
iex> assert %Section{range: 37..37, offset: -36, lines: ["alpha"]} = s1
iex> assert %Section{range: 38..39, offset: -36, lines: ["beta", "delta"]} = s2
iex> alias LogicalFile.Section
iex> section = Section.new("bar.source", 29..33, [" ", " ", "", "end", ""], -4)
iex> {s1, s2} = Section.split(section, 30)
iex> assert %Section{range: 29..29, offset: -4, lines: [" "]} = s1
iex> assert %Section{range: 30..33, offset: -4, lines: [" ", "", "end", ""]} = s2
splittable?/1
takes a Section
and determines whether it is splittable. In
general it's not splittable if it contains only one line.
Examples
iex> alias LogicalFile.Section
iex> section1 = Section.new("bar.source", 1..1, ["one"])
iex> section2 = Section.new("foo.source", 1..2, ["one", "two"])
iex> assert not Section.splittable?(section1)
iex> assert Section.splittable?(section2)
total_size/1
returns the number of lines contained in the given list of
Section
s.
Examples
iex> alias LogicalFile.Section
iex> section1 = Section.new("foo.source", 1..4, ["one", "two", "three", "four"])
iex> section2 = Section.new("bar.source", 5..7, ["alpha", "beta", "delta"])
iex> assert 7 = Section.total_size([section1, section2])
update_line/3
takes a Section
a logical number number expected to be
within the Section
and a function. It replaces that line with the result
of calling the function with the existing line.
Examples
iex> alias LogicalFile.Section
iex> section = Section.new("test/support/main.source")
...> |> Section.update_line(6, fn line -> String.duplicate(" ", String.length(line)) end)
iex> assert " " = Section.line(section, 6)