utopia-project 0.9.0 → 0.11.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b9fece64054731c29fd23e542e548d9da6e0105e62fef66fc6588b3a2637e5fe
4
- data.tar.gz: acda1b55bb672b64969496b9cc64f9e91c397ae3799c39af15417a3153d1628d
3
+ metadata.gz: '098dae8af0637c57f6b27ada06dd8a550b477187a40762681004fd147cd28590'
4
+ data.tar.gz: d3691badfcde2d47e3a174a9f8512d20ae6192f9f3ddd0f22a29d486b1ac22d4
5
5
  SHA512:
6
- metadata.gz: b0a9ceb4a8ac9cf660ca05f8941874ef16dd724f438b3be44033b96177227327087855058accfa8a6f34bbd6370c02a41cfdacf215d3a5c2956267c38b25a7ba
7
- data.tar.gz: c8b1f67c938eb4af0ae6be43a027a7fdea622e4e0253e481f82107965d547acdf3e54477de0f2019382b672fd7f9b237ab46aaa2161d45830ed82afccd44ea1e
6
+ metadata.gz: 4d119c825fd9da5284c3abfbb340a1bcf07458358c97a45ae01b567dd6bab64573d851632bb75c81b8b79a5b624d9269e0d199787ca816b64be1952d8a57eab9
7
+ data.tar.gz: c498be4408dd7b4397322145b55b77b1dbd10e91f24d2793072e722d700028d046b651ca4c7cff57958ff8ab8f6dd0f551d2ca3b9bd7491c4cc56e45d2831492
@@ -24,7 +24,7 @@ def serve(port: nil, bind: nil)
24
24
  end
25
25
 
26
26
  if port
27
- opttions << "--port" << port
27
+ options << "--port" << port
28
28
  end
29
29
 
30
30
  system("falcon", "serve", "--config", config_path, "--preload", preload_path, *options)
@@ -28,9 +28,9 @@ require 'decode'
28
28
 
29
29
  require 'thread/local'
30
30
 
31
- require 'kramdown'
32
-
31
+ require_relative 'document'
33
32
  require_relative 'guide'
33
+ require_relative 'linkify'
34
34
 
35
35
  module Utopia
36
36
  module Project
@@ -106,6 +106,16 @@ module Utopia
106
106
  end
107
107
  end
108
108
 
109
+ def linkify(text, definition, language: definition&.language)
110
+ rewriter = Linkify.new(self, language, text)
111
+
112
+ code = language.code_for(text, @index, relative_to: definition)
113
+
114
+ code.extract(rewriter)
115
+
116
+ return rewriter.apply
117
+ end
118
+
109
119
  # Format the given text in the context of the given definition and language.
110
120
  # See {document} for details.
111
121
  # @returns [Trenni::MarkupString]
@@ -126,41 +136,11 @@ module Utopia
126
136
 
127
137
  # Convert the given markdown text into HTML.
128
138
  #
129
- # - Updates source code references (`{language identifier}`) into links.
130
- # - Uses {Kramdown} to convert the text into HTML.
139
+ # Updates source code references (`{language identifier}`) into links.
131
140
  #
132
- # @returns [Kramdown::Document]
141
+ # @returns [Document]
133
142
  def document(text, definition = nil, language: definition&.language)
