lib/syn/src/span/model.zig

daab053ee43316e1809a84551d573ddd1e5bf3d2

  1 //! A scan produces marked byte ranges for one line, each with the role of the text it covers, and
  2 //! whether the marks of the line were kept. A renderer needs each range as offsets into the line
  3 //! and a role it can map to a color, and nothing more.
  4 //!
  5 //! The roles differ by language: code has keywords and types, a Lisp list has its head, TOML has
  6 //! tables, Markdown has headings, and a diff has added and removed lines.
  7 //!
  8 //! One list of roles (*span kind*) covers every scanner, so a renderer maps each role to a style
  9 //! once and every language can use it. A marked range (*span*) is a plain value of two byte offsets
 10 //! and a role, with no pointer into the text. A scan of one line reports whether the storage kept
 11 //! the line's marks or discarded them (*materialization*), and a line that does not fit the storage
 12 //! reports that they were discarded.
 13 //!
 14 //! - *text limit*: the longest line, in bytes, whose marks the storage keeps
 15 //! - *span storage*: the caller's buffer that receives one line's marks
 16 //! - *continuation state*: what one line leaves open for the next line
 17 /// The role of the text one span covers. A renderer switches on this role to pick a color or style
 18 /// for each span. Thirty-one roles serve every scanner, and each scanner uses the roles that fit
 19 /// its languages. The package attaches no color or style to any role.
 20 pub const Kind = enum {
 21     /// A reserved word of the language, such as `if`, `return` or `const`, or a CSS rule that
 22     /// starts with `@`, such as `@media`.
 23     keyword,
 24     /// A built-in type name, such as `u8`, `int` or `String`, marked by the generic scanner.
 25     type,
 26     /// A name followed by an opening parenthesis, marked by the generic scanner.
 27     function,
 28     /// A shell, PHP or Perl variable such as `$HOME`, or a Rust lifetime such as `'a`.
 29     variable,
 30     /// A name after a dot in code, a CSS property name inside a rule, or a command-line option such
 31     /// as `--help` in shell.
 32     property,
 33     /// A quoted string, including a Python or TOML triple-quoted string that runs over more than
 34     /// one line.
 35     string,
 36     /// A numeric literal, including hexadecimal and exponent forms, and a CSS number with its unit,
 37     /// such as `1rem`.
 38     number,
 39     /// A named constant value, such as `true`, `false`, `null` or `None`.
 40     literal,
 41     /// A comment: a line comment to the end of the line, or a block comment up to its closing
 42     /// delimiter, which can run over more than one line.
 43     comment,
 44     /// A bracket, brace, comma, colon, semicolon or dot, or an angle bracket around a markup tag.
 45     punctuation,
 46     /// A run of operator characters, such as `=`, `+=` or `->`, marked by the generic scanner.
 47     operator,
 48     /// An annotation such as `@Override` in Java, C#, Kotlin, Scala or Dart, or a Python decorator.
 49     decorator,
 50     /// A parenthesis in Lisp or Clojure code.
 51     delimiter,
 52     /// The first symbol after an opening parenthesis in Lisp or Clojure code, the position of the
 53     /// operator in a list.
 54     head,
 55     /// A key in JSON or YAML before a colon, or a key in TOML before an equals sign.
 56     key,
 57     /// A TOML table header, such as `[server]`.
 58     table,
 59     /// A TOML date or date and time.
 60     date,
 61     /// A YAML anchor or alias, such as `&base` or `*base`.
 62     anchor,
 63     /// An element name in HTML, XML, Vue or Svelte, or a YAML tag such as `!!str`.
 64     tag,
 65     /// An attribute name inside a markup tag.
 66     attribute,
 67     /// A CSS name outside the property position of a rule, which covers selectors and also property
 68     /// values.
 69     selector,
 70     /// The text of a Markdown heading after its `#` marks.
 71     heading,
 72     /// A Markdown structure mark: the `#` run of a heading, a `>` quote mark, or a list bullet or
 73     /// number.
 74     marker,
 75     /// Markdown emphasis or strong emphasis, delimiters included, such as `*word*` or `__word__`.
 76     emphasis,
 77     /// Markdown strikethrough between `~~` marks.
 78     strike,
 79     /// Markdown inline code between backticks.
 80     code,
 81     /// A Markdown inline link, from its `[` through the `)` that closes its address.
 82     link,
 83     /// A whole diff header line, such as one starting with `diff `, `index `, `--- `, `+++ ` or
 84     /// `rename from `.
 85     header,
 86     /// A whole diff hunk line, starting with `@@`.
 87     hunk,
 88     /// A whole diff line starting with `+`, other than a `+++ ` header.
 89     addition,
 90     /// A whole diff line starting with `-`, other than a `--- ` header.
 91     deletion,
 92 };
 93 
 94 /// One marked byte range of a line and its role. A renderer reads the spans of a line from
 95 /// `Storage.items` and styles each byte range. The spans of one line come in order and never
 96 /// overlap or have zero length. Touching spans of the same kind are merged into one. Bytes that no
 97 /// span covers carry no role.
 98 pub const Span = struct {
 99     /// The offset of the first covered byte, counted from the start of the line passed to the scan.
100     start: usize,
101     /// The offset one past the last covered byte, so `text[span.start..span.end]` is the covered
102     /// text. The offset is always greater than `start` and at most the length of the line.
103     end: usize,
104     /// The role of the covered text.
105     kind: Kind,
106 };
107 
108 /// What happened to the spans of one line. A caller checks it after each call to know whether the
109 /// storage holds the spans of the line. Both outcomes leave the continuation state exact.
110 pub const Materialization = enum {
111     /// The line fit within the text limit, and the storage holds its spans.
112     complete,
113     /// The line was longer than the text limit, and the storage holds no spans for it. The line was
114     /// still scanned in full, and the storage added one to its count of discarded lines.
115     discarded,
116 };
117 
118 /// The one error that span storage raises when a line is too long to keep:
119 /// `MaterializationCapacityExceeded`. `Storage.prepare` returns it for a line that is too long, and
120 /// `highlight` and `highlightLine` catch it and return `.discarded`, so their callers never receive
121 /// it. The repository's allocation check requires a storage type of this shape to name such an
122 /// error.
123 pub const Exhaustion = error{MaterializationCapacityExceeded};