antares 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: a1968f47a0c8ea17a5e98fa2a3b6d4c339d2dcda58d4ae5032c7799d75ed17a6
4
+ data.tar.gz: 70e780331521d82f0dcbbe1ca6aa22de7f8ff7c2736eaca03a3e458ddb0e71f7
5
+ SHA512:
6
+ metadata.gz: 1ccfedd6fce3a1095aa81da6bd5f2285c7757a8dba9138eef211fdac309d5b5309e1b514c82e7fd593e93a6a851d9edded3d80c165176357cc7b13bfa43c7040
7
+ data.tar.gz: 5c18ad134cbf9fb791f625b3354a592b80d1052374fdf8f17e5c01b7917dd0cf73e4c2be863265d6372476776f769d31a3b2090757fce5eb9629eef0fb5ea7be
data/CHANGELOG.md ADDED
@@ -0,0 +1,5 @@
1
+ # Changelog
2
+
3
+ ## 0.1.0 — 2026-09-10
4
+
5
+ - Initial release.
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2026 Yudai Takada
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,111 @@
1
+ # Antares
2
+
3
+ Incremental syntax highlighting for Rouge, with measured per-lexer compatibility.
4
+ The only runtime dependency is `rouge ~> 5.0`; document storage and colors belong
5
+ to the caller. Ruby 3.1 or later is supported.
6
+
7
+ ```ruby
8
+ require "antares"
9
+
10
+ lines = ["value = 1\n", "print(value)\n"]
11
+ highlighter = Antares::Highlighter.new(
12
+ lexer: Rouge::Lexers::Python.new,
13
+ lines: ->(index) { lines[index] },
14
+ line_count: -> { lines.length }
15
+ )
16
+
17
+ highlighter.tokens_for(0) # [[Rouge token class, UTF-8 text], ...]
18
+ lines[0] = "value = 2\n"
19
+ highlighter.edit(from_line: 0, removed: 1, inserted: 1)
20
+ highlighter.tokens_in(0..1) # one token array per line
21
+ ```
22
+
23
+ For a local checkout, `gem build antares.gemspec` creates an installable gem;
24
+ install that file with `gem install ./antares-0.1.0.gem`. Publication is separate
25
+ from building and is not performed by tests or CI.
26
+
27
+ ## API and strategies
28
+
29
+ Line indices are zero based. Providers return one valid UTF-8 logical line each,
30
+ preferably including its newline. Missing separators are added to non-final
31
+ lines. A trailing empty logical line returns an empty token array. Tokens contain
32
+ text, not offsets: sum `text.bytesize` for byte offsets, or `text.length` for
33
+ character offsets. Returned rows/pairs/text are frozen.
34
+
35
+ Call `edit` **after** updating the provider, with the old removed line count and
36
+ new inserted line count. `frontier` is the first line not yet proven current;
37
+ `advance(until_line: 200)` lets an event loop schedule incremental progress.
38
+ `last_scanned_lines` reports actual lexical work, and `checkpoint_bytes` reports
39
+ normalized checkpoint payload bytes. Highlighter instances are not thread safe.
40
+
41
+ | Strategy | Behavior |
42
+ |---|---|
43
+ | `:auto` | Uses the bundled, exact-Rouge-version compatibility verdict. Unknown versions and lexers use `:window`. |
44
+ | `:incremental` | Forces state snapshots and convergence. Use for certified lexers; forcing a failed lexer can return incorrect classifications. |
45
+ | `:window` | Restarts from root up to 200 lines before the requested range. Explicitly approximate for long-running constructs. |
46
+ | `:full` | Runs ordinary Rouge over the complete bounded document after every edit; use for exact results on small files with failed incremental lexers. |
47
+
48
+ `Antares.compatible?(Rouge::Lexers::Python)` returns `:incremental` or `:window`.
49
+ Every registered lexer has an entry in `COMPATIBILITY` and a reproducible result
50
+ in `COMPATIBILITY_DETAILS`; see the [complete compatibility table](docs/compatibility.md).
51
+ Do not infer support merely because a lexer subclasses `Rouge::RegexLexer`.
52
+
53
+ ## State, limits, and correctness
54
+
55
+ Antares reuses Rouge's rule interpreter and deep-copies persistent instance
56
+ state, including nested arrays/hashes, their subclasses, delegate lexers, heredoc
57
+ queues, sets and structs. Immutable rule templates are shared. Per-call scanners
58
+ and callbacks are excluded. Dynamic rule closures compare conservatively by
59
+ identity, and opaque state is rejected rather than shallow-copied.
60
+
61
+ Checkpoints are placed approximately every 64 completed lines, **after entire
62
+ rule callbacks**. State fingerprints between checkpoints allow early convergence;
63
+ edits shift cached suffixes and invalidate stale boundaries. Calling
64
+ `continue_lex` separately for each line is insufficient: Rouge regexes may consume
65
+ several lines or inspect surrounding text. The driver therefore materializes a
66
+ bounded source String on demand, uses a fixed-anchor scanner, and resumes lexical
67
+ work at a checkpoint. It retains no array of provider lines. Source materialization
68
+ is O(document bytes) after an edit and is included in reported timings.
69
+
70
+ Some grammars are inherently nonlocal: for example, adding a distant `=end` makes
71
+ Rouge classify an earlier unmatched Ruby `=begin` differently. These lexers fail
72
+ the delayed-closure probes and select `:window`; the fallback is intentional.
73
+ Other failures are classified as token mismatch (lookahead/state dependencies) or
74
+ unsupported custom stream driver. The matrix is an empirical corpus guarantee,
75
+ not a proof for every possible input or non-default lexer option.
76
+
77
+ Default limits are 100,000 lines, an 8 MiB source snapshot, 16 KiB per line,
78
+ 256 KiB per checkpoint, and 250 ms per scan. Configure them with `max_lines`,
79
+ `max_bytes`, `max_line_bytes`, `max_checkpoint_bytes`, and `max_seconds`.
80
+ Exceeding a source limit switches to window mode; oversized individual lines and
81
+ timed-out ranges return plain-text tokens without truncating content.
82
+ `fallback_reason` explains the transition. These limits also apply to `:full`.
83
+
84
+ ## Development and verification
85
+
86
+ ```sh
87
+ bundle install
88
+ bundle exec rake test
89
+ bundle exec ruby script/compatibility --write
90
+ BUDGET=1 bundle exec ruby --yjit bench/highlighting.rb
91
+ ```
92
+
93
+ The matrix enumerates every Rouge lexer, uses three source variants based on
94
+ Rouge's bundled MIT-licensed demos, applies 50 deterministic insert/delete/replace
95
+ mutations to each, and compares all per-line tokens against a fresh full lex.
96
+ Three extra distant-closure probes catch backward reclassification. The test suite
97
+ reruns the complete matrix. `MUTATIONS=5 ruby script/compatibility python rust`
98
+ is a short diagnostic run; `DETAILS=1` prints the full JSON failure details.
99
+ Only full runs with 50 or more mutations may replace the bundled matrix.
100
+
101
+ Scheduled CI updates Rouge, regenerates the matrix, reruns tests, and uploads the
102
+ generated source/table for review. It does not silently publish a gem or modify a
103
+ release. Regular CI tests Ruby 3.1–4.0 on Linux, macOS and Windows.
104
+
105
+ On the development Mac with Ruby 4.0.0/YJIT, the 5,000-line Python benchmark
106
+ measured 10.771 ms for the first 60 lines and 1.325 ms median for a one-line edit
107
+ including source materialization and convergence. One line was rescanned, with
108
+ 80 checkpoints and 10,560 normalized payload bytes. Run the benchmark for current
109
+ timings and retained-object memory; budgets are 15 ms / 5 ms / 2 MiB.
110
+
111
+ Released under the [MIT license](LICENSE.txt).