tipi-markup 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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: []