diff --git a/.gitignore b/.gitignore index e1411e08dd036f8f049b239834637a54733a5ae8..b1068495b4c6331373495a0fe922331423f12776 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,4 @@ manual/book vendor/ vendor.tar.xz /window-config.ion +manual/builtins/ diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 0b397596fb475a8d5bc9f4afbdfdcff9c945006f..9a728e6b9a9b01e53768af1ac13cb037c7dc8a00 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -45,6 +45,7 @@ pages: image: hrektts/mdbook stage: deploy script: + - make manual - mdbook build -d ../public manual artifacts: paths: diff --git a/Cargo.lock b/Cargo.lock index e6952f11945e9f5e9f7b174b37e481abef3a7e79..23d3549711237d438f01d87f6eab6278cc37ce97 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -156,6 +156,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" name = "builtins-proc" version = "0.1.0" dependencies = [ + "darling 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "ion-shell 1.0.0-alpha", "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", "syn 0.15.36 (registry+https://github.com/rust-lang/crates.io-index)", @@ -379,6 +380,38 @@ dependencies = [ "memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "darling" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "darling_core 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", + "darling_macro 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "darling_core" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "ident_case 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", + "strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.36 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "darling_macro" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "darling_core 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.36 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "decimal" version = "2.0.4" @@ -702,6 +735,11 @@ dependencies = [ "unicode-segmentation 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "image" version = "0.21.2" @@ -1675,6 +1713,11 @@ dependencies = [ "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "strsim" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "strsim" version = "0.8.0" @@ -2037,6 +2080,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "f8306fcef4a7b563b76b7dd949ca48f52bc1141aa067d2ea09565f3e2652aa5c" "checksum csv 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "9044e25afb0924b5a5fc5511689b0918629e85d68ea591e5e87fbf1e85ea1b3b" "checksum csv-core 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "fa5cdef62f37e6ffe7d1f07a381bc0db32b7a3ff1cac0de56cb0d81e71f53d65" +"checksum darling 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fcfbcb0c5961907597a7d1148e3af036268f2b773886b8bb3eeb1e1281d3d3d6" +"checksum darling_core 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6afc018370c3bff3eb51f89256a6bdb18b4fdcda72d577982a14954a7a0b402c" +"checksum darling_macro 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c6d8dac1c6f1d29a41c4712b4400f878cb4fcc4c7628f298dd75038e024998d1" "checksum decimal 2.0.4 (git+https://github.com/alkis/decimal.git)" = "<none>" "checksum deflate 0.7.19 (registry+https://github.com/rust-lang/crates.io-index)" = "8a6abb26e16e8d419b5c78662aa9f82857c2386a073da266840e474d5055ec86" "checksum derivative 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6073e9676dbebdddeabaeb63e3b7cefd23c86f5c41d381ee1237cc77b1079898" @@ -2074,6 +2120,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum glutin_wgl_sys 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "f801bbc91efc22dd1c4818a47814fc72bf74d024510451b119381579bfa39021" "checksum hashbrown 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e1de41fb8dba9714efd92241565cdff73f78508c95697dd56787d3cba27e2353" "checksum heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205" +"checksum ident_case 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" "checksum image 0.21.2 (registry+https://github.com/rust-lang/crates.io-index)" = "99198e595d012efccf12abf4abc08da2d97be0b0355a2b08d101347527476ba4" "checksum inflate 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "1cdb29978cc5797bd8dcc8e5bf7de604891df2a8dc576973d71a281e916db2ff" "checksum interpolation 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d3b7357d2bbc5ee92f8e899ab645233e43d21407573cceb37fed8bc3dede2c02" @@ -2182,6 +2229,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum stackvector 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "1c4725650978235083241fab0fdc8e694c3de37821524e7534a1a9061d1068af" "checksum static_assertions 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "c19be23126415861cb3a23e501d34a708f7f9b2183c5252d690941c2e69199d5" "checksum stb_truetype 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "69b7df505db8e81d54ff8be4693421e5b543e08214bd8d99eb761fcb4d5668ba" +"checksum strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4f380125926a99e52bc279241539c018323fab05ad6368b56f93d9369ff550" "checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" "checksum structopt 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)" = "fa19a5a708e22bb5be31c1b6108a2a902f909c4b9ba85cba44c06632386bc0ff" "checksum structopt-derive 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)" = "c6d59d0ae8ef8de16e49e3ca7afa16024a3e0dfd974a75ef93fdc5464e34523f" diff --git a/Cargo.toml b/Cargo.toml index 6cb85614d4c5bffe14f3bd6d9306f6f9c93aeb1b..924d852a4ee68d06d0375e856855e7c031a43fa5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,6 +29,7 @@ maintenance = { status = "experimental" } [features] advanced_arg_parsing = [] +man = ["builtins-proc/man"] [workspace] members = [ "members/builtins-proc", "members/ranges", "members/scopes-rs", "members/types-rs" ] diff --git a/Makefile b/Makefile index 00b23fe1bdcef9987ce0afaec8217beee7c54fd3..3b320dd188678c37817f1212576a8e512f406824 100644 --- a/Makefile +++ b/Makefile @@ -30,7 +30,7 @@ ifeq ($(RUSTUP),1) TOOLCHAIN_ARG = +$(TOOLCHAIN) endif -.PHONY: tests all clean distclean install uninstall +.PHONY: tests all clean distclean install uninstall manual all: $(SRC) $(GIT_REVISION) ifeq ($(REDOX),1) @@ -42,6 +42,14 @@ ifeq ($(VENDORED),1) endif cargo $(TOOLCHAIN_ARG) build $(ARGS) $(ARGSV) +manual: + cargo build --features man + echo -n "# Builtin commands" > manual/src/builtins.md + for man in manual/builtins/*; do \ + echo -n "\n\n## " >> manual/src/builtins.md; \ + cat $$man >> manual/src/builtins.md; \ + done + clean: cargo clean diff --git a/manual/src/builtins.md b/manual/src/builtins.md index ebe9edce43fbc58bb6336f5fa4c72dd2e717b2e2..543b69e5ca2929ffcd5d2f966bfbfa0c8e62e6da 100644 --- a/manual/src/builtins.md +++ b/manual/src/builtins.md @@ -1,445 +1,607 @@ -# Builtin Commands +# Builtin commands -## alias +## bg - sends jobs to background -``` -alias NAME=DEFINITION -alias NAME DEFINITION +```txt +SYNOPSIS + bg PID + +DESCRIPTION + bg sends the job to the background resuming it if it has stopped. ``` -View, set or unset aliases +## bool - Returns true if the value given to it is equal to '1' or 'true'. -## and +```txt +SYNOPSIS + bool VALUE -``` -COMMAND; and COMMAND +DESCRIPTION + Returns true if the value given to it is equal to '1' or 'true'. ``` -Execute the command if the shell's previous status is success +## calc - Floating-point calculator -## bg +```txt +SYNOPSIS + calc [EXPRESSION] -``` -bg [PID] -``` +DESCRIPTION + Evaluates arithmetic expressions -Resumes a stopped background process. If no process is specified, the previous -job will resume. +SPECIAL EXPRESSIONS + help (only in interactive mode) + prints this help text -## calc + --help (only in non-interactive mode) + prints this help text -``` -calc [EXPRESSION] -``` + exit (only in interactive mode) + exits the program -Calculate a mathematical expression. If no expression is given, it will open -an interactive expression engine. Type exit to leave the engine. +NOTATIONS + infix notation + e.g. 3 * 4 + 5 -## cd + polish notation + e.g. + * 3 4 5 -``` -cd [PATH] +EXAMPLES + Add two plus two in infix notation + calc 2+2 + + Add two plus two in polish notation + calc + 2 2 + +AUTHOR + Written by Hunter Goldstein. ``` -Change the current directory and push it to the stack. -Omit the directory to change to home +## cd - Change directory. -## contains +```txt +SYNOPSIS + cd DIRECTORY -``` -contains KEY [VALUE...] +DESCRIPTION + Without arguments cd changes the working directory to your home directory. + With arguments cd changes the working directory to the directory you provided. ``` -Evaluates if the supplied argument contains a given string +## contains - check if a given string starts with another one -## dirs +```txt +SYNOPSIS + starts_with <PATTERN> tests... -``` -dirs +DESCRIPTION + Returns 0 if any argument starts_with contains the first argument, else returns 0 ``` -Display the current directory stack +## dir_depth - set the dir stack depth -## disown +```txt +SYNOPSYS + dir_depth [DEPTH] -``` -disown [-r | -h | -a ][PID...] +DESCRIPTION + If DEPTH is given, set the dir stack max depth to DEPTH, else remove the limit ``` -Disowning a process removes that process from the shell's background process table. -If no process is specified, the most recently-used job is removed +## dirs - prints the directory stack -## drop +```txt +SYNOPSIS + dirs -``` -drop VARIABLE -drop -a ARRAY_VARIABLE +DESCRIPTION + dirs prints the current directory stack. ``` -Drops a variable from the shell's variable map. By default, this will drop string variables from -the string variable map. If the `-a` flag is specified, array variables will be dropped from the -array variable map instead. +## disown - disown processes -## echo +```txt +SYNOPSIS + disown [ --help | -r | -h | -a ][PID...] -``` -echo [ -h | --help ] [-e] [-n] [-s] [STRING]... +DESCRIPTION + Disowning a process removes that process from the shell's background process table. + +OPTIONS + -r Remove all running jobs from the background process list. + -h Specifies that each job supplied will not receive the SIGHUP signal when the shell receives a SIGHUP. + -a If no job IDs were supplied, remove all jobs from the background process list. ``` -Display a line of text +## drop - delete some variables or arrays -#### Options +```txt +SYNOPSIS + drop VARIABLES... -- **-e**: enable the interpretation of backslash escapes -- **-n**: do not output the trailing newline -- **-s**: do not separate arguments with spaces +DESCRIPTION + Deletes the variables given to it as arguments. The variables name must be supplied. + Instead of '$x' use 'x'. +``` -#### Escape Sequences +## echo - display text -When the -e argument is used, the following sequences will be interpreted: +```txt +SYNOPSIS + echo [ -h | --help ] [-e] [-n] [-s] [STRING]... -- **\\**: backslash -- **\a**: alert (BEL) -- **\b**: backspace (BS) -- **\c**: produce no further output -- **\e**: escape (ESC) -- **\f**: form feed (FF) -- **\n**: new line -- **\r**: carriage return -- **\t**: horizontal tab (HT) -- **\v**: vertical tab (VT) +DESCRIPTION + Print the STRING(s) to standard output. -## ends-with +OPTIONS + -e + enable the interpretation of backslash escapes + -n + do not output the trailing newline + -s + do not separate arguments with spaces -``` -ends-with KEY [VALUE...] + Escape Sequences + When the -e argument is used, the following sequences will be interpreted: + \\ backslash + \a alert (BEL) + \b backspace (BS) + \c produce no further output + \e escape (ESC) + \f form feed (FF) + \n new line + \r carriage return + \t horizontal tab (HT) + \v vertical tab (VT) ``` -Evaluates if the supplied argument ends with a given string +## ends_with - check if a given string starts with another one -## eq +```txt +SYNOPSIS + starts_with <PATTERN> tests... -``` -eq [ -h | --help ] [not] +DESCRIPTION + Returns 0 if any argument starts_with contains the first argument, else returns 0 ``` -Returns 0 if the two arguments are equal +## eval - evaluates the specified commands -## eval +```txt +SYNOPSIS + eval COMMANDS... -``` -eval COMMAND +DESCRIPTION + eval evaluates the given arguments as a command. If more than one argument is given, + all arguments are joined using a space as a separator. ``` -evaluates the evaluated expression +## exec - replace the shell with the given command -## exists +```txt +SYNOPSIS + exec [-ch] [--help] [command [arguments ...]] -``` -exists [-a ARRAY] [-b BINARY] [-d PATH] [--fn FUNCTION] [[-s] STRING] +DESCRIPTION + Execute <command>, replacing the shell with the specified program. + The <arguments> following the command become the arguments to + <command>. + +OPTIONS + -c Execute command with an empty environment. ``` -Performs tests on files and text +## exists - check whether items exist -## exec +```txt +SYNOPSIS + exists [EXPRESSION] -``` -exec [-ch] [--help] [command [arguments ...]] -``` +DESCRIPTION + Checks whether the given item exists and returns an exit status of 0 if it does, else 1. -Execute a command, replacing the shell with the specified program. -The arguments following the command become the arguments to the command. +OPTIONS + -a ARRAY + array var is not empty -#### options + -b BINARY + binary is in PATH -- **-a ARRAY**: array var is not empty -- **-b BINARY**: binary is in PATH -- **-d PATH**: path is a directory -- **-f PATH**: path is a file -- **--fn FUNCTION**: function is defined -- **-s STRING**: string var is not empty -- **STRING**: string is not empty + -d PATH + path is a directory + This is the same as test -d -## exit + -f PATH + path is a file + This is the same as test -f -``` -exit -``` + --fn FUNCTION + function is defined -Exits the current session and kills all background tasks + -s STRING + string var is not empty -## false + STRING + string is not empty + This is the same as test -n -``` -false -``` +EXAMPLES + Test if the file exists: + exists -f FILE && echo 'The FILE exists' || echo 'The FILE does not exist' -Do nothing, unsuccessfully + Test if some-command exists in the path and is executable: + exists -b some-command && echo 'some-command exists' || echo 'some-command does not exist' -## fg + Test if variable exists AND is not empty + exists -s myVar && echo "myVar exists: $myVar" || echo 'myVar does not exist or is empty' + NOTE: Don't use the '$' sigil, but only the name of the variable to check -``` -fg [PID] + Test if array exists and is not empty + exists -a myArr && echo "myArr exists: @myArr" || echo 'myArr does not exist or is empty' + NOTE: Don't use the '@' sigil, but only the name of the array to check + + Test if a function named 'myFunc' exists + exists --fn myFunc && myFunc || echo 'No function with name myFunc found' + +AUTHOR + Written by Fabian Würfl. + Heavily based on implementation of the test builtin, which was written by Michael Murphy. ``` -Resumes and sets a background process as the active process. If no process is specified, the previous job will be the active process. +## exit - exit the shell -## fn +```txt +SYNOPSIS + exit -``` -fn +DESCRIPTION + Makes ion exit. The exit status will be that of the last command executed. ``` -Print list of functions +## false - does nothing unsuccessfully -## help +```txt +SYNOPSIS + false -``` -help COMMAND +DESCRIPTION + Sets the exit status to 1. ``` -Display helpful information about a given command or list commands if -none specified +## fg - bring job to the foreground -## history +```txt +SYNOPSIS + fg PID +DESCRIPTION + fg brings the specified job to foreground resuming it if it has stopped. ``` -history -```` -Display a log of all commands previously executed +## fn - print a short description of every defined function -## ion_docs +```txt +SYNOPSIS + fn [ -h | --help ] -``` -ion_docs +DESCRIPTION + Prints all the defined functions along with their help, if provided ``` -Opens the Ion manual +## help - get help for builtins -## jobs +```txt +SYNOPSIS + help [BUILTIN] -``` -jobs +DESCRIPTION + Get the short description for BUILTIN. If no argument is provided, list all the builtins ``` -Displays all jobs that are attached to the background +## eq, is - checks if two arguments are the same -## matches +```txt +SYNOPSIS + is [ -h | --help ] [not] -``` -matches VARIABLE REGEX +DESCRIPTION + Returns 0 if the two arguments are equal + +OPTIONS + not + returns 0 if the two arguments are not equal. ``` -Checks if a string matches a given regex +## isatty - checks if the provided file descriptor is a tty -## not +```txt +SYNOPSIS + isatty [FD] +DESCRIPTION + Returns 0 exit status if the supplied file descriptor is a tty. ``` -not COMMAND -``` -Reverses the exit status value of the given command. -## or +## jobs - list all jobs running in the background -``` -COMMAND; or COMMAND +```txt +SYNOPSIS + jobs + +DESCRIPTION + Prints a list of all jobs running in the background. ``` -Execute the command if the shell's previous status is failure +## matches - checks if the second argument contains any proportion of the first -## popd +```txt +SYNOPSIS + matches VALUE VALUE -``` -popd +DESCRIPTION + Makes the exit status equal 0 if the first argument contains the second. + Otherwise matches makes the exit status equal 1. + +EXAMPLES + Returns true: + matches xs x + Returns false: + matches x xs ``` -Pop a directory from the stack and returns to the previous directory +## popd - shift through the directory stack -## pushd +```txt +SYNOPSIS + popd +DESCRIPTION + popd removes the top directory from the directory stack and changes the working directory to the new top directory. + pushd adds directories to the stack. ``` -pushd DIRECTORY -``` -Push a directory to the stack. -## random +## pushd - push a directory to the directory stack -``` -random -random SEED -random START END -random START STEP END -random choice [ITEMS...] -``` +```txt +SYNOPSIS + pushd DIRECTORY -RANDOM generates a pseudo-random integer from a uniform distribution. The range (inclusive) is -dependent on the arguments passed. No arguments indicate a range of [0; 32767]. If one argument -is specified, the internal engine will be seeded with the argument for future invocations of -RANDOM and no output will be produced. Two arguments indicate a range of [START; END]. Three -arguments indicate a range of [START; END] with a spacing of STEP between possible outputs. -RANDOM choice will select one random item from the succeeding arguments. +DESCRIPTION + pushd pushes a directory to the directory stack. +``` -> Due to limitations in the rand crate, seeding is not yet implemented +## random - generate a random number -## read +```txt +SYNOPSIS + random + random START END +DESCRIPTION + random generates a pseudo-random integer. IT IS NOT SECURE. + The range depends on what arguments you pass. If no arguments are given the range is [0, 32767]. + If two arguments are given the range is [START, END]. ``` -read VARIABLE -``` -Read some variables +## read - read a line of input into some variables -## set +```txt +SYNOPSIS + read VARIABLES... -``` -set [ --help ] [-e | +e] [- | --] [STRING]... +DESCRIPTION + For each variable reads from standard input and stores the results in the variable. ``` -Set or unset values of shell options and positional parameters. -Shell options may be set using the '-' character, -and unset using the '+' character. +## set - Set or unset values of shell options and positional parameters. -### OPTIONS +```txt +SYNOPSIS + set [ --help ] [-e | +e] [-x | +x] [-o [vi | emacs]] [- | --] [STRING]... -- **e**: Exit immediately if a command exits with a non-zero status. +DESCRIPTION + Shell options may be set using the '-' character, and unset using the '+' character. -- **--**: Following arguments will be set as positional arguments in the shell. - - If no argument are supplied, arguments will be unset. +OPTIONS + -e Exit immediately if a command exits with a non-zero status. -- **-**: Following arguments will be set as positional arguments in the shell. - - If no arguments are suppled, arguments will not be unset. + -o Specifies that an argument will follow that sets the key map. + The keymap argument may be either `vi` or `emacs`. -## source + -x Specifies that commands will be printed as they are executed. -``` -source [PATH] + -- Following arguments will be set as positional arguments in the shell. + If no argument are supplied, arguments will be unset. + + - Following arguments will be set as positional arguments in the shell. + If no arguments are suppled, arguments will not be unset. ``` -Evaluate the file following the command or re-initialize the init file +## source - evaluates given file -## starts-with +```txt +SYNOPSIS + source FILEPATH -``` -ends-with KEY [VALUE...] +DESCRIPTION + Evaluates the commands in a specified file in the current shell. All changes in shell + variables will affect the current shell because of this. ``` -Evaluates if the supplied argument starts with a given string +## starts_with - check if a given string starts with another one -## suspend +```txt +SYNOPSIS + starts_with <PATTERN> tests... +DESCRIPTION + Returns 0 if any argument starts_with contains the first argument, else returns 0 ``` -suspend -``` -Suspends the shell with a SIGTSTOP signal +## status - Evaluates the current runtime status + +```txt +SYNOPSIS + status [ -h | --help ] [-l] [-i] -## test +DESCRIPTION + With no arguments status displays the current login information of the shell. +OPTIONS + -l + returns true if the shell is a login shell. Also --is-login. + -i + returns true if the shell is interactive. Also --is-interactive. + -f + prints the filename of the currently running script or else stdio. Also --current-filename. ``` -test [EXPRESSION] + +## suspend - suspend the current shell + +```txt +SYNOPSIS + suspend + +DESCRIPTION + Suspends the current shell by sending it the SIGTSTP signal, + returning to the parent process. It can be resumed by sending it SIGCONT. ``` -Performs tests on files and text +## test - perform tests on files and text -#### Options +```txt +SYNOPSIS + test [EXPRESSION] -- **-n STRING**: the length of STRING is nonzero -- **STRING**: equivalent to -n STRING -- **-z STRING**: the length of STRING is zero -- **STRING = STRING**: the strings are equivalent -- **STRING != STRING**: the strings are not equal -- **INTEGER -eq INTEGER**: the integers are equal -- **INTEGER -ge INTEGER**: the first INTEGER is greater than or equal to the first INTEGER -- **INTEGER -gt INTEGER**: the first INTEGER is greater than the first INTEGER -- **INTEGER -le INTEGER**: the first INTEGER is less than or equal to the first INTEGER -- **INTEGER -lt INTEGER**: the first INTEGER is less than the first INTEGER -- **INTEGER -ne INTEGER**: the first INTEGER is not equal to the first INTEGER -- **FILE -ef FILE**: both files have the same device and inode numbers -- **FILE -nt FILE**: the first FILE is newer than the second FILE -- **FILE -ot FILE**: the first file is older than the second FILE -- **-b FILE**: FILE exists and is a block device -- **-c FILE**: FILE exists and is a character device -- **-d FILE**: FILE exists and is a directory -- **-e FILE**: FILE exists -- **-f FILE**: FILE exists and is a regular file -- **-h FILE**: FILE exists and is a symbolic link (same as -L) -- **-L FILE**: FILE exists and is a symbolic link (same as -h) -- **-r FILE**: FILE exists and read permission is granted -- **-s FILE**: FILE exists and has a file size greater than zero -- **-S FILE**: FILE exists and is a socket -- **-w FILE**: FILE exists and write permission is granted -- **-x FILE**: FILE exists and execute (or search) permission is granted +DESCRIPTION + Tests the expressions given and returns an exit status of 0 if true, else 1. -## true +OPTIONS + --help + prints this help text -``` -true -``` + -n STRING + the length of STRING is nonzero -Do nothing, successfully + STRING + equivalent to -n STRING -## unalias + -z STRING + the length of STRING is zero -``` -unalias VARIABLE... -``` + STRING = STRING + the strings are equivalent -Delete an alias + STRING != STRING + the strings are not equal -## wait + INTEGER -eq INTEGER + the integers are equal -``` -wait -``` + INTEGER -ge INTEGER + the first INTEGER is greater than or equal to the first INTEGER -Waits until all running background processes have completed + INTEGER -gt INTEGER + the first INTEGER is greater than the first INTEGER -## which + INTEGER -le INTEGER + the first INTEGER is less than or equal to the first INTEGER -``` -which COMMAND -``` + INTEGER -lt INTEGER + the first INTEGER is less than the first INTEGER -Shows the full path of commands + INTEGER -ne INTEGER + the first INTEGER is not equal to the first INTEGER -## status + FILE -ef FILE + both files have the same device and inode numbers -``` -status COMMAND -``` + FILE -nt FILE + the first FILE is newer than the second FILE -Evaluates the current runtime status + FILE -ot FILE + the first file is older than the second FILE -### Options + -b FILE + FILE exists and is a block device -- **-l**: returns true if shell is a login shell -- **-i**: returns true if shell is interactive -- **-f**: prints the filename of the currently running script or stdio + -c FILE + FILE exists and is a character device -## bool + -d FILE + FILE exists and is a directory -``` -bool VALUE -``` + -e FILE + FILE exists -If the value is '1' or 'true', returns the 0 exit status + -f FILE + FILE exists and is a regular file -## is + -h FILE + FILE exists and is a symbolic link (same as -L) -``` -is VALUE VALUE + -L FILE + FILE exists and is a symbolic link (same as -h) + + -r FILE + FILE exists and read permission is granted + + -s FILE + FILE exists and has a file size greater than zero + + -S FILE + FILE exists and is a socket + + -w FILE + FILE exists and write permission is granted + + -x FILE + FILE exists and execute (or search) permission is granted + +EXAMPLES + Test if the file exists: + test -e FILE && echo "The FILE exists" || echo "The FILE does not exist" + + Test if the file exists and is a regular file, and if so, write to it: + test -f FILE && echo "Hello, FILE" >> FILE || echo "Cannot write to a directory" + + Test if 10 is greater than 5: + test 10 -gt 5 && echo "10 is greater than 5" || echo "10 is not greater than 5" + + Test if the user is running a 64-bit OS (POSIX environment only): + test $(getconf LONG_BIT) = 64 && echo "64-bit OS" || echo "32-bit OS" + +AUTHOR + Written by Michael Murphy. ``` -Returns 0 if the two arguments are equal +## true - does nothing sucessfully -## isatty +```txt +SYNOPSIS + true +DESCRIPTION + Sets the exit status to 0. ``` -isatty [FD] + +## wait - wait for a background job + +```txt +SYNOPSIS + wait + +DESCRIPTION + Wait for the background jobs to finish ``` -Returns 0 exit status if the supplied file descriptor is a tty. +## which, type - locate a program file in the current user's path + +```txt +SYNOPSIS + which PROGRAM -### Options -- **not**: returns 0 if the two arguments are not equal. +DESCRIPTION + The which utility takes a list of command names and searches for the + alias/builtin/function/executable that would be executed if you ran that command. +``` \ No newline at end of file diff --git a/members/builtins-proc/Cargo.toml b/members/builtins-proc/Cargo.toml index 327516ba4c4ac2cdcac0410847c1379b687f4088..c5b370e60148fb07d5cc2a7017ed5e0a81c4e3c8 100644 --- a/members/builtins-proc/Cargo.toml +++ b/members/builtins-proc/Cargo.toml @@ -7,9 +7,13 @@ edition = "2018" [dependencies] quote = "0.6" syn = { version = "0.15", features = ["full"] } +darling = "0.9" [dev-dependencies] ion-shell = { path = "../.." } [lib] proc-macro = true + +[features] +man = [] diff --git a/members/builtins-proc/src/lib.rs b/members/builtins-proc/src/lib.rs index 3f892b7961d7ad0a1529d0e7e0f817d9f0a81116..71c04781601fbea1a35d637025bb970c22a848a8 100644 --- a/members/builtins-proc/src/lib.rs +++ b/members/builtins-proc/src/lib.rs @@ -1,8 +1,22 @@ extern crate proc_macro; +use darling::{util::Flag, FromMeta}; use proc_macro::TokenStream; use quote::quote; +use std::{fs::File, io::Write}; use syn; +#[derive(Debug, FromMeta)] +struct MacroArgs { + #[darling(default)] + names: Option<String>, + #[darling(rename = "man")] + help: String, + #[darling(default)] + authors: Flag, + #[darling(rename = "desc")] + short_description: String, +} + // TODO: It would be better if Man pages could be parsed of comments #[proc_macro_attribute] pub fn builtin(attr: TokenStream, item: TokenStream) -> TokenStream { @@ -10,47 +24,16 @@ pub fn builtin(attr: TokenStream, item: TokenStream) -> TokenStream { let attrs = syn::parse_macro_input!(attr as syn::AttributeArgs); let syn::ItemFn { vis, decl, block, ident, .. } = &input; let syn::FnDecl { ref fn_token, ref inputs, ref output, .. } = **decl; - let mut help = None; - let mut short_description = None; - let mut names = None; - let mut authors = true; + + let args = match MacroArgs::from_list(&attrs) { + Ok(v) => v, + Err(e) => return e.write_errors().into(), + }; let name = syn::Ident::new(&format!("builtin_{}", &ident), input.ident.span()); - for attr in attrs { - match attr { - syn::NestedMeta::Meta(syn::Meta::NameValue(ref attr)) if attr.ident == "man" => { - if let syn::Lit::Str(h) = &attr.lit { - help = Some(h.value()); - } else { - panic!("`man` attribute should be a string variable"); - } - } - syn::NestedMeta::Meta(syn::Meta::NameValue(ref attr)) if attr.ident == "desc" => { - if let syn::Lit::Str(h) = &attr.lit { - short_description = Some(h.value()); - } else { - panic!("`desc` attribute should be a string variable"); - } - } - syn::NestedMeta::Meta(syn::Meta::NameValue(ref attr)) if attr.ident == "names" => { - if let syn::Lit::Str(h) = &attr.lit { - names = Some(h.value()); - } else { - panic!("`desc` attribute should be a string variable"); - } - } - syn::NestedMeta::Meta(syn::Meta::Word(ref ident)) if ident == "no_authors" => { - authors = false; - } - _ => panic!("Only the `man` and `desc` attributes are allowed"), - } - } - let help = help.expect("A man page is required! Please add an attribute with name `man`"); - let help = help.trim(); - let short_description = short_description - .expect("A short description is required! Please add an attribute with name `desc`"); - let names = names.unwrap_or_else(|| ident.to_string()); + let help = args.help.trim(); + let names = args.names.unwrap_or_else(|| ident.to_string()); let bugs = "BUGS Please report all bugs at https://gitlab.redox-os.org/redox-os/ion/issues. @@ -65,12 +48,17 @@ AUTHORS let man = format!( "NAME\n {names} - {short_description}\n\n{help}\n\n{bugs}{extra}", names = names, - short_description = short_description, + short_description = args.short_description, help = help, bugs = bugs, - extra = if authors { &extra } else { "" }, + extra = if args.authors.is_none() { &extra } else { "" }, ); - let help = format!("{} - {}\n\n```txt\n{}\n```", names, short_description, help); + let help = format!("{} - {}\n\n```txt\n{}\n```", names, args.short_description, help); + + if cfg!(feature = "man") { + let mut man = File::create(format!("manual/builtins/{}.1", &ident)).unwrap(); + man.write(help.as_bytes()).unwrap(); + } let result = quote! { #[doc = #help]