markly 0.7.0 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/conduct.md +133 -0
  4. data/ext/markly/arena.c +9 -8
  5. data/ext/markly/autolink.c +217 -134
  6. data/ext/markly/blocks.c +27 -2
  7. data/ext/markly/cmark-gfm-core-extensions.h +11 -11
  8. data/ext/markly/cmark-gfm-extension_api.h +1 -0
  9. data/ext/markly/cmark-gfm.h +18 -2
  10. data/ext/markly/cmark.c +3 -3
  11. data/ext/markly/commonmark.c +19 -34
  12. data/ext/markly/extconf.rb +8 -1
  13. data/ext/markly/html.c +22 -6
  14. data/ext/markly/inlines.c +148 -51
  15. data/ext/markly/latex.c +6 -4
  16. data/ext/markly/man.c +7 -11
  17. data/ext/markly/map.c +11 -4
  18. data/ext/markly/map.h +5 -2
  19. data/ext/markly/markly.c +582 -586
  20. data/ext/markly/markly.h +1 -1
  21. data/ext/markly/node.c +76 -10
  22. data/ext/markly/node.h +42 -1
  23. data/ext/markly/parser.h +1 -0
  24. data/ext/markly/plaintext.c +12 -29
  25. data/ext/markly/references.c +1 -0
  26. data/ext/markly/render.c +15 -7
  27. data/ext/markly/scanners.c +13916 -10380
  28. data/ext/markly/scanners.h +8 -0
  29. data/ext/markly/scanners.re +47 -8
  30. data/ext/markly/strikethrough.c +1 -1
  31. data/ext/markly/table.c +81 -31
  32. data/ext/markly/xml.c +2 -1
  33. data/lib/markly/flags.rb +16 -0
  34. data/lib/markly/node/inspect.rb +59 -53
  35. data/lib/markly/node.rb +125 -58
  36. data/lib/markly/renderer/generic.rb +129 -124
  37. data/lib/markly/renderer/html.rb +294 -275
  38. data/lib/markly/version.rb +7 -1
  39. data/lib/markly.rb +36 -30
  40. data/license.md +39 -0
  41. data/readme.md +36 -0
  42. data.tar.gz.sig +0 -0
  43. metadata +61 -29
  44. metadata.gz.sig +0 -0
  45. data/bin/markly +0 -94
  46. data/lib/markly/markly.bundle +0 -0
data/lib/markly/node.rb CHANGED
@@ -1,72 +1,139 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # Released under the MIT License.
4
+ # Copyright, 2016-2019, by Garen Torikian.
5
+ # Copyright, 2016-2017, by Yuki Izumi.
6
+ # Copyright, 2017, by Goro Fuji.
7
+ # Copyright, 2018, by Jerry van Leeuwen.
8
+ # Copyright, 2020-2023, by Samuel Williams.
9
+
3
10
  require_relative 'node/inspect'
4
11
 
5
12
  module Markly
6
- class Node
7
- include Enumerable
8
- include Inspect
9
-
10
- # Public: An iterator that "walks the tree," descending into children recursively.
11
- #
12
- # blk - A {Proc} representing the action to take for each child
13
- def walk(&block)
14
- return enum_for(:walk) unless block_given?
13
+ class Node
14
+ include Enumerable
15
+ include Inspect
15
16
 
16
- yield self
17
- each do |child|
18
- child.walk(&block)
19
- end
20
- end
17
+ # Public: An iterator that "walks the tree," descending into children recursively.
18
+ #
19
+ # blk - A {Proc} representing the action to take for each child
20
+ def walk(&block)
21
+ return enum_for(:walk) unless block_given?
21
22
 
22
- # Public: Convert the node to an HTML string.
23
- #
24
- # options - A {Symbol} or {Array of Symbol}s indicating the render options
25
- # extensions - An {Array of Symbol}s indicating the extensions to use
26
- #
27
- # Returns a {String}.
28
- def to_html(flags: DEFAULT, extensions: [])
29
- _render_html(flags, extensions).force_encoding('utf-8')
30
- end
23
+ yield self
24
+ each do |child|
25
+ child.walk(&block)
26
+ end
27
+ end
31
28
 
