tipi-markup 0.0.1

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: b87186cc48230699aee8ca1f7994d298d7290debfcb5b139be5602f6e740f174
4
+ data.tar.gz: ceea3879d123997e59d5aebe8d89128cdb4ef4f5f5f3ba83e63d55e02f824a44
5
+ SHA512:
6
+ metadata.gz: 992a9db4ed8a971e579b3645a349f5a8c7dfeaed8aae4cb6a4a72c4189547173262ff7e3b9fbc9bfbe9a9975d0ec2b233074e7774b593ea43e3992b371c706dd
7
+ data.tar.gz: 047da29dc713a72717c0b23d1437b14fe9de287ba373f08ca0280abd514128f958c705b4d9562e63bf78ba53a5f4d10c50f2793bbda3ea8f71dbc1e52ddbeace
data/.gitignore ADDED
@@ -0,0 +1,14 @@
1
+ # Generated by Cargo
2
+ # will have compiled files and executables
3
+ debug/
4
+ target/
5
+
6
+ # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
7
+ # More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html
8
+ Cargo.lock
9
+
10
+ # These are backup files generated by rustfmt
11
+ **/*.rs.bk
12
+
13
+ # MSVC Windows builds of rustc generate these, which store debugging information
14
+ *.pdb
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source "https://rubygems.org"
2
+
3
+ gem "optparse"
4
+ gem "pdfkit"
5
+ gem 'wkhtmltopdf_runner'
6
+ gem 'wkhtmltopdf-binary' # or 'wkhtmltopdf-binary-edge'
data/README.tipi ADDED
@@ -0,0 +1,7 @@
1
+ = Tipi
2
+
3
+ == Installation
4
+
5
+ $ bundle install
6
+ $ bundle exec gem build tipi.gemspec
7
+ $ bundle install tipi-0.0.1.gem
data/bin/tipi ADDED
@@ -0,0 +1,63 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require_relative '../lib/tipi'
4
+ require 'wkhtmltopdf_runner'
5
+
6
+ def print_usage_and_exit
7
+ puts "Usage:"
8
+ puts " ./tipi html input.tipi output.html"
9
+ puts " ./tipi pdf input.tipi output.pdf"
10
+ exit(1)
11
+ end
12
+
13
+ # Ensure correct number of arguments
14
+ if ARGV.length != 3
15
+ print_usage_and_exit
16
+ end
17
+
18
+ command = ARGV[0]
19
+ input_file = ARGV[1]
20
+ output_file = ARGV[2]
21
+
22
+ # Validate command
23
+ unless ['html', 'pdf'].include?(command)
24
+ puts "Invalid command: #{command}"
25
+ print_usage_and_exit
26
+ end
27
+
28
+ # Read input file content
29
+ file_content = File.read(input_file)
30
+
31
+ # Process command
32
+ case command
33
+ when 'html'
34
+ html = Tipi.text_to_html(file_content)
35
+ File.open(output_file, "w") { |file| file.puts(html) }
36
+ puts "HTML conversion completed."
37
+ when 'pdf'
38
+ # Read input file content
39
+ file_content = File.read(input_file)
40
+
41
+ html = Tipi.text_to_html(file_content)
42
+ File.open('temp.html', "w") { |file| file.puts(html) }
43
+
44
+ file_path = 'temp.html'
45
+
46
+ # Open the file in read mode
47
+ File.open(file_path, "r") do |file|
48
+ # Read the content of the file and store it in a variable
49
+ file_content = file.read
50
+ puts(file_content)
51
+ # Output the content of the file
52
+
53
+ string = file_content
54
+
55
+ WkhtmltopdfRunner.pdf_from_string(string) do |pdf_file|
56
+ doc = File.open(output_file, 'w')
57
+ doc.write(pdf_file.read)
58
+ doc.close
59
+ end
60
+ File.delete('temp.html')
61
+ end
62
+ puts "PDF conversion completed."
63
+ end
@@ -0,0 +1,284 @@
1
+ require 'cgi'
2
+ require 'uri'
3
+
4
+ module Tipi
5
+ class Parser
6
+ attr_accessor :allowed_schemes
7
+ attr_writer :extensions
8
+ def extensions?; @extensions; end
9
+ attr_writer :no_escape
10
+ def no_escape?; @no_escape; end
11
+
12
+ def initialize(text, options = {})
13
+ @allowed_schemes = %w(http https ftp ftps)
14
+ @text = text
15
+ @extensions = @no_escape = nil
16
+ options.each_pair {|k,v| send("#{k}=", v) }
17
+ end
18
+
19
+ def to_html
20
+ @out = ''
21
+ @p = false
22
+ @stack = []
23
+ parse_block(@text)
24
+ @out
25
+ end
26
+
27
+ protected
28
+
29
+ def escape_html(string)
30
+ CGI::escapeHTML(string)
31
+ end
32
+
33
+ def escape_url(string)
34
+ CGI::escape(string)
35
+ end
36
+
37
+ def start_tag(tag)
38
+ @stack.push(tag)
39
+ @out << '<' << tag << '>'
40
+ end
41
+
42
+ def end_tag
43
+ @out << '</' << @stack.pop << '>'
44
+ end
45
+
46
+ def toggle_tag(tag, match)
47
+ if @stack.include?(tag)
48
+ if @stack.last == tag
49
+ end_tag
50
+ else
51
+ @out << escape_html(match)
52
+ end
53
+ else
54
+ start_tag(tag)
55
+ end
56
+ end
57
+
58
+ def end_paragraph
59
+ end_tag while !@stack.empty?
60
+ @p = false
61
+ end
62
+
63
+ def start_paragraph
64
+ if @p
65
+ @out << ' ' if @out[-1] != ?\s
66
+ else
67
+ end_paragraph
68
+ start_tag('p')
69
+ @p = true
70
+ end
71
+ end
72
+
73
+ def make_local_link(link) #:doc:
74
+ no_escape? ? link : escape_url(link)
75
+ end
76
+
77
+ def make_direct_link(url) #:doc:
78
+ url
79
+ end
80
+
81
+ def make_image_link(url) #:doc:
82
+ url
83
+ end
84
+
85
+ def make_image(uri, alt)
86
+ if alt
87
+ '<img src="' << escape_html(uri) << '" alt="' << escape_html(alt) << '"/>'
88
+ else
89
+ '<img src="' << escape_html(uri) << '"/>'
90
+ end
91
+ end
92
+
93
+ def make_headline(level, text)
94
+ "<h#{level}>" << escape_html(text) << "</h#{level}>"
95
+ end
96
+
97
+ def make_explicit_link(link)
98
+ begin
99
+ uri = URI.parse(link)
100
+ return uri.to_s if uri.scheme && @allowed_schemes.include?(uri.scheme)
101
+ rescue URI::InvalidURIError
102
+ end
103
+ make_local_link(link)
104
+ end
105
+
106
+ def parse_inline(str)
107
+ until str.empty?
108
+ case str
109
+ when /\A(\~)?((https?|ftps?):\/\/\S+?)(?=([\,.?!:;"'\)]+)?(\s|$))/
110
+ str = $'
111
+ if $1
112
+ @out << escape_html($2)
113
+ else
114
+ if uri = make_direct_link($2)
115
+ @out << '<a href="' << escape_html(uri) << '">' << escape_html($2) << '</a>'
116
+ else
117
+ @out << escape_html($&)
118
+ end
119
+ end
120
+ when /\A\[\[\s*([^|]*?)\s*(\|\s*(.*?))?\s*\]\]/m
121
+ str = $'
122
+ link, content = $1, $3
123
+ if uri = make_explicit_link(link)
124
+ @out << '<a href="' << escape_html(uri) << '">'
125
+ if content
126
+ until content.empty?
127
+ content = parse_inline_tag(content)
128
+ end
129
+ else
130
+ @out << escape_html(link)
131
+ end
132
+ @out << '</a>'
133
+ else
134
+ @out << escape_html($&)
135
+ end
136
+ else
137
+ str = parse_inline_tag(str)
138
+ end
139
+ end
140
+ end
141
+
142
+ def parse_inline_tag(str)
143
+ case str
144
+ when /\A\{\{\{(.*?\}*)\}\}\}/
145
+ @out << '<tt>' << escape_html($1) << '</tt>'
146
+ when /\A\{\{\s*(.*?)\s*(\|\s*(.*?)\s*)?\}\}/
147
+ if uri = make_image_link($1)
148
+ @out << make_image(uri, $3)
149
+ else
150
+ @out << escape_html($&)
151
+ end
152
+ when /\A([[:alpha:]]|[[:digit:]])+/
153
+ @out << $&
154
+ when /\A\s+/
155
+ @out << ' ' if @out[-1] != ?\s
156
+ when /\A\*\*/
157
+ toggle_tag 'strong', $&
158
+ when /\A\/\//
159
+ toggle_tag 'em', $&
160
+ when /\A\\\\/
161
+ @out << '<br/>'
162
+ else
163
+ if @extensions
164
+ case str
165
+ when /\A__/
166
+ toggle_tag 'u', $&
167
+ when /\A\-\-/
168
+ toggle_tag 'del', $&
169
+ when /\A\+\+/
170
+ toggle_tag 'ins', $&
171
+ when /\A\^\^/
172
+ toggle_tag 'sup', $&
173
+ when /\A\~\~/
174
+ toggle_tag 'sub', $&
175
+ when /\A\(R\)/i
176
+ @out << '&#174;'
177
+ when /\A\(C\)/i
178
+ @out << '&#169;'
179
+ when /\A~([^\s])/
180
+ @out << escape_html($1)
181
+ when /./
182
+ @out << escape_html($&)
183
+ end
184
+ else
185
+ case str
186
+ when /\A~([^\s])/
187
+ @out << escape_html($1)
188
+ when /./
189
+ @out << escape_html($&)
190
+ end
191
+ end
192
+ end
193
+ return $'
194
+ end
195
+
196
+ def parse_table_row(str)
197
+ @out << '<tr>'
198
+ str.scan(/\s*\|(=)?\s*((\[\[.*?\]\]|\{\{.*?\}\}|[^|~]|~.)*)(?=\||$)/) do
199
+ if !$2.empty? || !$'.empty?
200
+ @out << ($1 ? '<th>' : '<td>')
201
+ parse_inline($2) if $2
202
+ end_tag while @stack.last != 'table'
203
+ @out << ($1 ? '</th>' : '</td>')
204
+ end
205
+ end
206
+ @out << '</tr>'
207
+ end
208
+
209
+ def make_nowikiblock(input)
210
+ input.gsub(/^ (?=\}\}\})/, '')
211
+ end
212
+
213
+ def ulol?(x); x == 'ul' || x == 'ol'; end
214
+
215
+ def parse_block(str)
216
+ until str.empty?
217
+ case str
218
+ when /\A\{\{\{\r?\n(.*?)\r?\n\}\}\}/m
219
+ end_paragraph
220
+ nowikiblock = make_nowikiblock($1)
221
+ @out << '<pre>' << escape_html(nowikiblock) << '</pre>'
222
+ when /\A\s*-{4,}\s*$/
223
+ end_paragraph
224
+ @out << '<hr/>'
225
+ when /\A\s*(={1,6})\s*(.*?)\s*=*\s*$(\r?\n)?/
226
+ end_paragraph
227
+ level = $1.size
228
+ @out << make_headline(level, $2)
229
+ when /\A[ \t]*\|.*$(\r?\n)?/
230
+ if !@stack.include?('table')
231
+ end_paragraph
232
+ start_tag('table')
233
+ end
234
+ parse_table_row($&)
235
+ when /\A\s*$(\r?\n)?/
236
+ end_paragraph
237
+ when /\A(\s*([*#]+)\s*(.*?))$(\r?\n)?/
238
+ line, bullet, item = $1, $2, $3
239
+ tag = (bullet[0,1] == '*' ? 'ul' : 'ol')
240
+ if bullet[0,1] == '#' || bullet.size != 2 || @stack.find {|x| ulol?(x) }
241
+ count = @stack.select { |x| ulol?(x) }.size
242
+
243
+ while !@stack.empty? && count > bullet.size
244
+ count -= 1 if ulol?(@stack.last)
245
+ end_tag
246
+ end
247
+
248
+ end_tag while !@stack.empty? && @stack.last != 'li'
249
+
250
+ if @stack.last == 'li' && count == bullet.size
251
+ end_tag
252
+ if @stack.last != tag
253
+ end_tag
254
+ count -= 1
255
+ end
256
+ end
257
+
258
+ while count < bullet.size
259
+ start_tag tag
260
+ count += 1
261
+ start_tag 'li' if count < bullet.size
262
+ end
263
+
264
+ @p = true
265
+ start_tag('li')
266
+ parse_inline(item)
267
+ else
268
+ start_paragraph
269
+ parse_inline(line)
270
+ end
271
+ when /\A([ \t]*\S+.*?)$(\r?\n)?/
272
+ start_paragraph
273
+ parse_inline($1)
274
+ else
275
+ raise "Parse error at #{str[0,30].inspect}"
276
+ end
277
+ #p [$&, $']
278
+ str = $'
279
+ end
280
+ end_paragraph
281
+ @out
282
+ end
283
+ end
284
+ end
@@ -0,0 +1,3 @@
1
+ module Tipi
2
+ VERSION = '0.0.1'
3
+ end
data/lib/tipi.rb ADDED
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'tipi/parser'
4
+ require 'tipi/version'
5
+
6
+ module Tipi
7
+ def self.text_to_html(text, options = {})
8
+ Parser.new(text, options).to_html
9
+ end
10
+ end
data/tipi.gemspec ADDED
@@ -0,0 +1,21 @@
1
+ require File.dirname(__FILE__) + '/lib/tipi/version'
2
+ require 'date'
3
+
4
+ Gem::Specification.new do |s|
5
+ s.name = 'tipi-markup'
6
+ s.version = Tipi::VERSION
7
+ s.date = Date.today.to_s
8
+
9
+ s.authors = ['Timo Sarkar']
10
+ s.email = ['timosarkar@duck.com']
11
+ s.summary = 'authoring markup language'
12
+ s.description = 'Tipi is a lightweight authoring markup language.'
13
+ s.extra_rdoc_files = %w(README.tipi)
14
+
15
+ s.files = `git ls-files`.split("\n")
16
+ s.executables = ['tipi']
17
+ s.require_paths = %w(lib)
18
+
19
+ s.homepage = 'http://github.com/sartimo/tipi'
20
+ s.license = 'Ruby'
21
+ end
metadata ADDED
@@ -0,0 +1,53 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: tipi-markup
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Timo Sarkar
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2024-02-10 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: Tipi is a lightweight authoring markup language.
14
+ email:
15
+ - timosarkar@duck.com
16
+ executables:
17
+ - tipi
18
+ extensions: []
19
+ extra_rdoc_files:
20
+ - README.tipi
21
+ files:
22
+ - ".gitignore"
23
+ - Gemfile
24
+ - README.tipi
25
+ - bin/tipi
26
+ - lib/tipi.rb
27
+ - lib/tipi/parser.rb
28
+ - lib/tipi/version.rb
29
+ - tipi.gemspec
30
+ homepage: http://github.com/sartimo/tipi
31
+ licenses:
32
+ - Ruby
33
+ metadata: {}
34
+ post_install_message:
35
+ rdoc_options: []
36
+ require_paths:
37
+ - lib
38
+ required_ruby_version: !ruby/object:Gem::Requirement
39
+ requirements:
40
+ - - ">="
41
+ - !ruby/object:Gem::Version
42
+ version: '0'
43
+ required_rubygems_version: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ requirements: []
49
+ rubygems_version: 3.3.5
50
+ signing_key:
51
+ specification_version: 4
52
+ summary: authoring markup language
53
+ test_files: []