change section delimiters in log for OpenBSD
[view.love.git] / file.lua
blob228f1f37f3d1bb99c3a27aa2c5a4efadeff5b0d5
1 -- primitives for saving to file and loading from file
2 function file_exists(filename)
3 local infile = App.open_for_reading(filename)
4 if infile then
5 infile:close()
6 return true
7 else
8 return false
9 end
10 end
12 function load_from_disk(State)
13 local infile = App.open_for_reading(State.filename)
14 State.lines = load_from_file(infile)
15 if infile then infile:close() end
16 end
18 function load_from_file(infile)
19 local result = {}
20 if infile then
21 local infile_next_line = infile:lines() -- works with both Lua files and LÖVE Files (https://www.love2d.org/wiki/File)
22 while true do
23 local line = infile_next_line()
24 if line == nil then break end
25 if line == '```lines' then -- inflexible with whitespace since these files are always autogenerated
26 table.insert(result, load_drawing(infile_next_line))
27 else
28 table.insert(result, {mode='text', data=line})
29 end
30 end
31 end
32 if #result == 0 then
33 table.insert(result, {mode='text', data=''})
34 end
35 return result
36 end
38 function save_to_disk(State)
39 local outfile = App.open_for_writing(State.filename)
40 if not outfile then
41 error('failed to write to "'..State.filename..'"')
42 end
43 for _,line in ipairs(State.lines) do
44 if line.mode == 'drawing' then
45 store_drawing(outfile, line)
46 else
47 outfile:write(line.data)
48 outfile:write('\n')
49 end
50 end
51 outfile:close()
52 end
54 function load_drawing(infile_next_line)
55 local drawing = {mode='drawing', h=256/2, points={}, shapes={}, pending={}}
56 while true do
57 local line = infile_next_line()
58 assert(line)
59 if line == '```' then break end
60 local shape = json.decode(line)
61 if shape.mode == 'freehand' then
62 -- no changes needed
63 elseif shape.mode == 'line' or shape.mode == 'manhattan' then
64 local name = shape.p1.name
65 shape.p1 = Drawing.find_or_insert_point(drawing.points, shape.p1.x, shape.p1.y, --[[large width to minimize overlap]] 1600)
66 drawing.points[shape.p1].name = name
67 name = shape.p2.name
68 shape.p2 = Drawing.find_or_insert_point(drawing.points, shape.p2.x, shape.p2.y, --[[large width to minimize overlap]] 1600)
69 drawing.points[shape.p2].name = name
70 elseif shape.mode == 'polygon' or shape.mode == 'rectangle' or shape.mode == 'square' then
71 for i,p in ipairs(shape.vertices) do
72 local name = p.name
73 shape.vertices[i] = Drawing.find_or_insert_point(drawing.points, p.x,p.y, --[[large width to minimize overlap]] 1600)
74 drawing.points[shape.vertices[i]].name = name
75 end
76 elseif shape.mode == 'circle' or shape.mode == 'arc' then
77 local name = shape.center.name
78 shape.center = Drawing.find_or_insert_point(drawing.points, shape.center.x,shape.center.y, --[[large width to minimize overlap]] 1600)
79 drawing.points[shape.center].name = name
80 elseif shape.mode == 'deleted' then
81 -- ignore
82 else
83 print(shape.mode)
84 assert(false)
85 end
86 table.insert(drawing.shapes, shape)
87 end
88 return drawing
89 end
91 function store_drawing(outfile, drawing)
92 outfile:write('```lines\n')
93 for _,shape in ipairs(drawing.shapes) do
94 if shape.mode == 'freehand' then
95 outfile:write(json.encode(shape))
96 outfile:write('\n')
97 elseif shape.mode == 'line' or shape.mode == 'manhattan' then
98 local line = json.encode({mode=shape.mode, p1=drawing.points[shape.p1], p2=drawing.points[shape.p2]})
99 outfile:write(line)
100 outfile:write('\n')
101 elseif shape.mode == 'polygon' or shape.mode == 'rectangle' or shape.mode == 'square' then
102 local obj = {mode=shape.mode, vertices={}}
103 for _,p in ipairs(shape.vertices) do
104 table.insert(obj.vertices, drawing.points[p])
106 local line = json.encode(obj)
107 outfile:write(line)
108 outfile:write('\n')
109 elseif shape.mode == 'circle' then
110 outfile:write(json.encode({mode=shape.mode, center=drawing.points[shape.center], radius=shape.radius}))
111 outfile:write('\n')
112 elseif shape.mode == 'arc' then
113 outfile:write(json.encode({mode=shape.mode, center=drawing.points[shape.center], radius=shape.radius, start_angle=shape.start_angle, end_angle=shape.end_angle}))
114 outfile:write('\n')
115 elseif shape.mode == 'deleted' then
116 -- ignore
117 else
118 print(shape.mode)
119 assert(false)
122 outfile:write('```\n')
125 -- for tests
126 function load_array(a)
127 local result = {}
128 local next_line = ipairs(a)
129 local i,line,drawing = 0, ''
130 while true do
131 i,line = next_line(a, i)
132 if i == nil then break end
133 --? print(line)
134 if line == '```lines' then -- inflexible with whitespace since these files are always autogenerated
135 --? print('inserting drawing')
136 i, drawing = load_drawing_from_array(next_line, a, i)
137 --? print('i now', i)
138 table.insert(result, drawing)
139 else
140 --? print('inserting text')
141 table.insert(result, {mode='text', data=line})
144 if #result == 0 then
145 table.insert(result, {mode='text', data=''})
147 return result
150 function load_drawing_from_array(iter, a, i)
151 local drawing = {mode='drawing', h=256/2, points={}, shapes={}, pending={}}
152 local line
153 while true do
154 i, line = iter(a, i)
155 assert(i)
156 --? print(i)
157 if line == '```' then break end
158 local shape = json.decode(line)
159 if shape.mode == 'freehand' then
160 -- no changes needed
161 elseif shape.mode == 'line' or shape.mode == 'manhattan' then
162 local name = shape.p1.name
163 shape.p1 = Drawing.find_or_insert_point(drawing.points, shape.p1.x, shape.p1.y, --[[large width to minimize overlap]] 1600)
164 drawing.points[shape.p1].name = name
165 name = shape.p2.name
166 shape.p2 = Drawing.find_or_insert_point(drawing.points, shape.p2.x, shape.p2.y, --[[large width to minimize overlap]] 1600)
167 drawing.points[shape.p2].name = name
168 elseif shape.mode == 'polygon' or shape.mode == 'rectangle' or shape.mode == 'square' then
169 for i,p in ipairs(shape.vertices) do
170 local name = p.name
171 shape.vertices[i] = Drawing.find_or_insert_point(drawing.points, p.x,p.y, --[[large width to minimize overlap]] 1600)
172 drawing.points[shape.vertices[i]].name = name
174 elseif shape.mode == 'circle' or shape.mode == 'arc' then
175 local name = shape.center.name
176 shape.center = Drawing.find_or_insert_point(drawing.points, shape.center.x,shape.center.y, --[[large width to minimize overlap]] 1600)
177 drawing.points[shape.center].name = name
178 elseif shape.mode == 'deleted' then
179 -- ignore
180 else
181 print(shape.mode)
182 assert(false)
184 table.insert(drawing.shapes, shape)
186 return i, drawing
189 function is_absolute_path(path)
190 local os_path_separator = package.config:sub(1,1)
191 if os_path_separator == '/' then
192 -- POSIX systems permit backslashes in filenames
193 return path:sub(1,1) == '/'
194 elseif os_path_separator == '\\' then
195 if path:sub(2,2) == ':' then return true end -- DOS drive letter followed by volume separator
196 local f = path:sub(1,1)
197 return f == '/' or f == '\\'
198 else
199 error('What OS is this? LÖVE reports that the path separator is "'..os_path_separator..'"')
203 function is_relative_path(path)
204 return not is_absolute_path(path)