livetext 0.9.22 → 0.9.23

Sign up to get free protection for your applications and to get access to all the features.
Files changed (59) hide show
  1. checksums.yaml +4 -4
  2. data/README.lt3 +2 -2
  3. data/imports/tutorial.rb +1 -1
  4. data/lib/cmdargs.rb +2 -0
  5. data/lib/errors.rb +2 -0
  6. data/lib/formatline.rb +10 -108
  7. data/lib/funcall.rb +93 -0
  8. data/lib/functions.rb +1 -1
  9. data/lib/global_helpers.rb +39 -0
  10. data/lib/handler/import.rb +20 -11
  11. data/lib/handler.rb +2 -0
  12. data/lib/helpers.rb +12 -4
  13. data/lib/html.rb +2 -0
  14. data/lib/livetext.rb +23 -2
  15. data/lib/parser/file.rb +0 -2
  16. data/lib/parser/general.rb +0 -3
  17. data/lib/parser/mixin.rb +4 -8
  18. data/lib/parser/set.rb +0 -3
  19. data/lib/parser.rb +2 -0
  20. data/lib/parsing.rb +31 -0
  21. data/lib/processor.rb +65 -71
  22. data/lib/standard.rb +12 -1
  23. data/lib/userapi.rb +3 -1
  24. data/plugin/pyggish.rb +1 -0
  25. data/test/snapshots/error_inc_line_num/OUT +17 -0
  26. data/test/snapshots/error_inc_line_num/actual-error.txt +0 -14
  27. data/test/snapshots/error_inc_line_num/actual-output.txt +10 -0
  28. data/test/snapshots/error_invalid_name/actual-error.txt +6 -6
  29. data/test/snapshots/error_missing_end/actual-error.txt +5 -5
  30. data/test/snapshots/error_no_such_copy/actual-error.txt +7 -7
  31. data/test/snapshots/error_no_such_copy/match-error.txt +1 -1
  32. data/test/snapshots/error_no_such_copy/out-sdiff.txt +5 -0
  33. data/test/snapshots/error_no_such_inc/actual-error.txt +6 -6
  34. data/test/snapshots/error_no_such_inc/match-error.txt +1 -1
  35. data/test/snapshots/error_no_such_inc/out-sdiff.txt +6 -0
  36. data/test/snapshots/error_no_such_mixin/actual-error.txt +7 -7
  37. data/test/snapshots/{wtf_bookish → import_bookish}/expected-error.txt +0 -0
  38. data/test/snapshots/{wtf_bookish → import_bookish}/expected-output.txt +0 -0
  39. data/test/snapshots/{wtf_bookish → import_bookish}/source.lt3 +0 -0
  40. data/test/snapshots/{wtf_bookish → import_bookish}/toc.tmp +0 -0
  41. data/test/snapshots/{import/actual-output.txt → mixin_bookish/expected-error.txt} +0 -0
  42. data/test/snapshots/mixin_bookish/expected-output.txt +10 -0
  43. data/test/snapshots/mixin_bookish/source.lt3 +7 -0
  44. data/test/snapshots/mixin_bookish/toc.tmp +0 -0
  45. data/test/snapshots/subset.txt +4 -3
  46. data/test/snapshots.rb +15 -6
  47. data/test/unit/formatline.rb +2 -0
  48. data/test/unit/html.rb +1 -1
  49. data/test/unit/parser/general.rb +1 -2
  50. data/test/unit/parser/mixin.rb +1 -3
  51. data/test/unit/parser/set.rb +2 -2
  52. data/test/unit/parser/string.rb +1 -1
  53. data/test/unit/parser.rb +0 -1
  54. metadata +16 -12
  55. data/imports/markdown_importable.rb +0 -45
  56. data/test/snapshots/error_inc_line_num/out-sdiff.txt +0 -14
  57. data/test/snapshots/import/actual-error.txt +0 -13
  58. data/test/snapshots/import/out-sdiff.txt +0 -6
  59. data/test/unit/parser/importable.rb +0 -19
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3d2ff056cfc390401ec0517a7a74bb0eadf9128fff5eaff5c60a548775bdde9f
4
- data.tar.gz: c76d7b425e3c19b0c44c752ff5705757415f60ee1d2647b538cfb9e6eb263ec3
3
+ metadata.gz: 8b1fc83442ee9361739a1d0024eebcaa342b3d75242824d0127644a03c2a6d12
4
+ data.tar.gz: c6bb5f661e43f438b65f40d4cb3b7f71a7ebb8a87951d6c157f932d418c0ea4a
5
5
  SHA512:
6
- metadata.gz: bc98e86fdc72cbe0441ad2b80cbff64d3afbf4cae68eaba12e6e84ba5dd51913e6cdc9c687678782db61f64796347a2cf5d149e2eb74c4ed436634efa0c8b9fb
7
- data.tar.gz: e6359fd712953b1579bb36d56b5dfd9546963064e4a5f08165ccf4a61dcc1de0a52374a15d7f038e63fe9ff00f25a5d3c0febdac501fea067399bf3c682075eb
6
+ metadata.gz: 17ac68b8a91831199d1e6effaca85add11311251cbf6388214219768ebba937198cebc6fe314bed95d8b5c8ddabf86672601be274fbfe26601a6622c899049e6
7
+ data.tar.gz: cce50c49518fc8440ba7295d9d7bd6d711307115106b8f707d3b2f7a2f38a470b6a21f0dfa4ca2345329621e9c400dab9ea7758b4ad68cf345201dea2fcc970c
data/README.lt3 CHANGED
@@ -1,5 +1,5 @@
1
- .icanhaz tutorial
2
- .icanhaz markdown
1
+ .import tutorial
2
+ .import markdown
3
3
 
4
4
  . copy basic.css
5
5
 
data/imports/tutorial.rb CHANGED
@@ -3,7 +3,7 @@ require 'helpers'
3
3
  # Created as an "ad hoc" lib for generating the README
4
4
 
5
5
  module Tutorial
6
- include Helpers
6
+ include Livetext::Helpers
7
7
 
8
8
  def title(args = nil, body = nil)
9
9
  h1
data/lib/cmdargs.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # p __FILE__
2
+
1
3
  require_relative 'livetext'
2
4
 
3
5
  =begin
data/lib/errors.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # p __FILE__
2
+
1
3
 
2
4
  # More later?
3
5
 
data/lib/formatline.rb CHANGED
@@ -1,30 +1,14 @@
1
+ # p __FILE__
2
+
3
+ require_relative 'parsing'
4
+ require_relative 'funcall'
5
+
1
6
  # Class FormatLine handles the parsing of comments, dot commands, and
2
7
  # simple formatting characters.
3
8
 
4
- class FormatLine < StringParser
5
- SimpleFormats = {}
6
- SimpleFormats[:b] = %w[<b> </b>]
7
- SimpleFormats[:i] = %w[<i> </i>]
8
- SimpleFormats[:t] = ["<font size=+1><tt>", "</tt></font>"]
9
- SimpleFormats[:s] = %w[<strike> </strike>]
10
-
11
- BITS = SimpleFormats.keys
12
-
13
- Null = ""
14
- Space = " "
15
- Alpha = /[A-Za-z]/
16
- AlNum = /[A-Za-z0-9_]/
17
- LF = "\n"
18
- LBrack = "["
19
-
20
- Blank = [" ", nil, "\n"]
21
- Punc = [")", ",", ".", " ", "\n"]
22
- NoAlpha = /[^A-Za-z0-9_]/
23
- NoAlphaDot = /[^.A-Za-z0-9_]/
24
- Param = ["]", "\n", nil]
25
- Escape = "\\" # not an ESC char
26
-
27
- Syms = { "*" => :b, "_" => :i, "`" => :t, "~" => :s }
9
+ class Livetext::FormatLine < StringParser
10
+ include Livetext::ParsingConstants
11
+ include Livetext::FormatLine::FunCall
28
12
 
29
13
  attr_reader :out
30
14
  attr_reader :tokenlist
@@ -39,7 +23,6 @@ class FormatLine < StringParser
39
23
  return nil if line.nil?
40
24
  x = self.new(line.chomp)
41
25
  t = x.tokenize
42
- # TTY.puts "tokens = \n#{t.inspect}\n "
43
26
  x.evaluate
44
27
  end
45
28
 
@@ -47,7 +30,7 @@ class FormatLine < StringParser
47
30
  # add grab
