diff --git a/Manual_tests.md b/Manual_tests.md index b6f3c99..4220dee 100644 --- a/Manual_tests.md +++ b/Manual_tests.md @@ -17,7 +17,8 @@ Initializing settings: - start out editing source, move window, press ctrl+e twice; window is editing source in same position+dimensions - no log file; switching to source works - - run with an unsupported version. Error message pops up and waits for a key. The app attempts to continue, and doesn't receive the key. + - run with an untested version. Error message pops up and waits for a key. The app attempts to continue, and doesn't receive the key. + - run with a LÖVE v12 release candidate. No errors; it is a supported version. All tests pass. Code loading: * run love with directory; text editor runs @@ -29,7 +30,8 @@ Code loading: - analogously, how a shape precisely looks as you draw it * start out running the text editor, press ctrl+e to edit source, make a change to the source, press ctrl+e twice to return to the source editor; the change should be preserved. -* run with an unsupported version. Error message pops up and waits for a key. The app attempts to continue, and doesn't receive the key. Press ctrl+e to edit source. Source editor opens up without checking version. +* run with an untested version. Error message pops up. Press a key. Text editor comes up, and doesn't receive the key. Press ctrl+e. Error pops up. Press a key. Source editor opens up. Press ctrl+e. Error pops up. Press a key. Text editor returns. +* create a couple of spuriously failing tests. Run with an untested version. Error message includes message about untested version. ### Other compromises diff --git a/app.lua b/app.lua index e4b67cc..271fdc3 100644 --- a/app.lua +++ b/app.lua @@ -8,10 +8,10 @@ -- and a source editor, while giving each the illusion of complete -- control. function love.run() + Version, Major_version = App.love_version() App.snapshot_love() -- Tests always run at the start. App.run_tests_and_initialize() - App.version_check() --? print('==') love.timer.step() @@ -85,6 +85,12 @@ end App = {} +function App.love_version() + local major_version, minor_version = love.getVersion() + local version = major_version..'.'..minor_version + return version, major_version +end + -- save/restore various framework globals we care about -- only on very first load function App.snapshot_love() if Love_snapshot then return end @@ -102,7 +108,12 @@ function App.run_tests_and_initialize() Test_errors = {} App.run_tests() if #Test_errors > 0 then - error(('There were %d test failures:\n\n%s'):format(#Test_errors, table.concat(Test_errors))) + local error_message = '' + if Warning_before_tests then + error_message = Warning_before_tests..'\n\n' + end + error_message = error_message .. ('There were %d test failures:\n%s'):format(#Test_errors, table.concat(Test_errors)) + error(error_message) end App.disable_tests() App.initialize_globals() diff --git a/main.lua b/main.lua index 918d414..61b5939 100644 --- a/main.lua +++ b/main.lua @@ -32,6 +32,11 @@ function App.load() Current_app = Settings.current_app end + -- Current_app = + -- | run + -- | source + -- | {name=warning message='...' next_app = run|source} + if Current_app == nil then Current_app = 'run' end @@ -64,35 +69,21 @@ function App.load() load_file_from_source_or_save_directory('help.lua') load_file_from_source_or_save_directory('drawing_tests.lua') load_file_from_source_or_save_directory('source_tests.lua') - elseif Current_app == 'error' then + elseif current_app_is_warning() then else assert(false, 'unknown app "'..Current_app..'"') end end -function App.version_check() - -- available modes: run, error - Error_message = nil - Error_count = 0 - -- we'll reuse error mode on load for an initial version check - local supported_versions = {'11.5', '11.4', '12.0'} -- put the recommended version first - local minor_version - Major_version, minor_version = love.getVersion() - Version = Major_version..'.'..minor_version - if array.find(supported_versions, Version) == nil then - Current_app = 'error' - Error_message = ("This app doesn't support version %s; please use version %s. Press any key to try it with this version anyway."):format(Version, supported_versions[1]) - print(Error_message) - -- continue initializing everything; hopefully we won't have errors during initialization - end -end - function App.initialize_globals() + Supported_versions = {'11.5', '11.4', '12.0'} -- put the recommended version first + check_love_version_for_tests() + if Current_app == 'run' then run.initialize_globals() elseif Current_app == 'source' then source.initialize_globals() - elseif Current_app == 'error' then + elseif current_app_is_warning() then else assert(false, 'unknown app "'..Current_app..'"') end @@ -101,6 +92,25 @@ function App.initialize_globals() Current_time = 0 Last_focus_time = 0 -- https://love2d.org/forums/viewtopic.php?p=249700 Last_resize_time = 0 + + -- Another weird bit for a class of corner cases. E.g.: + -- * I press ctrl+e, switch Current_app. I don't want the new app to receive + -- text_input and key_release events. + -- If I try to avoid text_input events by switching modes on key_release, I + -- hit a new problem: + -- * I press ctrl+e, am running an untested version, Current_app goes to + -- 'warning', and immediately rolls back out of 'warning' in the + -- key_release event. + -- Skip_rest_of_key_events is ugly, but feels cleaner than creating yet + -- another possible value for Current_app. + Skip_rest_of_key_events = nil +end + +function check_love_version_for_tests() + if array.find(Supported_versions, Version) == nil then + -- warning to include in an error message if any tests failed + Warning_before_tests = ("This app hasn't been tested with LÖVE version %s."):format(Version) + end end function App.initialize(arg) @@ -113,18 +123,28 @@ function App.initialize(arg) run.initialize(arg) elseif Current_app == 'source' then source.initialize(arg) - elseif Current_app == 'error' then + elseif current_app_is_warning() then else assert(false, 'unknown app "'..Current_app..'"') end + + check_love_version() +end + +function check_love_version() + if array.find(Supported_versions, Version) == nil then + show_warning( + ("This app hasn't been tested with LÖVE version %s; please switch to version %s if you run into issues. Press any key to continue."):format(Version, Supported_versions[1])) + -- continue initializing everything; hopefully we won't have errors during initialization + end end function App.resize(w,h) + if current_app_is_warning() then return end if Current_app == 'run' then if run.resize then run.resize(w,h) end elseif Current_app == 'source' then if source.resize then source.resize(w,h) end - elseif Current_app == 'error' then else assert(false, 'unknown app "'..Current_app..'"') end @@ -132,17 +152,18 @@ function App.resize(w,h) end function App.filedropped(file) + if current_app_is_warning() then return end if Current_app == 'run' then if run.file_drop then run.file_drop(file) end elseif Current_app == 'source' then if source.file_drop then source.file_drop(file) end - elseif Current_app == 'error' then else assert(false, 'unknown app "'..Current_app..'"') end end function App.focus(in_focus) + if current_app_is_warning() then return end if in_focus then Last_focus_time = Current_time end @@ -150,7 +171,6 @@ function App.focus(in_focus) if run.focus then run.focus(in_focus) end elseif Current_app == 'source' then if source.focus then source.focus(in_focus) end - elseif Current_app == 'error' then else assert(false, 'unknown app "'..Current_app..'"') end @@ -161,11 +181,11 @@ function App.draw() run.draw() elseif Current_app == 'source' then source.draw() - elseif Current_app == 'error' then + elseif current_app_is_warning() then love.graphics.setColor(0,0,1) love.graphics.rectangle('fill', 0,0, App.screen.width, App.screen.height) love.graphics.setColor(1,1,1) - love.graphics.printf(Error_message, 40,40, 600) + love.graphics.printf(Current_app.message, 40,40, 600) else assert(false, 'unknown app "'..Current_app..'"') end @@ -173,6 +193,7 @@ end function App.update(dt) Current_time = Current_time + dt + if current_app_is_warning() then return end -- some hysteresis while resizing if Current_time < Last_resize_time + 0.1 then return @@ -182,7 +203,6 @@ function App.update(dt) run.update(dt) elseif Current_app == 'source' then source.update(dt) - elseif Current_app == 'error' then else assert(false, 'unknown app "'..Current_app..'"') end @@ -194,9 +214,13 @@ function App.keychord_press(chord, key) return end -- - if Current_app == 'error' then + Skip_rest_of_key_events = nil + if current_app_is_warning() then if chord == 'C-c' then love.system.setClipboardText(Error_message) + else + clear_warning() + Skip_rest_of_key_events = true end return end @@ -214,7 +238,7 @@ function App.keychord_press(chord, key) if source.quit then source.quit() end Current_app = 'run' Error_message = nil - elseif Current_app == 'error' then + elseif current_app_is_warning() then else assert(false, 'unknown app "'..Current_app..'"') end @@ -224,6 +248,7 @@ function App.keychord_press(chord, key) load_file_from_source_or_save_directory('main.lua') App.undo_initialize() App.run_tests_and_initialize() + Skip_rest_of_key_events = true return end if Current_app == 'run' then @@ -236,12 +261,13 @@ function App.keychord_press(chord, key) end function App.textinput(t) - if Current_app == 'error' then return end + if current_app_is_warning() then return end -- ignore events for some time after window in focus (mostly alt-tab) if Current_time < Last_focus_time + 0.01 then return end -- + if Skip_rest_of_key_events then return end if Current_app == 'run' then if run.text_input then run.text_input(t) end elseif Current_app == 'source' then @@ -252,14 +278,14 @@ function App.textinput(t) end function App.keyreleased(key, scancode) + if current_app_is_warning() then return end -- ignore events for some time after window in focus (mostly alt-tab) if Current_time < Last_focus_time + 0.01 then return end -- - if Current_app == 'error' then - Current_app = 'run' - elseif Current_app == 'run' then + if Skip_rest_of_key_events then return end + if Current_app == 'run' then if run.key_release then run.key_release(key, scancode) end elseif Current_app == 'source' then if source.key_release then source.key_release(key, scancode) end @@ -269,7 +295,7 @@ function App.keyreleased(key, scancode) end function App.mousepressed(x,y, mouse_button) - if Current_app == 'error' then return end + if current_app_is_warning() then return end --? print('mouse press', x,y) if Current_app == 'run' then if run.mouse_press then run.mouse_press(x,y, mouse_button) end @@ -281,7 +307,7 @@ function App.mousepressed(x,y, mouse_button) end function App.mousereleased(x,y, mouse_button) - if Current_app == 'error' then return end + if current_app_is_warning() then return end if Current_app == 'run' then if run.mouse_release then run.mouse_release(x,y, mouse_button) end elseif Current_app == 'source' then @@ -292,7 +318,7 @@ function App.mousereleased(x,y, mouse_button) end function App.wheelmoved(dx,dy) - if Current_app == 'error' then return end + if current_app_is_warning() then return end if Current_app == 'run' then if run.mouse_wheel_move then run.mouse_wheel_move(dx,dy) end elseif Current_app == 'source' then @@ -303,7 +329,7 @@ function App.wheelmoved(dx,dy) end function love.quit() - if Current_app == 'error' then return end + if current_app_is_warning() then return end if Current_app == 'run' then local source_settings = Settings.source Settings = run.settings() @@ -321,3 +347,21 @@ function love.quit() assert(false, 'unknown app "'..Current_app..'"') end end + +function current_app_is_warning() + return type(Current_app) == 'table' and Current_app.name == 'warning' +end + +function show_warning(message) + assert(type(Current_app) == 'string') + Current_app = { + name = 'warning', + message = message, + next_app = Current_app, + } +end + +function clear_warning() + assert(type(Current_app) == 'table') + Current_app = Current_app.next_app +end diff --git a/reference.md b/reference.md index d0956ba..1f1f724 100644 --- a/reference.md +++ b/reference.md @@ -11,6 +11,9 @@ automatically called for you as appropriate. * `flags` -- some properties of the app window. See [`flags` in `love.graphics.getMode`](https://love2d.org/wiki/love.window.getMode) for details. +* `Version` -- the running version of LÖVE as a string, e.g. '11.4'. +* `Major_version` -- just the part before the period as an int, e.g. 11. + ## Functions that get automatically called * `App.initialize_globals()` -- called before running each test and also