livetext 0.9.21 → 0.9.25
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 +4 -4
- data/README.lt3 +8 -8
- data/bin/livetext +57 -40
- data/imports/bookish.rb +89 -90
- data/imports/calibre.rb +3 -3
- data/imports/livemagick.rb +17 -17
- data/imports/markdown.rb +10 -10
- data/imports/pyggish.rb +15 -47
- data/imports/tutorial.rb +18 -18
- data/lib/cmdargs.rb +10 -6
- data/lib/{errors.rb → livetext/errors.rb} +1 -1
- data/lib/{formatline.rb → livetext/formatline.rb} +69 -125
- data/lib/livetext/funcall.rb +84 -0
- data/lib/{functions.rb → livetext/functions.rb} +16 -3
- data/lib/livetext/global_helpers.rb +37 -0
- data/lib/livetext/handler/import.rb +44 -0
- data/lib/livetext/handler/mixin.rb +37 -0
- data/lib/livetext/handler.rb +3 -0
- data/lib/{helpers.rb → livetext/helpers.rb} +89 -67
- data/lib/{html.rb → livetext/html.rb} +3 -2
- data/lib/{parser → livetext/parser}/general.rb +0 -3
- data/lib/{parser → livetext/parser}/set.rb +1 -6
- data/lib/{parser → livetext/parser}/string.rb +2 -2
- data/lib/{parser.rb → livetext/parser.rb} +0 -1
- data/lib/livetext/parsing.rb +29 -0
- data/lib/livetext/paths.rb +13 -0
- data/lib/livetext/processor.rb +89 -0
- data/lib/livetext/reopen.rb +12 -0
- data/lib/livetext/skeleton.rb +17 -0
- data/lib/{standard.rb → livetext/standard.rb} +152 -122
- data/lib/livetext/userapi.rb +153 -0
- data/lib/livetext/version.rb +6 -0
- data/lib/livetext.rb +66 -27
- data/plugin/bookish.rb +85 -85
- data/plugin/calibre.rb +3 -3
- data/plugin/livemagick.rb +17 -17
- data/plugin/markdown.rb +10 -10
- data/plugin/pyggish.rb +131 -162
- data/plugin/tutorial.rb +15 -16
- data/test/all.rb +6 -0
- data/test/snapshots/def_method/expected-output.txt +2 -0
- data/test/snapshots/def_method/source.lt3 +4 -2
- data/test/snapshots/error_inc_line_num/OUT +17 -0
- data/test/snapshots/error_inc_line_num/README.txt +20 -0
- data/test/snapshots/error_inc_line_num/expected-output.txt +0 -6
- data/test/snapshots/error_inc_line_num/match-error.txt +1 -1
- data/test/snapshots/error_line_num/match-error.txt +1 -1
- data/test/snapshots/error_missing_end/expected-output.txt +0 -1
- data/test/snapshots/error_name_not_permitted/expected-output.txt +4 -0
- data/test/snapshots/error_name_not_permitted/match-error.txt +1 -1
- data/test/snapshots/error_no_such_copy/duh +26 -0
- data/test/snapshots/error_no_such_copy/expected-output.txt +1 -0
- data/test/snapshots/error_no_such_copy/match-error.txt +1 -1
- data/test/snapshots/error_no_such_copy/mystery.txt +36 -0
- data/test/snapshots/error_no_such_inc/match-error.txt +1 -1
- data/test/snapshots/error_no_such_mixin/expected-output.txt +1 -0
- data/test/snapshots/error_no_such_mixin/match-error.txt +1 -1
- data/test/snapshots/error_no_such_mixin/source.lt3 +1 -1
- data/test/snapshots/example_alpha/source.lt3 +2 -2
- data/test/snapshots/example_alpha2/expected-output.txt +0 -2
- data/test/snapshots/example_alpha2/source.lt3 +5 -4
- data/test/snapshots/{icanhaz → import}/expected-output.txt +2 -1
- data/test/snapshots/import/match-error.txt +1 -0
- data/test/snapshots/{icanhaz → import}/simple_import.rb +1 -1
- data/test/snapshots/{icanhaz → import}/source.lt3 +2 -2
- data/test/snapshots/{icanhaz2 → import2}/expected-error.txt +0 -0
- data/test/snapshots/{icanhaz2 → import2}/expected-output.txt +3 -1
- data/test/snapshots/{icanhaz2/simple_canhaz.rb → import2/simple_import.rb} +1 -1
- data/test/snapshots/import2/source.lt3 +8 -0
- data/test/snapshots/import_bookish/expected-error.txt +0 -0
- data/test/snapshots/import_bookish/expected-output.txt +10 -0
- data/test/snapshots/import_bookish/source.lt3 +7 -0
- data/test/snapshots/import_bookish/toc.tmp +0 -0
- data/test/snapshots/mixin_bookish/expected-error.txt +0 -0
- data/test/snapshots/mixin_bookish/expected-output.txt +10 -0
- data/test/snapshots/mixin_bookish/source.lt3 +7 -0
- data/test/snapshots/mixin_bookish/toc.tmp +0 -0
- data/test/snapshots/more_functions/expected-error.txt +0 -0
- data/test/snapshots/more_functions/expected-output.txt +37 -0
- data/test/snapshots/more_functions/source.lt3 +40 -0
- data/test/snapshots/raw_lines/expected-output.txt +0 -2
- data/test/snapshots/simple_import/expected-output.txt +2 -0
- data/test/snapshots/simple_import/simple_import.rb +1 -1
- data/test/snapshots/simple_import/source.lt3 +3 -1
- data/test/snapshots/simple_mixin/simple_mixin.rb +1 -1
- data/test/snapshots/single_raw_line/expected-output.txt +0 -2
- data/test/snapshots/subset.txt +14 -14
- data/test/snapshots.rb +30 -13
- data/test/unit/formatline.rb +253 -134
- data/test/unit/html.rb +2 -3
- data/test/unit/parser/general.rb +1 -2
- data/test/unit/parser/mixin.rb +1 -3
- data/test/unit/parser/set.rb +8 -12
- data/test/unit/parser/string.rb +6 -6
- data/test/unit/parser.rb +0 -1
- data/test/unit/standard.rb +0 -2
- metadata +47 -30
- data/imports/markdown_importable.rb +0 -45
- data/lib/handler/icanhaz.rb +0 -35
- data/lib/handler.rb +0 -1
- data/lib/livetext/importable.rb +0 -2
- data/lib/parser/file.rb +0 -8
- data/lib/parser/import.rb +0 -15
- data/lib/parser/mixin.rb +0 -38
- data/lib/processor.rb +0 -83
- data/lib/userapi.rb +0 -160
- data/test/snapshots/icanhaz/match-error.txt +0 -1
- data/test/snapshots/icanhaz2/source.lt3 +0 -6
- data/test/unit/parser/importable.rb +0 -19
|
@@ -1,6 +1,4 @@
|
|
|
1
1
|
|
|
2
|
-
require_relative 'standard' # FIXME umm, why is this necessary??
|
|
3
|
-
|
|
4
2
|
# Class Functions is where '$$func' functions are stored dynamically...
|
|
5
3
|
# user-def AND pre-def??
|
|
6
4
|
|
|
@@ -13,6 +11,21 @@ class Livetext::Functions
|
|
|
13
11
|
attr_accessor :param # kill this?
|
|
14
12
|
end
|
|
15
13
|
|
|
14
|
+
# FIXME Function parameters need to be fixed...
|
|
15
|
+
|
|
16
|
+
def isqrt(param = nil) # "integer square root" - Just for testing
|
|
17
|
+
arg = num = param # Takes any number
|
|
18
|
+
if num.nil? || num.empty?
|
|
19
|
+
arg = "NO PARAM" # Just for error text
|
|
20
|
+
end
|
|
21
|
+
# Integer()/Float() can raise error
|
|
22
|
+
num = num.include?(".") ? Float(num) : Integer(num)
|
|
23
|
+
# Returns truncated integer
|
|
24
|
+
Math.sqrt(num).to_i # user need not do to_s
|
|
25
|
+
rescue => err # Malformed number? negative?
|
|
26
|
+
"[Error evaluating $$isqrt(#{arg})]"
|
|
27
|
+
end
|
|
28
|
+
|
|
16
29
|
def date(param=nil)
|
|
17
30
|
Time.now.strftime("%F")
|
|
18
31
|
end
|
|
@@ -40,7 +53,7 @@ class Livetext::Functions
|
|
|
40
53
|
"<br>"*n
|
|
41
54
|
end
|
|
42
55
|
|
|
43
|
-
def yt(param)
|
|
56
|
+
def yt(param) # FIXME uh, this is crap
|
|
44
57
|
param = self.class.param
|
|
45
58
|
"https://www.youtube.com/watch?v=#{param}"
|
|
46
59
|
end
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
|
|
2
|
+
module GlobalHelpers
|
|
3
|
+
|
|
4
|
+
def check_disallowed(name)
|
|
5
|
+
raise DisallowedName(name) if disallowed?(name)
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def check_file_exists(file)
|
|
9
|
+
graceful_error FileNotFound(file) unless File.exist?(file)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def grab_file(fname)
|
|
13
|
+
File.read(fname)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def search_upward(file)
|
|
17
|
+
value = nil
|
|
18
|
+
return file if File.exist?(file)
|
|
19
|
+
|
|
20
|
+
count = 1
|
|
21
|
+
loop do
|
|
22
|
+
front = "../" * count
|
|
23
|
+
count += 1
|
|
24
|
+
here = Pathname.new(front).expand_path.dirname.to_s
|
|
25
|
+
break if here == "/"
|
|
26
|
+
path = front + file
|
|
27
|
+
value = path if File.exist?(path)
|
|
28
|
+
break if value
|
|
29
|
+
end
|
|
30
|
+
::STDERR.puts "Cannot find #{file.inspect} from #{Dir.pwd}" unless value
|
|
31
|
+
return value
|
|
32
|
+
rescue
|
|
33
|
+
::STDERR.puts "Can't find #{file.inspect} from #{Dir.pwd}"
|
|
34
|
+
return nil
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
end
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
|
|
2
|
+
require_relative '../helpers'
|
|
3
|
+
|
|
4
|
+
class Livetext::Handler::Import
|
|
5
|
+
include Livetext::Helpers
|
|
6
|
+
include GlobalHelpers
|
|
7
|
+
|
|
8
|
+
attr_reader :file
|
|
9
|
+
|
|
10
|
+
def initialize(name)
|
|
11
|
+
@name = name
|
|
12
|
+
@file = find_file(name)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def self.get_mod_name
|
|
16
|
+
file = File.new(@file + ".rb")
|
|
17
|
+
str = nil
|
|
18
|
+
file.each_line do |line|
|
|
19
|
+
str = line
|
|
20
|
+
break if str =~ /^module /
|
|
21
|
+
end
|
|
22
|
+
junk, name, junk2 = str.split
|
|
23
|
+
name
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def self.get_module(filename, parent)
|
|
27
|
+
# TTY.puts "#{__method__}: filename = #{filename.inspect}"
|
|
28
|
+
handler = self.new(filename)
|
|
29
|
+
parent.graceful_error FileNotFound(filename) if handler.file.nil?
|
|
30
|
+
@file = handler.file.sub(/.rb$/, "")
|
|
31
|
+
require @file # + ".rb"
|
|
32
|
+
modname = get_mod_name
|
|
33
|
+
newmod = Object.const_get("::" + modname)
|
|
34
|
+
newmod # return actual module
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
private
|
|
38
|
+
|
|
39
|
+
def cwd_root?
|
|
40
|
+
File.dirname(File.expand_path(".")) == "/"
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
end
|
|
44
|
+
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
|
|
2
|
+
require_relative '../helpers'
|
|
3
|
+
|
|
4
|
+
class Livetext::Handler::Mixin
|
|
5
|
+
include Livetext::Helpers
|
|
6
|
+
include GlobalHelpers
|
|
7
|
+
|
|
8
|
+
attr_reader :file
|
|
9
|
+
|
|
10
|
+
def initialize(name, parent)
|
|
11
|
+
@name = name
|
|
12
|
+
@file = find_file(name, ".rb", "plugin")
|
|
13
|
+
parent.graceful_error FileNotFound(name) if @file.nil?
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def self.get_module(filename, parent)
|
|
17
|
+
handler = self.new(filename, parent)
|
|
18
|
+
modname, code = handler.read_mixin
|
|
19
|
+
eval(code) # Avoid in the future
|
|
20
|
+
newmod = Object.const_get("::" + modname)
|
|
21
|
+
newmod # return actual module
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def read_mixin
|
|
25
|
+
modname = @name.gsub("/","_").capitalize
|
|
26
|
+
meths = grab_file(@file) # already has .rb?
|
|
27
|
+
[modname, "module ::#{modname}; #{meths}\nend"]
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
private
|
|
31
|
+
|
|
32
|
+
def cwd_root?
|
|
33
|
+
File.dirname(File.expand_path(".")) == "/"
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
end
|
|
37
|
+
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
|
|
2
|
-
|
|
2
|
+
require_relative 'global_helpers'
|
|
3
|
+
|
|
4
|
+
module Livetext::Helpers
|
|
3
5
|
|
|
4
6
|
Space = " "
|
|
5
7
|
Sigil = "." # Can't change yet
|
|
@@ -7,6 +9,14 @@ module Helpers
|
|
|
7
9
|
ESCAPING = { "'" => ''', '&' => '&', '"' => '"',
|
|
8
10
|
'<' => '<', '>' => '>' }
|
|
9
11
|
|
|
12
|
+
def friendly_error(err)
|
|
13
|
+
return graceful_error(err) if self.respond_to?(:graceful_error)
|
|
14
|
+
return self.parent.graceful_error(err) if self.respond_to?(:parent)
|
|
15
|
+
raise err
|
|
16
|
+
rescue => myerr
|
|
17
|
+
TTY.puts "--- Warning: friendly_error #{myerr.inspect}"
|
|
18
|
+
end
|
|
19
|
+
|
|
10
20
|
def escape_html(string)
|
|
11
21
|
enc = string.encoding
|
|
12
22
|
unless enc.ascii_compatible?
|
|
@@ -23,108 +33,115 @@ module Helpers
|
|
|
23
33
|
string.gsub(/['&\"<>]/, ESCAPING)
|
|
24
34
|
end
|
|
25
35
|
|
|
26
|
-
def
|
|
27
|
-
|
|
36
|
+
def showme(obj, tag = "")
|
|
37
|
+
whence = caller[0]
|
|
38
|
+
file, line, meth = whence.split(":")
|
|
39
|
+
file = File.basename(file)
|
|
40
|
+
meth = meth[4..-2]
|
|
41
|
+
tag << " =" if tag
|
|
42
|
+
hide_class = [true, false, nil].include?(obj)
|
|
43
|
+
klass = hide_class ? "" : "(#{obj.class}) "
|
|
44
|
+
puts " #{tag} #{klass}#{obj.inspect} in ##{meth} [#{file} line #{line}]"
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def debug(*args)
|
|
48
|
+
puts(*args) if ENV['debug']
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def find_file(name, ext=".rb", which="imports")
|
|
52
|
+
failed = "#{__method__}: expected 'imports' or 'plugin'"
|
|
53
|
+
raise failed unless %w[imports plugin].include?(which)
|
|
54
|
+
paths = [Livetext::Path.sub(/lib.livetext/, "#{which}/"), "./"]
|
|
28
55
|
base = "#{name}#{ext}"
|
|
29
56
|
paths.each do |path|
|
|
30
57
|
file = path + base
|
|
31
58
|
return file if File.exist?(file)
|
|
32
59
|
end
|
|
33
|
-
|
|
34
|
-
raise "No such mixin '#{name}'"
|
|
35
|
-
|
|
36
|
-
# # Really want to search upward??
|
|
37
|
-
# raise "No such mixin '#{name}'" if cwd_root?
|
|
38
|
-
# Dir.chdir("..") { find_file(name) }
|
|
60
|
+
return nil
|
|
39
61
|
end
|
|
40
62
|
|
|
41
63
|
def self.rx(str, space=nil)
|
|
42
64
|
Regexp.compile("^" + Regexp.escape(str) + "#{space}")
|
|
43
65
|
end
|
|
44
66
|
|
|
45
|
-
Comment
|
|
46
|
-
|
|
47
|
-
|
|
67
|
+
Comment = rx(Sigil, Space)
|
|
68
|
+
DotCmd = rx(Sigil)
|
|
69
|
+
DollarDot = /^ *\$\.[A-Za-z]/
|
|
48
70
|
|
|
49
|
-
## FIXME process_file[!] should call process[_text]
|
|
71
|
+
## FIXME process_file[!] should call process[_text] ?
|
|
50
72
|
|
|
51
73
|
def process_file(fname, btrace=false)
|
|
74
|
+
graceful_error FileNotFound(fname) unless File.exist?(fname)
|
|
52
75
|
setfile(fname)
|
|
53
76
|
text = File.readlines(fname)
|
|
54
77
|
enum = text.each
|
|
55
78
|
@backtrace = btrace
|
|
56
79
|
@main.source(enum, fname, 0)
|
|
57
80
|
line = nil
|
|
58
|
-
loop do
|
|
81
|
+
loop do
|
|
59
82
|
line = @main.nextline
|
|
60
83
|
break if line.nil?
|
|
61
|
-
process_line(line)
|
|
84
|
+
success = process_line(line)
|
|
85
|
+
break unless success
|
|
62
86
|
end
|
|
63
|
-
val = @main.finalize
|
|
64
|
-
@body
|
|
87
|
+
val = @main.finalize rescue nil
|
|
88
|
+
@body # FIXME? @body.join("\n") # array
|
|
89
|
+
return true
|
|
65
90
|
end
|
|
66
91
|
|
|
67
92
|
def process_line(line)
|
|
68
|
-
|
|
93
|
+
success = true
|
|
69
94
|
case line # must apply these in order
|
|
70
95
|
when Comment
|
|
71
|
-
handle_scomment(line)
|
|
72
|
-
when
|
|
73
|
-
handle_dotcmd(line)
|
|
74
|
-
when
|
|
75
|
-
|
|
76
|
-
@indentation.push(indent)
|
|
77
|
-
line.sub!(/^ *\$/, "")
|
|
78
|
-
handle_dotcmd(line)
|
|
79
|
-
indentation.pop
|
|
96
|
+
success = handle_scomment(line)
|
|
97
|
+
when DotCmd
|
|
98
|
+
success = handle_dotcmd(line)
|
|
99
|
+
when DollarDot
|
|
100
|
+
success = handle_dollar_dot
|
|
80
101
|
else
|
|
81
|
-
|
|
102
|
+
api.passthru(line) # must succeed?
|
|
82
103
|
end
|
|
104
|
+
success
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def handle_dollar_dot
|
|
108
|
+
indent = line.index("$") + 1
|
|
109
|
+
@indentation.push(indent)
|
|
110
|
+
line.sub!(/^ *\$/, "")
|
|
111
|
+
success = handle_dotcmd(line)
|
|
112
|
+
indentation.pop
|
|
113
|
+
success
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def invoke_dotcmd(name)
|
|
117
|
+
# FIXME Add cmdargs stuff... depends on name, etc.
|
|
118
|
+
retval = @main.send(name)
|
|
119
|
+
retval
|
|
120
|
+
# rescue NoMethodError => err
|
|
121
|
+
# graceful_error(err)
|
|
122
|
+
rescue => err
|
|
123
|
+
graceful_error(err)
|
|
83
124
|
end
|
|
84
125
|
|
|
85
126
|
def handle_dotcmd(line, indent = 0)
|
|
127
|
+
# TTY.puts ">>> #{__method__} in #{__FILE__}" # if ENV['debug']
|
|
86
128
|
indent = @indentation.last # top of stack
|
|
87
|
-
line = line.sub(/# .*$/, "")
|
|
88
|
-
name = get_name(line)
|
|
89
|
-
|
|
129
|
+
line = line.sub(/# .*$/, "") # FIXME Could be problematic?
|
|
130
|
+
name = get_name(line)
|
|
131
|
+
success = true # Be optimistic... :P
|
|
90
132
|
case
|
|
91
133
|
when name == :end # special case
|
|
92
|
-
|
|
93
|
-
raise EndWithoutOpening()
|
|
134
|
+
graceful_error EndWithoutOpening()
|
|
94
135
|
when @main.respond_to?(name)
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
# NOTE: The above line is where the magic happens!
|
|
98
|
-
# A name like 'foobar' results in an invocation of
|
|
99
|
-
# @main.foobar (where @main is a Processor, and any
|
|
100
|
-
# new methods (e.g. from a mixin) are added to @main
|
|
101
|
-
#
|
|
102
|
-
# So all the functionality from _args and _raw_args
|
|
103
|
-
# and _data (among others?) will be encapsulated in
|
|
104
|
-
# 'some' kind of PORO which handles access to all
|
|
105
|
-
# these things as well as the 'body' between the
|
|
106
|
-
# command and its corresponding .end
|
|
107
|
-
#
|
|
108
|
-
# The 'body' functionality is so commonly used, I plan
|
|
109
|
-
# to pass it in separately as needed (even though the
|
|
110
|
-
# args object should make it available also).
|
|
111
|
-
#
|
|
112
|
-
# Every method corresponding to a dot commmand will
|
|
113
|
-
# get args and body passed in as needed. Every one of
|
|
114
|
-
# the signatures already has (args = nil, body = nil)
|
|
115
|
-
# but nothing is being passed in that way yet.
|
|
116
|
-
#
|
|
117
|
-
# Refer to lib/cmdargs.rb for more! This is *strictly*
|
|
118
|
-
# experimental and a "work in progress."
|
|
136
|
+
success = invoke_dotcmd(name)
|
|
119
137
|
else
|
|
120
|
-
|
|
121
|
-
raise "Name '#{name}' is unknown"
|
|
122
|
-
return
|
|
138
|
+
graceful_error UnknownMethod(name)
|
|
123
139
|
end
|
|
124
|
-
|
|
140
|
+
success
|
|
125
141
|
end
|
|
126
142
|
|
|
127
143
|
def handle_scomment(line)
|
|
144
|
+
return true
|
|
128
145
|
end
|
|
129
146
|
|
|
130
147
|
def get_name(line)
|
|
@@ -133,15 +150,17 @@ module Helpers
|
|
|
133
150
|
name = "dot_" + name if %w[include def].include?(name)
|
|
134
151
|
@main.check_disallowed(name)
|
|
135
152
|
@main.data = data
|
|
136
|
-
|
|
153
|
+
@main.api.data = data
|
|
154
|
+
name.to_sym
|
|
137
155
|
end
|
|
138
156
|
|
|
139
157
|
def check_disallowed(name)
|
|
140
|
-
|
|
158
|
+
friendly_error DisallowedName(name) if disallowed?(name)
|
|
141
159
|
end
|
|
142
160
|
|
|
143
161
|
def check_file_exists(file)
|
|
144
|
-
|
|
162
|
+
# raise FileNotFound(file) unless File.exist?(file)
|
|
163
|
+
return File.exist?(file)
|
|
145
164
|
end
|
|
146
165
|
|
|
147
166
|
def set_variables(pairs)
|
|
@@ -153,6 +172,9 @@ module Helpers
|
|
|
153
172
|
|
|
154
173
|
def grab_file(fname)
|
|
155
174
|
File.read(fname)
|
|
175
|
+
rescue
|
|
176
|
+
::STDERR.puts "Can't find #{fname.inspect} \n "
|
|
177
|
+
return nil
|
|
156
178
|
end
|
|
157
179
|
|
|
158
180
|
def search_upward(file)
|
|
@@ -169,15 +191,15 @@ module Helpers
|
|
|
169
191
|
value = path if File.exist?(path)
|
|
170
192
|
break if value
|
|
171
193
|
end
|
|
172
|
-
STDERR.puts "Cannot find #{file.inspect} from #{Dir.pwd}" unless value
|
|
194
|
+
::STDERR.puts "Cannot find #{file.inspect} from #{Dir.pwd}" unless value
|
|
173
195
|
return value
|
|
174
196
|
rescue
|
|
175
|
-
STDERR.puts "Can't find #{file.inspect} from #{Dir.pwd}"
|
|
197
|
+
::STDERR.puts "Can't find #{file.inspect} from #{Dir.pwd}"
|
|
176
198
|
return nil
|
|
177
199
|
end
|
|
178
200
|
|
|
179
201
|
def include_file(file)
|
|
180
|
-
|
|
202
|
+
api.args = [file]
|
|
181
203
|
dot_include
|
|
182
204
|
end
|
|
183
205
|
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
|
|
1
2
|
module HTMLHelper
|
|
2
3
|
|
|
3
4
|
def wrapped(str, *tags) # helper
|
|
@@ -15,9 +16,9 @@ module HTMLHelper
|
|
|
15
16
|
|
|
16
17
|
def wrap(*tags) # helper
|
|
17
18
|
open, close = open_close_tags(*tags)
|
|
18
|
-
|
|
19
|
+
api.out open
|
|
19
20
|
yield
|
|
20
|
-
|
|
21
|
+
api.out close
|
|
21
22
|
end
|
|
22
23
|
|
|
23
24
|
def open_close_tags(*tags)
|
|
@@ -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
|
|
|
@@ -107,7 +104,6 @@ class Livetext::ParseSet < StringParser
|
|
|
107
104
|
char = grab
|
|
108
105
|
break if eos?
|
|
109
106
|
break if char == quote
|
|
110
|
-
# break if char.nil?
|
|
111
107
|
char = escaped if char == "\\"
|
|
112
108
|
value << char
|
|
113
109
|
end
|
|
@@ -123,8 +119,7 @@ class Livetext::ParseSet < StringParser
|
|
|
123
119
|
value = ""
|
|
124
120
|
loop do
|
|
125
121
|
char = peek
|
|
126
|
-
break if eos?
|
|
127
|
-
# break if char.nil?
|
|
122
|
+
break if eos?
|
|
128
123
|
break if char == " " || char == ","
|
|
129
124
|
value << char
|
|
130
125
|
char = grab
|
|
@@ -24,7 +24,7 @@ class StringParser
|
|
|
24
24
|
check_eos
|
|
25
25
|
end
|
|
26
26
|
|
|
27
|
-
def
|
|
27
|
+
def lookahead
|
|
28
28
|
@line[@i + 1]
|
|
29
29
|
end
|
|
30
30
|
|
|
@@ -62,7 +62,7 @@ end
|
|
|
62
62
|
|
|
63
63
|
=begin
|
|
64
64
|
skip
|
|
65
|
-
|
|
65
|
+
lookahead skip! peek!(?)
|
|
66
66
|
expect_alpha
|
|
67
67
|
expect_number
|
|
68
68
|
skip_spaces
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
|
|
2
|
+
# Constants for parsing
|
|
3
|
+
|
|
4
|
+
module Livetext::ParsingConstants
|
|
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 }
|
|
28
|
+
|
|
29
|
+
end
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# Reopening for paths... do differently?
|
|
2
|
+
|
|
3
|
+
class Livetext
|
|
4
|
+
def self.get_path(dir = "")
|
|
5
|
+
path = File.join(File.dirname(__FILE__), dir)
|
|
6
|
+
File.expand_path(path)
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
Path = self.get_path
|
|
10
|
+
Plugins = self.get_path("../plugin")
|
|
11
|
+
Imports = self.get_path("../imports")
|
|
12
|
+
end
|
|
13
|
+
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
|
|
2
|
+
# Class Processor does the actual work of processing input.
|
|
3
|
+
|
|
4
|
+
class Processor
|
|
5
|
+
|
|
6
|
+
GenericError = Class.new(StandardError)
|
|
7
|
+
|
|
8
|
+
include Livetext::Standard
|
|
9
|
+
|
|
10
|
+
Disallowed =
|
|
11
|
+
%i[ __binding__ __id__ __send__ class
|
|
12
|
+
clone display dup enum_for
|
|
13
|
+
eql? equal? extend freeze
|
|
14
|
+
frozen? hash inspect instance_eval
|
|
15
|
+
instance_exec instance_of? is_a? kind_of?
|
|
16
|
+
method methods nil? object_id
|
|
17
|
+
pretty_inspect private_methods protected_methods public_method
|
|
18
|
+
public_methods public_send respond_to? send
|
|
19
|
+
singleton_class singleton_method singleton_methods taint
|
|
20
|
+
tainted? tap to_enum to_s
|
|
21
|
+
trust untaint untrust untrusted?
|
|
22
|
+
define_singleton_method instance_variable_defined?
|
|
23
|
+
instance_variable_get instance_variable_set
|
|
24
|
+
remove_instance_variable instance_variables ]
|
|
25
|
+
|
|
26
|
+
attr_reader :parent, :sources
|
|
27
|
+
|
|
28
|
+
def initialize(parent, output = nil)
|
|
29
|
+
@parent = parent
|
|
30
|
+
@nopass = false
|
|
31
|
+
@nopara = false
|
|
32
|
+
# Meh?
|
|
33
|
+
@output = ::Livetext.output = (output || File.open("/dev/null", "w"))
|
|
34
|
+
@sources = []
|
|
35
|
+
@indentation = @parent.indentation
|
|
36
|
+
@_mixins = []
|
|
37
|
+
@_imports = []
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def api
|
|
41
|
+
@parent.api # FIXME Is this weird??
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def output=(io)
|
|
45
|
+
@output = io
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def error(*args)
|
|
49
|
+
::STDERR.puts *args
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def _error!(err, raise_error=false, trace=false) # FIXME much bullshit happens here
|
|
53
|
+
where = @sources.last || @live.save_location
|
|
54
|
+
error "Error: #{err} (at #{where[1]} line #{where[2]})"
|
|
55
|
+
error(err.backtrace) rescue nil
|
|
56
|
+
raise GenericError.new("Error: #{err}") if raise_error
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def disallowed?(name)
|
|
60
|
+
Disallowed.include?(name.to_sym)
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def source(enum, file, line)
|
|
64
|
+
@sources.push([enum, file, line])
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def peek_nextline
|
|
68
|
+
return nil if @sources.empty?
|
|
69
|
+
source = @sources.last
|
|
70
|
+
line = source[0].peek
|
|
71
|
+
line
|
|
72
|
+
rescue StopIteration
|
|
73
|
+
@sources.pop
|
|
74
|
+
nil
|
|
75
|
+
rescue => err
|
|
76
|
+
TTY.puts "#{__method__}: RESCUE err = #{err.inspect}"
|
|
77
|
+
nil
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def nextline
|
|
81
|
+
return nil if @sources.empty?
|
|
82
|
+
line = @sources.last[0].next
|
|
83
|
+
@sources.last[2] += 1
|
|
84
|
+
line
|
|
85
|
+
rescue StopIteration
|
|
86
|
+
@sources.pop
|
|
87
|
+
nil
|
|
88
|
+
end
|
|
89
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
require_relative 'parser/string' # FIXME eh, should fix this
|
|
2
|
+
|
|
3
|
+
# Class Livetext skeleton (top level).
|
|
4
|
+
|
|
5
|
+
class Livetext
|
|
6
|
+
module Handler
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
module ParsingConstants
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
class FormatLine < StringParser
|
|
13
|
+
module FunCall
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|