– Some file utilities for searching for files recursively and using package.nomsupath lpeg = require ‘lpeg’ re = require ‘re’ Files = {}
run_cmd = (cmd)-> f = io.popen(cmd..’ 2>/dev/null’) lines = [line for line in f\lines!] return nil unless f\close! return lines
SPOOFEDFILES = {} BROWSECACHE = {}
– Create a fake file and put it in the cache
anonnumber = 0
Files.spoof = (filename, contents)->
if not contents
filename, contents = “
– Read a file’s contents Files.read = (filename)-> if contents = SPOOFEDFILES[filename] return contents if filename == ‘stdin’ or filename == ‘-’ contents = io.read(‘a’) Files.spoof(‘stdin’, contents) Files.spoof(‘-’, contents) return contents file = io.open(filename) return nil unless file contents = file\read(“a”) file\close! return contents or nil
{:match, :gsub} = string
– TODO: improve sanitization sanitize = (path)-> path = gsub(path,”\”,”\\”) path = gsub(path,”`”,””) path = gsub(path,’”’,’\”’) path = gsub(path,”$”,””) return path
Files.exists = (path)-> return true if SPOOFEDFILES[path] return true if path == ‘stdin’ or path == ‘-’ return true if run_cmd(“ls #{sanitize(path)}”) return false
Files.list = (path)-> unless BROWSECACHE[path] local files BROWSECACHE[path] = if SPOOFEDFILES[path] or path == ‘stdin’ or path == ‘-’ {path} else run_cmd(‘find -L “‘..path..’” -not -path “/\.” -type f’) or false return BROWSECACHE[path]
Files.makedirectory = (path)-> runcmd(‘mkdir ‘..path)
ok, lfs = pcall(require, “lfs”) if ok rawfileexists = (filename)-> mode = lfs.attributes(filename, ‘mode’) return if mode == ‘file’ or mode == ‘directory’ or mode == ‘link’ then true else false Files.exists = (path)-> return true if SPOOFEDFILES[path] return true if path == ‘stdin’ or path == ‘-’ or rawfileexists(path) return false
Files.list = (path)->
unless _BROWSE_CACHE[path]
_BROWSE_CACHE[path] = if _SPOOFED_FILES[path] or path == 'stdin' or path == '-'
{path}
else
file_type, err = lfs.attributes(path, 'mode')
switch file_type
when "file", "char device"
{path}
when "directory", "link"
files = {}
for subfile in lfs.dir(path)
continue if subfile == "." or subfile == ".."
for f in *(Files.list(path.."/"..subfile) or {})
files[#files+1] = f
files
else false
-- Filter out any "./" prefix to standardize
if _BROWSE_CACHE[path]
for i,f in ipairs(_BROWSE_CACHE[path])
if f\match("^%./") then _BROWSE_CACHE[path][i] = f\sub(3)
return _BROWSE_CACHE[path]
Files.make_directory = lfs.mkdir
else
unless run_cmd(‘find . -maxdepth 0’)
url = if jit
‘https://github.com/spacewander/luafilesystem’
else ‘https://github.com/keplerproject/luafilesystem’
error “Could not find ‘luafilesystem’ module and couldn’t run system command find (this might happen on Windows). Please install luafilesystem (which can be found at: #{url} or luarocks install luafilesystem)\n#{lfs}\npackage.cpath: #{package.cpath}”, 0
line_counter = re.compile([[ lines <- {| line (%nl line)* |} line <- {} (!%nl .)* ]], nl:lpeg.P(“\r”)^-1 * lpeg.P(“\n”))
– LINE_STARTS is a mapping from strings to a table that maps line number to character positions LINESTARTS = {} Files.getlinestarts = (str)-> if type(str) != ‘string’ str = tostring(str) if starts = LINESTARTS[str] return starts linestarts = linecounter\match(str) LINESTARTS[str] = linestarts return linestarts
Files.getlinenumber = (str, pos)-> linestarts = Files.getlinestarts(str) – Binary search for line number of position lo, hi = 1, #linestarts while lo <= hi mid = math.floor((lo+hi)/2) if line_starts[mid] > pos hi = mid-1 else lo = mid+1 return hi
Files.getline = (str, lineno)-> linestarts = Files.getlinestarts(str) start = linestarts[lineno] return unless start stop = linestarts[line_no+1] return unless stop return (str\sub(start, stop - 2))
return Files