32
- # Public: Convert the node to a CommonMark string.
33
- #
34
- # options - A {Symbol} or {Array of Symbol}s indicating the render options
35
- # width - Column to wrap the output at
36
- #
37
- # Returns a {String}.
38
- def to_commonmark(flags: DEFAULT, width: 120)
39
- _render_commonmark(flags, width).force_encoding('utf-8')
40
- end
29
+ # Public: Convert the node to an HTML string.
30
+ #
31
+ # options - A {Symbol} or {Array of Symbol}s indicating the render options
32
+ # extensions - An {Array of Symbol}s indicating the extensions to use
33
+ #
34
+ # Returns a {String}.
35
+ def to_html(flags: DEFAULT, extensions: [])
36
+ _render_html(flags, extensions).force_encoding('utf-8')
37
+ end
41
38
 
42
- alias to_markdown to_commonmark
39
+ # Public: Convert the node to a CommonMark string.
40
+ #
41
+ # options - A {Symbol} or {Array of Symbol}s indicating the render options
42
+ # width - Column to wrap the output at
43
+ #
44
+ # Returns a {String}.
45
+ def to_commonmark(flags: DEFAULT, width: 120)
46
+ _render_commonmark(flags, width).force_encoding('utf-8')
47
+ end
43
48
 
44
- # Public: Convert the node to a plain text string.
45
- #
46
- # options - A {Symbol} or {Array of Symbol}s indicating the render options
47
- # width - Column to wrap the output at
48
- #
49
- # Returns a {String}.
50
- def to_plaintext(flags: DEFAULT, width: 120)
51
- _render_plaintext(flags, width).force_encoding('utf-8')
52
- end
49
+ alias to_markdown to_commonmark
53
50
 
54
- # Public: Iterate over the children (if any) of the current pointer.
55
- def each
56
- return enum_for(:each) unless block_given?
51
+ # Public: Convert the node to a plain text string.
52
+ #
53
+ # options - A {Symbol} or {Array of Symbol}s indicating the render options
54
+ # width - Column to wrap the output at
55
+ #
56
+ # Returns a {String}.
57
+ def to_plaintext(flags: DEFAULT, width: 120)
58
+ _render_plaintext(flags, width).force_encoding('utf-8')
59
+ end
57
60
 
58
- child = first_child
59
- while child
60
- nextchild = child.next
61
- yield child
62
- child = nextchild
63
- end
64
- end
61
+ # Public: Iterate over the children (if any) of the current pointer.
62
+ def each
63
+ return enum_for(:each) unless block_given?
65
64
 
