#1 Miscellaneous fixes to file selector functions for Linux and OSX

Open
pgimeno wants to merge 4 commits from pgimeno/pg-fixes into pgimeno/master
3 changed files with 53 additions and 15 deletions
  1. 47 11
      Internal/Core/FileSystem.lua
  2. 5 3
      Internal/UI/Dialog.lua
  3. 1 1
      SlabTest.lua

+ 47 - 11
Internal/Core/FileSystem.lua

@@ -31,35 +31,66 @@ function FileSystem.Separator()
 	return "/"
 end
 
+local OS = love.system.getOS()  -- Cache it, as it's not expected to change
+
+local function BackslashEscapeQuotes(Str)
+	return "'" .. ("\\'"):rep(#Str) .. "'"
+end
+
+local function EscParam(Param)
+	if OS == "Windows" then
+		-- TODO: safer parameter quoting
+		return '"' .. Param .. '"'
+	end
+	return "'" .. Param:gsub("'+", BackslashEscapeQuotes) .. "'"
+end
+
+
+-- Unit tests
+--[=====[
+assert(EscParam("\"abc\"'def''gh") == "'\"abc\"'\\''def'\\'\\''gh'", "fails 1")
+assert(EscParam("") == "''", "fails 2")
+-- single quotes at the beginning and end could be improved...
+assert(EscParam("''abc''") == "''\\'\\''abc'\\'\\'''", "fails 3")
+assert(EscParam("\0") == "'\0'", "fails 4")
+assert(EscParam("\0xyz\0xyz\0") == "'\0xyz\0xyz\0'", "fails 5")
+print("EscParam tests passed")
+--]=====]
+
+
 function FileSystem.GetDirectoryItems(Directory, Options)
 	Options = Options == nil and {} or Options
 	Options.Files = Options.Files == nil and true or Options.Files
 	Options.Directories = Options.Directories == nil and true or Options.Directories
-	Options.Filter = Options.Filter == nil and "*.*" or Options.Filter
+	Options.Filter = Options.Filter ~= nil and Options.Filter or OS == "Windows" and "*.*" or "*"
 
 	local Cmd = ""
-	local OS = love.system.getOS()
 
 	if string.sub(Directory, #Directory, #Directory) ~= FileSystem.Separator() then
 		Directory = Directory .. FileSystem.Separator()
 	end
 
+	-- TODO: should ShowHidden be a user option?
+	local ShowHidden = false
+
 	if OS == "Windows" then
+		local HiddenStr = ShowHidden and '' or ' /A:-H'
 		Directory = string.gsub(Directory, "/", "\\")
 		if Options.Files and not Options.Directories then
-			Cmd = 'DIR "' .. Directory .. Options.Filter .. '" /B /A:-D-H'
+			Cmd = 'DIR ' .. EscParam(Directory .. Options.Filter) .. ' /B /A:-D' .. HiddenStr
 		elseif Options.Directories and not Options.Files then
-			Cmd = 'DIR "' .. Directory .. '" /B /A:D-H'
+			Cmd = 'DIR ' .. EscParam(Directory) .. ' /B /A:D' .. HiddenStr
 		else
-			Cmd = 'DIR "' .. Directory .. '" /B /A-H'
+			Cmd = 'DIR ' .. EscParam(Directory) .. ' /B' .. HiddenStr
 		end
 	else
+		local HiddenStr = ShowHidden and "" or " \\( '!' -name .\\* \\)"
 		if Options.Files and not Options.Directories then
-			Cmd = 'find "' .. Directory .. '" \\( ! -regex ".*/\\..*" \\) -maxdepth 1 -type f \\( -iname \\' .. Options.Filter .. ' \\)'
+			Cmd = 'find ' .. EscParam(Directory) .. " -maxdepth 1 '!' -type d -iname " .. EscParam(Options.Filter) .. HiddenStr .. ' -print0'
 		elseif Options.Directories and not Options.Files then
-			Cmd = 'find "' .. Directory .. '" ! -path ' .. Directory .. ' \\( ! -regex ".*/\\..*" \\) -maxdepth 1 -type d'
+			Cmd = 'find ' .. EscParam(Directory) .. ' -mindepth 1 -maxdepth 1 -type d' .. HiddenStr .. ' -print0'
 		else
-			Cmd = 'ls -1 ' .. Directory
+			Cmd = 'find ' .. EscParam(Directory) .. ' -mindepth 1 -maxdepth 1' .. HiddenStr .. ' -print0'
 		end
 	end
 
@@ -67,8 +98,14 @@ function FileSystem.GetDirectoryItems(Directory, Options)
 	local Handle, Error = io.popen(Cmd)
 	if Handle ~= nil then
 		local I = 1
-		for Item in Handle:lines() do
-			if Item ~= "nil" then
+		local Iterator
+		if OS == 'Windows' then
+			Iterator = Handle:lines()
+		else
+			Iterator = Handle:read('*all'):gmatch('%Z+')
+		end
+		for Item in Iterator do
+			if Item ~= "nil" or OS ~= "Windows" then
 				Result[I] = Item
 				I = I + 1
 			end
@@ -85,7 +122,6 @@ function FileSystem.Exists(Path)
 		io.close(Handle)
 		return true
 	else
-		local OS = love.system.getOS()
 		if OS == "Windows" then
 			local OK, Error, Code = os.rename(Path, Path)
 			if OK then

+ 5 - 3
Internal/UI/Dialog.lua

@@ -48,6 +48,8 @@ local Stack = {}
 local InstanceStack = {}
 local FileDialog_AskOverwrite = false
 local FilterW = 0.0
+local OS = love.system.getOS()
+local DefaultFilter = OS == "Windows" and "*.*" or "*"
 
 local function ValidateSaveFile(Files, Extension)
 	if Extension == nil or Extension == "" then
@@ -229,7 +231,7 @@ local function FileDialogExplorer(Instance, Root)
 end
 
 local function GetFilter(Instance, Index)
-	local Filter = "*.*"
+	local Filter = DefaultFilter
 	local Desc = "All Files"
 	if Instance ~= nil and #Instance.Filters > 0 then
 		if Index == nil then
@@ -260,7 +262,7 @@ local function GetExtension(Instance)
 	local Filter, Desc = GetFilter(Instance)
 	local Result = ""
 
-	if Filter ~= "*.*" then
+	if Filter ~= DefaultFilter then
 		local Index = string.find(Filter, ".", 1, true)
 
 		if Index ~= nil then
@@ -358,7 +360,7 @@ function Dialog.FileDialog(Options)
 	Options.AllowMultiSelect = Options.AllowMultiSelect == nil and true or Options.AllowMultiSelect
 	Options.Directory = Options.Directory == nil and nil or Options.Directory
 	Options.Type = Options.Type == nil and 'openfile' or Options.Type
-	Options.Filters = Options.Filters == nil and {{"*.*", "All Files"}} or Options.Filters
+	Options.Filters = Options.Filters == nil and {{DefaultFilter, "All Files"}} or Options.Filters
 
 	local Title = "Open File"
 	if Options.Type == 'savefile' then

+ 1 - 1
SlabTest.lua

@@ -993,7 +993,7 @@ local function DrawDialog()
 			DrawDialog_FileDialog = ''
 
 			if Result.Button == "OK" then
-				DrawDialog_FileDialog_Result = Result.Files[1]
+				DrawDialog_FileDialog_Result = Result.Files[1] or ''
 			end
 		end
 	end