packages feed

loc 0.1.2.1 → 0.1.2.2

raw patch · 4 files changed

+647/−1 lines, 4 filesbinary-addedPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

Files

+ README.md view
@@ -0,0 +1,230 @@+# loc++Overview of the concepts:++![Example text illustrating Loc, Span, and Area](example.png)++* `Loc` - a cursor position, starting at the origin `1:1`+* `Span` - a nonempty contiguous region between two locs+* `Area` - a set of zero or more spans with gaps between them++See also:++* [loc-test](https://hackage.haskell.org/package/loc-test) -+  Test-related utilities for this package.++## `Pos`++Since all of the numbers we're dealing with in this domain are positive, we+define a "positive integer" type. This is a newtype for `Natural` that doesn't+allow zero.++```haskell+newtype Pos = Pos Natural+  deriving (Eq, Ord)++instance Num Pos where+  fromInteger = Pos . checkForUnderflow . fromInteger+  Pos x + Pos y = Pos (x + y)+  Pos x - Pos y = Pos (checkForUnderflow (x - y))+  Pos x * Pos y = Pos (x * y)+  abs = id+  signum _ = Pos 1+  negate _ = throw Underflow++checkForUnderflow :: Natural -> Natural+checkForUnderflow n =+  if n == 0 then throw Underflow else n+```++`Pos` does not have an `Integral` instance, because that would require+implementing `quotRem :: Pos -> Pos -> (Pos, Pos)`, which doesn't make much+sense. Therefore we can't use `toInteger` on `Pos`. Instead we use our own+`ToNat` class to convert positive numbers to natural numbers.++```haskell+class ToNat a where+  toNat :: a -> Natural++instance ToNat Pos where+  toNat (Pos n) = n+```++## `Line`, `Column`++We then add some newtypes to be more specific about whether we're talking about+line or column numbers.++```haskell+newtype Line = Line Pos+  deriving (Eq, Ord, Num, Real, Enum, ToNat)++newtype Column = Column Pos+  deriving (Eq, Ord, Num, Real, Enum, ToNat)+```++## `Loc`++A `Loc` is a `Line` and a `Column`.++```haskell+data Loc = Loc+  { line   :: Line+  , column :: Column+  }+  deriving (Eq, Ord)+```++Note that this library has chosen to be remain entirely agnostic of the text+that the positions are referring to. Therefore there is no "plus one" operation+on `Loc`, because the next `Loc` after *4:17* could be either *4:18* or *5:1* -+we can't tell without knowing the line lengths.++## `Span`++A `Span` is a start `Loc` and an end `Loc`.++```haskell+data Span = Span+  { start :: Loc+  , end   :: Loc+  } deriving (Eq, Ord)+```++A `Span` is not allowed to be empty; in other words, `start` and `end` must be+different.++There are two functions for constructing a `Span`. They both reorder their+arguments as appropriate to make sure the start comes before the end (so that+spans are never backwards). They take different approaches to ensuring that+spans are never empty: the first can throw an exception, whereas the second is+typed as `Maybe`.++```haskell+fromTo :: Loc -> Loc -> Span+fromTo a b =+  maybe (throw EmptySpan) id (fromToMay a b)++fromToMay :: Loc -> Loc -> Maybe Span+fromToMay a b =+  case compare a b of+    LT -> Just (Span a b)+    GT -> Just (Span b a)+    EQ -> Nothing+```++The choice to use an exclusive upper bound *\[start, end)* rather than two+inclusive bounds *\[start, end\]* is forced by the decision to be text-agnostic.+With inclusive ranges, you couldn't tell whether span *4:16-4:17* abuts span+*5:1-5:2* without knowing whether the character at position *4:17* is a newline.++## `Area`++Conceptually, an area is a set of spans. To support efficient union and+difference operations, `Area` is defined like this:++```haskell+data Terminus = Start | End+  deriving (Eq, Ord)++newtype Area = Area (Map Loc Terminus)+  deriving (Eq, Ord)+```++You can think of this as a sorted list of the spans' start and end positions,+along with a tag indicating whether each is a start or an end.++## `Show`++We define custom `Show` and `Read` instances to be able to write terse+[doctests](https://hackage.haskell.org/package/doctest) like++```haskell+>>> addSpan (read "1:1-6:1") (read "[1:1-3:1,6:1-6:2,7:4-7:5]")+[1:1-6:2,7:4-7:5]+```++These are the `showsPrec` implementations for `Loc` and `Span`:++```haskell+locShowsPrec :: Int -> Loc -> ShowS+locShowsPrec _ (Loc l c) =+  shows l .+  showString ":" .+  shows c++spanShowsPrec :: Int -> Span -> ShowS+spanShowsPrec _ (Span a b) =+  locShowsPrec 10 a .+  showString "-" .+  locShowsPrec 10 b+```++## `Read`++The parser for `Pos` is based on the parser for `Natural`, applying `mfilter (/=+0)` to make the parser fail if the input represents a zero.++```haskell+posReadPrec :: ReadPrec Pos+posReadPrec =+  Pos <$> mfilter (/= 0) readPrec+```++As a reminder, the type of `mfilter` is:++```haskell+mfilter :: MonadPlus m => (a -> Bool) -> m a -> m a+```++The `Loc` parser uses a very typical `Applicative` pattern:++```haskell+-- | Parses a single specific character.+readPrecChar :: Char -> ReadPrec ()+readPrecChar = void . readP_to_Prec . const . ReadP.char++locReadPrec :: ReadPrec Loc+locReadPrec =+  Loc              <$>+  readPrec         <*+  readPrecChar ':' <*>+  readPrec+```++We used `mfilter` above to introduce failure into the `Pos` parser; for `Span`+we use `empty`.++```haskell+empty :: Alternative f => f a+```++First we use `fromToMay` to produce a `Maybe Span`, and then in the case where+the result is `Nothing` we use `empty` to make the parser fail.++```haskell+spanReadPrec :: ReadPrec Span+spanReadPrec =+  locReadPrec      >>= \a ->+  readPrecChar '-' *>+  locReadPrec      >>= \b ->+  maybe empty pure (fromToMay a b)+```++## Comparison to similar packages++### `srcloc`++[srcloc](https://hackage.haskell.org/package/srcloc) has a similar general+purpose: defining types related to positions in text files.++Some differences:++* `srcloc`'s `Pos` type (comparable to our `Loc` type) has a `FilePath`+  parameter, whereas this library doesn't consider file paths at all.+* `srcloc` has nothing comparable to the `Area` type.++There are some undocumented aspects of `srcloc` we find confusing:++* What does "character offset" mean?+* Does `srcloc`'s `Loc` type use inclusive or exclusive bounds?
+ example.png view