66
- # Deprecated: Please use `each` instead
67
- def each_child(&block)
68
- warn '[DEPRECATION] `each_child` is deprecated. Please use `each` instead.'
69
- each(&block)
70
- end
71
- end
65
+ child = first_child
66
+ while child
67
+ next_child = child.next
68
+ yield child
69
+ child = next_child
70
+ end
71
+ end
72
+
73
+ def find_header(title)
74
+ each do |child|
75
+ if child.type == :header && child.first_child.string_content == title
76
+ return child
77
+ end
78
+ end
79
+ end
80
+
81
+ # Delete all nodes until the block returns true.
82
+ #
83
+ # @returns [Markly::Node] the node that returned true.
84
+ def delete_until
85
+ current = self
86
+ while current
87
+ return current if yield(current)
88
+ next_node = current.next
89
+ current.delete
90
+ current = next_node
91
+ end
92
+ end
93
+
94
+ # Replace a section (header + content) with a new node.
95
+ #
96
+ # @parameter title [String] the title of the section to replace.
97
+ # @parameter new_node [Markly::Node] the node to replace the section with.
98
+ # @parameter replace_header [Boolean] whether to replace the header itself or not.
99
+ # @parameter remove_subsections [Boolean] whether to remove subsections or not.
100
+ def replace_section(new_node, replace_header: true, remove_subsections: true)
101
+ # Delete until the next heading:
102
+ self.next&.delete_until do |node|
103
+ node.type == :heading && (!remove_subsections || node.header_level <= self.header_level)
104
+ end
105
+
106
+ self.append_after(new_node) if new_node
107
+ self.delete if replace_header
108
+ end
109
+
110
+ def next_heading
111
+ current = self.next
112
+ while current
113
+ if current.type == :heading
114
+ return current
115
+ end
116
+ current = current.next
117
+ end
118
+ end
119
+
120
+ # Append the given node after the current node.
121
+ #
122
+ # It's okay to provide a document node, it's children will be appended.
123
+ #
124
+ # @parameter node [Markly::Node] the node to append.
125
+ def append_after(node)
126
+ if node.type == :document
127
+ node = node.first_child
128
+ end
129
+
130
+ current = self
131
+ while node
132
+ next_node = node.next
133
+ current.insert_after(node)
134
+ current = node
135
+ node = next_node
136
+ end
137
+ end
138
+ end
72
139
  end
@@ -1,131 +1,136 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # Released under the MIT License.
4
+ # Copyright, 2015-2019, by Garen Torikian.
5
+ # Copyright, 2016-2017, by Yuki Izumi.
6
+ # Copyright, 2020-2023, by Samuel Williams.
7
+
3
8
  require 'set'
4
9
  require 'stringio'
5
10
 
6
11
  module Markly
