View difference between Paste ID: JUEGJ4Bk and KJjpnJy2
SHOW: | | - or go back to the newest paste.
1
local expect
2
3
function loadstring(code, env)
4
    local e = _G
5
    local name = "@thing"
6
    if type(env) == "table" then e = env
7
    elseif type(env) == "string" then name = env end
8
    return load(code, name, "t", e)
9
end
10
11
do
12
    local h = fs.open("rom/modules/main/cc/expect.lua", "r")
13
    local f, err = loadstring(h.readAll(), "@expect.lua")
14
    h.close()
15
16
    if not f then error(err) end
17
    expect = f().expect
18
end
19
20
if _VERSION == "Lua 5.1" then
21
    -- If we're on Lua 5.1, install parts of the Lua 5.2/5.3 API so that programs can be written against it
22
    local type = type
23
    local nativeload = load
24
    local nativeloadstring = loadstring
25
    local nativesetfenv = setfenv
26
27
    --- Historically load/loadstring would handle the chunk name as if it has
28
    -- been prefixed with "=". We emulate that behaviour here.
29
    local function prefix(chunkname)
30
        if type(chunkname) ~= "string" then return chunkname end
31
        local head = chunkname:sub(1, 1)
32
        if head == "=" or head == "@" then
33
            return chunkname
34
        else
35
            return "=" .. chunkname
36
        end
37
    end
38
39
    function load( x, name, mode, env )
40
        expect(1, x, "function", "string")
41
        expect(2, name, "string", "nil")
42
        expect(3, mode, "string", "nil")
43
        expect(4, env, "table", "nil")
44
45
        local ok, p1, p2 = pcall( function()
46
            if type(x) == "string" then
47
                local result, err = nativeloadstring( x, name )
48
                if result then
49
                    if env then
50
                        env._ENV = env
51
                        nativesetfenv( result, env )
52
                    end
53
                    return result
54
                else
55
                    return nil, err
56
                end
57
            else
58
                local result, err = nativeload( x, name )
59
                if result then
60
                    if env then
61
                        env._ENV = env
62
                        nativesetfenv( result, env )
63
                    end
64
                    return result
65
                else
66
                    return nil, err
67
                end
68
            end
69
        end )
70
        if ok then
71
            return p1, p2
72
        else
73
            error( p1, 2 )
74
        end
75
    end
76
    table.unpack = unpack
77
    table.pack = function( ... ) return { n = select( "#", ... ), ... } end
78
79
    if _CC_DISABLE_LUA51_FEATURES then
80
        -- Remove the Lua 5.1 features that will be removed when we update to Lua 5.2, for compatibility testing.
81
        -- See "disable_lua51_functions" in ComputerCraft.cfg
82
        setfenv = nil
83
        getfenv = nil
84
        loadstring = nil
85
        unpack = nil
86
        math.log10 = nil
87
        table.maxn = nil
88
    else
89
        loadstring = function(string, chunkname) return nativeloadstring(string, prefix( chunkname )) end
90
91
        -- Inject a stub for the old bit library
92
        _G.bit = {
93
            bnot = bit32.bnot,
94
            band = bit32.band,
95
            bor = bit32.bor,
96
            bxor = bit32.bxor,
97
            brshift = bit32.arshift,
98
            blshift = bit32.lshift,
99
            blogic_rshift = bit32.rshift,
100
        }
101
    end
102
end
103
104
if _VERSION == "Lua 5.3" and not bit32 then
105
    -- If we're on Lua 5.3, install the bit32 api from Lua 5.2
106
    -- (Loaded from a string so this file will still parse on <5.3 lua)
