LogicalFile.Section (LogicalFile v1.1.1)
View SourceA Section represents lines of text from a backing file that represent
a range of logical line numbers within a LogicalFile.
Fields
source_paththe fully qualified file name of the backing file that theSectionrepresents.rangethe range of logical line numbers theSectionrepresentslinesa list of the lines in theSectionoffseta 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.
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
Sections.
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.
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
Sections.
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)