7
- module Renderer
8
- class Generic
9
- def initialize(flags: DEFAULT, extensions: [])
10
- @flags = flags
11
- @stream = StringIO.new(+'')
12
- @need_blocksep = false
13
- @in_tight = false
14
- @in_plain = false
15
- @tagfilter = extensions.include?(:tagfilter)
16
- end
17
-
18
- attr_accessor :in_tight
19
- attr_accessor :in_plain
20
-
21
- def out(*args)
22
- args.each do |arg|
23
- if arg == :children
24
- @node.each { |child| out(child) }
25
- elsif arg.is_a?(Array)
26
- arg.each { |x| render(x) }
27
- elsif arg.is_a?(Node)
28
- render(arg)
29
- else
30
- @stream.write(arg)
31
- end
32
- end
33
- end
34
-
35
- def render(node)
36
- @node = node
37
- if node.type == :document
38
- document(node)
39
- @stream.string
40
- elsif @in_plain && node.type != :text && node.type != :softbreak
41
- node.each { |child| render(child) }
42
- else
43
- send(node.type, node)
44
- end
45
- end
46
-
47
- def document(_node)
48
- out(:children)
49
- end
50
-
51
- def code_block(node)
52
- code_block(node)
53
- end
54
-
55
- def reference_def(_node); end
56
-
57
- def cr
58
- return if @stream.string.empty? || @stream.string[-1] == "\n"
59
-
60
- out("\n")
61
- end
62
-
63
- def blocksep
64
- out("\n")
65
- end
66
-
67
- def containersep
68
- cr unless @in_tight
69
- end
70
-
71
- def block
72
- cr
73
- yield
74
- cr
75
- end
76
-
77
- def container(starter, ender)
78
- out(starter)
79
- yield
80
- out(ender)
81
- end
82
-
83
- def plain
84
- old_in_plain = @in_plain
85
- @in_plain = true
86
- yield
87
- @in_plain = old_in_plain
88
- end
89
-
90
- private
91
-
92
- def escape_href(str)
93
- @node.html_escape_href(str)
94
- end
95
-
96
- def escape_html(str)
97
- @node.html_escape_html(str)
98
- end
99
-
100
- def tagfilter(str)
101
- if @tagfilter
102
- str.gsub(
103
- %r{
104
- <
105
- (
106
- title|textarea|style|xmp|iframe|
107
- noembed|noframes|script|plaintext
108
- )
109
- (?=\s|>|/>)
110
- }xi,
111
- '&lt;\1'
112
- )
113
- else
114
- str
115
- end
116
- end
117
-
118
- def source_position(node)
119
- return '' unless flag_enabled?(SOURCE_POSITION)
120
-
121
- s = node.source_position
122
- " data-sourcepos=\"#{s[:start_line]}:#{s[:start_column]}-" \
123
- "#{s[:end_line]}:#{s[:end_column]}\""
124
- end
125
-
126
- def flag_enabled?(flag)
127
- (@flags & flag) != 0
128
- end
129
- end
130
- end
12
+ module Renderer
13
+ class Generic
14
+ def initialize(flags: DEFAULT, extensions: [])
15
+ @flags = flags
16
+ @stream = StringIO.new(+'')
17
+ @need_blocksep = false
18
+ @in_tight = false
19
+ @in_plain = false
20
+ @tagfilter = extensions.include?(:tagfilter)
21
+ end
22
+
23
+ attr_accessor :in_tight
24
+ attr_accessor :in_plain
25
+
26
+ def out(*args)
27
+ args.each do |arg|
28
+ if arg == :children
29
+ @node.each { |child| out(child) }
30
+ elsif arg.is_a?(Array)
31
+ arg.each { |x| render(x) }
32
+ elsif arg.is_a?(Node)
33
+ render(arg)
34
+ else
35
+ @stream.write(arg)
36
+ end
37
+ end
38
+ end
39
+
40
+ def render(node)
41
+ @node = node
42
+ if node.type == :document
43
+ document(node)
44
+ @stream.string
45
+ elsif @in_plain && node.type != :text && node.type != :softbreak
46
+ node.each { |child| render(child) }
47
+ else
48
+ send(node.type, node)
49
+ end
50
+ end
51
+
52
+ def document(_node)
53
+ out(:children)
54
+ end
55
+
56
+ def code_block(node)
57
+ code_block(node)
58
+ end
59
+
60
+ def reference_def(_node); end
61
+
62
+ def cr
63
+ return if @stream.string.empty? || @stream.string[-1] == "\n"
64
+
65
+ out("\n")
66
+ end
67
+
68
+ def blocksep
69
+ out("\n")
70
+ end
71
+
72
+ def containersep
73
+ cr unless @in_tight
74
+ end
75
+
76
+ def block
77
+ cr
78
+ yield
79
+ cr
80
+ end
81
+
82
+ def container(starter, ender)
83
+ out(starter)
84
+ yield
85
+ out(ender)
86
+ end
87
+
88
+ def plain
89
+ old_in_plain = @in_plain
90
+ @in_plain = true
91
+ yield
92
+ @in_plain = old_in_plain
93
+ end
94
+
95
+ private
96
+
97
+ def escape_href(str)
98
+ @node.html_escape_href(str)
99
+ end
100
+
101
+ def escape_html(str)
102
+ @node.html_escape_html(str)
103
+ end
104
+
105
+ def tagfilter(str)
106
+ if @tagfilter
107
+ str.gsub(
108
+ %r{
109
+ <
110
+ (
111
+ title|textarea|style|xmp|iframe|
112
+ noembed|noframes|script|plaintext
113
+ )
114
+ (?=\s|>|/>)
115
+ }xi,
116
+ '&lt;\1'
117
+ )
118
+ else
119
+ str
120
+ end
121
+ end
122
+
123
+ def source_position(node)
124
+ return '' unless flag_enabled?(SOURCE_POSITION)
125
+
126
+ s = node.source_position
127
+ " data-sourcepos=\"#{s[:start_line]}:#{s[:start_column]}-" \
128
+ "#{s[:end_line]}:#{s[:end_column]}\""
129
+ end
130
+
131
+ def flag_enabled?(flag)
132
+ (@flags & flag) != 0
133
+ end
134
+ end
135
+ end
131
136
  end