mmmd 0.1.0 → 0.1.2

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8368bf270f4bdba9a1510c3c1f3106a5a56a43bdaf63673219bd7a082de436c6
4
- data.tar.gz: f7a9e9a9457be72c8ffae3edfb531d4193be174df5db1714fd215809a4c41825
3
+ metadata.gz: 1a8790d6e9e6e5a9e3164e1f6f3ecf019cc73876d231676c562eb33925cea1a1
4
+ data.tar.gz: 738942fca7cea39dbd6fd4fcb15b46d643646e5c5fbb90593f7bf330f967c8ae
5
5
  SHA512:
6
- metadata.gz: 53fea17654973076e1c9fab3256d8034577c04ea684ee64aaa620bf71bd228c98bed317f3c2b7028298a0eae7ccc6cef4587b3b95b83bc52396327f366d01544
7
- data.tar.gz: 469aba569708c8e2b88efa34bddf594ac6cd71fb389365e69ff3ef50fc09d7611eaf96c91bbe182ef52ba1c36505bf5df5a51ea733d0231defcaa4b72bb3ffca
6
+ metadata.gz: cc7e8c75e20ced1af9c502ebfc5453489c427a61f2c8b7e9e0fa26d50dcaf56df3f522c5e560fca0b27f4d06603ca8e6bb9a720f9dc00929c9c847f408301709
7
+ data.tar.gz: 03e2bcfff6462f28dc3439afdf02667a3944b6053e2b42da86fa2e1bfd4fffb8faa1bbfe2bcd4a0eaef006e6f22c9120a6cab365d475e294ccc3780e16dbba41
@@ -79,11 +79,12 @@ module PointBlank
79
79
  [process_destination(result[0].gsub(/\\(?=[><])/, '')[1..-2]),
80
80
  text.delete_prefix(result[0]).lstrip]
81
81
  elsif (result = text.match(/\A\S+/)) &&
82
- !result[0].start_with?('<') &&
83
- result &&
84
- balanced?(result[0])
85
- [process_destination(result[0]),
86
- text.delete_prefix(result[0]).lstrip]
82
+ (lnk = result[0]) &&
83
+ !lnk.start_with?('<') &&
84
+ (lnk = (ix = find_balanced_end(lnk)) ? lnk[..ix - 1] : lnk) &&
85
+ balanced?(lnk)
86
+ [process_destination(lnk),
87
+ text.delete_prefix(lnk).lstrip]
87
88
  else
88
89
  [nil, text]
89
90
  end
@@ -125,7 +126,7 @@ module PointBlank
125
126
  destination, remaining = read_destination(remaining[1..])
126
127
  return [nil, text] unless destination
127
128
 
128
- title, remaining = read_title(remaining)
129
+ title, remaining = read_title(remaining.lstrip)
129
130
  properties[:uri] = destination
130
131
  properties[:title] = title
131
132
  close_bracket = true
@@ -164,7 +165,7 @@ module PointBlank
164
165
  bracketcount += 1
165
166
  elsif part == ')'
166
167
  bracketcount -= 1
167
- return index if bracketcount.zero?
168
+ return index if bracketcount <= 0
168
169
  end
169
170
  index += part.length
170
171
  end
@@ -366,7 +367,7 @@ module PointBlank
366
367
 
367
368
  # (see ::PointBlank::Parsing::NullParser#consume)
368
369
  def consume(line, parent = nil, lazy: false)
369
- @lazy_triggered = lazy || @lazy_triggered
370
+ @lazy_triggered = lazy || @lazy_triggered unless line.strip.empty?
370
371
  return [nil, nil] if line.match?(/\A {0,3}\Z/)
371
372
  return [nil, nil] if @closed
372
373
  return [nil, nil] if check_candidates(line, parent)
@@ -956,9 +957,9 @@ module PointBlank
956
957
  parts = tokens
957
958
  @valid_parsers.each do |parser|
958
959
  newparts = []
959
- parts.each do |x|
960
+ parts.each_with_index do |x, i|
960
961
  if x.is_a? String
961
- newparts.append(*parser.tokenize(x))
962
+ newparts.append(*parser.tokenize(x, newparts.last, parts[i + 1]))
962
963
  else
963
964
  newparts.append(x)
964
965
  end
@@ -1012,8 +1013,10 @@ module PointBlank
1012
1013
 
1013
1014
  # Tokenize a string
1014
1015
  # @param string [String]
1016
+ # @param before [String, ::PointBlank::DOM::DOMObject]
1017
+ # @param after [String, ::PointBlank::DOM::DOMObject]
1015
1018
  # @return [Array<Array(String, Class, Symbol), String>]
1016
- def self.tokenize(string)
1019
+ def self.tokenize(string, _before, _after)
1017
1020
  [string]
1018
1021
  end
1019
1022
 
@@ -1141,18 +1144,11 @@ module PointBlank
1141
1144
  # Code inline parser
1142
1145
  class CodeInline < NullInline
1143
1146
  # (see ::PointBlank::Parsing::NullInline#tokenize)