107
    load( [[
108
        bit32 = {}
109
110
        function bit32.arshift( n, bits )
111
            if type(n) ~= "number" or type(bits) ~= "number" then
112
                error( "Expected number, number", 2 )
113
            end
114
            return n >> bits
115
        end
116
117
        function bit32.band( m, n )
118
            if type(m) ~= "number" or type(n) ~= "number" then
119
                error( "Expected number, number", 2 )
120
            end
121
            return m & n
122
        end
123
124
        function bit32.bnot( n )
125
            if type(n) ~= "number" then
126
                error( "Expected number", 2 )
127
            end
128
            return ~n
129
        end
130
131
        function bit32.bor( m, n )
132
            if type(m) ~= "number" or type(n) ~= "number" then
133
                error( "Expected number, number", 2 )
134
            end
135
            return m | n
136
        end
137
138
        function bit32.btest( m, n )
139
            if type(m) ~= "number" or type(n) ~= "number" then
140
                error( "Expected number, number", 2 )
141
            end
142
            return (m & n) ~= 0
143
        end
144
145
        function bit32.bxor( m, n )
146
            if type(m) ~= "number" or type(n) ~= "number" then
147
                error( "Expected number, number", 2 )
148
            end
149
            return m ~ n
150
        end
151
152
        function bit32.lshift( n, bits )
153
            if type(n) ~= "number" or type(bits) ~= "number" then
154
                error( "Expected number, number", 2 )
155
            end
156
            return n << bits
157
        end
158
159
        function bit32.rshift( n, bits )
160
            if type(n) ~= "number" or type(bits) ~= "number" then
161
                error( "Expected number, number", 2 )
162
            end
163
            return n >> bits
164
        end
165
    ]] )()
166
end
167
168
-- Install lua parts of the os api
169
function os.version()
170
    return "CraftOS 1.8"
171
end
172
173
function os.pullEventRaw( sFilter )
174
    return coroutine.yield( sFilter )
175
end
176
177
function os.pullEvent( sFilter )
178
    local eventData = table.pack( os.pullEventRaw( sFilter ) )
179
    if eventData[1] == "terminate" then
180
        error( "Terminated", 0 )
181
    end
182
    return table.unpack( eventData, 1, eventData.n )
183
end
184
185
-- Install globals
186
function sleep( nTime )
187
    expect(1, nTime, "number", "nil")
188
    local timer = os.startTimer( nTime or 0 )
189
    repeat
190
        local _, param = os.pullEvent( "timer" )
191
    until param == timer
192
end
193
194
function write( sText )
195
    expect(1, sText, "string", "number")
196
197
    local w, h = term.getSize()
198
    local x, y = term.getCursorPos()
199
200
    local nLinesPrinted = 0
201
    local function newLine()
202
        if y + 1 <= h then
203
            term.setCursorPos(1, y + 1)
204
        else
205
            term.setCursorPos(1, h)
206
            term.scroll(1)
207
        end
208
        x, y = term.getCursorPos()
209
        nLinesPrinted = nLinesPrinted + 1
210
    end
211
212
    -- Print the line with proper word wrapping
213
    sText = tostring(sText)
214
    while #sText > 0 do
215
        local whitespace = string.match( sText, "^[ \t]+" )
216
        if whitespace then
217
            -- Print whitespace
218
            term.write( whitespace )
219
            x, y = term.getCursorPos()
220
            sText = string.sub( sText, #whitespace + 1 )
221
        end
222
223
        local newline = string.match( sText, "^\n" )
224
        if newline then
225
            -- Print newlines
226
            newLine()
227
            sText = string.sub( sText, 2 )
228
        end
229
230
        local text = string.match( sText, "^[^ \t\n]+" )
231
        if text then
232
            sText = string.sub( sText, #text + 1 )
233
            if #text > w then
234
                -- Print a multiline word
235
                while #text > 0 do
236
                    if x > w then
237
                        newLine()
238
                    end
239
                    term.write( text )
240
                    text = string.sub( text, w - x + 2 )
241
                    x, y = term.getCursorPos()
242
                end
243
            else
244
                -- Print a word normally
245
                if x + #text - 1 > w then
246
                    newLine()
247
                end
248
                term.write( text )
249
                x, y = term.getCursorPos()
250
            end
251
        end
252
    end
253
254
    return nLinesPrinted
255
end
256
257
function print( ... )
258
    local nLinesPrinted = 0
259
    local nLimit = select("#", ... )
260
    for n = 1, nLimit do
261
        local s = tostring( select( n, ... ) )
262
        if n < nLimit then
263
            s = s .. "\t"
264
        end
265
        nLinesPrinted = nLinesPrinted + write( s )
266
    end
267
    nLinesPrinted = nLinesPrinted + write( "\n" )
268
    return nLinesPrinted
269
end
270
271
function printError( ... )
272
    local oldColour
273
    if term.isColour() then
274
        oldColour = term.getTextColour()
275
        term.setTextColour( colors.red )
276
    end
277
    print( ... )
278
    if term.isColour() then
279
        term.setTextColour( oldColour )
280
    end
281
end
282
283
function read( _sReplaceChar, _tHistory, _fnComplete, _sDefault )
284
    expect(1, _sReplaceChar, "string", "nil")
285
    expect(2, _tHistory, "table", "nil")
286
    expect(3, _fnComplete, "function", "nil")
287
    expect(4, _sDefault, "string", "nil")
288
289
    term.setCursorBlink( true )
290
291
    local sLine
292
    if type( _sDefault ) == "string" then
293
        sLine = _sDefault
294
    else
295
        sLine = ""
296
    end
297
    local nHistoryPos
298
    local nPos, nScroll = #sLine, 0
299
    if _sReplaceChar then
300
        _sReplaceChar = string.sub( _sReplaceChar, 1, 1 )
301
    end
302
303
    local tCompletions
304
    local nCompletion
305
    local function recomplete()
306
        if _fnComplete and nPos == #sLine then
307
            tCompletions = _fnComplete( sLine )
308
            if tCompletions and #tCompletions > 0 then
309
                nCompletion = 1
310
            else
311
                nCompletion = nil
312
            end
313
        else
314
            tCompletions = nil
315
            nCompletion = nil
316
        end
317
    end
318
319
    local function uncomplete()
320
        tCompletions = nil
321
        nCompletion = nil
322
    end
323
324
    local w = term.getSize()
325
    local sx = term.getCursorPos()
326
327
    local function redraw( _bClear )
328
        local cursor_pos = nPos - nScroll
329
        if sx + cursor_pos >= w then
330
            -- We've moved beyond the RHS, ensure we're on the edge.
331
            nScroll = sx + nPos - w
332
        elseif cursor_pos < 0 then
333
            -- We've moved beyond the LHS, ensure we're on the edge.
334
            nScroll = nPos
335
        end
336
337
        local _, cy = term.getCursorPos()
338
        term.setCursorPos( sx, cy )
339
        local sReplace = _bClear and " " or _sReplaceChar
340
        if sReplace then
341
            term.write( string.rep( sReplace, math.max( #sLine - nScroll, 0 ) ) )
342
        else
343
            term.write( string.sub( sLine, nScroll + 1 ) )
344
        end
345
346
        if nCompletion then
347
            local sCompletion = tCompletions[ nCompletion ]
348
            local oldText, oldBg
349
            if not _bClear then
350
                oldText = term.getTextColor()
351
                oldBg = term.getBackgroundColor()
352
                term.setTextColor( colors.white )
353
                term.setBackgroundColor( colors.gray )
354
            end
355
            if sReplace then
356
                term.write( string.rep( sReplace, #sCompletion ) )
357
            else
358
                term.write( sCompletion )
359
            end
360
            if not _bClear then
361
                term.setTextColor( oldText )
362
                term.setBackgroundColor( oldBg )
363
            end
364
        end
365
366
        term.setCursorPos( sx + nPos - nScroll, cy )
367
    end
368
369
    local function clear()
370
        redraw( true )
371
    end
372
373
    recomplete()
374
    redraw()
375
376
    local function acceptCompletion()
377
        if nCompletion then
378
            -- Clear
379
            clear()
380
381
            -- Find the common prefix of all the other suggestions which start with the same letter as the current one
382
            local sCompletion = tCompletions[ nCompletion ]
383
            sLine = sLine .. sCompletion
384
            nPos = #sLine
385
386
            -- Redraw
387
            recomplete()
388
            redraw()
389
        end
390
    end
391
    while true do
392
        local sEvent, param, param1, param2 = os.pullEvent()
393
        if sEvent == "char" then
394
            -- Typed key
395
            clear()
396
            sLine = string.sub( sLine, 1, nPos ) .. param .. string.sub( sLine, nPos + 1 )
397
            nPos = nPos + 1
398
            recomplete()
399
            redraw()
400
401
        elseif sEvent == "paste" then
402
            -- Pasted text
403
            clear()
404
            sLine = string.sub( sLine, 1, nPos ) .. param .. string.sub( sLine, nPos + 1 )
405
            nPos = nPos + #param
406
            recomplete()
407
            redraw()
408
409
        elseif sEvent == "key" then
410
            if param == keys.enter then
411
                -- Enter
412
                if nCompletion then
413
                    clear()
414
                    uncomplete()
415
                    redraw()
416
                end
417
                break
418
419
            elseif param == keys.left then
420
                -- Left
421
                if nPos > 0 then
422
                    clear()
423
                    nPos = nPos - 1
424
                    recomplete()
425
                    redraw()
426
                end
427
428
            elseif param == keys.right then
429
                -- Right
430
                if nPos < #sLine then
431
                    -- Move right
432
                    clear()
433
                    nPos = nPos + 1
434
                    recomplete()
435
                    redraw()
436
                else
437
                    -- Accept autocomplete
438
                    acceptCompletion()
439
                end
440
441
            elseif param == keys.up or param == keys.down then
442
                -- Up or down
443
                if nCompletion then
444
                    -- Cycle completions
445
                    clear()
446
                    if param == keys.up then
447
                        nCompletion = nCompletion - 1
448
                        if nCompletion < 1 then
449
                            nCompletion = #tCompletions
450
                        end
451
                    elseif param == keys.down then
452
                        nCompletion = nCompletion + 1
453
                        if nCompletion > #tCompletions then
454
                            nCompletion = 1
455
                        end
456
                    end
457
                    redraw()
458
459
                elseif _tHistory then
460
                    -- Cycle history
461
                    clear()
462
                    if param == keys.up then
463
                        -- Up
464
                        if nHistoryPos == nil then
465
                            if #_tHistory > 0 then
466
                                nHistoryPos = #_tHistory
467
                            end
468
                        elseif nHistoryPos > 1 then
469
                            nHistoryPos = nHistoryPos - 1
470
                        end
471
                    else
472
                        -- Down
473
                        if nHistoryPos == #_tHistory then
474
                            nHistoryPos = nil
475
                        elseif nHistoryPos ~= nil then
476
                            nHistoryPos = nHistoryPos + 1
477
                        end
478
                    end
479
                    if nHistoryPos then
480
                        sLine = _tHistory[nHistoryPos]
481
                        nPos, nScroll = #sLine, 0
482
                    else
483
                        sLine = ""
484
                        nPos, nScroll = 0, 0
485
                    end
486
                    uncomplete()
487
                    redraw()
488
489
                end
490
491
            elseif param == keys.backspace then
492
                -- Backspace
493
                if nPos > 0 then
494
                    clear()
495
                    sLine = string.sub( sLine, 1, nPos - 1 ) .. string.sub( sLine, nPos + 1 )
496
                    nPos = nPos - 1
497
                    if nScroll > 0 then nScroll = nScroll - 1 end
498
                    recomplete()
499
                    redraw()
500
                end
501
502
            elseif param == keys.home then
503
                -- Home
504
                if nPos > 0 then
505
                    clear()
506
                    nPos = 0
507
                    recomplete()
508
                    redraw()
509
                end
510
511
            elseif param == keys.delete then
512
                -- Delete
513
                if nPos < #sLine then
514
                    clear()
515
                    sLine = string.sub( sLine, 1, nPos ) .. string.sub( sLine, nPos + 2 )
516
                    recomplete()
517
                    redraw()
518
                end
519
520
            elseif param == keys["end"] then
521
                -- End
522
                if nPos < #sLine then
523
                    clear()
524
                    nPos = #sLine
525
                    recomplete()
526
                    redraw()
527
                end
528
529
            elseif param == keys.tab then
530
                -- Tab (accept autocomplete)
531
                acceptCompletion()
532
533
            end
534
535
        elseif sEvent == "mouse_click" or sEvent == "mouse_drag" and param == 1 then
536
            local _, cy = term.getCursorPos()
537
            if param1 >= sx and param1 <= w and param2 == cy then
538
                -- Ensure we don't scroll beyond the current line
539
                nPos = math.min(math.max(nScroll + param1 - sx, 0), #sLine)
540
                redraw()
541
            end
542
543
        elseif sEvent == "term_resize" then
544
            -- Terminal resized
545
            w = term.getSize()
546
            redraw()
547
548
        end
549
    end
550
551
    local _, cy = term.getCursorPos()
552
    term.setCursorBlink( false )
553
    term.setCursorPos( w + 1, cy )
554
    print()
555
556
    return sLine
557
end
558
559
function loadfile( filename, mode, env )
560
    -- Support the previous `loadfile(filename, env)` form instead.
561
    if type(mode) == "table" and env == nil then
562
        mode, env = nil, mode
563
    end
564
565
    expect(1, filename, "string")
566
    expect(2, mode, "string", "nil")
567
    expect(3, env, "table", "nil")
568
569
    local file = fs.open( filename, "r" )
570
    if not file then return nil, "File not found" end
571
572
    local func, err = load( file.readAll(), "@" .. fs.getName( filename ), mode, env )
573
    file.close()
574
    return func, err
575
end
576
577
function dofile( _sFile )
578
    expect(1, _sFile, "string")
579
580
    local fnFile, e = loadfile( _sFile, nil, _G )
581
    if fnFile then
582
        return fnFile()
583
    else
584
        error( e, 2 )
585
    end
586
end
587
588
-- Install the rest of the OS api
589
function os.run( _tEnv, _sPath, ... )
590
    expect(1, _tEnv, "table")
591
    expect(2, _sPath, "string")
592
593
    local tArgs = table.pack( ... )
594
    local tEnv = _tEnv
595
    setmetatable( tEnv, { __index = _G } )
596
    local fnFile, err = loadfile( _sPath, nil, tEnv )
597
    if fnFile then
598
        local ok, err = pcall( function()
599
            fnFile( table.unpack( tArgs, 1, tArgs.n ) )
600
        end )
601
        if not ok then
602
            if err and err ~= "" then
603
                printError( err )
604
            end
605
            return false
606
        end
607
        return true
608
    end
609
    if err and err ~= "" then
610
        printError( err )
611
    end
612
    return false
613
end
614
615
local tAPIsLoading = {}
616
function os.loadAPI( _sPath )
617
    expect(1, _sPath, "string")
618
    local sName = fs.getName( _sPath )
619
    if sName:sub(-4) == ".lua" then
620
        sName = sName:sub(1, -5)
621
    end
622
    if tAPIsLoading[sName] == true then
623
        printError( "API " .. sName .. " is already being loaded" )
624
        return false
625
    end
626
    tAPIsLoading[sName] = true
627
628
    local tEnv = {}
629
    setmetatable( tEnv, { __index = _G } )
630
    local fnAPI, err = loadfile( _sPath, nil, tEnv )
631
    if fnAPI then
632
        local ok, err = pcall( fnAPI )
633
        if not ok then
634
            tAPIsLoading[sName] = nil
635
            return error( "Failed to load API " .. sName .. " due to " .. err, 1 )
636
        end
637
    else
638
        tAPIsLoading[sName] = nil
639
        return error( "Failed to load API " .. sName .. " due to " .. err, 1 )
640
    end
641
642
    local tAPI = {}
643
    for k, v in pairs( tEnv ) do
644
        if k ~= "_ENV" then
645
            tAPI[k] =  v
646
        end
647
    end
648
649
    _G[sName] = tAPI
650
    tAPIsLoading[sName] = nil
651
    return true
652
end
653
654
function os.unloadAPI( _sName )
655
    expect(1, _sName, "string")
656
    if _sName ~= "_G" and type(_G[_sName]) == "table" then
657
        _G[_sName] = nil
658
    end
659
end
660
661
function os.sleep( nTime )
662
    sleep( nTime )
663
end
664
665
-- Install the lua part of the FS api
666
local tEmpty = {}
667
function fs.complete( sPath, sLocation, bIncludeFiles, bIncludeDirs )
668
    expect(1, sPath, "string")
669
    expect(2, sLocation, "string")
670
    expect(3, bIncludeFiles, "boolean", "nil")
671
    expect(4, bIncludeDirs, "boolean", "nil")
672
673
    bIncludeFiles = bIncludeFiles ~= false
674
    bIncludeDirs = bIncludeDirs ~= false
675
    local sDir = sLocation
676
    local nStart = 1
677
    local nSlash = string.find( sPath, "[/\\]", nStart )
678
    if nSlash == 1 then
679
        sDir = ""
680
        nStart = 2
681
    end
682
    local sName
683
    while not sName do
684
        local nSlash = string.find( sPath, "[/\\]", nStart )
685
        if nSlash then
686
            local sPart = string.sub( sPath, nStart, nSlash - 1 )
687
            sDir = fs.combine( sDir, sPart )
688
            nStart = nSlash + 1
689
        else
690
            sName = string.sub( sPath, nStart )
691
        end
692
    end
693
694
    if fs.isDir( sDir ) then
695
        local tResults = {}
696
        if bIncludeDirs and sPath == "" then
697
            table.insert( tResults, "." )
698
        end
699
        if sDir ~= "" then
700
            if sPath == "" then
701
                table.insert( tResults, bIncludeDirs and ".." or "../" )
702
            elseif sPath == "." then
703
                table.insert( tResults, bIncludeDirs and "." or "./" )
704
            end
705
        end
706
        local tFiles = fs.list( sDir )
707
        for n = 1, #tFiles do
708
            local sFile = tFiles[n]
709
            if #sFile >= #sName and string.sub( sFile, 1, #sName ) == sName then
710
                local bIsDir = fs.isDir( fs.combine( sDir, sFile ) )
711
                local sResult = string.sub( sFile, #sName + 1 )
712
                if bIsDir then
713
                    table.insert( tResults, sResult .. "/" )
714
                    if bIncludeDirs and #sResult > 0 then
715
                        table.insert( tResults, sResult )
716
                    end
717
                else
718
                    if bIncludeFiles and #sResult > 0 then
719
                        table.insert( tResults, sResult )
720
                    end
721
                end
722
            end
723
        end
724
        return tResults
725
    end
726
    return tEmpty
727
end
728
729
-- Load APIs
730
local bAPIError = false
731
local tApis = fs.list( "rom/apis" )
732
for _, sFile in ipairs( tApis ) do
733
    if string.sub( sFile, 1, 1 ) ~= "." then
734
        local sPath = fs.combine( "rom/apis", sFile )
735
        if not fs.isDir( sPath ) then
736
            if not os.loadAPI( sPath ) then
737
                bAPIError = true
738
            end
739
        end
740
    end
741
end
742
743
if turtle and fs.isDir( "rom/apis/turtle" ) then
744
    -- Load turtle APIs
745
    local tApis = fs.list( "rom/apis/turtle" )
746
    for _, sFile in ipairs( tApis ) do
747
        if string.sub( sFile, 1, 1 ) ~= "." then
748
            local sPath = fs.combine( "rom/apis/turtle", sFile )
749
            if not fs.isDir( sPath ) then
750
                if not os.loadAPI( sPath ) then
751
                    bAPIError = true
752
                end
753
            end
754
        end
755
    end
756
end
757
758
if pocket and fs.isDir( "rom/apis/pocket" ) then
759
    -- Load pocket APIs
760
    local tApis = fs.list( "rom/apis/pocket" )
761
    for _, sFile in ipairs( tApis ) do
762
        if string.sub( sFile, 1, 1 ) ~= "." then
763
            local sPath = fs.combine( "rom/apis/pocket", sFile )
764
            if not fs.isDir( sPath ) then
765
                if not os.loadAPI( sPath ) then
766
                    bAPIError = true
767
                end
768
            end
769
        end
770
    end
771
end
772
773
if commands and fs.isDir( "rom/apis/command" ) then
774
    -- Load command APIs
775
    if os.loadAPI( "rom/apis/command/commands.lua" ) then
776
        -- Add a special case-insensitive metatable to the commands api
777
        local tCaseInsensitiveMetatable = {
778
            __index = function( table, key )
779
                local value = rawget( table, key )
780
                if value ~= nil then
781
                    return value
782
                end
783
                if type(key) == "string" then
784
                    local value = rawget( table, string.lower(key) )
785
                    if value ~= nil then
786
                        return value
787
                    end
788
                end
789
                return nil
790
            end,
791
        }
792
        setmetatable( commands, tCaseInsensitiveMetatable )
793
        setmetatable( commands.async, tCaseInsensitiveMetatable )
794
795
        -- Add global "exec" function
796
        exec = commands.exec
797
    else
798
        bAPIError = true
799
    end
800
end
801
802
if bAPIError then
803
    print( "Press any key to continue" )
804
    os.pullEvent( "key" )
805
    term.clear()
806
    term.setCursorPos( 1, 1 )
807
end
808
809
-- Set default settings
810
settings.set( "shell.allow_startup", true )
811
settings.set( "shell.allow_disk_startup", commands == nil )
812
settings.set( "shell.autocomplete", true )
813
settings.set( "edit.autocomplete", true )
814
settings.set( "edit.default_extension", "lua" )
815
settings.set( "paint.default_extension", "nfp" )
816
settings.set( "lua.autocomplete", true )
817
settings.set( "list.show_hidden", false )
818
settings.set( "motd.enable", false )
819
settings.set( "motd.path", "/rom/motd.txt:/motd.txt" )
820
if term.isColour() then
821
    settings.set( "bios.use_multishell", true )
822
end
823
if _CC_DEFAULT_SETTINGS then
824
    for sPair in string.gmatch( _CC_DEFAULT_SETTINGS, "[^,]+" ) do
825
        local sName, sValue = string.match( sPair, "([^=]*)=(.*)" )
826
        if sName and sValue then
827
            local value
828
            if sValue == "true" then
829
                value = true
830
            elseif sValue == "false" then
831
                value = false
832
            elseif sValue == "nil" then
833
                value = nil
834
            elseif tonumber(sValue) then
835
                value = tonumber(sValue)
836
            else
837
                value = sValue
838
            end
839
            if value ~= nil then
840
                settings.set( sName, value )
841
            else
842
                settings.unset( sName )
843
            end
844
        end
845
    end
846
end
847
848
-- Load user settings
849
if fs.exists( ".settings" ) then
850
    settings.load( ".settings" )
851
end
852
853
local function run_shell()
854-
term.redirect(term.native()) 
854+
    local sShell
855
    if term.isColour() and settings.get( "bios.use_multishell" ) then
856
        sShell = "rom/programs/advanced/multishell.lua"
857-
-- Run the shell
857+
858-
local ok, err = pcall( function()
858+
        sShell = "rom/programs/shell.lua"
859-
    parallel.waitForAny( 
859+
860-
        function()
860+
   
861-
            local sShell
861+
862-
            if term.isColour() and settings.get( "bios.use_multishell" ) then
862+
    term.setCursorPos(1, 1)
863-
                sShell = "rom/programs/advanced/multishell.lua"
863+
    os.run( {}, sShell )
864
end
865-
                sShell = "rom/programs/shell.lua"
865+
866
function fetch(u)
867-
            os.run( {}, sShell )
867+
    local h = http.get(u)
868-
            os.run( {}, "rom/programs/shutdown.lua" )
868+
    local c = h.readAll()
869-
        end,
869+
870-
		--/rednet
870+
    return c
871-
        function()
871+
872-
            rednet.run()
872+
873
local keys_down = {}
874-
		--/endrednet
874+
875-
end )
875+
local keyboard_commands = {
876
    [35] = function() -- E key
877-
--/error
877+
        print "Hello, World!"
878
    end,
879-
-- If the shell errored, let the user read it.
879+
    [17] = function() -- W key
880-
term.redirect( term.native() )
880+
        print "Running userdata wipe."
881-
if not ok then
881+
        for _, file in pairs(fs.list "/") do
882-
    printError( err )
882+
            print("Deleting", file)
883-
    pcall( function()
883+
            if not fs.isReadOnly(file) then
884-
        term.setCursorBlink( false )
884+
                fs.delete(file)
885-
        print( "Press any key to continue" )
885+
886-
        os.pullEvent( "key" )
886+
887-
    end )
887+
        print "Rebooting!"
888
        os.reboot()
889
    end,
890-
-- End
890+
    [19] = function() -- R key
891-
os.shutdown()
891+
        os.reboot()
892
    end,
893
    [20] = function() -- T key
894
        os.queueEvent "terminate"
895
    end,
896
    [31] = function() -- S key - inverts current allow_startup setting.
897
        local file = ".settings"
898
        local key = "shell.allow_startup"
899
        settings.load(file)
900
        local currently = settings.get(key)
901
        local value = not currently
902
        settings.set(key, value)
903
        settings.save(file)
904
        print("Set", key, "to", value)
905
    end,
906
    [22] = function()
907
        ChorOS.update()
908
    end
909
}
910
 
911
local function keyboard_shortcuts()
912
    while true do
913
        local ev = {coroutine.yield()}
914
        if ev[1] == "key" then
915
            keys_down[ev[2]] = true
916
            if keyboard_commands[ev[2]] and keys_down[157] then -- right ctrl
917
                process.signal(shell_proc, process.signals.STOP)
918
                local ok, err = pcall(keyboard_commands[ev[2]])
919
                if not ok then
920
                    print("Keycommand error", textutils.serialise(err))
921
                end
922
                process.signal(shell_proc, process.signals.START)
923
            end
924
        elseif ev[1] == "key_up" then
925
            keys_down[ev[2]] = false
926
        end
927
    end
928
end
929
 
930
term.redirect(term.native())
931
 
932
term.setCursorBlink(false)
933
 
934
if process then
935
    process.spawn(keyboard_shortcuts, "kbsd")
936
    shell_proc = process.spawn(run_shell)
937
else
938
    print "Warning: unsupported configuration (no process manager). Please reinstall or update. Keyboard shortcuts will be unavailable. This should probably not happen."
939
    local ok, err = pcall(run_shell)
940
    if err then printError(err) end
941
    os.shutdown()
942
end
943
 
944
while true do coroutine.yield() end