diff --git a/sys/apps/Files.lua b/sys/apps/Files.lua index 1529c6d..8cb09cc 100644 --- a/sys/apps/Files.lua +++ b/sys/apps/Files.lua @@ -77,8 +77,8 @@ local Browser = UI.Page { grid = UI.ScrollingGrid { columns = { { heading = 'Name', key = 'name' }, - { key = 'flags', width = 2 }, - { heading = 'Size', key = 'fsize', width = 5 }, + { key = 'flags', width = 3, textColor = 'lightGray' }, + { heading = 'Size', key = 'fsize', width = 5, textColor = 'yellow' }, }, sortColumn = 'name', y = 2, ey = -2, @@ -211,7 +211,7 @@ function Browser:enable() self:setFocus(self.grid) end -function Browser.menuBar:getActive(menuItem) +function Browser.menuBar.getActive(_, menuItem) local file = Browser.grid:getSelected() if menuItem.flags == FILE then return file and not file.isDir @@ -223,7 +223,7 @@ function Browser:setStatus(status, ...) self.notification:info(string.format(status, ...)) end -function Browser:unmarkAll() +function Browser.unmarkAll() for _,m in pairs(marked) do m.marked = false end @@ -263,10 +263,11 @@ function Browser:updateDirectory(dir) dir.size = #files for _, file in pairs(files) do file.fullName = fs.combine(dir.name, file.name) - file.flags = '' + file.flags = file.fstype or ' ' if not file.isDir then dir.totalSize = dir.totalSize + file.size file.fsize = formatSize(file.size) + file.flags = file.flags .. ' ' else if config.showDirSizes then file.size = fs.getSize(file.fullName, true) @@ -274,11 +275,9 @@ function Browser:updateDirectory(dir) dir.totalSize = dir.totalSize + file.size file.fsize = formatSize(file.size) end - file.flags = 'D' - end - if file.isReadOnly then - file.flags = file.flags .. 'R' + file.flags = file.flags .. 'D' end + file.flags = file.flags .. (file.isReadOnly and 'R' or ' ') if config.showHidden or file.name:sub(1, 1) ~= '.' then dir.files[file.fullName] = file end @@ -467,7 +466,7 @@ function Browser:eventHandler(event) elseif event.type == 'paste' then for _,m in pairs(copied) do - local s, m = pcall(function() + pcall(function() if cutMode then fs.move(m.fullName, fs.combine(self.dir.name, m.name)) else diff --git a/sys/apps/Help.lua b/sys/apps/Help.lua index ba530c8..429c356 100644 --- a/sys/apps/Help.lua +++ b/sys/apps/Help.lua @@ -1,3 +1,4 @@ +local fuzzy = require('opus.fuzzy') local UI = require('opus.ui') local Util = require('opus.util') @@ -42,13 +43,13 @@ UI:addPage('main', UI.Page { elseif event.type == 'text_change' then if not event.text then - self.grid.values = topics + self.grid.sortColumn = 'lname' else - self.grid.values = { } - for _,f in pairs(topics) do - if string.find(f.lname, event.text:lower()) then - table.insert(self.grid.values, f) - end + self.grid.sortColumn = 'score' + self.grid.inverseSort = false + local pattern = event.text:lower() + for _,v in pairs(self.grid.values) do + v.score = -fuzzy(v.lname, pattern) end end self.grid:update() diff --git a/sys/apps/PackageManager.lua b/sys/apps/PackageManager.lua index ec8d9ea..4140732 100644 --- a/sys/apps/PackageManager.lua +++ b/sys/apps/PackageManager.lua @@ -41,7 +41,7 @@ local page = UI.Page { }, description = UI.TextArea { x = 16, y = 3, ey = -5, - marginRight = 0, marginLeft = 0, + marginRight = 2, marginLeft = 0, }, action = UI.SlideOut { titleBar = UI.TitleBar { @@ -140,9 +140,9 @@ function page:eventHandler(event) elseif event.type == 'grid_focus_row' then local manifest = event.selected.manifest - self.description.value = string.format('%s%s\n\n%s%s', + self.description:setValue(string.format('%s%s\n\n%s%s', Ansi.yellow, manifest.title, - Ansi.white, manifest.description) + Ansi.white, manifest.description)) self.description:draw() self:updateSelection(event.selected) diff --git a/sys/apps/shell.lua b/sys/apps/shell.lua index 54eeb2c..4f8d659 100644 --- a/sys/apps/shell.lua +++ b/sys/apps/shell.lua @@ -52,8 +52,8 @@ local function run(...) loadFn = loadfile end - local funkshun, err = loadFn(path, env) - if not funkshun then + local O_v_O, err = loadFn(path, env) + if not O_v_O then error(err, -1) end @@ -68,7 +68,7 @@ local function run(...) } env[ "arg" ] = { [0] = path, table.unpack(args) } - local r = { funkshun(table.unpack(args)) } + local r = { O_v_O(table.unpack(args)) } tProgramStack[#tProgramStack] = nil diff --git a/sys/init/2.vfs.lua b/sys/init/2.vfs.lua index e2406dc..816f38f 100644 --- a/sys/init/2.vfs.lua +++ b/sys/init/2.vfs.lua @@ -166,6 +166,13 @@ function fs.complete(partial, dir, includeFiles, includeSlash) return fs.native.complete(partial, dir, includeFiles, includeSlash) end +local displayFlags = { + urlfs = 'U', + linkfs = 'L', + ramfs = 'T', + netfs = 'N', +} + function fs.listEx(dir) dir = fs.combine(dir, '') local node = getNode(dir) @@ -176,20 +183,22 @@ function fs.listEx(dir) local t = { } local files = node.fs.list(node, dir) - pcall(function() - for _,f in ipairs(files) do + for _,f in ipairs(files) do + pcall(function() local fullName = fs.combine(dir, f) + local n = fs.getNode(fullName) local file = { name = f, isDir = fs.isDir(fullName), isReadOnly = fs.isReadOnly(fullName), + fstype = n.mountPoint == fullName and displayFlags[n.fstype], } if not file.isDir then file.size = fs.getSize(fullName) end table.insert(t, file) - end - end) + end) + end return t end diff --git a/sys/init/3.sys.lua b/sys/init/3.sys.lua index ace7684..d43bf53 100644 --- a/sys/init/3.sys.lua +++ b/sys/init/3.sys.lua @@ -6,37 +6,41 @@ fs.loadTab('sys/etc/fstab') -- add some Lua compatibility functions function os.remove(a) if fs.exists(a) then - local s = pcall(fs.delete, a) - return s and true or nil, a .. ': Unable to remove file' + local s = pcall(fs.delete, a) + return s and true or nil, a .. ': Unable to remove file' end return nil, a .. ': No such file or directory' end os.execute = function(cmd) - if not cmd then - return 1 - end + local env = _G.getfenv(2) + if not cmd then + return env.shell and 1 or 0 + end - local env = _G.getfenv(2) - local s, m = env.shell.run('sys/apps/shell.lua ' .. cmd) + if not env.shell then + return 0 + end - if not s then - return 1, m - end + local s, m = env.shell.run('sys/apps/shell.lua ' .. cmd) - return 0 + if not s then + return 1, m + end + + return 0 end os.tmpname = function() - local fname - repeat - fname = 'tmp/a' .. math.random(1, 32768) - until not fs.exists(fname) + local fname + repeat + fname = 'tmp/a' .. math.random(1, 32768) + until not fs.exists(fname) - return fname + return fname end -- non-standard - will raise error instead os.exit = function(code) - error('Terminated with ' .. code) + error('Terminated with ' .. code) end diff --git a/sys/init/6.packages.lua b/sys/init/6.packages.lua index 3ad43ab..ece54fd 100644 --- a/sys/init/6.packages.lua +++ b/sys/init/6.packages.lua @@ -13,7 +13,13 @@ table.insert(helpPaths, '/sys/help') for name in pairs(Packages:installed()) do local packageDir = fs.combine('packages', name) + local fstabPath = fs.combine(packageDir, 'etc/fstab') + if fs.exists(fstabPath) then + fs.loadTab(fstabPath) + end + table.insert(appPaths, 1, '/' .. packageDir) + local apiPath = fs.combine(packageDir, 'apis') -- TODO: rename dir to 'modules' (someday) if fs.exists(apiPath) then fs.mount(fs.combine('rom/modules/main', name), 'linkfs', apiPath) @@ -23,11 +29,6 @@ for name in pairs(Packages:installed()) do if fs.exists(helpPath) then table.insert(helpPaths, helpPath) end - - local fstabPath = fs.combine(packageDir, 'etc/fstab') - if fs.exists(fstabPath) then - fs.loadTab(fstabPath) - end end help.setPath(table.concat(helpPaths, ':')) diff --git a/sys/modules/opus/fuzzy.lua b/sys/modules/opus/fuzzy.lua index c71ac08..353c142 100644 --- a/sys/modules/opus/fuzzy.lua +++ b/sys/modules/opus/fuzzy.lua @@ -1,21 +1,56 @@ --- Based on Squid's fuzzy search --- https://github.com/SquidDev-CC/artist/blob/vnext/artist/lib/match.lua --- --- not very fuzzy anymore +local find = string.find +local floor = math.floor +local min = math.min +local max = math.max +local sub = string.sub -local SCORE_WEIGHT = 1000 -local LEADING_LETTER_PENALTY = -30 -local LEADING_LETTER_PENALTY_MAX = -90 - -local _find = string.find -local _max = math.max - -return function(str, pattern) - local start = _find(str, pattern, 1, true) - if start then - -- All letters before the current one are considered leading, so add them to our penalty - return SCORE_WEIGHT - + _max(LEADING_LETTER_PENALTY * (start - 1), LEADING_LETTER_PENALTY_MAX) - - (#str - #pattern) +-- https://rosettacode.org/wiki/Jaro_distance (ported to lua) +return function(s1, s2) + local l1, l2 = #s1, #s2; + if l1 == 0 then + return l2 == 0 and 1.0 or 0.0 end + + local match_distance = max(floor(max(l1, l2) / 2) - 1, 0) + local s1_matches = { } + local s2_matches = { } + local matches = 0 + + for i = 1, l1 do + local _end = min(i + match_distance + 1, l2) + for k = max(1, i - match_distance), _end do + if not s2_matches[k] and sub(s1, i, i) == sub(s2, k, k) then + s1_matches[i] = true + s2_matches[k] = true + matches = matches + 1 + break + end + end + end + if matches == 0 then + return 0.0 + end + + local t = 0.0 + local k = 1 + for i = 1, l1 do + if s1_matches[i] then + while not s2_matches[k] do + k = k + 1 + end + if sub(s1, i, i) ~= sub(s2, k, k) then + t = t + 0.5 + end + k = k + 1 + end + end + + -- provide a major boost for exact matches + local b = 0.0 + if find(s1, s2, 1, true) then + b = b + .5 + end + + local m = matches + return (m / l1 + m / l2 + (m - t) / m) / 3.0 + b end