Computer Craft のメモ
[PR]上記の広告は3ヶ月以上新規記事投稿のないブログに表示されています。新しい記事を書く事で広告が消えます。
ただいまコメントを受けつけておりません。
local function isOneOf(val, possibleValues)
for _, v in ipairs(possibleValues) do
if val == v then
return true;
end
end
return false;
end
local function startsWith(subject, prefix)
if subject:len() < prefix:len() then
return false;
end
for i = 1, prefix:len() do
if subject:sub(i, i) ~= prefix:sub(i, i) then
return false;
end
end
return true;
end
local function makePageData(width, height, directoryOnlyFlg)
local rawLst = fs.list(shell.dir());
local fLst = { };
local dLst = { };
for _, val in ipairs(rawLst) do
if fs.isDir(shell.dir() .. "/" .. val) then
table.insert(dLst, { name = val, isDir = true });
else
table.insert(fLst, { name = val, isDir = false });
end
end
function comp(a, b)
return a.name < b.name;
end
local lst = { };
if "" ~= shell.dir() then
table.insert(lst, { name = "..", isDir = true });
end
if directoryOnlyFlg then
table.insert(lst, { name = ".", isDir = true });
end
table.sort(dLst, comp);
for _, val in ipairs(dLst) do
table.insert(lst, val);
end
if not directoryOnlyFlg then
table.sort(fLst, comp);
for _, val in ipairs(fLst) do
table.insert(lst, val);
end
end
local pages = { };
local currPage = { };
for _, val in ipairs(lst) do
table.insert(currPage, val);
if height - 1 <= #currPage then
table.insert(pages, currPage);
currPage = { };
end
end
if 0 < #currPage then
table.insert(pages, currPage);
end
return pages;
end
local function resetTerm()
term.setBackgroundColor(colors.black);
term.setTextColor(colors.white);
term.clear();
term.setCursorPos(1, 1);
end
local function prepareExit(initialDir)
resetTerm();
shell.setDir(initialDir);
end
local function pagingAction(isUp, pageMode, pageIdx, lineIdx, pages, newNotice)
if isUp then
if pageMode then
pageIdx = math.max(pageIdx - 1, 1);
else
if lineIdx - 1 <= 0 then
if 2 <= pageIdx then
pageIdx = pageIdx - 1;
lineIdx = #pages[pageIdx];
end
else
lineIdx = lineIdx - 1;
end
end
else
if pageMode then
pageIdx = math.min(pageIdx + 1, #pages);
else
if #pages[pageIdx] < lineIdx + 1 then
if pageIdx <= #pages - 1 then
pageIdx = pageIdx + 1;
lineIdx = 1;
end
else
lineIdx = lineIdx + 1;
end
end
end
local elm = pages[pageIdx][lineIdx];
if not pageMode then
if elm.isDir and ".." == elm.name then
newNotice = ".. means parent directory.";
elseif elm.isDir and "." == elm.name then
newNotice = ". means current directory.";
end
end
return pageIdx, lineIdx, newNotice;
end
local function getParentPath(directoryPath)
local tmp = directoryPath:reverse();
return tmp:sub(tmp:find("/", 1, true) + 1):reverse();
end
local function ascendDirectory()
if "" == shell.dir() then
return false, "";
else
returnTrip = true;
shell.setDir(getParentPath(shell.dir()));
local newNotice;
if "" == shell.dir() then
newNotice = "ascended. /";
else
newNotice = "ascended. " .. shell.dir();
end
return true, newNotice;
end
end
local function lineModeAction(currentAction, currentSubject,
pathIndexStack, pageIdx_, lineIdx_,
toolIdx, moveToMode, moveSrcPath)
local directoryChanged = false;
local returnTrip = false;
local newNotice = "";
if startsWith(currentAction, "edit") then
shell.run("edit", currentSubject);
elseif startsWith(currentAction, "cd") then
if ".." == currentSubject then
returnTrip, newNotice = ascendDirectory();
else
table.insert(pathIndexStack, { pageIdx = pageIdx_, lineIdx = lineIdx_ });
shell.setDir(shell.dir() .. "/" .. currentSubject);
newNotice = "descended. " .. shell.dir();
end
directoryChanged = true;
elseif startsWith(currentAction, "delete") then
if "." == currentSubject or ".." == currentSubject then
newNotice = currentSubject .. " cannot delete.";
else
resetTerm();
print("[delete] " .. currentSubject);
print("Do you really want to delete this file?");
term.write("[y]es / [n]o >");
if "y" == read() then
shell.run("delete", currentSubject);
newNotice = currentSubject .. " was (maybe) deleted.";
directoryChanged = true;
else
newNotice = "delete canceled.";
end
end
elseif startsWith(currentAction, "rename") then
if "." == currentSubject or ".." == currentSubject then
newNotice = currentSubject .. " cannot rename.";
else
resetTerm();
print("[rename] " .. currentSubject);
print("Enter new name.");
print("To borrow original name, press [up] cursor key.");
print("If you want to cancel renaming, enter blank.");
term.write(">");
local newName = read(nil, { currentSubject });
if "" ~= newName then
shell.run("rename", currentSubject, newName);
newNotice = currentSubject .. " was (maybe) renamed.";
directoryChanged = true;
else
newNotice = "rename canceled.";
end
end
elseif startsWith(currentAction, "copy") then
if "." == currentSubject or ".." == currentSubject then
newNotice = currentSubject .. " cannot copy.";
else
resetTerm();
print("[copy] " .. currentSubject);
print("Enter new name.");
print("To borrow original name, press [up] cursor key.");
print("If you want to cancel copy, enter blank.");
term.write(">");
local newName = read(nil, { currentSubject });
if "" ~= newName then
shell.run("copy", currentSubject, newName);
newNotice = currentSubject .. " was (maybe) copied.";
directoryChanged = true;
else
newNotice = "copy canceled.";
end
end
elseif startsWith(currentAction, "move")
and not startsWith(currentAction, "moveTo") then
if "." == currentSubject or ".." == currentSubject then
newNotice = currentSubject .. " cannot copy.";
else
moveToMode = true;
newNotice = "<<move>> select moveTo directory.";
directoryChanged = true;
moveSrcPath = shell.dir() .. "/" .. currentSubject;
pageIdx_ = 1;
lineIdx_ = 1;
toolIdx = 1;
end
elseif startsWith(currentAction, "cancel move") then
moveToMode = false;
newNotice = "move canceled.";
directoryChanged = true;
pageIdx_ = 1;
lineIdx_ = 1;
toolIdx = 1;
elseif startsWith(currentAction, "moveTo") then
local choice = "move / copy";
local wrong = false;
local moveDstPath;
if "." == currentSubject then
moveDstPath = shell.dir();
elseif ".." == currentSubject then
moveDstPath = getParentPath(shell.dir());
else
moveDstPath = shell.dir() .. "/" .. currentSubject;
end
while true do
resetTerm();
print("[" .. choice .. "]");
print("source :");
print(" " .. moveSrcPath);
print("destination :");
print(" " .. moveDstPath);
print("select move or copy.");
if wrong then
wrong = false;
print("*** Wrong input. Please retry.");
end
print(" copy : input \"c\" and hit enter key.");
print(" move : hit enter key with no input.");
print(" or [r]eselect destination directory.");
print(" or [q]uit. (cancel move or copy.)");
term.write(">");
local input = read();
if "c" == input then
choice = "copy";
break;
elseif "" == input then
choice = "move";
break;
elseif "r" == input then
choice = "reselect";
break;
elseif "q" == input then
choice = "quit";
break;
else
wrong = true;
end
end
if "copy" == choice then
shell.run("copy", moveSrcPath, moveDstPath);
newNotice = "The copy was successful maybe.";
elseif "move" == choice then
shell.run("move", moveSrcPath, moveDstPath);
newNotice = "The move was successful maybe.";
elseif "reselect" == choice then
newNotice = "<<move>> select moveTo directory.";
toolIdx = 1;
elseif "quit" == choice then
newNotice = "copy canceled.";
end
if "reselect" ~= choice then
moveToMode = false;
directoryChanged = true;
pageIdx_ = 1;
lineIdx_ = 1;
toolIdx = 1;
end
elseif startsWith(currentAction, "[other]") then
if "." == currentSubject or ".." == currentSubject then
newNotice = currentSubject .. " cannot [other].";
else
resetTerm();
local stage = 1;
local input = "";
local ret;
while true do
print("[other]");
local hist = { };
table.insert(hist, currentSubject);
table.insert(hist, currentSubject .. " " .. currentSubject);
if "" ~= input then
table.insert(hist, input);
end
if 1 == stage then
print("Input command.");
term.write(">");
input = read(nil, hist);
if "" == input then
newNotice = "[other] canceled.";
break;
else
stage = 2;
end
elseif 2 == stage then
print("command = ");
print(input);
print("");
print("execute? [y]es, [e]dit, [c]ancel");
term.write(">");
local ch = read();
if "y" == ch then
ret = shell.run(input);
newNotice = "[other] returned " .. tostring(ret);
break;
elseif "e" == ch then
stage = 1;
elseif "c" == ch then
newNotice = "[other] canceled.";
break;
end
end
end
end
end
return directoryChanged, pathIndexStack, returnTrip, newNotice, moveToMode,
pageIdx_, lineIdx_, toolIdx, moveSrcPath;
end
local SPACE = " ";
local pageIdx = 1;
local lineIdx = 1;
local toolIdx = 1;
local pageMode = true;
local tools = { dir = { "cd --> ", "delete --> ", "rename --> ",
"copy --> ", "move --> ", "[other] --> "},
file = { "edit --> ", "delete --> ", "rename --> ",
"copy --> ", "move --> ", "[other] --> "},
move = { "cd --> ", "moveTo --> ", "cancel move " } };
local directoryChanged;
local pages;
local width, height = term.getSize();
local returnTrip = false;
local pathIndexStack = { };
local initialDir = shell.dir();
local miniHelp = { true_ = "[q]uit, up/down=paging, [->]=line mode",
false_ = "[->]=change action, enter=exec action" };
local statusBarText = "";
local newNotice = "";
local moveToMode = false;
local directoryOnlyFlg = false;
local moveSrcPath = "";
local KNtC = { };
for i = 0, 256 do
local name = keys.getName(i);
if nil ~= name then
KNtC[name] = i;
end
end
directoryChanged = true;
while true do
if moveToMode then
directoryOnlyFlg = true;
else
directoryOnlyFlg = false;
end
if directoryChanged then
pages = makePageData(width, height, directoryOnlyFlg);
pageIdx = math.min(#pages, pageIdx);
lineIdx = math.min(#pages[pageIdx], lineIdx);
if returnTrip and #pathIndexStack then
local o = table.remove(pathIndexStack);
pageIdx = o.pageIdx;
lineIdx = o.lineIdx;
end
returnTrip = false;
directoryChanged = false;
end
local currentLineIsDir;
local currentAction = "";
local currentSubject;
local toolSetKey;
resetTerm();
for i, val in ipairs(pages[pageIdx]) do
term.setCursorPos(1, i);
local arrow = "";
if not pageMode then
lineIdx = math.min(lineIdx, #pages[pageIdx]);
if moveToMode then
toolSetKey = "move";
else
if val.isDir then
toolSetKey = "dir";
else
toolSetKey = "file";
end
end
if i == lineIdx then
arrow = tools[toolSetKey][toolIdx];
currentAction = arrow;
currentLineIsDir = val.isDir;
currentSubject = val.name;
else
arrow = SPACE:rep(#tools[toolSetKey][toolIdx]);
end
end
if val.isDir then
term.write(arrow .. "<dir> " .. val.name
.. SPACE:rep(math.max(0, width - (#arrow + #val.name))));
else
term.write(arrow .. val.name
.. SPACE:rep(math.max(0, width - (#arrow + #val.name))));
end
end
for i = #pages[pageIdx] + 1, height do
term.setCursorPos(1, i);
term.write(SPACE:rep(width));
end
term.setCursorPos(1, height);
term.setTextColor(colors.black);
term.setBackgroundColor(colors.white);
if not moveToMode then
if "" ~= newNotice then
statusBarText = newNotice;
newNotice = "";
else
statusBarText = miniHelp[tostring(pageMode) .. "_"];
end
else
statusBarText = newNotice;
end
term.write(statusBarText .. SPACE:rep(math.max(0, width - #statusBarText)));
local easyExitFlg = false;
while true do
local event, scanCode = os.pullEvent("key");
-- key name
-- http://computercraft.info/wiki/Keys_(API)
if isOneOf(scanCode, { KNtC.up, KNtC.p, KNtC.b, KNtC.w, KNtC.a }) then
pageIdx, lineIdx, newNotice
= pagingAction(true, pageMode, pageIdx, lineIdx, pages, newNotice);
break;
elseif isOneOf(scanCode,
{ KNtC.down, KNtC.n, KNtC.f, KNtC.s, KNtC.d, KNtC.space }) then
pageIdx, lineIdx, newNotice
= pagingAction(false, pageMode, pageIdx, lineIdx, pages, newNotice);
break;
elseif isOneOf(scanCode, { KNtC.right }) then
if not pageMode then
toolIdx = (toolIdx % #tools[toolSetKey]) + 1;
if startsWith(
tools[toolSetKey][toolIdx], "copy") then
newNotice = "The copy on the same directory.";
elseif startsWith(tools[toolSetKey][toolIdx], "move")
and not startsWith(tools[toolSetKey][toolIdx], "moveTo") then
newNotice = "Move (or copy) to other directory.";
elseif startsWith(tools[toolSetKey][toolIdx], "[other]") then
newNotice = "A command can be executed manually.";
end
end
pageMode = false;
break;
elseif isOneOf(scanCode, { KNtC.left }) then
toolIdx = 1;
if pageMode then
returnTrip, newNotice = ascendDirectory();
directoryChanged = returnTrip;
end
if not moveToMode then
pageMode = true;
end
break;
elseif isOneOf(scanCode, { KNtC.q, KNtC.e }) then
prepareExit(initialDir);
return;
elseif isOneOf(scanCode, { KNtC.enter }) then
directoryChanged, pathIndexStack, returnTrip, newNotice, moveToMode,
pageIdx, lineIdx, toolIdx, moveSrcPath
= lineModeAction(currentAction, currentSubject, pathIndexStack,
pageIdx, lineIdx, toolIdx, moveToMode, moveSrcPath);
break;
end
sleep(0.5);
end
end