From be526c15d1e874ef1f1a932cff410ba7e9523e50 Mon Sep 17 00:00:00 2001 From: sammyette Date: Sat, 2 Dec 2023 08:23:40 -0400 Subject: [PATCH] doc(fs): rewrite docs --- golibs/fs/fs.go | 328 ++++++++++++++++++++++++++++-------------------- 1 file changed, 189 insertions(+), 139 deletions(-) diff --git a/golibs/fs/fs.go b/golibs/fs/fs.go index 1c1a5ca..848d82c 100644 --- a/golibs/fs/fs.go +++ b/golibs/fs/fs.go @@ -1,7 +1,10 @@ // filesystem interaction and functionality library -// The fs module provides easy and simple access to filesystem functions -// and other things, and acts an addition to the Lua standard library's -// I/O and filesystem functions. +/* +The fs module provides filesystem functions to Hilbish. While Lua's standard +library has some I/O functions, they're missing a lot of the basics. The `fs` +library offers more functions and will work on any operating system Hilbish does. +#field pathSep The operating system's path separator. +*/ package fs import ( @@ -42,9 +45,46 @@ func loaderFunc(rtm *rt.Runtime) (rt.Value, func()) { return rt.TableValue(mod), nil } +// abs(path) -> string +// Returns an absolute version of the `path`. +// This can be used to resolve short paths like `..` to `/home/user`. +// #param path string +// #returns string +func fabs(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { + path, err := c.StringArg(0) + if err != nil { + return nil, err + } + path = util.ExpandHome(path) + + abspath, err := filepath.Abs(path) + if err != nil { + return nil, err + } + + return c.PushingNext1(t.Runtime, rt.StringValue(abspath)), nil +} + +// basename(path) -> string +// Returns the "basename," or the last part of the provided `path`. If path is empty, +// `.` will be returned. +// #param path string Path to get the base name of. +// #returns string +func fbasename(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { + if err := c.Check1Arg(); err != nil { + return nil, err + } + path, err := c.StringArg(0) + if err != nil { + return nil, err + } + + return c.PushingNext(t.Runtime, rt.StringValue(filepath.Base(path))), nil +} + // cd(dir) -// Changes directory to `dir` -// --- @param dir string +// Changes Hilbish's directory to `dir`. +// #param dir string Path to change directory to. func fcd(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { if err := c.Check1Arg(); err != nil { return nil, err @@ -63,10 +103,102 @@ func fcd(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { return c.Next(), err } +// dir(path) -> string +// Returns the directory part of `path`. If a file path like +// `~/Documents/doc.txt` then this function will return `~/Documents`. +// #param path string Path to get the directory for. +// #returns string +func fdir(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { + if err := c.Check1Arg(); err != nil { + return nil, err + } + path, err := c.StringArg(0) + if err != nil { + return nil, err + } + + return c.PushingNext(t.Runtime, rt.StringValue(filepath.Dir(path))), nil +} + +// glob(pattern) -> matches (table) +// Match all files based on the provided `pattern`. +// For the syntax' refer to Go's filepath.Match function: https://pkg.go.dev/path/filepath#Match +// #param pattern string Pattern to compare files with. +// #returns table A list of file names/paths that match. +/* +#example +--[[ + Within a folder that contains the following files: + a.txt + init.lua + code.lua + doc.pdf +]]-- +local matches = fs.glob './*.lua' +print(matches) +-- -> {'init.lua', 'code.lua'} +#example +*/ +func fglob(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { + if err := c.Check1Arg(); err != nil { + return nil, err + } + pattern, err := c.StringArg(0) + if err != nil { + return nil, err + } + + matches, err := filepath.Glob(pattern) + if err != nil { + return nil, err + } + + luaMatches := rt.NewTable() + + for i, match := range matches { + luaMatches.Set(rt.IntValue(int64(i + 1)), rt.StringValue(match)) + } + + return c.PushingNext(t.Runtime, rt.TableValue(luaMatches)), nil +} + +// join(...path) -> string +// Takes any list of paths and joins them based on the operating system's path separator. +// #param path ...string Paths to join together +// #returns string The joined path. +/* +#example +-- This prints the directory for Hilbish's config! +print(fs.join(hilbish.userDir.config, 'hilbish')) +-- -> '/home/user/.config/hilbish' on Linux +#example +*/ +func fjoin(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { + strs := make([]string, len(c.Etc())) + for i, v := range c.Etc() { + if v.Type() != rt.StringType { + // +2; go indexes of 0 and first arg from above + return nil, fmt.Errorf("bad argument #%d to run (expected string, got %s)", i + 1, v.TypeName()) + } + strs[i] = v.AsString() + } + + res := filepath.Join(strs...) + + return c.PushingNext(t.Runtime, rt.StringValue(res)), nil +} + // mkdir(name, recursive) -// Makes a directory called `name`. If `recursive` is true, it will create its parent directories. -// --- @param name string -// --- @param recursive boolean +// Creates a new directory with the provided `name`. +// With `recursive`, mkdir will create parent directories. +// #param name string Name of the directory +// #param recursive boolean Whether to create parent directories for the provided name +/* +#example +-- This will create the directory foo, then create the directory bar in the +-- foo directory. If recursive is false in this case, it will fail. +fs.mkdir('./foo/bar', true) +*/ func fmkdir(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { if err := c.CheckNArgs(2); err != nil { return nil, err @@ -93,15 +225,58 @@ func fmkdir(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { return c.Next(), err } +// readdir(path) -> table[string] +// Returns a list of all files and directories in the provided path. +// #param dir string +// #returns table +func freaddir(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { + if err := c.Check1Arg(); err != nil { + return nil, err + } + dir, err := c.StringArg(0) + if err != nil { + return nil, err + } + dir = util.ExpandHome(dir) + names := rt.NewTable() + + dirEntries, err := os.ReadDir(dir) + if err != nil { + return nil, err + } + for i, entry := range dirEntries { + names.Set(rt.IntValue(int64(i + 1)), rt.StringValue(entry.Name())) + } + + return c.PushingNext1(t.Runtime, rt.TableValue(names)), nil +} + // stat(path) -> {} -// Returns a table of info about the `path`. -// It contains the following keys: +// Returns the information about a given `path`. +// The returned table contains the following values: // name (string) - Name of the path -// size (number) - Size of the path -// mode (string) - Permission mode in an octal format string (with leading 0) +// size (number) - Size of the path in bytes +// mode (string) - Unix permission mode in an octal format string (with leading 0) // isDir (boolean) - If the path is a directory -// --- @param path string -// --- @returns table +// #param path string +// #returns table +/* +#example +local inspect = require 'inspect' + +local stat = fs.stat '~' +print(inspect(stat)) +--[[ +Would print the following: +{ + isDir = true, + mode = "0755", + name = "username", + size = 12288 +} +]]-- +#example +*/ func fstat(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { if err := c.Check1Arg(); err != nil { return nil, err @@ -125,128 +300,3 @@ func fstat(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { return c.PushingNext1(t.Runtime, rt.TableValue(statTbl)), nil } -// readdir(dir) -> {} -// Returns a table of files in `dir`. -// --- @param dir string -// --- @return table -func freaddir(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { - if err := c.Check1Arg(); err != nil { - return nil, err - } - dir, err := c.StringArg(0) - if err != nil { - return nil, err - } - dir = util.ExpandHome(dir) - names := rt.NewTable() - - dirEntries, err := os.ReadDir(dir) - if err != nil { - return nil, err - } - for i, entry := range dirEntries { - names.Set(rt.IntValue(int64(i + 1)), rt.StringValue(entry.Name())) - } - - return c.PushingNext1(t.Runtime, rt.TableValue(names)), nil -} - -// abs(path) -> string -// Gives an absolute version of `path`. -// --- @param path string -// --- @returns string -func fabs(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { - path, err := c.StringArg(0) - if err != nil { - return nil, err - } - path = util.ExpandHome(path) - - abspath, err := filepath.Abs(path) - if err != nil { - return nil, err - } - - return c.PushingNext1(t.Runtime, rt.StringValue(abspath)), nil -} - -// basename(path) -> string -// Gives the basename of `path`. For the rules, -// see Go's filepath.Base -// --- @returns string -func fbasename(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { - if err := c.Check1Arg(); err != nil { - return nil, err - } - path, err := c.StringArg(0) - if err != nil { - return nil, err - } - - return c.PushingNext(t.Runtime, rt.StringValue(filepath.Base(path))), nil -} - -// dir(path) -> string -// Returns the directory part of `path`. For the rules, see Go's -// filepath.Dir -// --- @param path string -// --- @returns string -func fdir(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { - if err := c.Check1Arg(); err != nil { - return nil, err - } - path, err := c.StringArg(0) - if err != nil { - return nil, err - } - - return c.PushingNext(t.Runtime, rt.StringValue(filepath.Dir(path))), nil -} - -// glob(pattern) -> matches (table) -// Glob all files and directories that match the pattern. -// For the rules, see Go's filepath.Glob -// --- @param pattern string -// --- @returns table -func fglob(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { - if err := c.Check1Arg(); err != nil { - return nil, err - } - pattern, err := c.StringArg(0) - if err != nil { - return nil, err - } - - matches, err := filepath.Glob(pattern) - if err != nil { - return nil, err - } - - luaMatches := rt.NewTable() - - for i, match := range matches { - luaMatches.Set(rt.IntValue(int64(i + 1)), rt.StringValue(match)) - } - - return c.PushingNext(t.Runtime, rt.TableValue(luaMatches)), nil -} - -// join(...) -> string -// Takes paths and joins them together with the OS's -// directory separator (forward or backward slash). -// --- @vararg string -// --- @returns string -func fjoin(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { - strs := make([]string, len(c.Etc())) - for i, v := range c.Etc() { - if v.Type() != rt.StringType { - // +2; go indexes of 0 and first arg from above - return nil, fmt.Errorf("bad argument #%d to run (expected string, got %s)", i + 1, v.TypeName()) - } - strs[i] = v.AsString() - } - - res := filepath.Join(strs...) - - return c.PushingNext(t.Runtime, rt.StringValue(res)), nil -}