48
31
  loop do
49
32
  case peek
50
- when Escape; grab; add peek; grab; # add peek # <-- last is an error??
33
+ when Escape; grab; add peek; grab
51
34
  when "$"
52
35
  dollar
53
36
  when "*", "_", "`", "~"
@@ -82,7 +65,7 @@ class FormatLine < StringParser
82
65
  char = x.grab
83
66
  break if char == LF || char == nil
84
67
  x.handle_escaping if char == Escape
85
- x.dollar if char == "$"
68
+ x.dollar if char == "$" # Could be $$
86
69
  x.add char
87
70
  end
88
71
  x.add_token(:str)
@@ -121,18 +104,6 @@ class FormatLine < StringParser
121
104
  @out
122
105
  end
123
106
 
124
- def grab_func_param
125
- case lookahead
126
- when "["
127
- param = grab_bracket_param
128
- add_token(:brackets, param)
129
- when ":"
130
- param = grab_colon_param
131
- add_token(:colon, param)
132
- else # do nothing
133
- end
134
- end
135
-
136
107
  def add(str)
137
108
  @token << str unless str.nil?
138
109
  end
@@ -185,20 +156,6 @@ class FormatLine < StringParser
185
156
  end
186
157
  end
187
158
 
188
- def double_dollar
189
- case lookahead
190
- when Space; add_token :string, "$$ "; grab; return
191
- when LF, nil; add "$$"; add_token :str
192
- when Alpha
193
- add_token(:str, @token)
194
- func = grab_alpha
195
- add_token(:func, func)
196
- param = grab_func_param # may be null/missing
197
- else
198
- grab; add_token :str, "$$" + peek; return
199
- end
200
- end
201
-
202
159
  # def dollar_dot
203
160
  # add_token :ddot, @line[@i..-1]
204
161
  # end
@@ -309,19 +266,6 @@ class FormatLine < StringParser
309
266
  ::STDERR.puts "ERR = #{err}\n#{err.backtrace}"
310
267
  end
311
268
 
312
- def funcall(name, param)
313
- err = "[Error evaluating $$#{name}(#{param})]"
314
- func_name = name # "func_" + name.to_s
315
- result =
316
- if self.send?(func_name, param) # self.respond_to?(func_name)
317
- # do nothing
318
- else
319
- fobj = ::Livetext::Functions.new
320
- fobj.send(name, param) rescue err
321
- end
322
- result.to_s
323
- end
324
-
325
269
  def varsub(name)
326
270
  result = Livetext::Vars[name] || "[#{name} is undefined]"
327
271
  result
@@ -333,48 +277,6 @@ class FormatLine < StringParser
333
277
 
334
278
  private
335
279
 
336
- def grab_colon_param
337
- grab # grab :
338
- param = ""
339
- loop do
340
- case lookahead
341
- when Escape
342
- grab
343
- param << lookahead
344
- grab
345
- when Space, LF, nil; break
346
- else
347
- param << lookahead
348
- grab
349
- end
350
- end
351
-
352
- param = nil if param.empty?
353
- param
354
- end
355
-
356
- def grab_bracket_param
357
- grab # [
358
- param = ""
359
- loop do
360
- case lookahead
361
- when Escape
362
- grab
363
- param << lookahead
364
- grab
365
- when "]", LF, nil
366
- break
367
- else
368
- param << lookahead
369
- grab
370
- end
371
- end
372
- add peek
373
- grab
374
- param = nil if param.empty?
375
- param
376
- end
377
-
378
280
  def eval_bits(sym, val)
379
281
  val = Livetext.interpolate(val)
380
282
  @out << embed(sym, val)
