rouge-ddot 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: 2f88c6029952b82c0718d5e84838c76366d1b2bd9a26cbabdd36ecbbe52c49e8
4
+ data.tar.gz: 14439ccab259956c663b1eb0ba250ba34753f1817ba35c8c6bbdb318dc9542be
5
+ SHA512:
6
+ metadata.gz: 024f4d7e79864531850402223871f15b315cd897d9114506c66a37924d25246906744d616755d921077201b91566c8ae5e00fae94f88ce43b3f5914b516412d7
7
+ data.tar.gz: f170684e1c767d8333fd014dcad35b2f13a60988e21c50989fc393b8c90f420ebb59d521beef6ea1546682ca13f1b852ebb48ae6ff9e02a2253ca464415ddead
data/README.md ADDED
@@ -0,0 +1,69 @@
1
+ # rouge-ddot
2
+
3
+ [Rouge](https://github.com/rouge-ruby/rouge) lexer for the ddot.it knowledge
4
+ graph notation (https://ddot.it).
5
+
6
+ ## Usage
7
+
8
+ ```ruby
9
+ require 'rouge'
10
+ require 'rouge/lexers/ddot'
11
+
12
+ Rouge::Lexers::Ddot.new.lex("Project Eagle ..started in.. 2024") do |tok, val|
13
+ puts [tok.qualname, val].inspect
14
+ end
15
+ ```
16
+
17
+ In Asciidoctor with `:source-highlighter: rouge` set, `[source,ddot]` blocks
18
+ are dispatched here automatically — no extra wiring per document.
19
+
20
+ ## Token mapping
21
+
22
+ The lexer emits standard Rouge tokens; they map to the canonical ddot.it
23
+ token vocabulary in [`../../ddot.it/test-data/tokens.md`](../../ddot.it/test-data/tokens.md):
24
+
25
+ | Rouge | Canonical |
26
+ |-----------------------------|-----------------|
27
+ | `Name::Class` | `subject` |
28
+ | `Name::Function` | `relation` |
29
+ | `Literal::String::Symbol` | `object` |
30
+ | `Operator` | `operator` |
31
+ | `Keyword::Pseudo` | `command` |
32
+ | `Comment::Preproc` | `meta-delim` |
33
+ | `Comment::Hashbang` | `meta-operator` |
34
+ | `Comment::Doc` | `meta-relation` |
35
+ | `Comment::Special` | `meta-object` |
36
+ | `Comment::Multiline` | `meta-text` |
37
+ | `Comment::Single` | `disabled` |
38
+
39
+ ## Conformance
40
+
41
+ The lexer is asserted byte-equal to the corpus at
42
+ [`../../ddot.it/test-data/cases/*/expected.tokens.json`](../../ddot.it/test-data/cases/)
43
+ (after the mapping above). To run:
44
+
45
+ ```sh
46
+ # from the ddot.it-syntax-tools/ root
47
+ ruby tools/conformance-rouge.rb # exits non-zero on any case diverging
48
+ npm run conformance:rouge # npm-wrapped form
49
+ ```
50
+
51
+ The same corpus also feeds `npm run conformance:textmate`. Any change to the
52
+ canonical vocabulary or adding a case must keep both implementations in
53
+ lockstep.
54
+
55
+ ## Layout
56
+
57
+ ```
58
+ rouge/
59
+ ├── lib/
60
+ │ └── rouge/
61
+ │ └── lexers/
62
+ │ └── ddot.rb # the lexer
63
+ ├── README.md
64
+ └── rouge-ddot.gemspec
65
+ ```
66
+
67
+ ## License
68
+
69
+ MIT.
@@ -0,0 +1,272 @@
1
+ # frozen_string_literal: true
2
+ #
3
+ # Rouge lexer for ddot.it (https://ddot.it). Emits tokens that — after the
4
+ # scope-name mapping in `tools/conformance-rouge.rb` — equal the canonical
5
+ # token streams in `../../ddot.it/test-data/cases/*/expected.tokens.json`.
6
+ #
7
+ # Token mapping (Rouge → canonical, see ../../../ddot.it/test-data/tokens.md):
8
+ # Name::Class → subject
9
+ # Name::Function → relation
10
+ # Literal::String::Symbol → object
11
+ # Operator → operator
12
+ # Keyword::Pseudo → command
13
+ # Comment::Preproc → meta-delim
14
+ # Comment::Hashbang → meta-operator
15
+ # Comment::Doc → meta-relation
16
+ # Comment::Special → meta-object
17
+ # Comment::Multiline → meta-text
18
+ # Comment::Single → disabled
19
+ #
20
+ # State machine is flat by design: we use `goto` exclusively (no `push`), so
21
+ # the stack is always one deep and `\n` simply transitions back to `:root`.
22
+ # This keeps line-by-line dispatch clean — every line starts fresh.
23
+ #
24
+ # Rouge gotcha: `rule pat, Token do |m| ... end` IGNORES the Token arg when
25
+ # a block is given. To both emit a token AND transition, use a block that
26
+ # calls `token Token, m[0]` then `goto :next`.
27
+
28
+ require 'rouge'
29
+
30
+ module Rouge
31
+ module Lexers
32
+ class Ddot < RegexLexer
33
+ title 'ddot.it'
34
+ desc 'Knowledge graph notation (https://ddot.it)'
35
+ tag 'ddot'
36
+ aliases 'ddotit', 'ddot.it'
37
+ filenames '*.ddot'
38
+ mimetypes 'text/x-ddot'
39
+
40
+ OFF_RE = /(?:ddot\.it\/off|!!off)/.freeze
41
+ ON_RE = /(?:ddot\.it\/on|!!on)/.freeze
42
+ CMD_RE = /(?:ddot\.it(?:\/[\w.-]+)?|!![\w.-]*)/.freeze
43
+
44
+ # ─────────── line-dispatch root ───────────
45
+ state :root do
46
+ # Standalone ,, opens a free-form meta block.
47
+ rule(%r/^[ \t]*,,[ \t]*(?=\n|\z)/) do |m|
48
+ token Comment::Preproc, m[0]
49
+ goto :meta_block
50
+ end
51
+ # Off-marker enters disabled span.
52
+ rule(%r/^[ \t]*#{OFF_RE}[ \t]*(?=\n|\z)/) do |m|
53
+ token Keyword::Pseudo, m[0]
54
+ goto :disabled
55
+ end
56
+ # Empty / whitespace-only line.
57
+ rule %r/^[ \t]*\n/, Text
58
+ # Continuation line (starts with `..` or `....`).
59
+ rule(/^(?=[ \t]*\.{2,4})/) { goto :after_subject }
60
+ # Triple line — start with subject parsing.
61
+ rule(/^/) { goto :subject }
62
+ end
63
+
64
+ # ─────────── disabled span ───────────
65
+ state :disabled do
66
+ rule(%r/^[ \t]*#{ON_RE}[ \t]*(?=\n|\z)/) do |m|
67
+ token Keyword::Pseudo, m[0]
68
+ goto :root
69
+ end
70
+ rule %r/^[ \t]*\n/, Text
71
+ rule %r/[^\n]+/, Comment::Single
72
+ rule %r/\n/, Text
73
+ end
74
+
75
+ # ─────────── multi-line meta block (free-form) ───────────
76
+ state :meta_block do
77
+ rule(%r/^[ \t]*,,[ \t]*(?=\n|\z)/) do |m|
78
+ token Comment::Preproc, m[0]
79
+ goto :root
80
+ end
81
+ rule %r/^[ \t]*\n/, Text
82
+ rule %r/[^\n]+/, Comment::Multiline
83
+ rule %r/\n/, Text
84
+ end
85
+
86
+ # ─────────── triple line: subject phase ───────────
87
+ state :subject do
88
+ rule %r/[ \t]+/, Text
89
+ rule(/#{CMD_RE}(?=[ \t]+\.{2,4}|[ \t]*,,|[ \t]*$|\n|\z)/) do |m|
90
+ token Keyword::Pseudo, m[0]
91
+ goto :after_subject
92
+ end
93
+ rule(/[^\s.,][^\n,]*?(?=[ \t]+\.{2,4}|[ \t]*,,|[ \t]*$|\n|\z)/) do |m|
94
+ token Name::Class, m[0]
95
+ goto :after_subject
96
+ end
97
+ rule(%r/\n/) { token Text, "\n"; goto :root }
98
+ end
99
+
100
+ # ─────────── after subject (or continuation entry) ───────────
101
+ state :after_subject do
102
+ rule %r/[ \t]+/, Text
103
+ # `.. ..` (spaced operator) — emit as one operator token covering the
104
+ # whole sequence, matching the canonical corpus.
105
+ rule(%r/\.{2}[ \t]+\.{2}/) do |m|
106
+ token Operator, m[0]
107
+ goto :object
108
+ end
109
+ rule(%r/\.{4}/) do |m|
110
+ token Operator, m[0]
111
+ goto :object
112
+ end
113
+ rule(%r/\.{2}/) do |m|
114
+ token Operator, m[0]
115
+ goto :relation
116
+ end
117
+ rule(%r/,,/) do |m|
118
+ token Comment::Preproc, m[0]
119
+ goto :inline_meta
120
+ end
121
+ rule(%r/\n/) { token Text, "\n"; goto :root }
122
+ end
123
+
124
+ # ─────────── relation phase ───────────
125
+ state :relation do
126
+ rule(/[^\s.,][^\n.,]*?(?=[ \t]*\.{2}|[ \t]*$|\n|\z)/) do |m|
127
+ token Name::Function, m[0]
128
+ goto :after_relation
129
+ end
130
+ rule %r/[ \t]+/, Text
131
+ rule(%r/\n/) { token Text, "\n"; goto :root }
132
+ end
133
+
134
+ state :after_relation do
135
+ rule %r/[ \t]+/, Text
136
+ rule(%r/\.{2}/) do |m|
137
+ token Operator, m[0]
138
+ goto :object
139
+ end
140
+ rule(%r/,,/) do |m|
141
+ token Comment::Preproc, m[0]
142
+ goto :inline_meta
143
+ end
144
+ rule(%r/\n/) { token Text, "\n"; goto :root }
145
+ end
146
+
147
+ # ─────────── object phase ───────────
148
+ state :object do
149
+ rule(/[^\s,][^\n,]*?(?=[ \t]*,,|[ \t]*$|\n|\z)/) do |m|
150
+ token Literal::String::Symbol, m[0]
151
+ goto :after_object
152
+ end
153
+ rule %r/[ \t]+/, Text
154
+ rule(%r/\n/) { token Text, "\n"; goto :root }
155
+ end
156
+
157
+ state :after_object do
158
+ rule %r/[ \t]+/, Text
159
+ # Trailing `,,` at end-of-line opens a typed multi-line meta block:
160
+ # subsequent lines are `..key.. value` triples emitted as meta-*
161
+ # until a closing standalone `,,`.
162
+ rule(%r/,,(?=[ \t]*(?:\n|\z))/) do |m|
163
+ token Comment::Preproc, m[0]
164
+ goto :typed_meta_open
165
+ end
166
+ # Inline `,,` followed by content on the same line.
167
+ rule(%r/,,/) do |m|
168
+ token Comment::Preproc, m[0]
169
+ goto :inline_meta
170
+ end
171
+ rule(%r/\n/) { token Text, "\n"; goto :root }
172
+ end
173
+
174
+ # Right after trailing `,,` — wait for the newline, then enter
175
+ # :typed_meta_block for subsequent lines.
176
+ state :typed_meta_open do
177
+ rule %r/[ \t]+/, Text
178
+ rule(%r/\n/) { token Text, "\n"; goto :typed_meta_block }
179
+ end
180
+
181
+ # Typed meta block: each line is `..relation.. object`, closed by `,,`.
182
+ state :typed_meta_block do
183
+ rule(%r/^[ \t]*,,[ \t]*(?=\n|\z)/) do |m|
184
+ token Comment::Preproc, m[0]
185
+ goto :root
186
+ end
187
+ rule %r/^[ \t]*\n/, Text
188
+ rule(/^(?=[ \t]*\.{2,4})/) { goto :typed_meta_op1 }
189
+ rule %r/[^\n]+/, Comment::Multiline # free-form fallback
190
+ rule %r/\n/, Text
191
+ end
192
+
193
+ state :typed_meta_op1 do
194
+ rule %r/[ \t]+/, Text
195
+ rule(%r/\.{2}/) do |m|
196
+ token Comment::Hashbang, m[0]
197
+ goto :typed_meta_relation
198
+ end
199
+ rule(%r/\n/) { token Text, "\n"; goto :typed_meta_block }
200
+ end
201
+
202
+ state :typed_meta_relation do
203
+ rule(/[^\s.,][^\n.,]*?(?=[ \t]*\.{2}|[ \t]*$|\n|\z)/) do |m|
204
+ token Comment::Doc, m[0]
205
+ goto :typed_meta_after_relation
206
+ end
207
+ rule %r/[ \t]+/, Text
208
+ rule(%r/\n/) { token Text, "\n"; goto :typed_meta_block }
209
+ end
210
+
211
+ state :typed_meta_after_relation do
212
+ rule %r/[ \t]+/, Text
213
+ rule(%r/\.{2}/) do |m|
214
+ token Comment::Hashbang, m[0]
215
+ goto :typed_meta_object
216
+ end
217
+ rule(%r/\n/) { token Text, "\n"; goto :typed_meta_block }
218
+ end
219
+
220
+ state :typed_meta_object do
221
+ rule(/[^\s,][^\n,]*?(?=[ \t]*$|\n|\z)/) do |m|
222
+ token Comment::Special, m[0]
223
+ goto :typed_meta_after_object
224
+ end
225
+ rule %r/[ \t]+/, Text
226
+ rule(%r/\n/) { token Text, "\n"; goto :typed_meta_block }
227
+ end
228
+
229
+ state :typed_meta_after_object do
230
+ rule %r/[ \t]+/, Text
231
+ rule(%r/\n/) { token Text, "\n"; goto :typed_meta_block }
232
+ end
233
+
234
+ # ─────────── inline metadata (after `,,` on a triple line) ───────────
235
+ state :inline_meta do
236
+ rule %r/[ \t]+/, Text
237
+ rule(%r/\.{2}/) do |m|
238
+ token Comment::Hashbang, m[0]
239
+ goto :inline_meta_relation
240
+ end
241
+ rule(%r/\n/) { token Text, "\n"; goto :root }
242
+ end
243
+
244
+ state :inline_meta_relation do
245
+ rule(/[^\s.,][^\n.,]*?(?=[ \t]*\.{2}|[ \t]*$|\n|\z)/) do |m|
246
+ token Comment::Doc, m[0]
247
+ goto :inline_meta_after_relation
248
+ end
249
+ rule %r/[ \t]+/, Text
250
+ rule(%r/\n/) { token Text, "\n"; goto :root }
251
+ end
252
+
253
+ state :inline_meta_after_relation do
254
+ rule %r/[ \t]+/, Text
255
+ rule(%r/\.{2}/) do |m|
256
+ token Comment::Hashbang, m[0]
257
+ goto :inline_meta_object
258
+ end
259
+ rule(%r/\n/) { token Text, "\n"; goto :root }
260
+ end
261
+
262
+ state :inline_meta_object do
263
+ rule(/[^\s,][^\n,]*?(?=[ \t]*$|\n|\z)/) do |m|
264
+ token Comment::Special, m[0]
265
+ goto :after_object
266
+ end
267
+ rule %r/[ \t]+/, Text
268
+ rule(%r/\n/) { token Text, "\n"; goto :root }
269
+ end
270
+ end
271
+ end
272
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = 'rouge-ddot'
5
+ s.version = '0.1.0'
6
+ s.summary = 'Rouge lexer for ddot.it'
7
+ s.description = 'Syntax highlighter for the ddot.it knowledge graph notation. ' \
8
+ 'Plugs into Rouge so any tool that uses Rouge for source ' \
9
+ 'highlighting (Asciidoctor, Jekyll, GitLab, …) can colourise ' \
10
+ '[source,ddot] blocks against the canonical token vocabulary.'
11
+ s.authors = ['Calpano']
12
+ s.email = ['hello@calpano.com']
13
+ s.homepage = 'https://ddot.it'
14
+ s.license = 'MIT'
15
+
16
+ s.required_ruby_version = '>= 2.7'
17
+ s.add_runtime_dependency 'rouge', '>= 3.30'
18
+
19
+ s.files = Dir[
20
+ 'lib/**/*.rb',
21
+ 'README.md',
22
+ 'rouge-ddot.gemspec'
23
+ ]
24
+ s.require_paths = ['lib']
25
+
26
+ s.metadata = {
27
+ 'source_code_uri' => 'https://github.com/calpano/ddot.it-syntax-tools',
28
+ 'bug_tracker_uri' => 'https://github.com/calpano/ddot.it-syntax-tools/issues'
29
+ }
30
+ end
metadata ADDED
@@ -0,0 +1,64 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rouge-ddot
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Calpano
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2026-05-08 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rouge
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '3.30'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '3.30'
27
+ description: Syntax highlighter for the ddot.it knowledge graph notation. Plugs into
28
+ Rouge so any tool that uses Rouge for source highlighting (Asciidoctor, Jekyll,
29
+ GitLab, …) can colourise [source,ddot] blocks against the canonical token vocabulary.
30
+ email:
31
+ - hello@calpano.com
32
+ executables: []
33
+ extensions: []
34
+ extra_rdoc_files: []
35
+ files:
36
+ - README.md
37
+ - lib/rouge/lexers/ddot.rb
38
+ - rouge-ddot.gemspec
39
+ homepage: https://ddot.it
40
+ licenses:
41
+ - MIT
42
+ metadata:
43
+ source_code_uri: https://github.com/calpano/ddot.it-syntax-tools
44
+ bug_tracker_uri: https://github.com/calpano/ddot.it-syntax-tools/issues
45
+ post_install_message:
46
+ rdoc_options: []
47
+ require_paths:
48
+ - lib
49
+ required_ruby_version: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: '2.7'
54
+ required_rubygems_version: !ruby/object:Gem::Requirement
55
+ requirements:
56
+ - - ">="
57
+ - !ruby/object:Gem::Version
58
+ version: '0'
59
+ requirements: []
60
+ rubygems_version: 3.5.22
61
+ signing_key:
62
+ specification_version: 4
63
+ summary: Rouge lexer for ddot.it
64
+ test_files: []