binary file changed (absent → 58574 bytes)

+ example.svg view
@@ -0,0 +1,411 @@+<?xml version="1.0" encoding="UTF-8" standalone="no"?>+<!-- Created with Inkscape (http://www.inkscape.org/) -->++<svg+   xmlns:dc="http://purl.org/dc/elements/1.1/"+   xmlns:cc="http://creativecommons.org/ns#"+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"+   xmlns:svg="http://www.w3.org/2000/svg"+   xmlns="http://www.w3.org/2000/svg"+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"+   width="119.54762mm"+   height="52.56461mm"+   viewBox="0 0 119.54762 52.56461"+   version="1.1"+   id="svg8"+   inkscape:version="0.92.0 r15299"+   sodipodi:docname="example.svg"+   inkscape:export-filename="/home/chris/chris-martin.org/in/posts/2017-05-09-loc/example.png"+   inkscape:export-xdpi="185.481"+   inkscape:export-ydpi="185.481">+  <defs+     id="defs2" />+  <sodipodi:namedview+     id="base"+     pagecolor="#ffffff"+     bordercolor="#666666"+     borderopacity="1.0"+     inkscape:pageopacity="0.0"+     inkscape:pageshadow="2"+     inkscape:zoom="1.4"+     inkscape:cx="184.29443"+     inkscape:cy="134.58074"+     inkscape:document-units="mm"+     inkscape:current-layer="layer1"+     showgrid="false"+     inkscape:snap-nodes="false"+     inkscape:snap-global="false"+     inkscape:window-width="1920"+     inkscape:window-height="1016"+     inkscape:window-x="0"+     inkscape:window-y="27"+     inkscape:window-maximized="1"+     fit-margin-top="2"+     fit-margin-left="2"+     fit-margin-right="2"+     fit-margin-bottom="2" />+  <metadata+     id="metadata5">+    <rdf:RDF>+      <cc:Work+         rdf:about="">+        <dc:format>image/svg+xml</dc:format>+        <dc:type+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />+        <dc:title></dc:title>+      </cc:Work>+    </rdf:RDF>+  </metadata>+  <g+     inkscape:label="Layer 1"+     inkscape:groupmode="layer"+     id="layer1"+     transform="translate(-40.943916,-27.525532)">+    <rect+       style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.13800001;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#898200;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.14111111;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"+       id="rect4898"+       width="12.552429"+       height="4.21416"+       x="74.334846"+       y="48.584148" />+    <text+       xml:space="preserve"+       style="font-style:normal;font-weight:normal;font-size:4.23333311px;line-height:4.93888903px;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"+       x="43.832203"+       y="52.181114"+       id="text4487"><tspan+         sodipodi:role="line"+         id="tspan4485"+         x="43.832203"+         y="52.181114"+         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.23333311px;line-height:4.93888903px;font-family:'Fira Mono';-inkscape-font-specification:'Fira Mono';stroke-width:0.26458332px">Lorem ipsum dolor sit amet, consectetur</tspan><tspan+         sodipodi:role="line"+         x="43.832203"+         y="57.202133"+         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.23333311px;line-height:4.93888903px;font-family:'Fira Mono';-inkscape-font-specification:'Fira Mono';stroke-width:0.26458332px"+         id="tspan4489">adipiscing elit, sed do eiusmod tempor</tspan><tspan+         sodipodi:role="line"+         x="43.832203"+         y="62.223156"+         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.23333311px;line-height:4.93888903px;font-family:'Fira Mono';-inkscape-font-specification:'Fira Mono';stroke-width:0.26458332px"+         id="tspan4491">incididunt ut labore et dolore magna aliqua.</tspan></text>+    <path+       style="fill:none;fill-rule:evenodd;stroke:#d69000;stroke-width:0.35277778;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"+       d="m 53.861606,47.913689 v 5.575149"+       id="path4493"+       inkscape:connector-curvature="0" />+    <text+       xml:space="preserve"+       style="font-style:normal;font-weight:normal;font-size:4.23333311px;line-height:4.93888903px;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#d69000;fill-opacity:1;stroke:none;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"+       x="52.474232"+       y="40.50515"+       id="text4497"><tspan+         sodipodi:role="line"+         id="tspan4495"+         x="52.474232"+         y="40.50515"+         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.23333311px;font-family:Merriweather;-inkscape-font-specification:Merriweather;fill:#d69000;fill-opacity:1;stroke-width:0.26458332px">Loc 1:5</tspan></text>+    <text+       id="text4787"+       y="37.443539"+       x="79.263298"+       style="font-style:normal;font-weight:normal;font-size:4.23333311px;line-height:4.93888903px;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#898200;fill-opacity:1;stroke:none;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"+       xml:space="preserve"><tspan+         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.23333311px;font-family:Merriweather;-inkscape-font-specification:Merriweather;fill:#898200;fill-opacity:1;stroke-width:0.26458332px"+         y="37.443539"+         x="79.263298"+         sodipodi:role="line"+         id="tspan4853">Span 1:13-1:18</tspan></text>+    <path+       style="fill:#d69000;fill-opacity:1;fill-rule:evenodd;stroke:#d69000;stroke-width:0.26499999;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"+       d="m 53.821401,41.54614 v 4.482401"+       id="path4499"+       inkscape:connector-curvature="0"+       sodipodi:nodetypes="cc" />+    <path+       sodipodi:type="star"+       style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#d69000;fill-opacity:1;fill-rule:nonzero;stroke:#d69000;stroke-width:0.33763754;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"+       id="path4815"+       sodipodi:sides="3"+       sodipodi:cx="53.721176"+       sodipodi:cy="45.499374"+       sodipodi:r1="1.7372519"+       sodipodi:r2="0.86862594"+       sodipodi:arg1="1.5707963"+       sodipodi:arg2="2.6179939"+       inkscape:flatsided="false"+       inkscape:rounded="0"+       inkscape:randomized="0"+       d="m 53.721176,47.236626 -0.752252,-1.302939 -0.752252,-1.302939 1.504504,0 1.504504,0 -0.752252,1.302939 z"+       inkscape:transform-center-y="0.068559171"+       transform="matrix(0.42264893,0,0,0.41327698,31.116206,27.39379)" />+    <path+       inkscape:connector-curvature="0"+       id="path4817"+       d="m 44.069338,47.913689 v 5.575149"+       style="fill:none;fill-rule:evenodd;stroke:#d60000;stroke-width:0.35277778;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />+    <text+       id="text4839"+       y="32.671593"+       x="42.741344"+       style="font-style:normal;font-weight:normal;font-size:4.23333311px;line-height:4.93888903px;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#d60000;fill-opacity:1;stroke:none;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"+       xml:space="preserve"><tspan+         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.23333311px;font-family:Merriweather;-inkscape-font-specification:Merriweather;fill:#d60000;fill-opacity:1;stroke-width:0.26458332px"+         y="32.671593"+         x="42.741344"+         id="tspan4837"+         sodipodi:role="line">Loc 1:1</tspan></text>+    <path+       inkscape:connector-curvature="0"+       id="path4841"+       d="m 43.899526,33.806143 v 12.2224"+       style="fill:#d60000;fill-opacity:1;fill-rule:evenodd;stroke:#d60000;stroke-width:0.26499999;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"+       sodipodi:nodetypes="cc" />+    <path+       transform="matrix(0.42264893,0,0,0.41327698,21.194331,27.39379)"+       inkscape:transform-center-y="0.068559171"+       d="m 53.721176,47.236626 -0.752252,-1.302939 -0.752252,-1.302939 1.504504,0 1.504504,0 -0.752252,1.302939 z"+       inkscape:randomized="0"+       inkscape:rounded="0"+       inkscape:flatsided="false"+       sodipodi:arg2="2.6179939"+       sodipodi:arg1="1.5707963"+       sodipodi:r2="0.86862594"+       sodipodi:r1="1.7372519"+       sodipodi:cy="45.499374"+       sodipodi:cx="53.721176"+       sodipodi:sides="3"+       id="path4843"+       style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#d60000;fill-opacity:1;fill-rule:nonzero;stroke:#d60000;stroke-width:0.33763754;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"+       sodipodi:type="star" />+    <path+       inkscape:connector-curvature="0"+       id="path4857"+       d="m 80.468723,38.834159 v 7.723547"+       style="fill:#898200;fill-opacity:1;fill-rule:evenodd;stroke:#898200;stroke-width:0.26499999;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />+    <path+       transform="matrix(0.42264893,0,0,0.41327698,57.763529,27.922957)"+       inkscape:transform-center-y="0.068559171"+       d="m 53.721176,47.236626 -0.752252,-1.302939 -0.752252,-1.302939 1.504504,0 1.504504,0 -0.752252,1.302939 z"+       inkscape:randomized="0"+       inkscape:rounded="0"+       inkscape:flatsided="false"+       sodipodi:arg2="2.6179939"+       sodipodi:arg1="1.5707963"+       sodipodi:r2="0.86862594"+       sodipodi:r1="1.7372519"+       sodipodi:cy="45.499374"+       sodipodi:cx="53.721176"+       sodipodi:sides="3"+       id="path4859"+       style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#898200;fill-opacity:1;fill-rule:nonzero;stroke:#898200;stroke-width:0.33763754;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"+       sodipodi:type="star" />+    <path+       inkscape:connector-curvature="0"+       id="path4888"+       d="m 142.76163,47.913689 v 5.575149"+       style="fill:none;fill-rule:evenodd;stroke:#6ab59b;stroke-width:0.35277778;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />+    <text+       id="text4892"+       y="40.50515"+       x="141.37424"+       style="font-style:normal;font-weight:normal;font-size:4.23333311px;line-height:4.93888903px;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#6ab59b;fill-opacity:1;stroke:none;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"+       xml:space="preserve"><tspan+         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.23333311px;font-family:Merriweather;-inkscape-font-specification:Merriweather;fill:#6ab59b;fill-opacity:1;stroke-width:0.26458332px"+         y="40.50515"+         x="141.37424"+         id="tspan4890"+         sodipodi:role="line">Loc 1:40</tspan></text>+    <path+       inkscape:connector-curvature="0"+       id="path4894"+       d="m 142.72142,41.612956 v 4.482401"+       style="fill:#6ab59b;fill-opacity:1;fill-rule:evenodd;stroke:#6ab59b;stroke-width:0.26499999;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"+       sodipodi:nodetypes="cc" />+    <path+       transform="matrix(0.42264893,0,0,0.41327698,120.01621,27.460606)"+       inkscape:transform-center-y="0.068559171"+       d="m 53.721176,47.236626 -0.752252,-1.302939 -0.752252,-1.302939 1.504504,0 1.504504,0 -0.752252,1.302939 z"+       inkscape:randomized="0"+       inkscape:rounded="0"+       inkscape:flatsided="false"+       sodipodi:arg2="2.6179939"+       sodipodi:arg1="1.5707963"+       sodipodi:r2="0.86862594"+       sodipodi:r1="1.7372519"+       sodipodi:cy="45.499374"+       sodipodi:cx="53.721176"+       sodipodi:sides="3"+       id="path4896"+       style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#6ab59b;fill-opacity:1;fill-rule:nonzero;stroke:#6ab59b;stroke-width:0.33763754;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"+       sodipodi:type="star" />+    <rect+       style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.18600003;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#2865a3;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.14111111;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"+       id="rect4898-4"+       width="15.331899"+       height="4.3347769"+       x="86.98941"+       y="53.612862" />+    <path+       inkscape:connector-curvature="0"+       id="path4915"+       d="m 74.332062,48.592293 v 4.215314"+       style="fill:none;fill-rule:evenodd;stroke:#898200;stroke-width:0.35277778;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />+    <path+       style="fill:none;fill-rule:evenodd;stroke:#898200;stroke-width:0.35277778;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"+       d="m 86.965246,48.592293 v 4.215314"+       id="path4917"+       inkscape:connector-curvature="0" />+    <path+       inkscape:connector-curvature="0"+       id="path4915-3"+       d="m 86.965246,53.626655 v 4.321584"+       style="fill:none;fill-rule:evenodd;stroke:#2865a3;stroke-width:0.35277778;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />+    <path+       style="fill:none;fill-rule:evenodd;stroke:#2865a3;stroke-width:0.35277778;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"+       d="m 102.39444,53.626655 v 4.321584"+       id="path4934"+       inkscape:connector-curvature="0" />+    <rect+       y="53.570915"+       x="125.20956"+       height="4.7904701"+       width="15.331899"+       id="rect4936"+       style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.18600003;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#2865a3;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.14111111;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />+    <path+       style="fill:none;fill-rule:evenodd;stroke:#2865a3;stroke-width:0.35277778;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"+       d="m 125.18544,53.586154 v 4.775892"+       id="path4938"+       inkscape:connector-curvature="0" />+    <rect+       style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.18600003;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#2865a3;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.14111111;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"+       id="rect4898-4-7"+       width="10.019917"+       height="4.5752463"+       x="43.959404"+       y="58.546028" />+    <path+       style="fill:none;fill-rule:evenodd;stroke:#2865a3;stroke-width:0.35277778;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"+       d="m 54.005945,58.560582 v 4.561323"+       id="path4934-3"+       inkscape:connector-curvature="0" />+    <rect+       style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.18600003;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#2865a3;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.14111111;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"+       id="rect4898-4-8"+       width="15.331899"+       height="4.568501"+       x="79.387222"+       y="58.50029" />+    <path+       inkscape:connector-curvature="0"+       id="path4915-3-0"+       d="m 79.363058,58.514829 v 4.554598"+       style="fill:none;fill-rule:evenodd;stroke:#2865a3;stroke-width:0.35277778;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />+    <path+       style="fill:none;fill-rule:evenodd;stroke:#2865a3;stroke-width:0.35277778;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"+       d="m 94.792252,58.514829 v 4.554598"+       id="path4934-9"+       inkscape:connector-curvature="0" />+    <text+       xml:space="preserve"+       style="font-style:normal;font-weight:normal;font-size:4.23333311px;line-height:4.93888903px;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#2865a3;fill-opacity:1;stroke:none;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"+       x="52.028664"+       y="77.157898"+       id="text4992"><tspan+         id="tspan4990"+         sodipodi:role="line"+         x="52.028664"+         y="77.157898"+         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.23333311px;font-family:Merriweather;-inkscape-font-specification:Merriweather;fill:#2865a3;fill-opacity:1;stroke-width:0.26458332px">Area [2:18-2:24, 2:33-3:5, 3:15-3:21]</tspan></text>+    <path+       inkscape:connector-curvature="0"+       id="path4841-7"+       d="M 96.163115,73.02495 V 59.589093"+       style="fill:#2865a3;fill-opacity:1;fill-rule:evenodd;stroke:#2865a3;stroke-width:0.26499999;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />+    <path+       transform="matrix(0.42264894,0,0,-0.41327697,73.457922,78.223848)"+       inkscape:transform-center-y="-0.068556884"+       d="m 53.721176,47.236626 -0.752252,-1.302939 -0.752252,-1.302939 1.504504,0 1.504504,0 -0.752252,1.302939 z"+       inkscape:randomized="0"+       inkscape:rounded="0"+       inkscape:flatsided="false"+       sodipodi:arg2="2.6179939"+       sodipodi:arg1="1.5707963"+       sodipodi:r2="0.86862594"+       sodipodi:r1="1.7372519"+       sodipodi:cy="45.499374"+       sodipodi:cx="53.721176"+       sodipodi:sides="3"+       id="path4843-9"+       style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#2865a3;fill-opacity:1;fill-rule:nonzero;stroke:#2865a3;stroke-width:0.33763754;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"+       sodipodi:type="star" />+    <path+       style="fill:#2865a3;fill-opacity:1;fill-rule:evenodd;stroke:#2865a3;stroke-width:0.26499999;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"+       d="M 86.638115,73.038044 V 64.88076"+       id="path5014"+       inkscape:connector-curvature="0" />+    <path+       sodipodi:type="star"+       style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#2865a3;fill-opacity:1;fill-rule:nonzero;stroke:#2865a3;stroke-width:0.33763754;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"+       id="path5016"+       sodipodi:sides="3"+       sodipodi:cx="53.721176"+       sodipodi:cy="45.499374"+       sodipodi:r1="1.7372519"+       sodipodi:r2="0.86862594"+       sodipodi:arg1="1.5707963"+       sodipodi:arg2="2.6179939"+       inkscape:flatsided="false"+       inkscape:rounded="0"+       inkscape:randomized="0"+       d="m 53.721176,47.236626 -0.752252,-1.302939 -0.752252,-1.302939 1.504504,0 1.504504,0 -0.752252,1.302939 z"+       inkscape:transform-center-y="-0.068556884"+       transform="matrix(0.42264894,0,0,-0.41327697,63.932922,83.515515)" />+    <path+       style="fill:#2865a3;fill-opacity:1;fill-rule:evenodd;stroke:#2865a3;stroke-width:0.26499999;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"+       d="M 127.51224,73.02495 V 59.589093"+       id="path5022"+       inkscape:connector-curvature="0" />+    <path+       sodipodi:type="star"+       style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#2865a3;fill-opacity:1;fill-rule:nonzero;stroke:#2865a3;stroke-width:0.33763754;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"+       id="path5024"+       sodipodi:sides="3"+       sodipodi:cx="53.721176"+       sodipodi:cy="45.499374"+       sodipodi:r1="1.7372519"+       sodipodi:r2="0.86862594"+       sodipodi:arg1="1.5707963"+       sodipodi:arg2="2.6179939"+       inkscape:flatsided="false"+       inkscape:rounded="0"+       inkscape:randomized="0"+       d="m 53.721176,47.236626 -0.752252,-1.302939 -0.752252,-1.302939 1.504504,0 1.504504,0 -0.752252,1.302939 z"+       inkscape:transform-center-y="-0.068556884"+       transform="matrix(0.42264894,0,0,-0.41327697,104.80703,78.223848)" />+    <path+       inkscape:connector-curvature="0"+       id="path5026"+       d="M 53.434247,73.038044 V 64.88076"+       style="fill:#2865a3;fill-opacity:1;fill-rule:evenodd;stroke:#2865a3;stroke-width:0.26499999;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />+    <path+       transform="matrix(0.42264894,0,0,-0.41327697,30.729054,83.515515)"+       inkscape:transform-center-y="-0.068556884"+       d="m 53.721176,47.236626 -0.752252,-1.302939 -0.752252,-1.302939 1.504504,0 1.504504,0 -0.752252,1.302939 z"+       inkscape:randomized="0"+       inkscape:rounded="0"+       inkscape:flatsided="false"+       sodipodi:arg2="2.6179939"+       sodipodi:arg1="1.5707963"+       sodipodi:r2="0.86862594"+       sodipodi:r1="1.7372519"+       sodipodi:cy="45.499374"+       sodipodi:cx="53.721176"+       sodipodi:sides="3"+       id="path5028"+       style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#2865a3;fill-opacity:1;fill-rule:nonzero;stroke:#2865a3;stroke-width:0.33763754;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"+       sodipodi:type="star" />+  </g>+</svg>
loc.cabal view
@@ -3,7 +3,7 @@ -- see: https://github.com/sol/hpack  name:           loc-version:        0.1.2.1+version:        0.1.2.2 synopsis:       Types representing line and column positions and ranges in text files.  description:    The package name /loc/ stands for “location” and is also an allusion to the@@ -20,6 +20,11 @@ license-file:   license.txt build-type:     Simple cabal-version:  >= 1.10++extra-source-files:+    example.png+    example.svg+    README.md  library   hs-source-dirs: