1
0
mirror of https://github.com/kepler155c/opus synced 2024-12-29 10:00:26 +00:00

better fuzzy matching + vfs type flag in Files

This commit is contained in:
kepler155c@gmail.com 2020-05-19 17:09:10 -06:00
parent b93d69c261
commit 985830fcfd
8 changed files with 115 additions and 66 deletions

View File

@ -77,8 +77,8 @@ local Browser = UI.Page {
grid = UI.ScrollingGrid { grid = UI.ScrollingGrid {
columns = { columns = {
{ heading = 'Name', key = 'name' }, { heading = 'Name', key = 'name' },
{ key = 'flags', width = 2 }, { key = 'flags', width = 3, textColor = 'lightGray' },
{ heading = 'Size', key = 'fsize', width = 5 }, { heading = 'Size', key = 'fsize', width = 5, textColor = 'yellow' },
}, },
sortColumn = 'name', sortColumn = 'name',
y = 2, ey = -2, y = 2, ey = -2,
@ -211,7 +211,7 @@ function Browser:enable()
self:setFocus(self.grid) self:setFocus(self.grid)
end end
function Browser.menuBar:getActive(menuItem) function Browser.menuBar.getActive(_, menuItem)
local file = Browser.grid:getSelected() local file = Browser.grid:getSelected()
if menuItem.flags == FILE then if menuItem.flags == FILE then
return file and not file.isDir return file and not file.isDir
@ -223,7 +223,7 @@ function Browser:setStatus(status, ...)
self.notification:info(string.format(status, ...)) self.notification:info(string.format(status, ...))
end end
function Browser:unmarkAll() function Browser.unmarkAll()
for _,m in pairs(marked) do for _,m in pairs(marked) do
m.marked = false m.marked = false
end end
@ -263,10 +263,11 @@ function Browser:updateDirectory(dir)
dir.size = #files dir.size = #files
for _, file in pairs(files) do for _, file in pairs(files) do
file.fullName = fs.combine(dir.name, file.name) file.fullName = fs.combine(dir.name, file.name)
file.flags = '' file.flags = file.fstype or ' '
if not file.isDir then if not file.isDir then
dir.totalSize = dir.totalSize + file.size dir.totalSize = dir.totalSize + file.size
file.fsize = formatSize(file.size) file.fsize = formatSize(file.size)
file.flags = file.flags .. ' '
else else
if config.showDirSizes then if config.showDirSizes then
file.size = fs.getSize(file.fullName, true) file.size = fs.getSize(file.fullName, true)
@ -274,11 +275,9 @@ function Browser:updateDirectory(dir)
dir.totalSize = dir.totalSize + file.size dir.totalSize = dir.totalSize + file.size
file.fsize = formatSize(file.size) file.fsize = formatSize(file.size)
end end
file.flags = 'D' file.flags = file.flags .. 'D'
end
if file.isReadOnly then
file.flags = file.flags .. 'R'
end end
file.flags = file.flags .. (file.isReadOnly and 'R' or ' ')
if config.showHidden or file.name:sub(1, 1) ~= '.' then if config.showHidden or file.name:sub(1, 1) ~= '.' then
dir.files[file.fullName] = file dir.files[file.fullName] = file
end end
@ -467,7 +466,7 @@ function Browser:eventHandler(event)
elseif event.type == 'paste' then elseif event.type == 'paste' then
for _,m in pairs(copied) do for _,m in pairs(copied) do
local s, m = pcall(function() pcall(function()
if cutMode then if cutMode then
fs.move(m.fullName, fs.combine(self.dir.name, m.name)) fs.move(m.fullName, fs.combine(self.dir.name, m.name))
else else

View File

@ -1,3 +1,4 @@
local fuzzy = require('opus.fuzzy')
local UI = require('opus.ui') local UI = require('opus.ui')
local Util = require('opus.util') local Util = require('opus.util')
@ -42,13 +43,13 @@ UI:addPage('main', UI.Page {
elseif event.type == 'text_change' then elseif event.type == 'text_change' then
if not event.text then if not event.text then
self.grid.values = topics self.grid.sortColumn = 'lname'
else else
self.grid.values = { } self.grid.sortColumn = 'score'
for _,f in pairs(topics) do self.grid.inverseSort = false
if string.find(f.lname, event.text:lower()) then local pattern = event.text:lower()
table.insert(self.grid.values, f) for _,v in pairs(self.grid.values) do
end v.score = -fuzzy(v.lname, pattern)
end end
end end
self.grid:update() self.grid:update()

View File

@ -41,7 +41,7 @@ local page = UI.Page {
}, },
description = UI.TextArea { description = UI.TextArea {
x = 16, y = 3, ey = -5, x = 16, y = 3, ey = -5,
marginRight = 0, marginLeft = 0, marginRight = 2, marginLeft = 0,
}, },
action = UI.SlideOut { action = UI.SlideOut {
titleBar = UI.TitleBar { titleBar = UI.TitleBar {
@ -140,9 +140,9 @@ function page:eventHandler(event)
elseif event.type == 'grid_focus_row' then elseif event.type == 'grid_focus_row' then
local manifest = event.selected.manifest 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.yellow, manifest.title,
Ansi.white, manifest.description) Ansi.white, manifest.description))
self.description:draw() self.description:draw()
self:updateSelection(event.selected) self:updateSelection(event.selected)

View File

@ -52,8 +52,8 @@ local function run(...)
loadFn = loadfile loadFn = loadfile
end end
local funkshun, err = loadFn(path, env) local O_v_O, err = loadFn(path, env)
if not funkshun then if not O_v_O then
error(err, -1) error(err, -1)
end end
@ -68,7 +68,7 @@ local function run(...)
} }
env[ "arg" ] = { [0] = path, table.unpack(args) } env[ "arg" ] = { [0] = path, table.unpack(args) }
local r = { funkshun(table.unpack(args)) } local r = { O_v_O(table.unpack(args)) }
tProgramStack[#tProgramStack] = nil tProgramStack[#tProgramStack] = nil

View File

@ -166,6 +166,13 @@ function fs.complete(partial, dir, includeFiles, includeSlash)
return fs.native.complete(partial, dir, includeFiles, includeSlash) return fs.native.complete(partial, dir, includeFiles, includeSlash)
end end
local displayFlags = {
urlfs = 'U',
linkfs = 'L',
ramfs = 'T',
netfs = 'N',
}
function fs.listEx(dir) function fs.listEx(dir)
dir = fs.combine(dir, '') dir = fs.combine(dir, '')
local node = getNode(dir) local node = getNode(dir)
@ -176,20 +183,22 @@ function fs.listEx(dir)
local t = { } local t = { }
local files = node.fs.list(node, dir) 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 fullName = fs.combine(dir, f)
local n = fs.getNode(fullName)
local file = { local file = {
name = f, name = f,
isDir = fs.isDir(fullName), isDir = fs.isDir(fullName),
isReadOnly = fs.isReadOnly(fullName), isReadOnly = fs.isReadOnly(fullName),
fstype = n.mountPoint == fullName and displayFlags[n.fstype],
} }
if not file.isDir then if not file.isDir then
file.size = fs.getSize(fullName) file.size = fs.getSize(fullName)
end end
table.insert(t, file) table.insert(t, file)
end end)
end) end
return t return t
end end

View File

@ -6,37 +6,41 @@ fs.loadTab('sys/etc/fstab')
-- add some Lua compatibility functions -- add some Lua compatibility functions
function os.remove(a) function os.remove(a)
if fs.exists(a) then if fs.exists(a) then
local s = pcall(fs.delete, a) local s = pcall(fs.delete, a)
return s and true or nil, a .. ': Unable to remove file' return s and true or nil, a .. ': Unable to remove file'
end end
return nil, a .. ': No such file or directory' return nil, a .. ': No such file or directory'
end end
os.execute = function(cmd) os.execute = function(cmd)
if not cmd then local env = _G.getfenv(2)
return 1 if not cmd then
end return env.shell and 1 or 0
end
local env = _G.getfenv(2) if not env.shell then
local s, m = env.shell.run('sys/apps/shell.lua ' .. cmd) return 0
end
if not s then local s, m = env.shell.run('sys/apps/shell.lua ' .. cmd)
return 1, m
end
return 0 if not s then
return 1, m
end
return 0
end end
os.tmpname = function() os.tmpname = function()
local fname local fname
repeat repeat
fname = 'tmp/a' .. math.random(1, 32768) fname = 'tmp/a' .. math.random(1, 32768)
until not fs.exists(fname) until not fs.exists(fname)
return fname return fname
end end
-- non-standard - will raise error instead -- non-standard - will raise error instead
os.exit = function(code) os.exit = function(code)
error('Terminated with ' .. code) error('Terminated with ' .. code)
end end

View File

@ -13,7 +13,13 @@ table.insert(helpPaths, '/sys/help')
for name in pairs(Packages:installed()) do for name in pairs(Packages:installed()) do
local packageDir = fs.combine('packages', name) 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) table.insert(appPaths, 1, '/' .. packageDir)
local apiPath = fs.combine(packageDir, 'apis') -- TODO: rename dir to 'modules' (someday) local apiPath = fs.combine(packageDir, 'apis') -- TODO: rename dir to 'modules' (someday)
if fs.exists(apiPath) then if fs.exists(apiPath) then
fs.mount(fs.combine('rom/modules/main', name), 'linkfs', apiPath) 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 if fs.exists(helpPath) then
table.insert(helpPaths, helpPath) table.insert(helpPaths, helpPath)
end end
local fstabPath = fs.combine(packageDir, 'etc/fstab')
if fs.exists(fstabPath) then
fs.loadTab(fstabPath)
end
end end
help.setPath(table.concat(helpPaths, ':')) help.setPath(table.concat(helpPaths, ':'))

View File

@ -1,21 +1,56 @@
-- Based on Squid's fuzzy search local find = string.find
-- https://github.com/SquidDev-CC/artist/blob/vnext/artist/lib/match.lua local floor = math.floor
-- local min = math.min
-- not very fuzzy anymore local max = math.max
local sub = string.sub
local SCORE_WEIGHT = 1000 -- https://rosettacode.org/wiki/Jaro_distance (ported to lua)
local LEADING_LETTER_PENALTY = -30 return function(s1, s2)
local LEADING_LETTER_PENALTY_MAX = -90 local l1, l2 = #s1, #s2;
if l1 == 0 then
local _find = string.find return l2 == 0 and 1.0 or 0.0
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)
end 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 end