1144
- def self.tokenize(string)
1145
- open = {}
1147
+ def self.tokenize(string, *_lookaround)
1146
1148
  iterate_tokens(string, "`") do |_before, current_text, matched|
1147
1149
  if matched
1148
1150
  match = current_text.match(/^`+/)[0]
1149
- if open[match]
1150
- open[match] = nil
1151
- [match, self, :close]
1152
- else
1153
- open[match] = true
1154
- [match, self, :open]
1155
- end
1151
+ [match, self, :open]
1156
1152
  else
1157
1153
  current_text[0]
1158
1154
  end
@@ -1169,9 +1165,9 @@ module PointBlank
1169
1165
  text = (part.is_a?(Array) ? part.first : part)
1170
1166
  buffer += text
1171
1167
  next unless part.is_a? Array
1168
+ next if idx.zero?
1172
1169
 
1173
- break (cutoff = idx) if part.first == opening &&
1174
- part.last == :close
1170
+ break (cutoff = idx) if part.first == opening
1175
1171
  end
1176
1172
  buffer = construct_literal(buffer[opening.length..(-1 - opening.length)])
1177
1173
  [cutoff.positive? ? build([buffer]) : opening, parts[(cutoff + 1)..]]
@@ -1181,7 +1177,7 @@ module PointBlank
1181
1177
  # Autolink inline parser
1182
1178
  class AutolinkInline < NullInline
1183
1179
  # (see ::PointBlank::Parsing::NullInline#tokenize)
1184
- def self.tokenize(string)
1180
+ def self.tokenize(string, *_lookaround)
1185
1181
  iterate_tokens(string, /[<>]/) do |_before, current_text, matched|
1186
1182
  if matched
1187
1183
  if current_text.start_with?("<")
@@ -1237,11 +1233,10 @@ module PointBlank
1237
1233
  linkinfo = capture[-1][2]
1238
1234
  obj = build(capture[1..-2])
1239
1235
  if linkinfo[:label]
1240
- if (props = doc.root.properties[:linkdefs][linkinfo[:label]])
1241
- linkinfo = props
1242
- else
1236
+ unless (props = doc.root.properties[:linkdefs][linkinfo[:label]])
1243
1237
  return nil
1244
1238
  end
1239
+ linkinfo = props
1245
1240
  end
1246
1241
  obj.properties = linkinfo
1247
1242
  obj
@@ -1276,7 +1271,7 @@ module PointBlank
1276
1271
  end
1277
1272
 
1278
1273
  # (see ::PointBlank::Parsing::NullInline#tokenize)
1279
- def self.tokenize(string)
1274
+ def self.tokenize(string, *_lookaround)
1280
1275
  iterate_tokens(string, /(?:!\[|\]\()/) do |_before, text, matched|
1281
1276
  next text[0] unless matched
1282
1277
  next ["![", self, :open] if text.start_with? "!["
@@ -1295,7 +1290,7 @@ module PointBlank
1295
1290
  end
1296
1291
 
1297
1292
  # (see ::PointBlank::Parsing::NullInline#tokenize)
1298
- def self.tokenize(string)
1293
+ def self.tokenize(string, *_lookaround)
1299
1294
  iterate_tokens(string, /(?:\[|\][(\[])/) do |_before, text, matched|
1300
1295
  next text[0] unless matched
1301
1296
  next ["[", self, :open] if text.start_with? "["
@@ -1307,20 +1302,61 @@ module PointBlank
1307
1302
  end
1308
1303
  end
1309
1304
 
1305
+ # TODO: this seems way too complicated for something that's supposed
1306
+ # to be a goddamn emphasis markup parser. i'd blame it on commonmark's
1307
+ # convoluted specs.
1308
+ # (P.S: it could be possible to make this easier for implementers by
1309
+ # making a claims system with pointers that do not modify the string
1310
+ # while it's being parsed. however that would just move complexity from
1311
+ # the parser into the scanner instead. and it does not resolve the
1312
+ # problem of overlapping claims as efficiently as simply splitting text
1313
+ # into tokens and remaining string bits.)
1314
+
1310
1315
  # Emphasis and strong emphasis inline parser
1311
1316
  class EmphInline < NullInline
1312
1317
  INFIX_TOKENS = /^[^\p{S}\p{P}\p{Zs}_]_++[^\p{S}\p{P}\p{Zs}_]$/
1313
1318
  # (see ::PointBlank::Parsing::NullInline#tokenize)
1314
- def self.tokenize(string)
1319
+ def self.tokenize(string, before, after)
1320
+ bfrb = extract_left(before)
1321
+ afra = extract_right(after)
1315
1322
  iterate_tokens(string, /(?:_++|\*++)/) do |bfr, text, matched|
1316
1323
  token, afr = text.match(/^(_++|\*++)(.?)/)[1..2]
1317
- left = left_token?(bfr[-1] || "", token, afr)
1318
- right = right_token?(bfr[-1] || "", token, afr)
1324
+ bfr = bfr[-1] || bfrb || ""
1325
+ afr = afr.empty? ? afra || "" : afr
1326
+ left = left_token?(bfr, token, afr)
1327
+ right = right_token?(bfr, token, afr)
1319
1328
  break_into_elements(token, [bfr[-1] || "", token, afr].join(''),
1320
1329
  left, right, matched)
1321
1330
  end
1322
1331
  end
1323
1332
 
1333
+ # Extract left-flanking token from before the tokenized string
1334
+ # @param bfr [String, ::PointBlank::DOM::DOMObject, Array(String, Class, Symbol)]
1335
+ # @return [String]
1336
+ def self.extract_left(bfr)
1337
+ case bfr
1338
+ when String
1339
+ bfr[-1]
1340
+ when ::PointBlank::DOM::DOMObject
1341
+ "."
1342
+ when Array
1343
+ bfr.first[-1]
1344
+ end
1345
+ end
1346
+
1347
+ # Extract right-flanking token from after the tokenized string
1348
+ # @param afr [String, ::PointBlank::DOM::DOMObject, Array(String, Class, Symbol)]
1349
+ # @return [String]
1350
+ def self.extract_right(afr)
1351
+ case afr
1352
+ when String
1353
+ afr[0]
1354
+ when ::PointBlank::DOM::DOMObject
1355
+ "."
1356
+ when Array
1357
+ afr.first[0]
1358
+ end
1359
+ end
1324
1360
  # Is this token, given these surrounding characters, left-flanking?
1325
1361
  # @param bfr [String]
1326
1362
  # @param token [String]
@@ -1385,8 +1421,9 @@ module PointBlank
1385
1421
  ((blk.first.length % 3).zero? &&
1386
1422
  (closer.first.length % 3).zero?))
1387
1423
  (open ? capture : before).prepend(blk)
1388
- next unless blk.is_a?(Array)
1389
- return backlog unless blk[1].check_contents(capture)
1424
+ next unless blk.is_a?(Array) && !open
1425
+
1426
+ return backlog unless closer[1].check_contents(capture)
1390
1427
  end
1391
1428
  return backlog if open
1392
1429
 
@@ -1430,7 +1467,7 @@ module PointBlank
1430
1467
  # Hard break
1431
1468
  class HardBreakInline < NullInline
1432
1469
  # (see ::PointBlank::Parsing::NullInline#tokenize)
1433
- def self.tokenize(string)
1470
+ def self.tokenize(string, *_lookaround)
1434
1471
  iterate_tokens(string, /(?: \n|\\\n)/) do |_before, token, matched|
1435
1472
  next ["\n", self, :close] if token.start_with?(" \n")
1436
1473
  next ["\n", self, :close] if matched
@@ -165,6 +165,12 @@ module MMMD
165
165
  TEXT
166
166
  end
167
167
 
168
+ # Draw a horizontal rule
169
+ def hrule(_text, options)
170
+ size = options[:hsize]
171
+ " #{'─' * (size - 2)} "
172
+ end
173
+
168
174
  # Draw text right-justified
169
175
  def rjust(text, options)
170
176
  size = options[:hsize]
@@ -314,11 +320,12 @@ module MMMD
314
320
  increase_level: true
315
321
  },
316
322
  "PointBlank::DOM::HorizontalRule" => {
317
- underline_full_block: true
323
+ hrule: true
318
324
  }
319
325
  }.freeze
320
326
 
321
327
  DEFAULT_EFFECT_PRIORITY = {
328
+ hrule: 10_500,
322
329
  numbered: 10_000,
323
330
  leftline: 9500,
324
331
  bullet: 9000,
data/test.md ADDED
@@ -0,0 +1 @@
1
+ tokens blahblah **[test](/pee)** more tokens
data/test2.md ADDED
@@ -0,0 +1,12 @@
1
+ > **Quote block**
2
+ >
3
+ > a**.not even emphasis.**b
4
+ >
5
+ > a**[neither is this emphasis](/uri 'but should it be?')**x
6
+ >
7
+ > **[emphasized image link ![image](/uri)](/link)**
8
+ >
9
+ > titlet
10
+ > ======
11
+ >
12
+ > amongus
data/test3.md ADDED
@@ -0,0 +1 @@
1
+ **test<http://autolink`>[stuff`[dat](#lonk)[`...](#stuff)**
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mmmd
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yessiest
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir:
10
10
  - bin
11
11
  cert_chain: []
12
- date: 2025-03-08 00:00:00.000000000 Z
12
+ date: 2012-01-01 00:00:00.000000000 Z
13
13
  dependencies: []
14
14
  description: |
15
15
  MMMD (short for Mark My Manuscript Down) is a Markdown processor
@@ -23,6 +23,9 @@ extra_rdoc_files:
23
23
  - README.md
24
24
  - architecture.md
25
25
  - security.md
26
+ - test.md
27
+ - test2.md
28
+ - test3.md
26
29
  files:
27
30
  - README.md
28
31
  - architecture.md
@@ -35,6 +38,9 @@ files:
35
38
  - lib/mmmd/renderers/plainterm.rb
36
39
  - lib/mmmd/util.rb
37
40
  - security.md
41
+ - test.md
42
+ - test2.md
43
+ - test3.md
38
44
  homepage: https://adastra7.net/git/Yessiest/rubymark
39
45
  licenses:
40
46
  - AGPL-3.0-or-later