kramdown-man 0.1.8 → 1.0.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.
@@ -1,20 +1,25 @@
1
- # encoding: utf-8
2
- require_relative '../man/version'
1
+ # frozen_string_literal: true
2
+
3
+ require 'kramdown/man/version'
3
4
 
4
5
  require 'kramdown/converter/base'
5
6
 
6
7
  module Kramdown
7
- module Converter
8
+ module Man
8
9
  #
9
10
  # Converts markdown into a roff man-page.
10
11
  #
11
- class Man < ::Kramdown::Converter::Base
12
+ # @since 1.0.0
13
+ #
14
+ # @api private
15
+ #
16
+ class Converter < Kramdown::Converter::Base
12
17
 
13
18
  # Comment header
14
- HEADER = [
15
- ".\\\" Generated by kramdown-man #{::Kramdown::Man::VERSION}",
16
- ".\\\" https://github.com/postmodern/kramdown-man#readme"
17
- ].join("\n")
19
+ HEADER = <<~ROFF
20
+ .\\\" Generated by kramdown-man #{VERSION}
21
+ .\\\" https://github.com/postmodern/kramdown-man#readme
22
+ ROFF
18
23
 
19
24
  # Typographic Symbols and their UTF8 chars
20
25
  TYPOGRAPHIC_SYMS = {
@@ -426,7 +431,7 @@ module Kramdown
426
431
  # The roff output.
427
432
  #
428
433
  def convert(root)
429
- "#{HEADER}\n#{convert_root(root)}"
434
+ "#{HEADER}#{convert_root(root)}"
430
435
  end
431
436
 
432
437
  #
@@ -439,9 +444,7 @@ module Kramdown
439
444
  # The roff output.
440
445
  #
441
446
  def convert_root(root)
442
- root.children.map { |child|
443
- convert_element(child)
444
- }.compact.join("\n")
447
+ convert_children_of(root)
445
448
  end
446
449
 
447
450
  #
@@ -455,20 +458,19 @@ module Kramdown
455
458
  #
456
459
  def convert_element(element)
457
460
  method = "convert_#{element.type}"
461
+
458
462
  send(method,element) if respond_to?(method)
459
463
  end
460
-
464
+
461
465
  #
462
466
  # Converts a `kd:blank` element.
463
467
  #
464
468
  # @param [Kramdown::Element] blank
465
469
  # A `kd:blank` element.
466
470
  #
467
- # @return [String]
468
- # The roff output.
471
+ # @return [nil]
469
472
  #
470
473
  def convert_blank(blank)
471
- '.LP'
472
474
  end
473
475
 
474
476
  #
@@ -481,7 +483,7 @@ module Kramdown
481
483
  # The roff output.
482
484
  #
483
485
  def convert_text(text)
484
- escape(text.value.gsub(/^( +|\t)/,''))
486
+ escape(text.value)
485
487
  end
486
488
 
487
489
  #
@@ -523,23 +525,30 @@ module Kramdown
523
525
  text = header.options[:raw_text]
524
526
 
525
527
  case header.options[:level]
526
- when 1 then ".TH #{text}"
527
- when 2 then ".SH #{text}"
528
- else ".SS #{text}"
528
+ when 1
529
+ <<~ROFF
530
+ .TH #{text}
531
+ ROFF
532
+ when 2
533
+ <<~ROFF
534
+ .SH #{text}
535
+ ROFF
536
+ else
537
+ <<~ROFF
538
+ .SS #{text}
539
+ ROFF
529
540
  end
530
541
  end
531
542
 
532
543
  #
533
- # Converts a `kd:hr` element.
544
+ # Ignore `kd:hr` elements.
534
545
  #
535
546
  # @param [Kramdown::Element] hr
536
547
  # A `kd:hr` element.
537
548
  #
538
- # @return [String]
539
- # The roff output.
549
+ # @return [nil]
540
550
  #
541
551
  def convert_hr(hr)
542
- ".ti 0\n\\l'\\n(.lu'"
543
552
  end
544
553
 
545
554
  #
@@ -552,9 +561,17 @@ module Kramdown
552
561
  # The roff output.
553
562
  #
554
563
  def convert_ul(ul)
555
- content = ul.children.map { |li| convert_ul_li(li) }.join("\n")
564
+ contents = String.new(encoding: Encoding::UTF_8)
556
565
 
557
- return ".RS\n#{content}\n.RE"
566
+ ul.children.each do |li|
567
+ contents << convert_ul_li(li)
568
+ end
569
+
570
+ return <<~ROFF
571
+ .RS
572
+ #{contents.chomp}
573
+ .RE
574
+ ROFF
558
575
  end
559
576
 
560
577
  #
@@ -567,15 +584,27 @@ module Kramdown
567
584
  # The roff output.
568
585
  #
569
586
  def convert_ul_li(li)
570
- li.children.each_with_index.map { |child,index|
587
+ roff = String.new(encoding: Encoding::UTF_8)
588
+
589
+ li.children.each_with_index do |child,index|
571
590
  if child.type == :p
572
- content = convert_children(child.children)
591
+ contents = convert_children_of(child)
573
592
 
574
- if index == 0 then ".IP \\(bu 2\n#{content}"
575
- else ".IP \\( 2\n#{content}"
576
- end
593
+ roff << if index == 0
594
+ <<~ROFF
595
+ .IP \\(bu 2
596
+ #{contents.chomp}
597
+ ROFF
598
+ else
599
+ <<~ROFF
600
+ .IP \\( 2
601
+ #{contents.chomp}
602
+ ROFF
603
+ end
577
604
  end
578
- }.compact.join("\n")
605
+ end
606
+
607
+ return roff
579
608
  end
580
609
 
581
610
  #
@@ -590,10 +619,18 @@ module Kramdown
590
619
  def convert_ol(ol)
591
620
  @ol_index += 1
592
621
 
593
- header = ".nr step#{@ol_index} 0 1"
594
- content = ol.children.map { |li| convert_ol_li(li) }.join("\n")
622
+ contents = String.new(encoding: Encoding::UTF_8)
623
+
624
+ ol.children.each do |li|
625
+ contents << convert_ol_li(li)
626
+ end
595
627
 
596
- return "#{header}\n.RS\n#{content}\n.RE"
628
+ return <<~ROFF
629
+ .nr step#{@ol_index} 0 1
630
+ .RS
631
+ #{contents.chomp}
632
+ .RE
633
+ ROFF
597
634
  end
598
635
 
599
636
  #
@@ -606,15 +643,133 @@ module Kramdown
606
643
  # The roff output.
607
644
  #
608
645
  def convert_ol_li(li)
609
- li.children.each_with_index.map { |child,index|
646
+ roff = String.new(encoding: Encoding::UTF_8)
647
+
648
+ li.children.each_with_index do |child,index|
610
649
  if child.type == :p
611
- content = convert_children(child.children)
650
+ contents = convert_children_of(child)
651
+
652
+ roff << if index == 0
653
+ <<~ROFF
654
+ .IP \\n+[step#{@ol_index}]
655
+ #{contents.chomp}
656
+ ROFF
657
+ else
658
+ <<~ROFF
659
+ .IP \\n
660
+ #{contents.chomp}
661
+ ROFF
662
+ end
663
+ end
664
+ end
665
+
666
+ return roff
667
+ end
612
668
 
613
- if index == 0 then ".IP \\n+[step#{@ol_index}]\n#{content}"
614
- else ".IP \\n\n#{content}"
669
+ #
670
+ # Converts a `kd:dl` element.
671
+ #
672
+ # @param [Kramdown::Element] dl
673
+ # A `kd:dl` element.
674
+ #
675
+ # @return [String]
676
+ # The roff output.
677
+ #
678
+ def convert_dl(dl)
679
+ roff = String.new(encoding: Encoding::UTF_8)
680
+
681
+ dt_index = 0
682
+ dd_index = 0
683
+
684
+ dl.children.each do |element|
685
+ case element.type
686
+ when :dt
687
+ roff << convert_dt(element, index: dt_index)
688
+
689
+ dt_index += 1 # increment the dt count
690
+ dd_index = 0 # reset the dd count
691
+ when :dd
692
+ roff << convert_dd(element, index: dd_index)
693
+
694
+ dd_index += 1 # increment the dd count
695
+ dt_index = 0 # reset the dt count
696
+ else
697
+ roff << convert(element)
698
+
699
+ # reset both the dt_index and dd_index counters
700
+ dt_index = 0
701
+ dd_index = 0
702
+ end
703
+ end
704
+
705
+ return roff
706
+ end
707
+
708
+ #
709
+ # Converts a `kd:dt` element within a `kd:dl`.
710
+ #
711
+ # @param [Kramdown::Element] dt
712
+ # A `kd:dt` element.
713
+ #
714
+ # @param [Integer] index
715
+ # The index of the `kd:dt` element. Used to indicate whether this is the
716
+ # first `kd:dt` element or additional `kd:dt` elements.
717
+ #
718
+ # @return [String]
719
+ # The roff output.
720
+ #
721
+ def convert_dt(dt, index: 0)
722
+ text = convert_text_elements(dt.children)
723
+
724
+ if index == 0
725
+ <<~ROFF
726
+ .TP
727
+ #{text}
728
+ ROFF
729
+ else
730
+ <<~ROFF
731
+ .TQ
732
+ #{text}
733
+ ROFF
734
+ end
735
+ end
736
+
737
+ #
738
+ # Converts a `kd:dd` element within a `kd:dd`.
739
+ #
740
+ # @param [Kramdown::Element] dd
741
+ # A `kd:dd` element.
742
+ #
743
+ # @param [Integer] index
744
+ # The index of the `kd:dd` element. Used to indicate whether this is the
745
+ # first `kd:dd` element following a `kd;dt` element or additional
746
+ # `kd:dt` elements.
747
+ #
748
+ # @return [String]
749
+ # The roff output.
750
+ #
751
+ def convert_dd(dd, index: 0)
752
+ roff = String.new(encoding: Encoding::UTF_8)
753
+
754
+ dd.children.each_with_index do |child,child_index|
755
+ if index == 0 && child_index == 0 && child.type == :p
756
+ contents = convert_children_of(child)
757
+
758
+ # omit the .PP macro for the first paragraph
759
+ roff << "#{contents.chomp}\n"
760
+ else
761
+ if (contents = convert_element(child))
762
+ # indent all other following paragraphs or other elements
763
+ roff << <<~ROFF
764
+ .RS
765
+ #{contents.chomp}
766
+ .RE
767
+ ROFF
615
768
  end
616
769
  end
617
- }.compact.join("\n")
770
+ end
771
+
772
+ return roff
618
773
  end
619
774
 
620
775
  #
@@ -640,14 +795,13 @@ module Kramdown
640
795
  # The roff output.
641
796
  #
642
797
  def convert_blockquote(blockquote)
643
- content = blockquote.children.map { |child|
644
- case child.type
645
- when :p then convert_children(child.children)
646
- else convert_element(child)
647
- end
648
- }.join("\n")
798
+ contents = convert_children_of(blockquote)
649
799
 
650
- return ".PP\n.RS\n#{content}\n.RE"
800
+ return <<~ROFF
801
+ .RS
802
+ #{contents.chomp}
803
+ .RE
804
+ ROFF
651
805
  end
652
806
 
653
807
  #
@@ -660,7 +814,16 @@ module Kramdown
660
814
  # The roff output.
661
815
  #
662
816
  def convert_codeblock(codeblock)
663
- ".nf\n#{escape(codeblock.value).rstrip}\n.fi"
817
+ contents = escape(codeblock.value)
818
+
819
+ return <<~ROFF
820
+ .PP
821
+ .RS 4
822
+ .EX
823
+ #{contents.chomp}
824
+ .EE
825
+ .RE
826
+ ROFF
664
827
  end
665
828
 
666
829
  #
@@ -673,9 +836,15 @@ module Kramdown
673
836
  # The roff output.
674
837
  #
675
838
  def convert_comment(comment)
676
- comment.value.lines.map { |line|
677
- ".\\\" #{line}"
678
- }.join("\n")
839
+ roff = String.new(encoding: Encoding::UTF_8)
840
+
841
+ comment.value.lines.each do |line|
842
+ roff << <<~ROFF
843
+ .\\" #{line}
844
+ ROFF
845
+ end
846
+
847
+ return roff
679
848
  end
680
849
 
681
850
  #
@@ -688,26 +857,12 @@ module Kramdown
688
857
  # The roff output.
689
858
  #
690
859
  def convert_p(p)
691
- children = p.children
692
-
693
- if ((children.length >= 2) && (children.first.type == :codespan ||
694
- children.first.type == :em ||
695
- children.first.type == :strong))
696
- newline = children.find_index { |el|
697
- el.type == :text && el.value.start_with?("\n")
698
- }
860
+ contents = convert_text_elements(p.children)
699
861
 
700
- if newline
701
- first_line = convert_children(children[0...newline])
702
- rest = convert_children(children[newline..-1]).strip
703
-
704
- ".TP\n#{first_line}\n#{rest}"
705
- else
706
- ".HP\n#{convert_children(children)}"
707
- end
708
- else
709
- ".PP\n#{convert_children(children)}"
710
- end
862
+ return <<~ROFF
863
+ .PP
864
+ #{contents.chomp}
865
+ ROFF
711
866
  end
712
867
 
713
868
  #
@@ -720,7 +875,7 @@ module Kramdown
720
875
  # The roff output.
721
876
  #
722
877
  def convert_em(em)
723
- "\\fI#{convert_children(em.children)}\\fP"
878
+ "\\fI#{convert_text_elements(em.children)}\\fP"
724
879
  end
725
880
 
726
881
  #
@@ -733,7 +888,7 @@ module Kramdown
733
888
  # The roff output.
734
889
  #
735
890
  def convert_strong(strong)
736
- "\\fB#{convert_children(strong.children)}\\fP"
891
+ "\\fB#{convert_text_elements(strong.children)}\\fP"
737
892
  end
738
893
 
739
894
  #
@@ -759,38 +914,122 @@ module Kramdown
759
914
  # The roff output.
760
915
  #
761
916
  def convert_a(a)
762
- href = escape(a.attr['href'])
763
- text = convert_children(a.children)
917
+ href = a.attr['href']
918
+ scheme, path = href.split(':',2)
764
919
 
765
- case href
766
- when /^mailto:/
767
- email = href[7..-1]
920
+ text = convert_text_elements(a.children)
768
921
 
769
- unless text == email then "#{text}\n.MT #{email}\n.ME"
770
- else "\n.MT #{email}\n.ME"
922
+ case scheme
923
+ when 'mailto'
924
+ email = escape(path)
925
+
926
+ unless text == email
927
+ <<~ROFF
928
+ #{text.chomp}
929
+ .MT #{email}
930
+ .ME
931
+ ROFF
932
+ else
933
+ <<~ROFF
934
+ .MT #{email}
935
+ .ME
936
+ ROFF
771
937
  end
772
- when /^man:/
773
- match = href.match(/man:([A-Za-z0-9_-]+)(?:\((\d[a-z]?)\))?/)
938
+ when 'man'
939
+ if (match = path.match(/\A(?<page>[A-Za-z0-9_-]+)(?:\((?<section>\d[a-z]?)\)|\.(?<section>\d[a-z]?))\z/))
940
+ man_page_link(match[:page],match[:section])
941
+ else
942
+ page = escape(path)
774
943
 
775
- if match[2] then "\n.BR #{match[1]} (#{match[2]})"
776
- else "\n.BR #{match[1]}"
944
+ <<~ROFF
945
+ .BR #{page}
946
+ ROFF
947
+ end
948
+ else
949
+ if (match = href.match(/(?<page>[A-Za-z0-9_-]+)\.(?<section>\d[a-z]?)\.md\z/))
950
+ man_page_link(match[:page],match[:section])
951
+ else
952
+ <<~ROFF
953
+ #{text.chomp}
954
+ .UR #{escape(href)}
955
+ .UE
956
+ ROFF
777
957
  end
958
+ end
959
+ end
960
+
961
+ #
962
+ # Outputs a man page link.
963
+ #
964
+ # @param [String] page
965
+ # The man page name.
966
+ #
967
+ # @param [String, nil] section
968
+ # The optional section of the man page.
969
+ #
970
+ # @return [String]
971
+ # The roff output.
972
+ #
973
+ def man_page_link(page,section=nil)
974
+ if section
975
+ <<~ROFF
976
+ .BR #{escape(page)} (#{escape(section)})
977
+ ROFF
778
978
  else
779
- "#{text}\n.UR #{href}\n.UE"
979
+ <<~ROFF
980
+ .BR #{escape(page)}
981
+ ROFF
780
982
  end
781
983
  end
782
984
 
783
985
  #
784
986
  # Converts the children of an element.
785
987
  #
786
- # @param [Array<Kramdown::Element>] children
787
- # The children of an element.
988
+ # @param [Array<Kramdown::Element>] element
989
+ # The elements to convert.
990
+ #
991
+ # @return [String]
992
+ # The combined roff output.
993
+ #
994
+ def convert_children_of(element)
995
+ roff = String.new(encoding: Encoding::UTF_8)
996
+
997
+ element.children.each do |child|
998
+ if (contents = convert_element(child))
999
+ roff << contents
1000
+ end
1001
+ end
1002
+
1003
+ return roff
1004
+ end
1005
+
1006
+ #
1007
+ # Converts the children of an element.
1008
+ #
1009
+ # @param [Array<Kramdown::Element>] elements
1010
+ # The text elements to convert.
788
1011
  #
789
1012
  # @return [String]
790
1013
  # The roff output.
791
1014
  #
792
- def convert_children(children)
793
- children.map { |child| convert_element(child) }.join.strip
1015
+ def convert_text_elements(elements)
1016
+ roff = String.new(encoding: Encoding::UTF_8)
1017
+
1018
+ elements.each do |element|
1019
+ if (contents = convert_element(element))
1020
+ if contents.start_with?('.') && !roff.empty? && !roff.end_with?("\n")
1021
+ # roff macross must exist on their own line
1022
+ roff << "\n#{contents}"
1023
+ elsif contents.start_with?(' ') && roff.end_with?("\n")
1024
+ # remove leadning whitespace following a newline
1025
+ roff << contents.lstrip
1026
+ else
1027
+ roff << contents
1028
+ end
1029
+ end
1030
+ end
1031
+
1032
+ return roff
794
1033
  end
795
1034
 
796
1035
  #
@@ -803,7 +1042,7 @@ module Kramdown
803
1042
  # The escaped text.
804
1043
  #
805
1044
  def escape(text)
806
- text.gsub(GLYPH_REGEXP) { |char| GLYPHS[char] }
1045
+ text.gsub(GLYPH_REGEXP,GLYPHS)
807
1046
  end
808
1047
 
809
1048
  end
@@ -1,5 +1,7 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'kramdown'
2
- require_relative '../converter/man'
4
+ require 'kramdown/man'
3
5
 
4
6
  require 'rake/tasklib'
5
7
 
@@ -1,6 +1,8 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Kramdown
2
4
  module Man
3
5
  # kramdown-man version
4
- VERSION = "0.1.8"
6
+ VERSION = "1.0.0"
5
7
  end
6
8
  end
data/lib/kramdown/man.rb CHANGED
@@ -1,5 +1,30 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'kramdown'
2
4
 
3
- # HACK: load our version of kramdown/converter/man.rb and not kramdown's
4
- require_relative './converter/man'
5
- require_relative './man/version'
5
+ require 'kramdown/man/version'
6
+ require 'kramdown/man/converter'
7
+
8
+ module Kramdown
9
+ class Document
10
+ #
11
+ # Converts the parsed markdown document to a man page.
12
+ #
13
+ # @param [Hash] options
14
+ # Additional options.
15
+ #
16
+ # @return [String]
17
+ # The converted man page contents.
18
+ #
19
+ # @since 1.0.0
20
+ #
21
+ # @api public
22
+ #
23
+ def to_man(options={})
24
+ output, warnings = Kramdown::Man::Converter.convert(@root,options)
25
+
26
+ @warnings.concat(warnings)
27
+ return output
28
+ end
29
+ end
30
+ end