menu.lua (f0cb3b6b258df56324123c8732a9b5470a88383c) | menu.lua (aedd6be5c7c3096828fafa6c1528f3966b9e3aa5) |
---|---|
1-- 2-- Copyright (c) 2015 Pedro Souza <pedrosouza@freebsd.org> 3-- Copyright (C) 2018 Kyle Evans <kevans@FreeBSD.org> 4-- All rights reserved. 5-- 6-- Redistribution and use in source and binary forms, with or without 7-- modification, are permitted provided that the following conditions 8-- are met: --- 14 unchanged lines hidden (view full) --- 23-- LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24-- OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25-- SUCH DAMAGE. 26-- 27-- $FreeBSD$ 28-- 29 30 | 1-- 2-- Copyright (c) 2015 Pedro Souza <pedrosouza@freebsd.org> 3-- Copyright (C) 2018 Kyle Evans <kevans@FreeBSD.org> 4-- All rights reserved. 5-- 6-- Redistribution and use in source and binary forms, with or without 7-- modification, are permitted provided that the following conditions 8-- are met: --- 14 unchanged lines hidden (view full) --- 23-- LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24-- OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25-- SUCH DAMAGE. 26-- 27-- $FreeBSD$ 28-- 29 30 |
31local core = require("core"); 32local color = require("color"); 33local config = require("config"); 34local screen = require("screen"); 35local drawer = require("drawer"); | 31local core = require("core") 32local color = require("color") 33local config = require("config") 34local screen = require("screen") 35local drawer = require("drawer") |
36 | 36 |
37local menu = {}; | 37local menu = {} |
38 | 38 |
39local skip; 40local run; 41local autoboot; | 39local skip 40local run 41local autoboot |
42 43local OnOff = function(str, b) 44 if (b) then 45 return str .. color.escapef(color.GREEN) .. "On" .. | 42 43local OnOff = function(str, b) 44 if (b) then 45 return str .. color.escapef(color.GREEN) .. "On" .. |
46 color.escapef(color.WHITE); | 46 color.escapef(color.WHITE) |
47 else 48 return str .. color.escapef(color.RED) .. "off" .. | 47 else 48 return str .. color.escapef(color.RED) .. "off" .. |
49 color.escapef(color.WHITE); | 49 color.escapef(color.WHITE) |
50 end 51end 52 53-- Module exports 54menu.handlers = { 55 -- Menu handlers take the current menu and selected entry as parameters, 56 -- and should return a boolean indicating whether execution should 57 -- continue or not. The return value may be omitted if this entry should 58 -- have no bearing on whether we continue or not, indicating that we 59 -- should just continue after execution. 60 [core.MENU_ENTRY] = function(current_menu, entry) 61 -- run function | 50 end 51end 52 53-- Module exports 54menu.handlers = { 55 -- Menu handlers take the current menu and selected entry as parameters, 56 -- and should return a boolean indicating whether execution should 57 -- continue or not. The return value may be omitted if this entry should 58 -- have no bearing on whether we continue or not, indicating that we 59 -- should just continue after execution. 60 [core.MENU_ENTRY] = function(current_menu, entry) 61 -- run function |
62 entry.func(); | 62 entry.func() |
63 end, 64 [core.MENU_CAROUSEL_ENTRY] = function(current_menu, entry) 65 -- carousel (rotating) functionality | 63 end, 64 [core.MENU_CAROUSEL_ENTRY] = function(current_menu, entry) 65 -- carousel (rotating) functionality |
66 local carid = entry.carousel_id; 67 local caridx = config.getCarouselIndex(carid); 68 local choices = entry.items(); | 66 local carid = entry.carousel_id 67 local caridx = config.getCarouselIndex(carid) 68 local choices = entry.items() |
69 70 if (#choices > 0) then | 69 70 if (#choices > 0) then |
71 caridx = (caridx % #choices) + 1; 72 config.setCarouselIndex(carid, caridx); 73 entry.func(caridx, choices[caridx], choices); | 71 caridx = (caridx % #choices) + 1 72 config.setCarouselIndex(carid, caridx) 73 entry.func(caridx, choices[caridx], choices) |
74 end 75 end, 76 [core.MENU_SUBMENU] = function(current_menu, entry) 77 -- recurse | 74 end 75 end, 76 [core.MENU_SUBMENU] = function(current_menu, entry) 77 -- recurse |
78 return menu.run(entry.submenu()); | 78 return menu.run(entry.submenu()) |
79 end, 80 [core.MENU_RETURN] = function(current_menu, entry) 81 -- allow entry to have a function/side effect 82 if (entry.func ~= nil) then | 79 end, 80 [core.MENU_RETURN] = function(current_menu, entry) 81 -- allow entry to have a function/side effect 82 if (entry.func ~= nil) then |
83 entry.func(); | 83 entry.func() |
84 end | 84 end |
85 return false; | 85 return false |
86 end, | 86 end, |
87}; | 87} |
88-- loader menu tree is rooted at menu.welcome 89 90menu.boot_options = { 91 entries = { 92 -- return to welcome menu 93 { 94 entry_type = core.MENU_RETURN, 95 name = function() 96 return "Back to main menu" .. | 88-- loader menu tree is rooted at menu.welcome 89 90menu.boot_options = { 91 entries = { 92 -- return to welcome menu 93 { 94 entry_type = core.MENU_RETURN, 95 name = function() 96 return "Back to main menu" .. |
97 color.highlight(" [Backspace]"); | 97 color.highlight(" [Backspace]") |
98 end 99 }, 100 101 -- load defaults 102 { 103 entry_type = core.MENU_ENTRY, 104 name = function() 105 return "Load System " .. color.highlight("D") .. | 98 end 99 }, 100 101 -- load defaults 102 { 103 entry_type = core.MENU_ENTRY, 104 name = function() 105 return "Load System " .. color.highlight("D") .. |
106 "efaults"; | 106 "efaults" |
107 end, 108 func = function() | 107 end, 108 func = function() |
109 core.setDefaults(); | 109 core.setDefaults() |
110 end, 111 alias = {"d", "D"} 112 }, 113 114 { 115 entry_type = core.MENU_SEPARATOR, 116 name = function() | 110 end, 111 alias = {"d", "D"} 112 }, 113 114 { 115 entry_type = core.MENU_SEPARATOR, 116 name = function() |
117 return ""; | 117 return "" |
118 end 119 }, 120 121 { 122 entry_type = core.MENU_SEPARATOR, 123 name = function() | 118 end 119 }, 120 121 { 122 entry_type = core.MENU_SEPARATOR, 123 name = function() |
124 return "Boot Options:"; | 124 return "Boot Options:" |
125 end 126 }, 127 128 -- acpi 129 { 130 entry_type = core.MENU_ENTRY, 131 visible = core.isSystem386, 132 name = function() 133 return OnOff(color.highlight("A") .. | 125 end 126 }, 127 128 -- acpi 129 { 130 entry_type = core.MENU_ENTRY, 131 visible = core.isSystem386, 132 name = function() 133 return OnOff(color.highlight("A") .. |
134 "CPI :", core.acpi); | 134 "CPI :", core.acpi) |
135 end, 136 func = function() | 135 end, 136 func = function() |
137 core.setACPI(); | 137 core.setACPI() |
138 end, 139 alias = {"a", "A"} 140 }, 141 -- safe mode 142 { 143 entry_type = core.MENU_ENTRY, 144 name = function() 145 return OnOff("Safe " .. color.highlight("M") .. | 138 end, 139 alias = {"a", "A"} 140 }, 141 -- safe mode 142 { 143 entry_type = core.MENU_ENTRY, 144 name = function() 145 return OnOff("Safe " .. color.highlight("M") .. |
146 "ode :", core.sm); | 146 "ode :", core.sm) |
147 end, 148 func = function() | 147 end, 148 func = function() |
149 core.setSafeMode(); | 149 core.setSafeMode() |
150 end, 151 alias = {"m", "M"} 152 }, 153 -- single user 154 { 155 entry_type = core.MENU_ENTRY, 156 name = function() 157 return OnOff(color.highlight("S") .. | 150 end, 151 alias = {"m", "M"} 152 }, 153 -- single user 154 { 155 entry_type = core.MENU_ENTRY, 156 name = function() 157 return OnOff(color.highlight("S") .. |
158 "ingle user:", core.su); | 158 "ingle user:", core.su) |
159 end, 160 func = function() | 159 end, 160 func = function() |
161 core.setSingleUser(); | 161 core.setSingleUser() |
162 end, 163 alias = {"s", "S"} 164 }, 165 -- verbose boot 166 { 167 entry_type = core.MENU_ENTRY, 168 name = function() 169 return OnOff(color.highlight("V") .. | 162 end, 163 alias = {"s", "S"} 164 }, 165 -- verbose boot 166 { 167 entry_type = core.MENU_ENTRY, 168 name = function() 169 return OnOff(color.highlight("V") .. |
170 "erbose :", core.verbose); | 170 "erbose :", core.verbose) |
171 end, 172 func = function() | 171 end, 172 func = function() |
173 core.setVerbose(); | 173 core.setVerbose() |
174 end, 175 alias = {"v", "V"} 176 }, 177 }, | 174 end, 175 alias = {"v", "V"} 176 }, 177 }, |
178}; | 178} |
179 180menu.welcome = { 181 entries = function() | 179 180menu.welcome = { 181 entries = function() |
182 local menu_entries = menu.welcome.all_entries; | 182 local menu_entries = menu.welcome.all_entries |
183 -- Swap the first two menu items on single user boot 184 if (core.isSingleUserBoot()) then 185 -- We'll cache the swapped menu, for performance 186 if (menu.welcome.swapped_menu ~= nil) then | 183 -- Swap the first two menu items on single user boot 184 if (core.isSingleUserBoot()) then 185 -- We'll cache the swapped menu, for performance 186 if (menu.welcome.swapped_menu ~= nil) then |
187 return menu.welcome.swapped_menu; | 187 return menu.welcome.swapped_menu |
188 end 189 -- Shallow copy the table | 188 end 189 -- Shallow copy the table |
190 menu_entries = core.shallowCopyTable(menu_entries); | 190 menu_entries = core.shallowCopyTable(menu_entries) |
191 192 -- Swap the first two menu entries 193 menu_entries[1], menu_entries[2] = | 191 192 -- Swap the first two menu entries 193 menu_entries[1], menu_entries[2] = |
194 menu_entries[2], menu_entries[1]; | 194 menu_entries[2], menu_entries[1] |
195 196 -- Then set their names to their alternate names 197 menu_entries[1].name, menu_entries[2].name = 198 menu_entries[1].alternate_name, | 195 196 -- Then set their names to their alternate names 197 menu_entries[1].name, menu_entries[2].name = 198 menu_entries[1].alternate_name, |
199 menu_entries[2].alternate_name; 200 menu.welcome.swapped_menu = menu_entries; | 199 menu_entries[2].alternate_name 200 menu.welcome.swapped_menu = menu_entries |
201 end | 201 end |
202 return menu_entries; | 202 return menu_entries |
203 end, 204 all_entries = { 205 -- boot multi user 206 { 207 entry_type = core.MENU_ENTRY, 208 name = function() 209 return color.highlight("B") .. 210 "oot Multi user " .. | 203 end, 204 all_entries = { 205 -- boot multi user 206 { 207 entry_type = core.MENU_ENTRY, 208 name = function() 209 return color.highlight("B") .. 210 "oot Multi user " .. |
211 color.highlight("[Enter]"); | 211 color.highlight("[Enter]") |
212 end, 213 -- Not a standard menu entry function! 214 alternate_name = function() 215 return color.highlight("B") .. | 212 end, 213 -- Not a standard menu entry function! 214 alternate_name = function() 215 return color.highlight("B") .. |
216 "oot Multi user"; | 216 "oot Multi user" |
217 end, 218 func = function() | 217 end, 218 func = function() |
219 core.setSingleUser(false); 220 core.boot(); | 219 core.setSingleUser(false) 220 core.boot() |
221 end, 222 alias = {"b", "B"} 223 }, 224 225 -- boot single user 226 { 227 entry_type = core.MENU_ENTRY, 228 name = function() 229 return "Boot " .. color.highlight("S") .. | 221 end, 222 alias = {"b", "B"} 223 }, 224 225 -- boot single user 226 { 227 entry_type = core.MENU_ENTRY, 228 name = function() 229 return "Boot " .. color.highlight("S") .. |
230 "ingle user"; | 230 "ingle user" |
231 end, 232 -- Not a standard menu entry function! 233 alternate_name = function() 234 return "Boot " .. color.highlight("S") .. | 231 end, 232 -- Not a standard menu entry function! 233 alternate_name = function() 234 return "Boot " .. color.highlight("S") .. |
235 "ingle user " .. color.highlight("[Enter]"); | 235 "ingle user " .. color.highlight("[Enter]") |
236 end, 237 func = function() | 236 end, 237 func = function() |
238 core.setSingleUser(true); 239 core.boot(); | 238 core.setSingleUser(true) 239 core.boot() |
240 end, 241 alias = {"s", "S"} 242 }, 243 244 -- escape to interpreter 245 { 246 entry_type = core.MENU_RETURN, 247 name = function() 248 return color.highlight("Esc") .. | 240 end, 241 alias = {"s", "S"} 242 }, 243 244 -- escape to interpreter 245 { 246 entry_type = core.MENU_RETURN, 247 name = function() 248 return color.highlight("Esc") .. |
249 "ape to loader prompt"; | 249 "ape to loader prompt" |
250 end, 251 func = function() | 250 end, 251 func = function() |
252 loader.setenv("autoboot_delay", "NO"); | 252 loader.setenv("autoboot_delay", "NO") |
253 end, 254 alias = {core.KEYSTR_ESCAPE} 255 }, 256 257 -- reboot 258 { 259 entry_type = core.MENU_ENTRY, 260 name = function() | 253 end, 254 alias = {core.KEYSTR_ESCAPE} 255 }, 256 257 -- reboot 258 { 259 entry_type = core.MENU_ENTRY, 260 name = function() |
261 return color.highlight("R") .. "eboot"; | 261 return color.highlight("R") .. "eboot" |
262 end, 263 func = function() | 262 end, 263 func = function() |
264 loader.perform("reboot"); | 264 loader.perform("reboot") |
265 end, 266 alias = {"r", "R"} 267 }, 268 269 270 { 271 entry_type = core.MENU_SEPARATOR, 272 name = function() | 265 end, 266 alias = {"r", "R"} 267 }, 268 269 270 { 271 entry_type = core.MENU_SEPARATOR, 272 name = function() |
273 return ""; | 273 return "" |
274 end 275 }, 276 277 { 278 entry_type = core.MENU_SEPARATOR, 279 name = function() | 274 end 275 }, 276 277 { 278 entry_type = core.MENU_SEPARATOR, 279 name = function() |
280 return "Options:"; | 280 return "Options:" |
281 end 282 }, 283 284 -- kernel options 285 { 286 entry_type = core.MENU_CAROUSEL_ENTRY, 287 carousel_id = "kernel", 288 items = core.kernelList, 289 name = function(idx, choice, all_choices) 290 if (#all_choices == 0) then | 281 end 282 }, 283 284 -- kernel options 285 { 286 entry_type = core.MENU_CAROUSEL_ENTRY, 287 carousel_id = "kernel", 288 items = core.kernelList, 289 name = function(idx, choice, all_choices) 290 if (#all_choices == 0) then |
291 return "Kernel: "; | 291 return "Kernel: " |
292 end 293 | 292 end 293 |
294 local is_default = (idx == 1); 295 local kernel_name = ""; 296 local name_color; | 294 local is_default = (idx == 1) 295 local kernel_name = "" 296 local name_color |
297 if (is_default) then | 297 if (is_default) then |
298 name_color = color.escapef(color.GREEN); 299 kernel_name = "default/"; | 298 name_color = color.escapef(color.GREEN) 299 kernel_name = "default/" |
300 else | 300 else |
301 name_color = color.escapef(color.BLUE); | 301 name_color = color.escapef(color.BLUE) |
302 end 303 kernel_name = kernel_name .. name_color .. | 302 end 303 kernel_name = kernel_name .. name_color .. |
304 choice .. color.default(); | 304 choice .. color.default() |
305 return color.highlight("K") .. "ernel: " .. 306 kernel_name .. " (" .. idx .. " of " .. | 305 return color.highlight("K") .. "ernel: " .. 306 kernel_name .. " (" .. idx .. " of " .. |
307 #all_choices .. ")"; | 307 #all_choices .. ")" |
308 end, 309 func = function(idx, choice, all_choices) | 308 end, 309 func = function(idx, choice, all_choices) |
310 config.selectkernel(choice); | 310 config.selectkernel(choice) |
311 end, 312 alias = {"k", "K"} 313 }, 314 315 -- boot options 316 { 317 entry_type = core.MENU_SUBMENU, 318 name = function() 319 return "Boot " .. color.highlight("O") .. | 311 end, 312 alias = {"k", "K"} 313 }, 314 315 -- boot options 316 { 317 entry_type = core.MENU_SUBMENU, 318 name = function() 319 return "Boot " .. color.highlight("O") .. |
320 "ptions"; | 320 "ptions" |
321 end, 322 submenu = function() | 321 end, 322 submenu = function() |
323 return menu.boot_options; | 323 return menu.boot_options |
324 end, 325 alias = {"o", "O"} 326 }, 327 }, | 324 end, 325 alias = {"o", "O"} 326 }, 327 }, |
328}; | 328} |
329 330function menu.run(m) 331 332 if (menu.skip()) then | 329 330function menu.run(m) 331 332 if (menu.skip()) then |
333 core.autoboot(); 334 return false; | 333 core.autoboot() 334 return false |
335 end 336 337 if (m == nil) then | 335 end 336 337 if (m == nil) then |
338 m = menu.welcome; | 338 m = menu.welcome |
339 end 340 341 -- redraw screen | 339 end 340 341 -- redraw screen |
342 screen.clear(); 343 screen.defcursor(); 344 local alias_table = drawer.drawscreen(m); | 342 screen.clear() 343 screen.defcursor() 344 local alias_table = drawer.drawscreen(m) |
345 | 345 |
346 menu.autoboot(); | 346 menu.autoboot() |
347 | 347 |
348 cont = true; | 348 cont = true |
349 while (cont) do | 349 while (cont) do |
350 local key = io.getchar(); | 350 local key = io.getchar() |
351 352 -- Special key behaviors 353 if ((key == core.KEY_BACKSPACE) or (key == core.KEY_DELETE)) and 354 (m ~= menu.welcome) then | 351 352 -- Special key behaviors 353 if ((key == core.KEY_BACKSPACE) or (key == core.KEY_DELETE)) and 354 (m ~= menu.welcome) then |
355 break; | 355 break |
356 elseif (key == core.KEY_ENTER) then | 356 elseif (key == core.KEY_ENTER) then |
357 core.boot(); | 357 core.boot() |
358 -- Should not return 359 end 360 361 key = string.char(key) 362 -- check to see if key is an alias | 358 -- Should not return 359 end 360 361 key = string.char(key) 362 -- check to see if key is an alias |
363 local sel_entry = nil; | 363 local sel_entry = nil |
364 for k, v in pairs(alias_table) do 365 if (key == k) then | 364 for k, v in pairs(alias_table) do 365 if (key == k) then |
366 sel_entry = v; | 366 sel_entry = v |
367 end 368 end 369 370 -- if we have an alias do the assigned action: 371 if (sel_entry ~= nil) then 372 -- Get menu handler | 367 end 368 end 369 370 -- if we have an alias do the assigned action: 371 if (sel_entry ~= nil) then 372 -- Get menu handler |
373 local handler = menu.handlers[sel_entry.entry_type]; | 373 local handler = menu.handlers[sel_entry.entry_type] |
374 if (handler ~= nil) then 375 -- The handler's return value indicates whether 376 -- we need to exit this menu. An omitted return 377 -- value means "continue" by default. | 374 if (handler ~= nil) then 375 -- The handler's return value indicates whether 376 -- we need to exit this menu. An omitted return 377 -- value means "continue" by default. |
378 cont = handler(m, sel_entry); | 378 cont = handler(m, sel_entry) |
379 if (cont == nil) then | 379 if (cont == nil) then |
380 cont = true; | 380 cont = true |
381 end 382 end 383 -- if we got an alias key the screen is out of date: | 381 end 382 end 383 -- if we got an alias key the screen is out of date: |
384 screen.clear(); 385 screen.defcursor(); 386 alias_table = drawer.drawscreen(m); | 384 screen.clear() 385 screen.defcursor() 386 alias_table = drawer.drawscreen(m) |
387 end 388 end 389 390 if (m == menu.welcome) then | 387 end 388 end 389 390 if (m == menu.welcome) then |
391 screen.defcursor(); 392 print("Exiting menu!"); 393 return false; | 391 screen.defcursor() 392 print("Exiting menu!") 393 return false |
394 end 395 | 394 end 395 |
396 return true; | 396 return true |
397end 398 399function menu.skip() 400 if (core.isSerialBoot()) then | 397end 398 399function menu.skip() 400 if (core.isSerialBoot()) then |
401 return true; | 401 return true |
402 end | 402 end |
403 local c = string.lower(loader.getenv("console") or ""); | 403 local c = string.lower(loader.getenv("console") or "") |
404 if ((c:match("^efi[ ;]") or c:match("[ ;]efi[ ;]")) ~= nil) then | 404 if ((c:match("^efi[ ;]") or c:match("[ ;]efi[ ;]")) ~= nil) then |
405 return true; | 405 return true |
406 end 407 | 406 end 407 |
408 c = string.lower(loader.getenv("beastie_disable") or ""); 409 print("beastie_disable", c); 410 return c == "yes"; | 408 c = string.lower(loader.getenv("beastie_disable") or "") 409 print("beastie_disable", c) 410 return c == "yes" |
411end 412 413function menu.autoboot() 414 if (menu.already_autoboot == true) then | 411end 412 413function menu.autoboot() 414 if (menu.already_autoboot == true) then |
415 return; | 415 return |
416 end | 416 end |
417 menu.already_autoboot = true; | 417 menu.already_autoboot = true |
418 | 418 |
419 local ab = loader.getenv("autoboot_delay"); | 419 local ab = loader.getenv("autoboot_delay") |
420 if (ab ~= nil) and (ab:lower() == "no") then | 420 if (ab ~= nil) and (ab:lower() == "no") then |
421 return; | 421 return |
422 elseif (tonumber(ab) == -1) then | 422 elseif (tonumber(ab) == -1) then |
423 core.boot(); | 423 core.boot() |
424 end | 424 end |
425 ab = tonumber(ab) or 10; | 425 ab = tonumber(ab) or 10 |
426 | 426 |
427 local x = loader.getenv("loader_menu_timeout_x") or 5; 428 local y = loader.getenv("loader_menu_timeout_y") or 22; | 427 local x = loader.getenv("loader_menu_timeout_x") or 5 428 local y = loader.getenv("loader_menu_timeout_y") or 22 |
429 | 429 |
430 local endtime = loader.time() + ab; 431 local time; | 430 local endtime = loader.time() + ab 431 local time |
432 433 repeat | 432 433 repeat |
434 time = endtime - loader.time(); 435 screen.setcursor(x, y); | 434 time = endtime - loader.time() 435 screen.setcursor(x, y) |
436 print("Autoboot in " .. time .. 437 " seconds, hit [Enter] to boot" .. | 436 print("Autoboot in " .. time .. 437 " seconds, hit [Enter] to boot" .. |
438 " or any other key to stop "); 439 screen.defcursor(); | 438 " or any other key to stop ") 439 screen.defcursor() |
440 if (io.ischar()) then | 440 if (io.ischar()) then |
441 local ch = io.getchar(); | 441 local ch = io.getchar() |
442 if (ch == core.KEY_ENTER) then | 442 if (ch == core.KEY_ENTER) then |
443 break; | 443 break |
444 else 445 -- erase autoboot msg | 444 else 445 -- erase autoboot msg |
446 screen.setcursor(0, y); | 446 screen.setcursor(0, y) |
447 print(" " | 447 print(" " |
448 .. " "); 449 screen.defcursor(); 450 return; | 448 .. " ") 449 screen.defcursor() 450 return |
451 end 452 end 453 | 451 end 452 end 453 |
454 loader.delay(50000); 455 until time <= 0; 456 core.boot(); | 454 loader.delay(50000) 455 until time <= 0 456 core.boot() |
457 458end 459 | 457 458end 459 |
460return menu; | 460return menu |