data/lib/funcall.rb ADDED
@@ -0,0 +1,93 @@
1
+ # p __FILE__
2
+
3
+ require_relative 'livetext'
4
+ # require_relative 'formatline'
5
+
6
+ # Parse function calls
7
+
8
+ module Livetext::FormatLine::FunCall
9
+
10
+ include Livetext::ParsingConstants
11
+
12
+ def grab_colon_param
13
+ grab # grab :
14
+ param = ""
15
+ loop do
16
+ case lookahead
17
+ when Escape
18
+ grab
19
+ param << lookahead
20
+ grab
21
+ when Space, LF, nil; break
22
+ else
23
+ param << lookahead
24
+ grab
25
+ end
26
+ end
27
+
28
+ param = nil if param.empty?
29
+ param
30
+ end
31
+
32
+ def grab_bracket_param
33
+ grab # [
34
+ param = ""
35
+ loop do
36
+ case lookahead
37
+ when Escape
38
+ grab
39
+ param << lookahead
40
+ grab
41
+ when "]", LF, nil
42
+ break
43
+ else
44
+ param << lookahead
45
+ grab
46
+ end
47
+ end
48
+ add peek
49
+ grab
50
+ param = nil if param.empty?
51
+ param
52
+ end
53
+
54
+ def funcall(name, param)
55
+ err = "[Error evaluating $$#{name}(#{param})]"
56
+ func_name = name # "func_" + name.to_s
57
+ result =
58
+ if self.send?(func_name, param) # self.respond_to?(func_name)
59
+ # do nothing
60
+ else
61
+ fobj = ::Livetext::Functions.new
62
+ fobj.send(name, param) rescue err
63
+ end
64
+ result.to_s
65
+ end
66
+
67
+ def double_dollar
68
+ case lookahead
69
+ when Space; add_token :string, "$$ "; grab; return
70
+ when LF, nil; add "$$"; add_token :str
71
+ when Alpha
72
+ add_token(:str, @token)
73
+ func = grab_alpha
74
+ add_token(:func, func)
75
+ param = grab_func_param # may be null/missing
76
+ else
77
+ grab; add_token :str, "$$" + peek; return
78
+ end
79
+ end
80
+
81
+ def grab_func_param
82
+ case lookahead
83
+ when "["
84
+ param = grab_bracket_param
85
+ add_token(:brackets, param)
86
+ when ":"
87
+ param = grab_colon_param
88
+ add_token(:colon, param)
89
+ else # do nothing
90
+ end
91
+ end
92
+
93
+ end
data/lib/functions.rb CHANGED
@@ -1,5 +1,5 @@
1
+ # p __FILE__
1
2
 
2
- require_relative 'standard' # FIXME umm, why is this necessary??
3
3
 
4
4
  # Class Functions is where '$$func' functions are stored dynamically...
5
5
  # user-def AND pre-def??
@@ -0,0 +1,39 @@
1
+ # p __FILE__
2
+
3
+
4
+ module GlobalHelpers
5
+
6
+ def check_disallowed(name)
7
+ raise DisallowedName(name) if disallowed?(name)
8
+ end
9
+
10
+ def check_file_exists(file)
11
+ raise FileNotFound(file) unless File.exist?(file)
12
+ end
13
+
14
+ def grab_file(fname)
15
+ File.read(fname)
16
+ end
17
+
18
+ def search_upward(file)
19
+ value = nil
20
+ return file if File.exist?(file)
21
+
22
+ count = 1
23
+ loop do
24
+ front = "../" * count
25
+ count += 1
26
+ here = Pathname.new(front).expand_path.dirname.to_s
27
+ break if here == "/"
28
+ path = front + file
29
+ value = path if File.exist?(path)
30
+ break if value
31
+ end
32
+ ::STDERR.puts "Cannot find #{file.inspect} from #{Dir.pwd}" unless value
33
+ return value
34
+ rescue
35
+ ::STDERR.puts "Can't find #{file.inspect} from #{Dir.pwd}"
36
+ return nil
37
+ end
38
+
39
+ end
@@ -1,6 +1,10 @@
1
1
 
2
+ require_relative '../helpers'
3
+ require_relative '../global_helpers'
4
+
2
5
  class Livetext::Handler::Import
3
- include Helpers
6
+ include Livetext::Helpers
7
+ include GlobalHelpers
4
8
 
5
9
  attr_reader :file
6
10
 
@@ -9,15 +13,23 @@ class Livetext::Handler::Import
9
13
  @file = find_file(name)
10
14
  end
11
15
 
12
- def self.get_module(name)
13
- handler = self.new(name)
14
- const1 = Object.constants
16
+ def self.get_mod_name
17
+ file = File.new(@file + ".rb")
18
+ str = nil
19
+ file.each_line do |line|
20
+ str = line
21
+ break if str =~ /^module /
22
+ end
23
+ junk, name, junk2 = str.split
24
+ name
25
+ end
26
+
27
+ def self.get_module(filename)
28
+ handler = self.new(filename)
15
29
  @file = handler.file.sub(/.rb$/, "")
