elisp2any 0.0.5 → 0.0.7
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 +4 -4
- data/CHANGELOG.md +15 -0
- data/LICENSE.txt +674 -202
- data/README.md +31 -7
- data/Rakefile +5 -52
- data/exe/elisp2any +27 -17
- data/lib/elisp/comment.rb +32 -0
- data/lib/elisp/default.css +11 -0
- data/lib/elisp/doc_string_parser.rb +96 -0
- data/lib/elisp/heading.rb +31 -0
- data/lib/elisp/parser.rb +161 -0
- data/lib/elisp/version.rb +18 -0
- data/lib/elisp.rb +99 -0
- metadata +12 -96
- data/.document +0 -4
- data/.envrc +0 -3
- data/.rdoc_options +0 -2
- data/.rubocop.yml +0 -11
- data/lib/elisp2any/asciidoc_renderer/index.adoc.erb +0 -15
- data/lib/elisp2any/asciidoc_renderer.rb +0 -57
- data/lib/elisp2any/aside.rb +0 -23
- data/lib/elisp2any/blanklines.rb +0 -20
- data/lib/elisp2any/code.rb +0 -49
- data/lib/elisp2any/codeblock.rb +0 -56
- data/lib/elisp2any/comment.rb +0 -19
- data/lib/elisp2any/commentary.rb +0 -32
- data/lib/elisp2any/expression.rb +0 -90
- data/lib/elisp2any/file.rb +0 -63
- data/lib/elisp2any/footer_line.rb +0 -28
- data/lib/elisp2any/header_line.rb +0 -80
- data/lib/elisp2any/heading.rb +0 -68
- data/lib/elisp2any/html_renderer/index.html.erb +0 -23
- data/lib/elisp2any/html_renderer.erb +0 -22
- data/lib/elisp2any/html_renderer.rb +0 -149
- data/lib/elisp2any/inline_code.rb +0 -10
- data/lib/elisp2any/line.rb +0 -52
- data/lib/elisp2any/node.rb +0 -67
- data/lib/elisp2any/paragraph.rb +0 -37
- data/lib/elisp2any/section.rb +0 -49
- data/lib/elisp2any/text.rb +0 -33
- data/lib/elisp2any/tree_sitter_parser.rb +0 -36
- data/lib/elisp2any/version.rb +0 -4
- data/lib/elisp2any.rb +0 -27
- data/manifest.scm +0 -87
- data/sig/elisp2any.gen.rbs +0 -112
- data/sig/elisp2any.rbs +0 -4
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
require "elisp2any/comment"
|
|
2
|
-
require "elisp2any/expression"
|
|
3
|
-
|
|
4
|
-
module Elisp2any
|
|
5
|
-
class HeaderLine
|
|
6
|
-
attr_reader :filename, :description, :variables
|
|
7
|
-
|
|
8
|
-
def self.scan(scanner)
|
|
9
|
-
scanner = StringScanner.new(scanner) unless scanner.respond_to?(:pos)
|
|
10
|
-
pos = scanner.pos
|
|
11
|
-
unless (heading = Elisp2any.scan_top_heading(scanner))
|
|
12
|
-
scanner.pos = pos
|
|
13
|
-
return
|
|
14
|
-
end
|
|
15
|
-
cscanner = StringScanner.new(heading)
|
|
16
|
-
unless (filename = Elisp2any.scan_filename(cscanner))
|
|
17
|
-
scanner.pos = pos
|
|
18
|
-
return
|
|
19
|
-
end
|
|
20
|
-
unless cscanner.skip(/ +--- +/)
|
|
21
|
-
scanner.pos = pos
|
|
22
|
-
return
|
|
23
|
-
end
|
|
24
|
-
description = +""
|
|
25
|
-
variables = nil
|
|
26
|
-
until cscanner.eos?
|
|
27
|
-
if (variables = scan_variables(cscanner)) # nop
|
|
28
|
-
break
|
|
29
|
-
else
|
|
30
|
-
description << cscanner.getch
|
|
31
|
-
end
|
|
32
|
-
end
|
|
33
|
-
if description.empty?
|
|
34
|
-
scanner.pos = pos
|
|
35
|
-
return
|
|
36
|
-
end
|
|
37
|
-
new(filename:, description:, variables:)
|
|
38
|
-
end
|
|
39
|
-
|
|
40
|
-
def self.scan_variables(scanner)
|
|
41
|
-
scanner = StringScanner.new(scanner) unless scanner.respond_to?(:pos)
|
|
42
|
-
scanner.skip(/ *-[*]- +/) or return
|
|
43
|
-
variables = {}
|
|
44
|
-
until scanner.skip(/ +-[*]- */)
|
|
45
|
-
if scanner.eos?
|
|
46
|
-
raise Error, "unexpected end"
|
|
47
|
-
elsif (assign = scan_assignments(scanner))
|
|
48
|
-
variables[assign[:variable]] = assign[:expression]
|
|
49
|
-
elsif scanner.skip(";")
|
|
50
|
-
break
|
|
51
|
-
else
|
|
52
|
-
raise Error, scanner.inspect
|
|
53
|
-
end
|
|
54
|
-
end
|
|
55
|
-
variables
|
|
56
|
-
end
|
|
57
|
-
private_class_method :scan_variables
|
|
58
|
-
|
|
59
|
-
def self.scan_assignments(scanner)
|
|
60
|
-
pos = scanner.pos
|
|
61
|
-
variable = Elisp2any.scan_variable(scanner) or return
|
|
62
|
-
unless scanner.skip(/ *: */)
|
|
63
|
-
scanner.pos = pos
|
|
64
|
-
return
|
|
65
|
-
end
|
|
66
|
-
unless (expression = Expression.scan(scanner))
|
|
67
|
-
scanner.pos = pos
|
|
68
|
-
return
|
|
69
|
-
end
|
|
70
|
-
{ variable:, expression: }
|
|
71
|
-
end
|
|
72
|
-
private_class_method :scan_assignments
|
|
73
|
-
|
|
74
|
-
def initialize(filename:, description:, variables:)
|
|
75
|
-
@filename = filename
|
|
76
|
-
@description = description
|
|
77
|
-
@variables = variables
|
|
78
|
-
end
|
|
79
|
-
end
|
|
80
|
-
end
|
data/lib/elisp2any/heading.rb
DELETED
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
require 'strscan'
|
|
2
|
-
require 'forwardable'
|
|
3
|
-
|
|
4
|
-
module Elisp2any
|
|
5
|
-
class Heading
|
|
6
|
-
attr_reader :level
|
|
7
|
-
attr_accessor :content
|
|
8
|
-
|
|
9
|
-
def self.scan(scanner)
|
|
10
|
-
pos = scanner.pos
|
|
11
|
-
comment = Comment.scan(scanner) or return
|
|
12
|
-
unless comment.colons >= 3
|
|
13
|
-
scanner.pos = pos
|
|
14
|
-
return
|
|
15
|
-
end
|
|
16
|
-
new(:TODO, comment.colons - 3,
|
|
17
|
-
comment.content # do not scan as text at this point
|
|
18
|
-
)
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
def deconstruct_keys(*keys)
|
|
22
|
-
result = {}
|
|
23
|
-
keys => [keys]
|
|
24
|
-
keys.each do |key|
|
|
25
|
-
case key
|
|
26
|
-
in :level
|
|
27
|
-
result[:level] = @level
|
|
28
|
-
in :content
|
|
29
|
-
result[:content] = @content
|
|
30
|
-
end
|
|
31
|
-
end
|
|
32
|
-
result
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
# TODO: delete node. Use kwargs.
|
|
36
|
-
def initialize(node, level, content) # :nodoc:
|
|
37
|
-
@node = node
|
|
38
|
-
@level = level
|
|
39
|
-
@content = content
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
# Returns nil if failed
|
|
43
|
-
def name_and_synopsis # :nodoc:
|
|
44
|
-
scanner = StringScanner.new(@content)
|
|
45
|
-
name = scanner.scan_until(/\.el/) or return
|
|
46
|
-
name = name[nil...-3] or return
|
|
47
|
-
scanner.skip(/\s+---\s+/) or return
|
|
48
|
-
scanner.skip(/(?<synopsis>.+?)(:?\s+-\*- .+? -\*-)?\Z/) or return
|
|
49
|
-
synopsis = scanner[:synopsis]
|
|
50
|
-
return name, synopsis
|
|
51
|
-
end
|
|
52
|
-
|
|
53
|
-
def commentary? # :nodoc:
|
|
54
|
-
@level == 1 && @content == 'Commentary:'
|
|
55
|
-
end
|
|
56
|
-
|
|
57
|
-
def code? # :nodoc:
|
|
58
|
-
@level == 1 && @content == 'Code:'
|
|
59
|
-
end
|
|
60
|
-
|
|
61
|
-
def final_name # :nodoc:
|
|
62
|
-
@content.match(/\A(?<name>.+?)\.el ends here\Z/)[:name]
|
|
63
|
-
end
|
|
64
|
-
|
|
65
|
-
extend Forwardable # :nodoc:
|
|
66
|
-
def_delegator :@level, :<=>
|
|
67
|
-
end
|
|
68
|
-
end
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
<!doctype html>
|
|
2
|
-
<html>
|
|
3
|
-
<head>
|
|
4
|
-
<meta charset="UTF-8">
|
|
5
|
-
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
6
|
-
<title><%= name %></title>
|
|
7
|
-
<link rel="stylesheet" href="<%= @css %>">
|
|
8
|
-
</head>
|
|
9
|
-
<body>
|
|
10
|
-
<main>
|
|
11
|
-
<h1><%= name %></h1>
|
|
12
|
-
<p><%= synopsis %></p>
|
|
13
|
-
<h2>Commentary</h2>
|
|
14
|
-
<% commentary.each do |paragraph| %>
|
|
15
|
-
<p><%= render_paragraph(paragraph) %></p>
|
|
16
|
-
<% end %>
|
|
17
|
-
<h2>Code</h2>
|
|
18
|
-
<% code.each do |block| %>
|
|
19
|
-
<%= render_block(block, level: 2) %>
|
|
20
|
-
<% end %>
|
|
21
|
-
</main>
|
|
22
|
-
</body>
|
|
23
|
-
</html>
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
<!doctype html>
|
|
2
|
-
<html>
|
|
3
|
-
<head>
|
|
4
|
-
<meta charset="UTF-8">
|
|
5
|
-
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
6
|
-
<title><%= name %></title>
|
|
7
|
-
<link rel="stylesheet" href="<%= @css %>">
|
|
8
|
-
</head>
|
|
9
|
-
<body>
|
|
10
|
-
<main>
|
|
11
|
-
<h1><%= name %><small> — <%= synopsis %></small></h1>
|
|
12
|
-
<div style="text-align:right"><%= render(header_line.variables) %></div>
|
|
13
|
-
<% commentary.each do |paragraph| %>
|
|
14
|
-
<%= render(paragraph) %>
|
|
15
|
-
<% end %>
|
|
16
|
-
<h2>Code</h2>
|
|
17
|
-
<% self.code.each do |block| %>
|
|
18
|
-
<%= render(block) %>
|
|
19
|
-
<% end %>
|
|
20
|
-
</main>
|
|
21
|
-
</body>
|
|
22
|
-
</html>
|
|
@@ -1,149 +0,0 @@
|
|
|
1
|
-
require 'erb'
|
|
2
|
-
require 'forwardable'
|
|
3
|
-
require 'cgi/util'
|
|
4
|
-
require_relative 'inline_code'
|
|
5
|
-
require_relative 'heading'
|
|
6
|
-
require_relative 'paragraph'
|
|
7
|
-
require_relative 'codeblock'
|
|
8
|
-
|
|
9
|
-
module Elisp2any
|
|
10
|
-
class HTMLRenderer
|
|
11
|
-
def initialize(file, css: nil, mode:)
|
|
12
|
-
@file = file
|
|
13
|
-
@css = css || "https://unpkg.com/mvp.css"
|
|
14
|
-
@mode = mode
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
# Write gradually?
|
|
18
|
-
def render(node = nil)
|
|
19
|
-
if node
|
|
20
|
-
case node
|
|
21
|
-
in Paragraph
|
|
22
|
-
par = node.sum(+"") { |line| render(line) }
|
|
23
|
-
"<p>#{par}</p>"
|
|
24
|
-
in Line
|
|
25
|
-
begin
|
|
26
|
-
node.sum(+"") { |chunk| render(chunk) }
|
|
27
|
-
rescue => e
|
|
28
|
-
warn node.inspect
|
|
29
|
-
raise e
|
|
30
|
-
end
|
|
31
|
-
in String
|
|
32
|
-
h(node)
|
|
33
|
-
in [] # huh? nop.
|
|
34
|
-
in Section
|
|
35
|
-
result = render(node.heading)
|
|
36
|
-
node.blocks.each { |blo| result << render(blo) }
|
|
37
|
-
node.sections.each { |sec| result << render(sec) }
|
|
38
|
-
result
|
|
39
|
-
in Heading[level:, content:]
|
|
40
|
-
lev = level + 2
|
|
41
|
-
"<h#{lev}>#{render(content)}</h#{lev}>"
|
|
42
|
-
in Codeblock
|
|
43
|
-
"<pre><code>#{h(node.source.chomp)}</code></pre>"
|
|
44
|
-
in { code: }
|
|
45
|
-
"<code>#{h(code)}</code>"
|
|
46
|
-
in Hash
|
|
47
|
-
result = node.sum(+"<dl>") do |key, value|
|
|
48
|
-
"<dt>#{render(key)}</dt><dd>#{render(value)}</dd>"
|
|
49
|
-
end
|
|
50
|
-
"#{result}</dl>"
|
|
51
|
-
in Expression
|
|
52
|
-
"<code>#{h(node.source)}</code>"
|
|
53
|
-
in Text
|
|
54
|
-
node.sum(+"") { |ele| render(ele) }
|
|
55
|
-
else
|
|
56
|
-
raise Error, node.inspect
|
|
57
|
-
end
|
|
58
|
-
else
|
|
59
|
-
case @mode
|
|
60
|
-
in :old
|
|
61
|
-
erb_render('index.html.erb')
|
|
62
|
-
in :new
|
|
63
|
-
source = ::File.read(::File.join(__dir__, 'html_renderer.erb'))
|
|
64
|
-
ERB.new(source).result(binding)
|
|
65
|
-
end
|
|
66
|
-
end
|
|
67
|
-
end
|
|
68
|
-
|
|
69
|
-
private
|
|
70
|
-
|
|
71
|
-
def render_paragraph(paragraph)
|
|
72
|
-
html = ''
|
|
73
|
-
paragraph.each do |line|
|
|
74
|
-
line.each do |chunk|
|
|
75
|
-
case chunk
|
|
76
|
-
in InlineCode
|
|
77
|
-
html << "<code>#{h(chunk.content)}</code>"
|
|
78
|
-
in String
|
|
79
|
-
html << h(chunk)
|
|
80
|
-
in { code: }
|
|
81
|
-
html << "<code>#{h(code)}</code>"
|
|
82
|
-
else
|
|
83
|
-
raise Error, chunk.inspect
|
|
84
|
-
end
|
|
85
|
-
end
|
|
86
|
-
end
|
|
87
|
-
html
|
|
88
|
-
end
|
|
89
|
-
|
|
90
|
-
# TODO: remove level
|
|
91
|
-
def render_block(block, level: nil)
|
|
92
|
-
html = ''
|
|
93
|
-
case block
|
|
94
|
-
when Heading
|
|
95
|
-
lev = level
|
|
96
|
-
if level
|
|
97
|
-
lev = level + block.level - 1
|
|
98
|
-
else
|
|
99
|
-
lev = block.level
|
|
100
|
-
end
|
|
101
|
-
name = "h#{lev}"
|
|
102
|
-
html << "<#{name}>#{h(block.content)}</#{name}>"
|
|
103
|
-
when Paragraph
|
|
104
|
-
html << render_paragraph(block)
|
|
105
|
-
when Codeblock
|
|
106
|
-
html << "<pre><code>#{h(block.content)}</code></pre>"
|
|
107
|
-
when [] # huh? nop
|
|
108
|
-
when Section
|
|
109
|
-
render_block(block.heading)
|
|
110
|
-
block.blocks.each do |blo|
|
|
111
|
-
render_block(blo)
|
|
112
|
-
end
|
|
113
|
-
block.sections.each do |sec|
|
|
114
|
-
render_block(sec)
|
|
115
|
-
end
|
|
116
|
-
else
|
|
117
|
-
raise Error, block.inspect
|
|
118
|
-
end
|
|
119
|
-
html
|
|
120
|
-
end
|
|
121
|
-
|
|
122
|
-
def erb_render(path)
|
|
123
|
-
source = ::File.read(::File.join(__dir__, 'html_renderer', path))
|
|
124
|
-
ERB.new(source).result(binding)
|
|
125
|
-
end
|
|
126
|
-
|
|
127
|
-
def h(arg)
|
|
128
|
-
case arg
|
|
129
|
-
in String
|
|
130
|
-
CGI.escape_html(arg)
|
|
131
|
-
in Array
|
|
132
|
-
arg.map do |ele|
|
|
133
|
-
h(ele)
|
|
134
|
-
end.join
|
|
135
|
-
in Symbol
|
|
136
|
-
h(arg.to_s)
|
|
137
|
-
in Expression
|
|
138
|
-
h(arg.source)
|
|
139
|
-
in Integer
|
|
140
|
-
h(arg.to_s)
|
|
141
|
-
in Aside
|
|
142
|
-
h(arg.content)
|
|
143
|
-
end
|
|
144
|
-
end
|
|
145
|
-
|
|
146
|
-
extend Forwardable # :nodoc:
|
|
147
|
-
def_delegators :@file, :name, :synopsis, :commentary, :code, :header_line
|
|
148
|
-
end
|
|
149
|
-
end
|
data/lib/elisp2any/line.rb
DELETED
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
require 'strscan'
|
|
2
|
-
require 'forwardable'
|
|
3
|
-
require_relative 'inline_code'
|
|
4
|
-
require "elisp2any/comment"
|
|
5
|
-
require "elisp2any/text"
|
|
6
|
-
|
|
7
|
-
module Elisp2any
|
|
8
|
-
class Line
|
|
9
|
-
def self.scan(scanner)
|
|
10
|
-
pos = scanner.pos
|
|
11
|
-
comment = Comment.scan(scanner) or return
|
|
12
|
-
unless comment.colons == 2
|
|
13
|
-
scanner.pos = pos
|
|
14
|
-
return
|
|
15
|
-
end
|
|
16
|
-
unless comment.padding[0] == " "
|
|
17
|
-
raise Error, "line comment should have a whitespace padding"
|
|
18
|
-
end
|
|
19
|
-
content = "#{comment.padding[1..]}#{comment.content}"
|
|
20
|
-
new(Text.scan(content).to_a)
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
def initialize(chunks) # :nodoc:
|
|
24
|
-
@chunks = chunks
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
def self.parse(string) # :nodoc:
|
|
28
|
-
scanner = StringScanner.new(string)
|
|
29
|
-
chunks = []
|
|
30
|
-
|
|
31
|
-
until scanner.eos?
|
|
32
|
-
if scanner.skip(/`(?<content>[^']+)'/)
|
|
33
|
-
chunks << InlineCode.new(scanner[:content])
|
|
34
|
-
else
|
|
35
|
-
chunk = scanner.getch
|
|
36
|
-
if (last = chunks.last).is_a?(String)
|
|
37
|
-
last << chunk
|
|
38
|
-
else
|
|
39
|
-
chunks << chunk
|
|
40
|
-
end
|
|
41
|
-
end
|
|
42
|
-
end
|
|
43
|
-
|
|
44
|
-
new(chunks)
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
extend Forwardable # :nodoc:
|
|
48
|
-
def_delegators :@chunks, :each, :deconstruct
|
|
49
|
-
|
|
50
|
-
include Enumerable
|
|
51
|
-
end
|
|
52
|
-
end
|
data/lib/elisp2any/node.rb
DELETED
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
require_relative 'codeblock'
|
|
2
|
-
require_relative 'line'
|
|
3
|
-
require_relative 'heading'
|
|
4
|
-
require_relative 'paragraph'
|
|
5
|
-
require 'strscan'
|
|
6
|
-
|
|
7
|
-
module Elisp2any
|
|
8
|
-
# TODO: delete
|
|
9
|
-
class Node
|
|
10
|
-
attr_reader :range # :nodoc:
|
|
11
|
-
attr_reader :content
|
|
12
|
-
|
|
13
|
-
def self.from_tree_sitter(source, ts_node) #:nodoc:
|
|
14
|
-
nodes = []
|
|
15
|
-
(0 ... ts_node.child_count).map { |index| ts_node[index] }.each do |top_level_node|
|
|
16
|
-
range = top_level_node.start_byte .. top_level_node.end_byte
|
|
17
|
-
content = source.byteslice(range)
|
|
18
|
-
node = Node.new(content, range)
|
|
19
|
-
case top_level_node.type
|
|
20
|
-
when :comment
|
|
21
|
-
scanner = StringScanner.new(content)
|
|
22
|
-
scanner.skip(';') or raise Error, 'no semicolon for comment'
|
|
23
|
-
scanner.skip(';') or
|
|
24
|
-
begin
|
|
25
|
-
(last_node = nodes.last) && last_node.is_a?(Codeblock) or raise Error, 'no prior code for single semicolon comment'
|
|
26
|
-
last_node.append(source, range.end)
|
|
27
|
-
next
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
if (level = scanner.skip(/;+/))
|
|
31
|
-
scanner.skip(' ') or raise Error, 'no space after heading semicolons'
|
|
32
|
-
nodes << Heading.new(node, level, scanner.rest.chomp)
|
|
33
|
-
next
|
|
34
|
-
elsif scanner.skip("\n")
|
|
35
|
-
next
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
scanner.skip(' ') or raise Error, "no space after semicolons: #{scanner.inspect}"
|
|
39
|
-
line = Line.parse(scanner.rest)
|
|
40
|
-
if (last_node = nodes.last) && last_node.is_a?(Paragraph) && last_node.end_row + 1 == top_level_node.start_point.row
|
|
41
|
-
last_node << line
|
|
42
|
-
else
|
|
43
|
-
paragraph = Paragraph.new(node, [line], top_level_node.end_point.row)
|
|
44
|
-
nodes << paragraph
|
|
45
|
-
end
|
|
46
|
-
else
|
|
47
|
-
if (last_node = nodes.last) && last_node.is_a?(Codeblock)
|
|
48
|
-
last_node.append(source, range.end)
|
|
49
|
-
else
|
|
50
|
-
nodes << Codeblock.new(node)
|
|
51
|
-
end
|
|
52
|
-
end
|
|
53
|
-
end
|
|
54
|
-
nodes
|
|
55
|
-
end
|
|
56
|
-
|
|
57
|
-
def append(source, end_byte) # :nodoc:
|
|
58
|
-
@range = range = @range.begin .. end_byte
|
|
59
|
-
@content = source.byteslice(range)
|
|
60
|
-
end
|
|
61
|
-
|
|
62
|
-
def initialize(content, range) # :nodoc:
|
|
63
|
-
@content = content
|
|
64
|
-
@range = range
|
|
65
|
-
end
|
|
66
|
-
end
|
|
67
|
-
end
|
data/lib/elisp2any/paragraph.rb
DELETED
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
require 'forwardable'
|
|
2
|
-
require "elisp2any/line"
|
|
3
|
-
|
|
4
|
-
module Elisp2any
|
|
5
|
-
class Paragraph
|
|
6
|
-
def self.scan(scanner)
|
|
7
|
-
scanner = StringScanner.new(scanner) unless scanner.respond_to?(:skip)
|
|
8
|
-
lines = []
|
|
9
|
-
while (line = Line.scan(scanner))
|
|
10
|
-
lines << line
|
|
11
|
-
end
|
|
12
|
-
lines.empty? and return
|
|
13
|
-
new(:TODO, lines, :TODO)
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
# TODO: delete
|
|
17
|
-
attr_reader :end_row # :nodoc:
|
|
18
|
-
|
|
19
|
-
# TODO: delete node and end_row
|
|
20
|
-
def initialize(node, lines, end_row) # :nodoc:
|
|
21
|
-
@node = node
|
|
22
|
-
@lines = lines
|
|
23
|
-
@end_row = end_row
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
# TODO: delete
|
|
27
|
-
def code?
|
|
28
|
-
false
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
extend Forwardable # :nodoc:
|
|
32
|
-
def_delegators :@lines, :empty?, :clear, :<<, :each, :deconstruct, :size
|
|
33
|
-
def_delegators :@node, :adjucent?
|
|
34
|
-
|
|
35
|
-
include Enumerable
|
|
36
|
-
end
|
|
37
|
-
end
|
data/lib/elisp2any/section.rb
DELETED
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
require "forwardable"
|
|
2
|
-
require "elisp2any/heading"
|
|
3
|
-
require "elisp2any/blanklines"
|
|
4
|
-
require "elisp2any/text"
|
|
5
|
-
|
|
6
|
-
module Elisp2any
|
|
7
|
-
class Section
|
|
8
|
-
attr_reader :heading,
|
|
9
|
-
# TODO: gather blocks and sections
|
|
10
|
-
:blocks,
|
|
11
|
-
:sections
|
|
12
|
-
|
|
13
|
-
def self.scan(scanner)
|
|
14
|
-
heading = Heading.scan(scanner) or return
|
|
15
|
-
heading.content = Text.scan(heading.content)
|
|
16
|
-
Blanklines.scan(scanner) # optional
|
|
17
|
-
blocks = []
|
|
18
|
-
while (blo = Paragraph.scan(scanner) || Codeblock.scan(scanner))
|
|
19
|
-
blocks << blo
|
|
20
|
-
Blanklines.scan(scanner) # optional
|
|
21
|
-
end
|
|
22
|
-
pos = scanner.pos
|
|
23
|
-
sections = []
|
|
24
|
-
while (section = scan(scanner))
|
|
25
|
-
if section.level == heading.level + 1
|
|
26
|
-
sections << section
|
|
27
|
-
pos = scanner.pos
|
|
28
|
-
elsif section.level >= heading.level + 2
|
|
29
|
-
raise Error, "too demoted heading"
|
|
30
|
-
else
|
|
31
|
-
scanner.pos = pos
|
|
32
|
-
break
|
|
33
|
-
end
|
|
34
|
-
end
|
|
35
|
-
new(heading:, blocks:, sections:)
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
def initialize(heading:, blocks:, sections:)
|
|
39
|
-
@heading = heading
|
|
40
|
-
@blocks = blocks
|
|
41
|
-
@sections = sections
|
|
42
|
-
end
|
|
43
|
-
|
|
44
|
-
alias paragraphs blocks # TODO: delete
|
|
45
|
-
|
|
46
|
-
extend Forwardable # :nodoc:
|
|
47
|
-
def_delegator :@heading, :level
|
|
48
|
-
end
|
|
49
|
-
end
|
data/lib/elisp2any/text.rb
DELETED
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
require "forwardable"
|
|
2
|
-
|
|
3
|
-
module Elisp2any
|
|
4
|
-
class Text
|
|
5
|
-
def self.scan(scanner)
|
|
6
|
-
scanner = StringScanner.new(scanner) unless scanner.respond_to?(:skip)
|
|
7
|
-
tokens = []
|
|
8
|
-
until scanner.eos?
|
|
9
|
-
if scanner.skip(/`(?<content>[^']+)'/)
|
|
10
|
-
tokens << { code: scanner[:content] }
|
|
11
|
-
else
|
|
12
|
-
char = scanner.getch
|
|
13
|
-
case tokens
|
|
14
|
-
in [*, String => last]
|
|
15
|
-
last << char
|
|
16
|
-
else
|
|
17
|
-
tokens << char
|
|
18
|
-
end
|
|
19
|
-
end
|
|
20
|
-
end
|
|
21
|
-
new(tokens)
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
def initialize(tokens)
|
|
25
|
-
@tokens = tokens
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
extend Forwardable # :nodoc:
|
|
29
|
-
def_delegators :@tokens, :each, :deconstruct
|
|
30
|
-
|
|
31
|
-
include Enumerable
|
|
32
|
-
end
|
|
33
|
-
end
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
require 'tree_sitter'
|
|
2
|
-
|
|
3
|
-
module Elisp2any
|
|
4
|
-
class TreeSitterParser # :nodoc:
|
|
5
|
-
def self.parse(source)
|
|
6
|
-
new(source).parse
|
|
7
|
-
end
|
|
8
|
-
|
|
9
|
-
def parse
|
|
10
|
-
@node = parser.parse_string(nil, @source).root_node
|
|
11
|
-
end
|
|
12
|
-
|
|
13
|
-
private
|
|
14
|
-
|
|
15
|
-
def initialize(source)
|
|
16
|
-
@source = source
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
def parser
|
|
20
|
-
TreeSitter::Parser.new.tap do |p|
|
|
21
|
-
p.language = TreeSitter::Language.load('elisp', elisp_library)
|
|
22
|
-
end
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
def elisp_library
|
|
26
|
-
shared_object = 'libtree-sitter-elisp.so'
|
|
27
|
-
|
|
28
|
-
# Set this env var for Guix shell environment or shared object file is not found
|
|
29
|
-
if ENV['ELISP2ANY_GUIX_USE_PROFILE_PATH']
|
|
30
|
-
shared_object = ::File.join(ENV["GUIX_ENVIRONMENT"], "lib/tree-sitter", shared_object)
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
shared_object
|
|
34
|
-
end
|
|
35
|
-
end
|
|
36
|
-
end
|
data/lib/elisp2any/version.rb
DELETED
data/lib/elisp2any.rb
DELETED
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
require_relative 'elisp2any/version'
|
|
2
|
-
require_relative 'elisp2any/file'
|
|
3
|
-
require_relative 'elisp2any/heading'
|
|
4
|
-
|
|
5
|
-
module Elisp2any
|
|
6
|
-
autoload :HeaderLine, "elisp2any/header_line.rb"
|
|
7
|
-
autoload :Blanklines, "elisp2any/blanklines.rb"
|
|
8
|
-
Error = Class.new(StandardError)
|
|
9
|
-
|
|
10
|
-
def self.scan_filename(scanner) # :nodoc:
|
|
11
|
-
scanner.scan(/[a-z]+[.]el\b/)
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
def self.scan_variable(scanner) # :nodoc:
|
|
15
|
-
scanner.scan(/[a-z-]+\b/)
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
def self.scan_top_heading(scanner) # :nodoc:
|
|
19
|
-
pos = scanner.pos
|
|
20
|
-
heading = Heading.scan(scanner) or return
|
|
21
|
-
unless heading.level.zero?
|
|
22
|
-
scanner.pos = pos
|
|
23
|
-
return
|
|
24
|
-
end
|
|
25
|
-
heading.content
|
|
26
|
-
end
|
|
27
|
-
end
|