qiita_marker 0.23.6.2 → 0.23.9.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.
@@ -15,6 +15,10 @@ bufsize_t _scan_autolink_uri(const unsigned char *p);
15
15
  bufsize_t _scan_autolink_email(const unsigned char *p);
16
16
  bufsize_t _scan_html_tag(const unsigned char *p);
17
17
  bufsize_t _scan_liberal_html_tag(const unsigned char *p);
18
+ bufsize_t _scan_html_comment(const unsigned char *p);
19
+ bufsize_t _scan_html_pi(const unsigned char *p);
20
+ bufsize_t _scan_html_declaration(const unsigned char *p);
21
+ bufsize_t _scan_html_cdata(const unsigned char *p);
18
22
  bufsize_t _scan_html_block_start(const unsigned char *p);
19
23
  bufsize_t _scan_html_block_start_7(const unsigned char *p);
20
24
  bufsize_t _scan_html_block_end_1(const unsigned char *p);
@@ -37,6 +41,10 @@ bufsize_t _scan_footnote_definition(const unsigned char *p);
37
41
  #define scan_autolink_email(c, n) _scan_at(&_scan_autolink_email, c, n)
38
42
  #define scan_html_tag(c, n) _scan_at(&_scan_html_tag, c, n)
39
43
  #define scan_liberal_html_tag(c, n) _scan_at(&_scan_liberal_html_tag, c, n)
44
+ #define scan_html_comment(c, n) _scan_at(&_scan_html_comment, c, n)
45
+ #define scan_html_pi(c, n) _scan_at(&_scan_html_pi, c, n)
46
+ #define scan_html_declaration(c, n) _scan_at(&_scan_html_declaration, c, n)
47
+ #define scan_html_cdata(c, n) _scan_at(&_scan_html_cdata, c, n)
40
48
  #define scan_html_block_start(c, n) _scan_at(&_scan_html_block_start, c, n)
41
49
  #define scan_html_block_start_7(c, n) _scan_at(&_scan_html_block_start_7, c, n)
42
50
  #define scan_html_block_end_1(c, n) _scan_at(&_scan_html_block_end_1, c, n)