16
30
  require @file # + ".rb"
17
- const2 = Object.constants
18
- names = (const2 - const1)
19
- abort "Expected ONE new constant: #{names.inspect}" if names.size != 1
20
- modname = names.first.to_s
31
+ modname = get_mod_name
32
+ # TTY.puts "modname = #{modname.inspect}"
21
33
  newmod = Object.const_get("::" + modname)
22
34
  newmod # return actual module
23
35
  end
@@ -28,8 +40,5 @@ class Livetext::Handler::Import
28
40
  File.dirname(File.expand_path(".")) == "/"
29
41
  end
30
42
 
31
- def fname2module(name)
32
- end
33
-
34
43
  end
35
44
 
data/lib/handler.rb CHANGED
@@ -1 +1,3 @@
1
+ # p __FILE__
2
+
1
3
  require_relative 'handler/import'
data/lib/helpers.rb CHANGED
@@ -1,5 +1,7 @@
1
+ # p __FILE__
1
2
 
2
- module Helpers
3
+
4
+ module Livetext::Helpers
3
5
 
4
6
  Space = " "
5
7
  Sigil = "." # Can't change yet
@@ -23,8 +25,10 @@ module Helpers
23
25
  string.gsub(/['&\"<>]/, ESCAPING)
24
26
  end
25
27
 
26
- def find_file(name, ext=".rb")
27
- paths = [Livetext::Path.sub(/lib/, "imports/"), "./"]
28
+ def find_file(name, ext=".rb", which="imports")
29
+ failed = "#{__method__}: expected 'imports' or 'plugin'"
30
+ raise failed unless %w[imports plugin].include?(which)
31
+ paths = [Livetext::Path.sub(/lib/, "#{which}/"), "./"]
28
32
  base = "#{name}#{ext}"
29
33
  paths.each do |path|
30
34
  file = path + base
@@ -61,7 +65,11 @@ module Helpers
61
65
  process_line(line)
62
66
  end
63
67
  val = @main.finalize rescue nil
64
- @body
68
+ @body # FIXME? @body.join("\n") # array
69
+ rescue StandardError => err
70
+ # TTY.puts ">>> rescue in process_file!! (helpers)"
71
+ # TTY.puts @body
72
+ raise err
65
73
  end
66
74
 
67
75
  def process_line(line)
data/lib/html.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # p __FILE__
2
+
1
3
  module HTMLHelper
2
4
 
3
5
  def wrapped(str, *tags) # helper
data/lib/livetext.rb CHANGED
@@ -1,11 +1,23 @@
1
+ # p __FILE__
2
+
3
+ require_relative 'parser/string'
4
+
1
5
  # Class Livetext skeleton (top level).
2
6
 
3
7
  class Livetext
4
- VERSION = "0.9.22"
8
+ VERSION = "0.9.23"
5
9
  Path = File.expand_path(File.join(File.dirname(__FILE__)))
6
10
 
7
11
  module Handler
8
12
  end
13
+
14
+ module ParsingConstants
15
+ end
16
+
17
+ class FormatLine < StringParser
18
+ module FunCall
19
+ end
20
+ end
9
21
  end
10
22
 
11
23
  require 'fileutils'
@@ -21,14 +33,15 @@ class Object
21
33
  end
22
34
 
23
35
  require_relative 'errors'
36
+ require_relative 'standard'
24
37
  require_relative 'functions'
25
38
  require_relative 'userapi'
26
- require_relative 'standard'
27
39
  require_relative 'formatline'
28
40
  require_relative 'processor'
29
41
  require_relative 'helpers'
30
42
  require_relative 'handler'
31
43
 
44
+
32
45
  Plugins = File.expand_path(File.join(File.dirname(__FILE__), "../plugin"))
33
46
  Imports = File.expand_path(File.join(File.dirname(__FILE__), "../imports"))
34
47
 
@@ -57,6 +70,11 @@ class Livetext
57
70
  Livetext::Vars.dup
58
71
  end
59
72
 
73
+ def self.interpolate(str)
74
+ # FIXME There are issues here...
75
+ Livetext::FormatLine.var_func_parse(str)
76
+ end
77
+
60
78
  def self.customize(mix: [], call: [], vars: {})
61
79
  obj = self.new
62
80
  mix = Array(mix)
@@ -88,6 +106,9 @@ class Livetext
88
106
  initial_vars
89
107
  end
90
108
 
109
+ def interpolate(str)
110
+ end
111
+
91
112
  def initial_vars
92
113
  # Other predefined variables (see also setfile)
93
114
  setvar(:User, `whoami`.chomp)
data/lib/parser/file.rb CHANGED
@@ -1,6 +1,4 @@
1
1
 
2
- require_relative '../livetext'
3
-
4
2
  # Hmm. not today?
5
3
 
6
4
  class Livetext::ParseFile
@@ -1,7 +1,4 @@
1
1
 
2
- require_relative '../livetext'
3
- require_relative 'string'
4
-
5
2
  make_exception(:MismatchedQuotes, "Error: mismatched quotes")
6
3
  make_exception(:NilValue, "Error: nil value")
7
4
  make_exception(:NullString, "Error: null string")
data/lib/parser/mixin.rb CHANGED
@@ -1,15 +1,13 @@
1
- require_relative '../livetext'
2
- require_relative '../helpers'
3
- require_relative 'string'
1
+ require_relative '../helpers' # FIXME This seems wrong
4
2
 
5
3
  make_exception(:NoEqualSign, "Error: no equal sign found")
6
4
 
7
5
  class Livetext::ParseMixin
8
- include Helpers
6
+ include Livetext::Helpers
9
7
 
10
8
  def initialize(name)
11
9
  @name = name
12
- @file = find_file(name)
10
+ @file = find_file(name, ".rb", "plugin")
13
11
  end
14
12
 
15
13
  def self.get_module(name)
@@ -17,8 +15,7 @@ class Livetext::ParseMixin
17
15
  modname, code = parse.read_mixin
18
16
  eval(code) # Avoid in the future
19
17
  newmod = Object.const_get("::" + modname)
20
- # return actual module
21
- newmod
18
+ newmod # return actual module
22
19
  end
23
20
 
24
21
  def read_mixin
@@ -33,6 +30,5 @@ class Livetext::ParseMixin
33
30
  File.dirname(File.expand_path(".")) == "/"
34
31
  end
35
32
 
36
-
37
33
  end
38
34
 
data/lib/parser/set.rb CHANGED
@@ -1,7 +1,4 @@
1
1
 
2
- require_relative '../livetext'
3
- require_relative 'string'
4
-
5
2
  make_exception(:BadVariableName, "Error: invalid variable name")
6
3
  make_exception(:NoEqualSign, "Error: no equal sign found")
7
4
 
data/lib/parser.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # p __FILE__
2
+
1
3
 
2
4
  require_relative 'parser/string'
3
5
  require_relative 'parser/general'
data/lib/parsing.rb ADDED
@@ -0,0 +1,31 @@
1
+ # p __FILE__
2
+
3
+
4
+ # Constants for parsing
5
+
6
+ module Livetext::ParsingConstants
7
+ SimpleFormats = {}
8
+ SimpleFormats[:b] = %w[<b> </b>]
9
+ SimpleFormats[:i] = %w[<i> </i>]
10
+ SimpleFormats[:t] = ["<font size=+1><tt>", "</tt></font>"]
11
+ SimpleFormats[:s] = %w[<strike> </strike>]
12
+
13
+ BITS = SimpleFormats.keys
14
+
15
+ Null = ""
16
+ Space = " "
17
+ Alpha = /[A-Za-z]/
18
+ AlNum = /[A-Za-z0-9_]/
19
+ LF = "\n"
20
+ LBrack = "["
21
+
22
+ Blank = [" ", nil, "\n"]
23
+ Punc = [")", ",", ".", " ", "\n"]
24
+ NoAlpha = /[^A-Za-z0-9_]/
25
+ NoAlphaDot = /[^.A-Za-z0-9_]/
26
+ Param = ["]", "\n", nil]
27
+ Escape = "\\" # not an ESC char
28
+
29
+ Syms = { "*" => :b, "_" => :i, "`" => :t, "~" => :s }
30
+
31
+ end