134
- text = text&.gsub(/(?<!`){(.*?)}/) do |match|
135
- linkify($1, definition, language: language)
136
- end
137
-
138
- return Kramdown::Document.new(text, syntax_highlighter: nil)
139
- end
140
-
141
- # Replace source code references in the given text with HTML anchors.
142
- #
143
- # @returns [Trenni::Builder]
144
- def linkify(text, definition = nil, language: definition&.language)
145
- reference = @index.languages.parse_reference(text, default_language: language)
146
-
147
- Trenni::Builder.fragment do |builder|
148
- if reference and definition = @index.lookup(reference, relative_to: definition)&.first
149
- builder.inline('a', href: link_for(definition)) do
150
- builder.inline('code', class: "language-#{definition.language.name}") do
151
- builder.text definition.qualified_form
152
- end
153
- end
154
- elsif reference
155
- builder.inline('code', class: "language-#{reference.language.name}") do
156
- builder.text text
157
- end
158
- else
159
- builder.inline('code') do
160
- builder.text text
161
- end
162
- end
163
- end
143
+ Document.new(text, self, definition: definition, default_language: language)
164
144
  end
165
145
 
166
146
  # Compute a unique string which can be used as `id` attribute in the HTML output.
@@ -0,0 +1,180 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright, 2020, by Samuel G. D. Williams. <http://www.codeotaku.com>
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.
22
+
23
+ require 'markly'
24
+
25
+ module Utopia
26
+ module Project
27
+ class Document
28
+ def initialize(text, base = nil, definition: nil, default_language: nil)
29
+ @text = text
30
+ @base = base
31
+ @index = base&.index
32
+
33
+ @definition = definition
34
+ @default_language = default_language
35
+
36
+ @root = nil
37
+ end
38
+
39
+ def root
40
+ @root ||= resolve(Markly.parse(@text))
41
+ end
42
+
43
+ def first_child
44
+ self.root.first_child
45
+ end
46
+
47
+ def replace_section(name)
48
+ child = self.first_child
49
+
50
+ while child
51
+ if child.type == :header
52
+ header = child
53
+
54
+ # We found the matched header:
55
+ if header.first_child.to_plaintext.include?(name)
56
+ # Now subsequent children:
57
+ current = header.next
58
+ while current.type != :header and following = current.next
59
+ current.delete
60
+ current = following
61
+ end
62
+
63
+ return yield(header)
64
+ end
65
+ end
66
+
67
+ child = child.next
68
+ end
69
+ end
70
+
71
+ def to_html(node = self.root)
72
+ renderer = Markly::HTMLRenderer.new(ids: true, flags: Markly::UNSAFE)
73
+ Trenni::MarkupString.raw(renderer.render(node))
74
+ end
75
+
76
+ def paragraph_node(child)
77
+ node = Markly::Node.new(:paragraph)
78
+ node.append_child(child)
79
+ return node
80
+ end
81
+
82
+ def html_node(content, type = :html)
83
+ node = Markly::Node.new(:html)
84
+ node.string_content = content
85
+ return node
86
+ end
87
+
88
+ def inline_html_node(content)
89
+ node = Markly::Node.new(:inline_html)
90
+ node.string_content = content
91
+ return node
92
+ end
93
+
94
+ def text_node(content)
95
+ node = Markly::Node.new(:text)
96
+ node.string_content = content
97
+ return node
98
+ end
99
+
100
+ def link_node(title, url, child)
101
+ node = Markly::Node.new(:link)
102
+ node.title = title
103
+ node.url = url.to_s
104
+
105
+ node.append_child(child)
106
+
107
+ return node
108
+ end
109
+
110
+ def code_node(content, language)
111
+ if language
112
+ node = inline_html_node(
113
+ "<code class=\"language-#{language}\">#{Trenni::Strings.to_html(content)}</code>"
114
+ )
115
+ else
116
+ node = Markly::Node.new(:code)
117
+ node.string_content = content
118
+ return node
119
+ end
120
+
121
+ return node
122
+ end
123
+
124
+ private
125
+
126
+ # Replace source code references in the given text with HTML anchors.
127
+ #
128
+ def reference_node(content)
129
+ if reference = @index.languages.parse_reference(content, default_language: @default_language)
130
+ definition = @index.lookup(reference, relative_to: @definition)
131
+ end
132
+
133
+ if definition
134
+ link_node(reference.identifier, @base.link_for(definition),
135
+ code_node(definition.qualified_form, reference.language.name)
136
+ )
137
+ elsif reference
138
+ code_node(reference.identifier, reference.language.name)
139
+ else
140
+ code_node(content)
141
+ end
142
+ end
143
+
144
+ def resolve(root)
145
+ return root if @index.nil?
146
+
147
+ root.walk do |node|
148
+ if node.type == :text
149
+ content = node.string_content
150
+ offset = 0
151
+
152
+ while match = content.match(/{(?<reference>.*?)}/, offset)
153
+ a, b = match.offset(0)
154
+
155
+ if a > offset
156
+ node.insert_before(
157
+ text_node(content[offset...a])
158
+ )
159
+ end
160
+
161
+ node.insert_before(
162
+ reference_node(match[:reference])
163
+ )
164
+
165
+ offset = b
166
+ end
167
+
168
+ if offset == content.bytesize
169
+ node.delete
170
+ else
171
+ node.string_content = content[offset..-1]
172
+ end
173
+ end
174
+ end
175
+
176
+ return root
177
+ end
178
+ end
179
+ end
180
+ end
@@ -23,7 +23,6 @@
23
23
  require 'utopia/path'
24
24
  require 'trenni/reference'
25
25
  require 'decode'
26
- require 'kramdown'
27
26
 
28
27
  module Utopia
29
28
  module Project
@@ -64,25 +63,16 @@ module Utopia
64
63
  end
65
64
 
66
65
  # The document for the README, if one exists.
67
- # @returns [Kramdown::Document]
68
66
  def document
69
67
  if self.readme?
70
68
  @document ||= self.readme_document.tap do |document|
71
- root = document.root
72
- if element = root.children.first
73
- if element.type == :header
74
- @title = element.children.first.value
75
-
76
- # Remove the title:
77
- root.children.shift
78
-
79
- # Remove any blank lines:
80
- root.children.shift while root.children.first&.type == :blank
81
-
82
- # Read the description:
83
- root.children.first.options[:encoding] = root.options[:encoding]
84
- @description = Kramdown::Converter::Kramdown.convert(root.children.first).first
85
- end
69
+ child = document.first_child
70
+
71
+ if child.type == :header
72
+ @title = child.first_child.string_content
73
+
74
+ @description = child.next
75
+ child.delete
86
76
  end
87
77
  end
88
78
  end
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright, 2020, by Samuel G. D. Williams. <http://www.codeotaku.com>
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.
22
+
23
+ require 'decode/syntax/rewriter'
24
+
25
+ module Utopia
26
+ module Project
27
+ class Linkify < Decode::Syntax::Rewriter
28
+ # @parameter base [Base] The base data.
29
+ def initialize(base, language, text)
30
+ @base = base
31
+ @language = language
32
+
33
+ super(text)
34
+ end
35
+
36
+ def text_for(range)
37
+ text = super(range)
38
+
39
+ return Trenni::Strings.to_html(text)
40
+ end
41
+
42
+ def link_to(definition, text)
43
+ Trenni::Builder.fragment do |builder|
44
+ builder.inline('a', href: @base.link_for(definition)) do
45
+ builder.text(definition.qualified_name)
46
+ end
47
+ end
48
+ end
49
+
50
+ def apply(output = Trenni::Builder.new)
51
+ output.inline('code', class: "language-#{@language.name}") do
52
+ super
53
+ end
54
+
55
+ return output.to_str
56
+ end
57
+ end
58
+ end
59
+ end
@@ -22,6 +22,6 @@
22
22
 
23
23
  module Utopia
24
24
  module Project
25
- VERSION = "0.9.0"
25
+ VERSION = "0.11.3"
26
26
  end
27
27
  end
@@ -20,4 +20,4 @@
20
20
  end
21
21
  ?>)<?r
22
22
  end
23
- ?></nav>
23
+ ?></nav>
@@ -1,5 +1,3 @@
1
- <h2>Usage</h2>
2
-
3
1
  <p>Please browse the <a href="source/">source code index</a> or refer to the guides below.</p>
4
2
 
5
3
  <?r
@@ -12,10 +10,10 @@
12
10
  <?r if documentation = guide.documentation ?>
13
11
  #{base.format(documentation.text, language: guide.documentation.language)}
14
12
  <?r elsif description = guide.description ?>
15
- #{MarkupString.raw Kramdown::Document.new(description, syntax_highlighter: nil).to_html}
13
+ #{MarkupString.raw description.to_html}
16
14
  <?r else ?>
17
15
  <p>No description.</p>
18
16
  <?r end ?>
19
17
  <?r
20
18
  end
21
- ?>
19
+ ?>
@@ -5,21 +5,10 @@ on 'index' do
5
5
  @base = Utopia::Project::Base.instance
6
6
 
7
7
  if readme_path = @base.path_for('README.md')
8
- @document = Kramdown::Document.new(File.read(readme_path), syntax_highlighter: nil)
8
+ @document = Utopia::Project::Document.new(File.read(readme_path), @base)
9
9
 
10
- start = @document.root.children.index{|node| node.children.first&.value == "Usage"}
11
- finish = start + 1
12
-
13
- while node = @document.root.children[finish]
14
- if node.type == :header
15
- break
16
- else
17
- finish += 1
18
- end
10
+ @document.replace_section("Usage") do |header|
11
+ header.insert_after(@document.html_node("<content:usage/>"))
19
12
  end
20
-
21
- @document.root.children[start...finish] = [
22
- Kramdown::Element.new(:raw, "<content:usage/>")
23
- ]
24
13
  end
25
14
  end
@@ -1,17 +1,18 @@
1
1
  <content:page>
2
2
  <?r
3
3
  if document = self[:document]
4
- children = document.root.children
4
+ child = document.first_child
5
5
 
6
- if children.first.type == :header
7
- header = children.shift
8
- title = header.children.first
6
+ if child.type == :header
7
+ header = child
8
+ child.delete
9
+ title = header.first_child
10
+
9
11
  case title.type
10
12
  when :text
11
- ?><content:heading>#{title.value}</content:heading><?r
12
- when :img
13
- self.document.attributes[:title] ||= title.attr["alt"]
14
- ?><header><img src="#{title.attr["src"]}" /></header><?r
13
+ ?><content:heading>#{title.string_content}</content:heading><?r
14
+ when :image
15
+ ?><header><img src="#{title.url}" /></header><?r
15
16
  else
16
17
  ?><content:heading>Project</content:heading><?r
17
18
  end