5 -- called both in tests and real run
6 function source
.initialize_globals()
7 -- tests currently mostly clear their own state
9 Show_log_browser_side
= false
11 Show_file_navigator
= false
47 cursors
= {}, -- filename to cursor1, screen_top1
49 File_navigation
.candidates
= File_navigation
.all_candidates
-- modified with filter
51 Menu_status_bar_height
= 5 + --[[line height in tests]] 15 + 5
57 -- called only for real run
58 function source
.initialize()
60 if Settings
and Settings
.source
then
61 source
.load_settings()
63 source
.initialize_default_settings()
66 source
.initialize_edit_side()
67 source
.initialize_log_browser_side()
69 Menu_status_bar_height
= 5 + Editor_state
.line_height
+ 5
70 Editor_state
.top
= Editor_state
.top
+ Menu_status_bar_height
71 Log_browser_state
.top
= Log_browser_state
.top
+ Menu_status_bar_height
75 -- keep a few blank lines around: https://merveilles.town/@akkartik/110084833821965708
76 love
.window
.setTitle('lines.love - source')
82 -- environment for a mutable file
83 -- TODO: some initialization is also happening in load_settings/initialize_default_settings. Clean that up.
84 function source
.initialize_edit_side()
85 load_from_disk(Editor_state
)
86 Text
.redraw_all(Editor_state
)
87 if File_navigation
.cursors
[Editor_state
.filename
] then
88 Editor_state
.screen_top1
= File_navigation
.cursors
[Editor_state
.filename
].screen_top1
89 Editor_state
.cursor1
= File_navigation
.cursors
[Editor_state
.filename
].cursor1
91 Editor_state
.screen_top1
= {line
=1, pos
=1}
92 Editor_state
.cursor1
= {line
=1, pos
=1}
94 edit
.check_locs(Editor_state
)
96 if Editor_state
.cursor1
.line
> #Editor_state
.lines
then
97 Editor_state
.cursor1
= {line
=1, pos
=1}
99 if Editor_state
.screen_top1
.line
> #Editor_state
.lines
then
100 Editor_state
.screen_top1
= {line
=1, pos
=1}
103 if rawget(_G
, 'jit') then
109 function print_and_log(s
)
114 function source
.load_settings()
115 local settings
= Settings
.source
116 love
.graphics
.setFont(love
.graphics
.newFont(settings
.font_height
))
117 -- set up desired window dimensions and make window resizable
118 _
, _
, App
.screen
.flags
= App
.screen
.size()
119 App
.screen
.flags
.resizable
= true
120 App
.screen
.width
, App
.screen
.height
= settings
.width
, settings
.height
121 App
.screen
.resize(App
.screen
.width
, App
.screen
.height
, App
.screen
.flags
)
122 source
.set_window_position_from_settings(settings
)
123 Show_log_browser_side
= settings
.show_log_browser_side
124 local right
= App
.screen
.width
- Margin_right
125 if Show_log_browser_side
then
126 right
= App
.screen
.width
/2 - Margin_right
128 Editor_state
= edit
.initialize_state(Margin_top
, Margin_left
, right
, settings
.font_height
, math
.floor(settings
.font_height
*1.3))
129 Editor_state
.filename
= settings
.filename
130 Editor_state
.filename
= basename(Editor_state
.filename
) -- migrate settings that used full paths; we now support only relative paths within the app
131 if settings
.cursors
then
132 File_navigation
.cursors
= settings
.cursors
133 Editor_state
.screen_top1
= File_navigation
.cursors
[Editor_state
.filename
].screen_top1
134 Editor_state
.cursor1
= File_navigation
.cursors
[Editor_state
.filename
].cursor1
136 -- migrate old settings
137 Editor_state
.screen_top1
= {line
=1, pos
=1}
138 Editor_state
.cursor1
= {line
=1, pos
=1}
142 function source
.set_window_position_from_settings(settings
)
143 local os
= love
.system
.getOS()
144 if os
== 'Linux' then
145 -- love.window.setPosition doesn't quite seem to do what is asked of it on Linux.
146 App
.screen
.move(settings
.x
, settings
.y
-37, settings
.displayindex
)
148 App
.screen
.move(settings
.x
, settings
.y
, settings
.displayindex
)
152 function source
.initialize_default_settings()
153 local font_height
= 20
154 love
.graphics
.setFont(love
.graphics
.newFont(font_height
))
155 source
.initialize_window_geometry()
156 Editor_state
= edit
.initialize_state(Margin_top
, Margin_left
, App
.screen
.width
-Margin_right
)
157 Editor_state
.filename
= 'run.lua'
158 Editor_state
.font_height
= font_height
159 Editor_state
.line_height
= math
.floor(font_height
*1.3)
162 function source
.initialize_window_geometry()
163 -- Initialize window width/height and make window resizable.
165 -- I get tempted to have opinions about window dimensions here, but they're
167 -- - maximizing doesn't work on mobile and messes things up
168 -- - maximizing keeps the title bar on screen in Linux, but off screen on
169 -- Windows. And there's no way to get the height of the title bar.
170 -- It seems more robust to just follow LÖVE's default window size until
171 -- someone overrides it.
172 App
.screen
.width
, App
.screen
.height
, App
.screen
.flags
= App
.screen
.size()
173 App
.screen
.flags
.resizable
= true
174 App
.screen
.resize(App
.screen
.width
, App
.screen
.height
, App
.screen
.flags
)
177 function source
.resize(w
, h
)
178 --? print(("Window resized to width: %d and height: %d."):format(w, h))
179 App
.screen
.width
, App
.screen
.height
= w
, h
180 Text
.redraw_all(Editor_state
)
181 Editor_state
.selection1
= {} -- no support for shift drag while we're resizing
182 if Show_log_browser_side
then
183 Editor_state
.right
= App
.screen
.width
/2 - Margin_right
185 Editor_state
.right
= App
.screen
.width
-Margin_right
187 Log_browser_state
.left
= App
.screen
.width
/2 + Margin_right
188 Log_browser_state
.right
= App
.screen
.width
-Margin_right
189 Editor_state
.width
= Editor_state
.right
-Editor_state
.left
190 Text
.tweak_screen_top_and_cursor(Editor_state
, Editor_state
.left
, Editor_state
.right
)
191 --? print('end resize')
194 function source
.file_drop(file
)
195 -- first make sure to save edits on any existing file
196 if Editor_state
.next_save
then
197 save_to_disk(Editor_state
)
199 -- clear the slate for the new file
200 Editor_state
.filename
= file
:getFilename()
202 Editor_state
.lines
= load_from_file(file
)
204 Text
.redraw_all(Editor_state
)
205 Editor_state
.screen_top1
= {line
=1, pos
=1}
206 Editor_state
.cursor1
= {line
=1, pos
=1}
210 -- keep a few blank lines around: https://merveilles.town/@akkartik/110084833821965708
211 love
.window
.setTitle('lines.love - source')
217 -- a copy of source.file_drop when given a filename
218 function source
.switch_to_file(filename
)
219 -- first make sure to save edits on any existing file
220 if Editor_state
.next_save
then
221 save_to_disk(Editor_state
)
223 -- save cursor position
224 File_navigation
.cursors
[Editor_state
.filename
] = {cursor1
=Editor_state
.cursor1
, screen_top1
=Editor_state
.screen_top1
}
225 -- clear the slate for the new file
226 Editor_state
.filename
= filename
227 load_from_disk(Editor_state
)
228 Text
.redraw_all(Editor_state
)
229 if File_navigation
.cursors
[filename
] then
230 Editor_state
.screen_top1
= File_navigation
.cursors
[filename
].screen_top1
231 Editor_state
.cursor1
= File_navigation
.cursors
[filename
].cursor1
233 Editor_state
.screen_top1
= {line
=1, pos
=1}
234 Editor_state
.cursor1
= {line
=1, pos
=1}
238 function source
.draw()
239 edit
.draw(Editor_state
, --[[hide cursor?]] Show_file_navigator
)
240 if Show_log_browser_side
then
242 App
.color(Divider_color
)
243 love
.graphics
.rectangle('fill', App
.screen
.width
/2-1,Menu_status_bar_height
, 3,App
.screen
.height
)
245 log_browser
.draw(Log_browser_state
, --[[hide_cursor]] Focus
~= 'log_browser')
247 source
.draw_menu_bar()
248 if Error_message
then
249 local height
= math
.min(20*Editor_state
.line_height
, App
.screen
.height
*0.2)
250 App
.color
{r
=0.8,g
=0,b
=0}
251 love
.graphics
.rectangle('fill', 150, App
.screen
.height
- height
-10, App
.screen
.width
, height
+10)
252 App
.color
{r
=0,g
=0,b
=0}
253 love
.graphics
.print(Error_message
, 150+10, App
.screen
.height
- height
)
257 function source
.update(dt
)
258 Cursor_time
= Cursor_time
+ dt
259 if App
.mouse_x() < Editor_state
.right
then
260 edit
.update(Editor_state
, dt
)
261 elseif Show_log_browser_side
then
262 log_browser
.update(Log_browser_state
, dt
)
266 function source
.quit()
267 edit
.quit(Editor_state
)
268 log_browser
.quit(Log_browser_state
)
271 function source
.settings()
272 if Settings
== nil then Settings
= {} end
273 if Settings
.source
== nil then Settings
.source
= {} end
274 Settings
.source
.x
, Settings
.source
.y
, Settings
.source
.displayindex
= App
.screen
.position()
275 File_navigation
.cursors
[Editor_state
.filename
] = {cursor1
=Editor_state
.cursor1
, screen_top1
=Editor_state
.screen_top1
}
277 x
=Settings
.source
.x
, y
=Settings
.source
.y
, displayindex
=Settings
.source
.displayindex
,
278 width
=App
.screen
.width
, height
=App
.screen
.height
,
279 font_height
=Editor_state
.font_height
,
280 filename
=Editor_state
.filename
,
281 cursors
=File_navigation
.cursors
,
282 show_log_browser_side
=Show_log_browser_side
,
287 function source
.mouse_press(x
,y
, mouse_button
)
288 Cursor_time
= 0 -- ensure cursor is visible immediately after it moves
289 --? print('mouse click', x, y)
290 --? print(Editor_state.left, Editor_state.right)
291 --? print(Log_browser_state.left, Log_browser_state.right)
292 if Show_file_navigator
and y
< Menu_status_bar_height
+ File_navigation
.num_lines
* Editor_state
.line_height
then
293 -- send click to buttons
294 edit
.mouse_press(Editor_state
, x
,y
, mouse_button
)
297 if x
< Editor_state
.right
+ Margin_right
then
298 --? print('click on edit side')
299 if Focus
~= 'edit' then
303 edit
.mouse_press(Editor_state
, x
,y
, mouse_button
)
304 elseif Show_log_browser_side
and Log_browser_state
.left
<= x
and x
< Log_browser_state
.right
then
305 --? print('click on log_browser side')
306 if Focus
~= 'log_browser' then
307 Focus
= 'log_browser'
310 log_browser
.mouse_press(Log_browser_state
, x
,y
, mouse_button
)
311 for _
,line_cache
in ipairs(Editor_state
.line_cache
) do line_cache
.starty
= nil end -- just in case we scroll
315 function source
.mouse_release(x
,y
, mouse_button
)
316 Cursor_time
= 0 -- ensure cursor is visible immediately after it moves
317 if Focus
== 'edit' then
318 return edit
.mouse_release(Editor_state
, x
,y
, mouse_button
)
320 return log_browser
.mouse_release(Log_browser_state
, x
,y
, mouse_button
)
324 function source
.mouse_wheel_move(dx
,dy
)
325 Cursor_time
= 0 -- ensure cursor is visible immediately after it moves
326 if Focus
== 'edit' then
327 return edit
.mouse_wheel_move(Editor_state
, dx
,dy
)
329 return log_browser
.mouse_wheel_move(Log_browser_state
, dx
,dy
)
333 function source
.text_input(t
)
334 Cursor_time
= 0 -- ensure cursor is visible immediately after it moves
335 if Show_file_navigator
then
336 text_input_on_file_navigator(t
)
339 if Focus
== 'edit' then
340 return edit
.text_input(Editor_state
, t
)
342 return log_browser
.text_input(Log_browser_state
, t
)
346 function source
.keychord_press(chord
, key
)
347 Cursor_time
= 0 -- ensure cursor is visible immediately after it moves
348 --? print('source keychord')
349 if Show_file_navigator
then
350 keychord_press_on_file_navigator(chord
, key
)
353 if chord
== 'C-l' then
355 Show_log_browser_side
= not Show_log_browser_side
356 if Show_log_browser_side
then
357 Editor_state
.right
= App
.screen
.width
/2 - Margin_right
358 Editor_state
.width
= Editor_state
.right
-Editor_state
.left
359 Text
.redraw_all(Editor_state
)
360 Log_browser_state
.left
= App
.screen
.width
/2 + Margin_left
361 Log_browser_state
.right
= App
.screen
.width
- Margin_right
363 Editor_state
.right
= App
.screen
.width
- Margin_right
364 Editor_state
.width
= Editor_state
.right
-Editor_state
.left
365 Text
.redraw_all(Editor_state
)
369 if chord
== 'C-k' then
371 love
.filesystem
.remove('log')
372 -- restart to reload state of logs on screen
373 Settings
.source
= source
.settings()
375 love
.filesystem
.write('config', json
.encode(Settings
))
376 load_file_from_source_or_save_directory('main.lua')
377 App
.undo_initialize()
378 App
.run_tests_and_initialize()
381 if chord
== 'C-g' then
382 Show_file_navigator
= true
385 if Focus
== 'edit' then
386 return edit
.keychord_press(Editor_state
, chord
, key
)
388 return log_browser
.keychord_press(Log_browser_state
, chord
, key
)
392 function source
.key_release(key
, scancode
)
393 Cursor_time
= 0 -- ensure cursor is visible immediately after it moves
394 if Focus
== 'edit' then
395 return edit
.key_release(Editor_state
, key
, scancode
)
397 return log_browser
.keychord_press(Log_browser_state
, chordkey
, scancode
)