@@ -67,6 +67,7 @@ static delimiter *insert(cmark_syntax_extension *self, cmark_parser *parser,
67
67
  strikethrough->end_column = closer->inl_text->start_column + closer->inl_text->as.literal.len - 1;
68
68
  cmark_node_free(closer->inl_text);
69
69
 
70
+ done:
70
71
  delim = closer;
71
72
  while (delim != NULL && delim != opener) {
72
73
  tmp_delim = delim->previous;
@@ -76,7 +77,6 @@ static delimiter *insert(cmark_syntax_extension *self, cmark_parser *parser,
76
77
 
77
78
  cmark_inline_parser_remove_delimiter(inline_parser, opener);
78
79
 
79
- done:
80
80
  return res;
81
81
  }
82
82
 
@@ -11,13 +11,21 @@
11
11
  #include "table.h"
12
12
  #include "cmark-gfm-core-extensions.h"
13
13
 
14
+ // Custom node flag, initialized in `create_table_extension`.
15
+ static cmark_node_internal_flags CMARK_NODE__TABLE_VISITED;
16
+
14
17
  cmark_node_type CMARK_NODE_TABLE, CMARK_NODE_TABLE_ROW,
15
18
  CMARK_NODE_TABLE_CELL;
16
19
 
20
+ typedef struct {
21
+ cmark_strbuf *buf;
22
+ int start_offset, end_offset, internal_offset;
23
+ } node_cell;
24
+
17
25
  typedef struct {
18
26
  uint16_t n_columns;
19
27
  int paragraph_offset;
20
- cmark_llist *cells;
28
+ node_cell *cells;
21
29
  } table_row;
22
30
 
23
31
  typedef struct {
@@ -29,24 +37,24 @@ typedef struct {
29
37
  bool is_header;
30
38
  } node_table_row;
31
39
 
32
- typedef struct {
33
- cmark_strbuf *buf;
34
- int start_offset, end_offset, internal_offset;
35
- } node_cell;
36
-
37
- static void free_table_cell(cmark_mem *mem, void *data) {
38
- node_cell *cell = (node_cell *)data;
40
+ static void free_table_cell(cmark_mem *mem, node_cell *cell) {
39
41
  cmark_strbuf_free((cmark_strbuf *)cell->buf);
40
42
  mem->free(cell->buf);
41
- mem->free(cell);
43
+ }
44
+
45
+ static void free_row_cells(cmark_mem *mem, table_row *row) {
46
+ while (row->n_columns > 0) {
47
+ free_table_cell(mem, &row->cells[--row->n_columns]);
48
+ }
49
+ mem->free(row->cells);
50
+ row->cells = NULL;
42
51
  }
43
52
 
44
53
  static void free_table_row(cmark_mem *mem, table_row *row) {
45
54
  if (!row)
46
55
  return;
47
56
 
48
- cmark_llist_free_full(mem, row->cells, (cmark_free_func)free_table_cell);
49
-
57
+ free_row_cells(mem, row);
50
58
  mem->free(row);
51
59
  }
52
60
 
@@ -111,6 +119,24 @@ static cmark_strbuf *unescape_pipes(cmark_mem *mem, unsigned char *string, bufsi
111
119
  return res;
112
120
  }
113
121
 
122
+ // Adds a new cell to the end of the row. A pointer to the new cell is returned
123
+ // for the caller to initialize.
124
+ static node_cell* append_row_cell(cmark_mem *mem, table_row *row) {
125
+ const uint32_t n_columns = row->n_columns + 1;
126
+ // realloc when n_columns is a power of 2
127
+ if ((n_columns & (n_columns-1)) == 0) {
128
+ // make sure we never wrap row->n_columns
129
+ // offset will != len and our exit will clean up as intended
130
+ if (n_columns > UINT16_MAX) {
131
+ return NULL;
132
+ }
133
+ // Use realloc to double the size of the buffer.
134
+ row->cells = (node_cell *)mem->realloc(row->cells, (2 * n_columns - 1) * sizeof(node_cell));
135
+ }
136
+ row->n_columns = (uint16_t)n_columns;
137
+ return &row->cells[n_columns-1];
138
+ }
139
+
114
140
  static table_row *row_from_string(cmark_syntax_extension *self,
115
141
  cmark_parser *parser, unsigned char *string,
116
142
  int len) {
@@ -152,24 +178,22 @@ static table_row *row_from_string(cmark_syntax_extension *self,
152
178
  cell_matched);
153
179
  cmark_strbuf_trim(cell_buf);
154
180
 
155
- node_cell *cell = (node_cell *)parser->mem->calloc(1, sizeof(*cell));
181
+ node_cell *cell = append_row_cell(parser->mem, row);
182
+ if (!cell) {
183
+ int_overflow_abort = 1;
184
+ cmark_strbuf_free(cell_buf);
185
+ parser->mem->free(cell_buf);
186
+ break;
187
+ }
156
188
  cell->buf = cell_buf;
157
189
  cell->start_offset = offset;
158
190
  cell->end_offset = offset + cell_matched - 1;
191
+ cell->internal_offset = 0;
159
192
 
160
- while (cell->start_offset > 0 && string[cell->start_offset - 1] != '|') {
193
+ while (cell->start_offset > row->paragraph_offset && string[cell->start_offset - 1] != '|') {
161
194
  --cell->start_offset;
162
195
  ++cell->internal_offset;
163
196
  }
164
-
165
- // make sure we never wrap row->n_columns
166
- // offset will != len and our exit will clean up as intended
167
- if (row->n_columns == UINT16_MAX) {
168
- int_overflow_abort = 1;
169
- break;
170
- }
171
- row->n_columns += 1;
172
- row->cells = cmark_llist_append(parser->mem, row->cells, cell);
173
197
  }
174
198
 
175
199
  offset += cell_matched + pipe_matched;
@@ -187,9 +211,7 @@ static table_row *row_from_string(cmark_syntax_extension *self,
187
211
  if (row_end_offset && offset != len) {
188
212
  row->paragraph_offset = offset;
189
213
 
190
- cmark_llist_free_full(parser->mem, row->cells, (cmark_free_func)free_table_cell);
191
- row->cells = NULL;
192
- row->n_columns = 0;
214
+ free_row_cells(parser->mem, row);
193
215
 
194
216
  // Scan past the (optional) leading pipe.
195
217
  offset += scan_table_cell_end(string, len, offset);
@@ -240,6 +262,10 @@ static cmark_node *try_opening_table_header(cmark_syntax_extension *self,
240
262
  const char *parent_string;
241
263
  uint16_t i;
242
264
 
265
+ if (parent_container->flags & CMARK_NODE__TABLE_VISITED) {
266
+ return parent_container;
267
+ }
268
+
243
269
  if (!scan_table_start(input, len, cmark_parser_get_first_nonspace(parser))) {
244
270
  return parent_container;
245
271
  }
@@ -267,6 +293,7 @@ static cmark_node *try_opening_table_header(cmark_syntax_extension *self,
267
293
  free_table_row(parser->mem, marker_row);
268
294
  free_table_row(parser->mem, header_row);
269
295
  cmark_arena_pop();
296
+ parent_container->flags |= CMARK_NODE__TABLE_VISITED;
270
297
  return parent_container;
271
298
  }
272
299
 
@@ -303,9 +330,8 @@ static cmark_node *try_opening_table_header(cmark_syntax_extension *self,
303
330
  // since we populate the alignments array based on marker_row->cells
304
331
  uint8_t *alignments =
305
332
  (uint8_t *)parser->mem->calloc(marker_row->n_columns, sizeof(uint8_t));
306
- cmark_llist *it = marker_row->cells;
307
- for (i = 0; it; it = it->next, ++i) {
308
- node_cell *node = (node_cell *)it->data;
333
+ for (i = 0; i < marker_row->n_columns; ++i) {
334
+ node_cell *node = &marker_row->cells[i];
309
335
  bool left = node->buf->ptr[0] == ':', right = node->buf->ptr[node->buf->size - 1] == ':';
310
336
 
311
337
  if (left && right)
@@ -328,10 +354,8 @@ static cmark_node *try_opening_table_header(cmark_syntax_extension *self,
328
354
  ntr->is_header = true;
329
355
 
330
356
  {
331
- cmark_llist *tmp;
332
-
333
- for (tmp = header_row->cells; tmp; tmp = tmp->next) {
334
- node_cell *cell = (node_cell *) tmp->data;
357
+ for (i = 0; i < header_row->n_columns; ++i) {
358
+ node_cell *cell = &header_row->cells[i];
335
359
  cmark_node *header_cell = cmark_parser_add_child(parser, table_header,
336
360
  CMARK_NODE_TABLE_CELL, parent_container->start_column + cell->start_offset);
337
361
  header_cell->start_line = header_cell->end_line = parent_container->start_line;
@@ -378,11 +402,10 @@ static cmark_node *try_opening_table_row(cmark_syntax_extension *self,
378
402
  }
379
403
 
380
404
  {
381
- cmark_llist *tmp;
382
405
  int i, table_columns = get_n_table_columns(parent_container);
383
406
 
384
- for (tmp = row->cells, i = 0; tmp && i < table_columns; tmp = tmp->next, ++i) {
385
- node_cell *cell = (node_cell *) tmp->data;
407
+ for (i = 0; i < row->n_columns && i < table_columns; ++i) {
408
+ node_cell *cell = &row->cells[i];
386
409
  cmark_node *node = cmark_parser_add_child(parser, table_row_block,
387
410
  CMARK_NODE_TABLE_CELL, parent_container->start_column + cell->start_offset);
388
411
  node->internal_offset = cell->internal_offset;
@@ -785,6 +808,7 @@ static int escape(cmark_syntax_extension *self, cmark_node *node, int c) {
785
808
  cmark_syntax_extension *create_table_extension(void) {
786
809
  cmark_syntax_extension *self = cmark_syntax_extension_new("table");
787
810
 
811
+ cmark_register_node_flag(&CMARK_NODE__TABLE_VISITED);
788
812
  cmark_syntax_extension_set_match_block_func(self, matches);
789
813
  cmark_syntax_extension_set_open_block_func(self, try_opening_table_block);
790
814
  cmark_syntax_extension_set_get_type_string_func(self, get_type_string);
@@ -11,6 +11,7 @@
11
11
  #include "syntax_extension.h"
12
12
 
13
13
  #define BUFFER_SIZE 100
14
+ #define MAX_INDENT 40
14
15
 
15
16
  // Functions to convert cmark_nodes to XML strings.
16
17
 
@@ -26,7 +27,7 @@ struct render_state {
26
27
 
27
28
  static CMARK_INLINE void indent(struct render_state *state) {
28
29
  int i;
29
- for (i = 0; i < state->indent; i++) {
30
+ for (i = 0; i < state->indent && i < MAX_INDENT; i++) {
30
31
  cmark_strbuf_putc(state->xml, ' ');
31
32
  }
32
33
  }
@@ -38,20 +38,22 @@ module QiitaMarker
38
38
  format: [:html, :xml, :commonmark, :plaintext].freeze,
39
39
  }.freeze
40
40
 
41
- def self.process_options(option, type)
42
- case option
43
- when Symbol
44
- OPTS.fetch(type).fetch(option)
45
- when Array
46
- raise TypeError if option.none?
41
+ class << self
42
+ def process_options(option, type)
43
+ case option
44
+ when Symbol
45
+ OPTS.fetch(type).fetch(option)
46
+ when Array
47
+ raise TypeError if option.none?
47
48
 
48
- # neckbearding around. the map will both check the opts and then bitwise-OR it
49
- OPTS.fetch(type).fetch_values(*option).inject(0, :|)
50
- else
51
- raise TypeError, "option type must be a valid symbol or array of symbols within the #{name}::OPTS[:#{type}] context"
49
+ # neckbearding around. the map will both check the opts and then bitwise-OR it
50
+ OPTS.fetch(type).fetch_values(*option).inject(0, :|)
51
+ else
52
+ raise TypeError, "option type must be a valid symbol or array of symbols within the #{name}::OPTS[:#{type}] context"
53
+ end
54
+ rescue KeyError => e
55
+ raise TypeError, "option ':#{e.key}' does not exist for #{name}::OPTS[:#{type}]"
52
56
  end
53
- rescue KeyError => e
54
- raise TypeError, "option ':#{e.key}' does not exist for #{name}::OPTS[:#{type}]"
55
57
  end
56
58
  end
57
59
  end
@@ -9,8 +9,15 @@ module QiitaMarker
9
9
 
10
10
  def header(node)
11
11
  block do
12
- out("<h", node.header_level, "#{sourcepos(node)}>", :children,
13
- "</h", node.header_level, ">")
12
+ out(
13
+ "<h",
14
+ node.header_level,
15
+ "#{sourcepos(node)}>",
16
+ :children,
17
+ "</h",
18
+ node.header_level,
19
+ ">",
20
+ )
14
21
  end
15
22
  end
16
23
 
@@ -133,8 +140,12 @@ module QiitaMarker
133
140
  out("<em>", :children, "</em>")
134
141
  end
135
142
 
136
- def strong(_)
137
- out("<strong>", :children, "</strong>")
143
+ def strong(node)
144
+ if node.parent&.type == :strong
145
+ out(:children)
146
+ else
147
+ out("<strong>", :children, "</strong>")
148
+ end
138
149
  end
139
150
 
140
151
  def link(node)
@@ -113,7 +113,7 @@ module QiitaMarker
113
113
  )
114
114
  (?=\s|>|/>)
115
115
  }xi,
116
- '&lt;\1'
116
+ '&lt;\1',
117
117
  )
118
118
  else
119
119
  str
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module QiitaMarker
4
- VERSION = "0.23.6.2"
4
+ VERSION = "0.23.9.0"
5
5
  end
data/lib/qiita_marker.rb CHANGED
@@ -12,32 +12,34 @@ begin
12
12
  require "awesome_print"
13
13
  rescue LoadError; end # rubocop:disable Lint/SuppressedException
14
14
  module QiitaMarker
15
- # Public: Parses a Markdown string into an HTML string.
16
- #
17
- # text - A {String} of text
18
- # option - Either a {Symbol} or {Array of Symbol}s indicating the render options
19
- # extensions - An {Array of Symbol}s indicating the extensions to use
20
- #
21
- # Returns a {String} of converted HTML.
22
- def self.render_html(text, options = :DEFAULT, extensions = [])
23
- raise TypeError, "text must be a String; got a #{text.class}!" unless text.is_a?(String)
15
+ class << self
16
+ # Public: Parses a Markdown string into an HTML string.
17
+ #
18
+ # text - A {String} of text
19
+ # option - Either a {Symbol} or {Array of Symbol}s indicating the render options
20
+ # extensions - An {Array of Symbol}s indicating the extensions to use
21
+ #
22
+ # Returns a {String} of converted HTML.
23
+ def render_html(text, options = :DEFAULT, extensions = [])
24
+ raise TypeError, "text must be a String; got a #{text.class}!" unless text.is_a?(String)
24
25
 
25
- opts = Config.process_options(options, :render)
26
- Node.markdown_to_html(text.encode("UTF-8"), opts, extensions)
27
- end
26
+ opts = Config.process_options(options, :render)
27
+ Node.markdown_to_html(text.encode("UTF-8"), opts, extensions)
28
+ end
28
29
 
29
- # Public: Parses a Markdown string into a `document` node.
30
- #
31
- # string - {String} to be parsed
32
- # option - A {Symbol} or {Array of Symbol}s indicating the parse options
33
- # extensions - An {Array of Symbol}s indicating the extensions to use
34
- #
35
- # Returns the `document` node.
36
- def self.render_doc(text, options = :DEFAULT, extensions = [])
37
- raise TypeError, "text must be a String; got a #{text.class}!" unless text.is_a?(String)
30
+ # Public: Parses a Markdown string into a `document` node.
31
+ #
32
+ # string - {String} to be parsed
33
+ # option - A {Symbol} or {Array of Symbol}s indicating the parse options
34
+ # extensions - An {Array of Symbol}s indicating the extensions to use
35
+ #
36
+ # Returns the `document` node.
37
+ def render_doc(text, options = :DEFAULT, extensions = [])
38
+ raise TypeError, "text must be a String; got a #{text.class}!" unless text.is_a?(String)
38
39
 
39
- opts = Config.process_options(options, :parse)
40
- text = text.encode("UTF-8")
41
- Node.parse_document(text, text.bytesize, opts, extensions)
40
+ opts = Config.process_options(options, :parse)
41
+ text = text.encode("UTF-8")
42
+ Node.parse_document(text, text.bytesize, opts, extensions)
43
+ end
42
44
  end
43
45
  end
data/qiita_marker.gemspec CHANGED
@@ -20,7 +20,7 @@ Gem::Specification.new do |s|
20
20
 
21
21
  s.executables = ["qiita_marker"]
22
22
  s.require_paths = ["lib", "ext"]
23
- s.required_ruby_version = [">= 2.7", "< 4.0"]
23
+ s.required_ruby_version = [">= 3.0", "< 4.0"]
24
24
 
25
25
  s.metadata["rubygems_mfa_required"] = "true"
26
26
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: qiita_marker
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.23.6.2
4
+ version: 0.23.9.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Qiita Inc.
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-11-21 00:00:00.000000000 Z
11
+ date: 2023-05-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: awesome_print
@@ -252,7 +252,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
252
252
  requirements:
253
253
  - - ">="
254
254
  - !ruby/object:Gem::Version
255
- version: '2.7'
255
+ version: '3.0'
256
256
  - - "<"
257
257
  - !ruby/object:Gem::Version
258
258
  version: '4.0'
@@ -262,7 +262,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
262
262
  - !ruby/object:Gem::Version
263
263
  version: '0'
264
264
  requirements: []
265
- rubygems_version: 3.1.4
265
+ rubygems_version: 3.2.33
266
266
  signing_key:
267
267
  specification_version: 4
268
268
  summary: Qiita Marker is a Ruby library for Markdown processing, based on CommonMarker.