.\" Automatically generated by Pod::Man v1.37, Pod::Parser v1.32 .\" .\" Standard preamble: .\" ======================================================================== .de Sh \" Subsection heading .br .if t .Sp .ne 5 .PP \fB\\$1\fR .PP .. .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Vb \" Begin verbatim text .ft CW .nf .ne \\$1 .. .de Ve \" End verbatim text .ft R .fi .. .\" Set up some character translations and predefined strings. \*(-- will .\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left .\" double quote, and \*(R" will give a right double quote. | will give a .\" real vertical bar. \*(C+ will give a nicer C++. Capital omega is used to .\" do unbreakable dashes and therefore won't be available. \*(C` and \*(C' .\" expand to `' in nroff, nothing in troff, for use with C<>. .tr \(*W-|\(bv\*(Tr .ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' .ie n \{\ . ds -- \(*W- . ds PI pi . if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch . if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch . ds L" "" . ds R" "" . ds C` "" . ds C' "" 'br\} .el\{\ . ds -- \|\(em\| . ds PI \(*p . ds L" `` . ds R" '' 'br\} .\" .\" If the F register is turned on, we'll generate index entries on stderr for .\" titles (.TH), headers (.SH), subsections (.Sh), items (.Ip), and index .\" entries marked with X<> in POD. Of course, you'll have to process the .\" output yourself in some meaningful fashion. .if \nF \{\ . de IX . tm Index:\\$1\t\\n%\t"\\$2" .. . nr % 0 . rr F .\} .\" .\" For nroff, turn off justification. Always turn off hyphenation; it makes .\" way too many mistakes in technical documents. .hy 0 .if n .na .\" .\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). .\" Fear. Run. Save yourself. No user-serviceable parts. . \" fudge factors for nroff and troff .if n \{\ . ds #H 0 . ds #V .8m . ds #F .3m . ds #[ \f1 . ds #] \fP .\} .if t \{\ . ds #H ((1u-(\\\\n(.fu%2u))*.13m) . ds #V .6m . ds #F 0 . ds #[ \& . ds #] \& .\} . \" simple accents for nroff and troff .if n \{\ . ds ' \& . ds ` \& . ds ^ \& . ds , \& . ds ~ ~ . ds / .\} .if t \{\ . ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" . ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' . ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' . ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' . ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' . ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' .\} . \" troff and (daisy-wheel) nroff accents .ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' .ds 8 \h'\*(#H'\(*b\h'-\*(#H' .ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] .ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' .ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' .ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] .ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] .ds ae a\h'-(\w'a'u*4/10)'e .ds Ae A\h'-(\w'A'u*4/10)'E . \" corrections for vroff .if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' .if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' . \" for low resolution devices (crt and lpr) .if \n(.H>23 .if \n(.V>19 \ \{\ . ds : e . ds 8 ss . ds o a . ds d- d\h'-1'\(ga . ds D- D\h'-1'\(hy . ds th \o'bp' . ds Th \o'LP' . ds ae ae . ds Ae AE .\} .rm #[ #] #H #V #F C .\" ======================================================================== .\" .IX Title "ZOIDDEVEL 1" .TH ZOIDDEVEL 1 "2006-02-11" "perl v5.8.8" "User Contributed Perl Documentation" .SH "NAME" zoiddevel \- Development documentation for zoid .SH "DESCRIPTION" .IX Header "DESCRIPTION" .Sh "Debugging" .IX Subsection "Debugging" If you switch on the global debug bit and the verbose bit both your input and debug information are echoed to \s-1STDERR\s0. Thus by piping both \s-1STDOUT\s0 and \s-1STDERR\s0 to a file you get a detailed log of what is happening. .PP To set both bits type: .PP .Vb 2 \& zoid$ set debug \& zoid$ set verbose .Ve .PP or start zoid with: .PP .Vb 1 \& $ zoid -vD .Ve .PP You can also get debug information from just one module by setting a global variable \f(CW$DEBUG\fR in the module's namespace. .PP If you set the debug variable to a number higher than 1, you get a stack trace of that number of frames for each exception thrown using the \f(CW\*(C`error()\*(C'\fR method. .Sh "Structure" .IX Subsection "Structure" \fIclass diagram\fR .IX Subsection "class diagram" .PP .Vb 10 \& Zoidberg::Shell \& /|\e Zoidberg::Contractor \& | /|\e /|\e \& |__________________| | \& | | \& | Zoidberg::Job \& Zoidberg /|\e \& | \& | \& Zoidberg::Job::Builtin .Ve .PP All other classes stand on their own (except perhaps for some internal helper classes). .PP Zoidberg::Shell is an interface class to be used in perl scripts like \fIzoidrc\fR. Zoidberg inheriting from it in order to make this interface also available through the \f(CW$shell\fR object in the eval scope and to plugins. The Zoidberg::Contractor class contains the code to manage Jobs. Because the Job class also inherits from it sub-jobs are possible. .PP \fIobject structure\fR .IX Subsection "object structure" .PP .Vb 14 \& main object class Zoidberg \& | \& |___ {eval} Zoidberg::Eval object \& |___ {stringparser} Zoidberg::StringParser object \& | \& |___ {jobs} Array with Job objects \& | |_ items of class Zoidberg::Job \& | \& |___ {settings} Settings and config hashes \& |___ {objects} Plugin objects - tied Zoidberg::PluginHash \& |___ {parser} Custom parsing - tied Zoidberg::DispatchTable \& |___ {events} Event code refs - tied Zoidberg::DispatchTable \& |___ {commands} Command code refs - tied Zoidberg::DispatchTable \& |___ {aliases} Alias definitions .Ve .PP \&\s-1FIXME\s0 explanation .PP \fIProcess flow\fR .IX Subsection "Process flow" .PP .Vb 18 \& start \& | \& | incomplete input - readmore \& | .--------------------. \& | | | \& | | | \& V V string | tree \& input loop --------> parse string ------> execute tree \& Z:main_loop() Z:shell_string() Z:C:shell_list() \& readline | \& A reincarnate | \& | ,------> | \& new | next chunk | | \& input | of blocks | | logic chunk \& | | | \& | | V \& '---------------------------------------+--- execute job \& Z:J:exec() .Ve .PP .Vb 3 \& Z: = Zoidberg:: \& Z:C: = Zoidberg::Contractor:: \& Z:J: = Zoidberg::Job:: .Ve .PP The parse tree going to \f(CW\*(C`shell_list()\*(C'\fR is a simple parse tree consisting of scalars and scalar references (see \s-1FIXME\s0 below). This tree is processed in logic chunks, corresponding to one job each. The blocks references in a logic chunk are parsed by \f(CW\*(C`parse_block()\*(C'\fR just before executing. This is where the context is determined and things like expansions and subtitutions are done. .Sh "Parsing" .IX Subsection "Parsing" \&\s-1FIXME\s0 put devel opts in scheme .PP .Vb 1 \& string --> shell_string() .Ve .PP .Vb 1 \& split script_gram .Ve .PP .Vb 2 \& | \& V .Ve .PP .Vb 1 \& list --> shell_list() ... FIXME tell bout this format below .Ve .PP .Vb 2 \& | \& V .Ve .PP .Vb 1 \& ref --> parse_block() ... FIXME tell bout possible block forms .Ve .PP .Vb 17 \& | \& V ------------. \& | \& parse_env() | if word block \& | \& split word_gram | \& split redir_gram | \& strip env declaration A | \& | | \& | <------------------' \& V | \& alias expansion -------' if multiple blocks result \& custom filtering \& decide context unless already known \& - context on whole string like perl \& - custom word lists \& - default word context .Ve .PP .Vb 8 \& |----> custom parser \& | \& |----> parse_perl() for perl context \& | \& | for word context ---------. if 'FIXME' \& V | \& | \& parse_words() V .Ve .PP .Vb 2 \& expansion ... FIXME list them in zoiduser \& (globs) .Ve .PP A block that originates from \f(CW\*(C`shell()\*(C'\fR or \f(CW\*(C`Zoidberg::Shell::AUTOLOAD\*(C'\fR is recognised as having already been split into words. This means the parsing of words, redirections and environment declarations is skipped. Only alias are checked so this interface is consistent in command names etc. with the commandline interface. .PP If you use \f(CW\*(C`builtin()\*(C'\fR or \f(CW\*(C`command()\*(C'\fR, these are understood as simple command with parsed words and effectively all parsing is skipped. .PP \fIParse tree\fR .IX Subsection "Parse tree" .PP \&\s-1FIXME\s0 tell about the blocks used in lots of hooks .PP \&\s-1FIXME\s0 renice this stuff .PP This part describes the form of a parse tree as used between the various Zoidberg objects. .PP Example .IX Subsection "Example" .PP .Vb 1 \& # Commandline input: .Ve .PP .Vb 1 \& $ ls -al | perl{ while () { print $_ } }abc && echo done .Ve .PP .Vb 1 \& # Would be parsed to: .Ve .PP .Vb 6 \& [ \& [{context => 'CMD'}, qw/ls -al/], \& [{context => 'PERL', opts => 'abc'}, q{ while () { print $_ } } ], \& 'AND', \& [{context => 'CMD'}, qw/echo done/] \& ] .Ve .PP .Vb 1 \& # Commandline input: .Ve .PP .Vb 1 \& $ cd .. && ls -al ; cp dus ~/tmp/ & .Ve .PP .Vb 1 \& # Would be parsed to: .Ve .PP .Vb 8 \& [ \& [{context => 'CMD'}, qw/cd ../], \& 'AND', \& [{context => 'CMD'}, qw/ls -al/], \& 'EOS', # End Of Statement \& [{context => 'CMD'}, qw{cp dus ~/tmp/}], \& 'EOS_BG' # background statement \& ] .Ve .PP .Vb 1 \& # FIXME an example with redirections .Ve .PP There are a lot more meta fields like 'fork_job', \s-1FIXME\s0 where to read bout them? .PP Basics .IX Subsection "Basics" .PP A parse tree is an array consisting of blocks and tokens. A block can be any kind of shell code and is stored in a nested array. Blocks directly following each other are supposed to be a pipeline. A token is a delimiter between blocks. .PP The first field of a block is a hash which contains information about the block, all other field in a block make up the content. The most important information about a block is the context, which tells the parser how to execute the block. You are free to store all kinds of specific information in this first field, but some key names are reserved. .PP \&\s-1FIXME\s0 reserved meta fields .PP Pseudo parse trees .IX Subsection "Pseudo parse trees" .PP These are forms that can be used with the \f(CW\*(C`shell()\*(C'\fR function provided by Zoidberg::Shell. Just as by the real parse tree blocks of code are references and tokens are plain scalars. A block that is a scalar reference will be split into words and parsed completely (although still expected to be one block). A block that is an array reference will be considered to be completely parsed if the first element is a hash reference and the context defined, else it is considered a word list, possibly with meta data defined in the first element. .PP .Vb 8 \& # for example "ls -al | perl{ while () { print $_ } }abc && echo done" \& # can be executed by calling : \& shell( \& [qw/ls -al/], \& \e'perl{ while () { print $_ } }abc', \& 'AND' \& [{context => 'CMD'}, qw/echo done/] \& ); .Ve .PP Using this kind of pseudo trees only makes sense if you are lazy or you don't know exactly what the command is but you have some clues you want to pass to the parser. .PP Built-in contexts .IX Subsection "Built-in contexts" .PP The contexts '\s-1PERL\s0', '\s-1CMD\s0' and '\s-1SUBZ\s0' are used by the built-in parser: '\s-1PERL\s0' flags code as perl code, '\s-1CMD\s0' as a system or built-in command and the '\s-1SUBZ\s0' context is used for sub\-shells. .PP \fIParser hooks\fR .IX Subsection "Parser hooks" .PP The hash called 'parser' in the main object is a tied hash of the class Zoidberg::DispatchTable. This hash contains stacks of code refs to be called at certain parser stages. .PP Subroutines in these stacks should in general return a \s-1BLOCK\s0 (a array ref with a meta field and words) at success and \f(CW\*(C`undef\*(C'\fR otherwise. .IP "filter \s-1BLOCK\s0" 4 .IX Item "filter BLOCK" Stack called before contexts are decided and before the block is splitted into words. Used to claim a block for a certain context by setting the 'context' field in the meta hash. .IP "word_expansion \s-1BLOCK\s0" 4 .IX Item "word_expansion BLOCK" Allows you to define a custom expansion routine. .IP "word_list \s-1BLOCK\s0" 4 .IX Item "word_list BLOCK" Stack with a dual function: used to claim a block for a certain context \&\fBafter word splitting\fR, but also for listing completions for this context. .Sp If called in \f(CW\*(C`wantarray\*(C'\fR context should return a list of possible completions for the first word in \s-1BLOCK\s0. .Sp If not in \f(CW\*(C`wantarray\*(C'\fR context can either return a block with the 'context' field set to claim this block for a certain context. .PP You can define a custom context by putting a sub-hash into the parser hash (using the context name as the key). See \*(L"Custom contexts\*(R" for the keys to be defined in such a sub-hash (note that some of the stacks are included there also \&\- but these won't go in the sub\-hash). .Sh "Settings" .IX Subsection "Settings" Notice that every plugin has it's own config hash in the settings hash, it is suggested that settings only affecting one plugin are placed in this sub\-hash. This rule is broken for some settings required by the posix specification of the \&\f(CW\*(C`set\*(C'\fR built\-in. .PP \&\s-1FIXME\s0 list these posix settings somwhere .PP Below are listed advanced settings only needed for development. Common settings can be found in zoiduser. .PP The parser settings can be set globally, but also per block. \&\s-1FIXME\s0 they should also be settable per mode/context .IP "split_script" 4 .IX Item "split_script" Split a command according to the script grammar. .IP "split_words" 4 .IX Item "split_words" Split a command into words. .IP "parse_fd" 4 .IX Item "parse_fd" Parse redirections. .IP "parse_env" 4 .IX Item "parse_env" Parse environment declerations. .IP "parse_aliases" 4 .IX Item "parse_aliases" Check for aliases. .IP "parse_def_contexts" 4 .IX Item "parse_def_contexts" Use the default contexts \s-1PERL\s0 and \s-1CMD\s0. .IP "expand_comm" 4 .IX Item "expand_comm" Expand commands in \*(L"word\*(R" contexts. .IP "expand_param" 4 .IX Item "expand_param" Expand parameters in \*(L"word\*(R" contexts. .IP "expand_path" 4 .IX Item "expand_path" Expand globs in \*(L"word\*(R" contexts. .IP "debug" 4 .IX Item "debug" Turn on _all_ debug messages. .IP "plain_words" 4 .IX Item "plain_words" This is not a global setting, but if used for a single block it is identical to turning off all parser settings except for 'parse_aliases'. .Sh "Events" .IX Subsection "Events" The hash called 'events' in the main object is a tied hash of the class Zoidberg::DispatchTable. This hash contains stacks of code refs to be called when certain events happen. .PP Some events used: .PP \&\s-1FIXME\s0 more events .IP "beat" 4 .IX Item "beat" Called every idle second when using Term::ReadLine::Zoid. Used for asynchronous stuff. .IP "newpwd" 4 .IX Item "newpwd" Called if \f(CW$ENV{PWD}\fR has changed. The old pwd can be found in \f(CW$ENV{OLDPWD}\fR. .IP "prompt" 4 .IX Item "prompt" This event is called from the main loop just before respawning the prompt. It can be used to update routines. .IP "cmd" 4 .IX Item "cmd" This event is called after the input prompt with the commandline as the first argument. It is intended for interactive input only. .IP "envupdate" 4 .IX Item "envupdate" This event is called after the spawning of every job. Like 'prompt' it can be used for update routines; since 'envupdate' is called more often then 'prompt', use 'prompt' if it makes no difference, 'envupdate' should only be used for atomic updates. .IP "loadrc" 4 .IX Item "loadrc" Called after all the plugins are loaded, it triggers reading the rcfiles. Can be used by plugins to set hooks that depend on other plugins being loaded. .IP "exit" 4 .IX Item "exit" Called just before \f(CW\*(C`round_up()\*(C'\fR, used as replacement for \fI.bash_logout\fR. .IP "set_*" 4 .IX Item "set_*" Whenever a setting is changed a event is called which is the name of the setting prefixed by 'set_' . Arguments are the new value and the old value of the setting. When the new value is 'undef' the setting was deleted. .Sp These events are generated by the Zoidberg::SettingHash class, which is used to tie the settings hash of the main Zoidberg object. .IP "plug_*" 4 .IX Item "plug_*" .PD 0 .IP "unplug_*" 4 .IX Item "unplug_*" .PD Called when a plugin is loaded or deleted. .Sh "Plugins" .IX Subsection "Plugins" Zoid makes extensive use of plugins to perform tasks that are not considered the core functionality of a shell (and very little is). A plugin has three ways of communicating with the the shell and other plugins: .IP "builtins" 4 .IX Item "builtins" These are commands implemented in the shell to offer some function to both the user and other plugins. .IP "events" 4 .IX Item "events" A plugin can both trigger events ('broadcast') or listen to certain events. When an event is triggered all code 'listening' to it is executed, this is a one-to-many dispatcher. .IP "contexts" 4 .IX Item "contexts" Used to extend the code types zoid knows. By default only command syntax and perl are recognized, but a plugin might want to add other syntaxes. .Sp A context is typically used when it is unconvenient to define all commands the plugin can handle as builtins, or when a plugin want to handle the whole code block instead of the individual (possibly expanded) words. .Sp Also some methods are provided to hook into certain parser stages. .PP Some general tips for writing plugins: .IP "\(bu" 4 See the Zoidberg::Utils namespace for common functions. Using these functions will make your plugin more coherent with the rest of the shell. .IP "\(bu" 4 Try to use api's, not data structures; unless the structures are specified in the documentation they can change without notice. Api's are in general more stable. .IP "\(bu" 4 Try to use AutoLoader if you have a lot of optional functionality. .Sp ( When using AutoLoader make sure your subs have names that are case-insensitive unique, else you'll run into problems on \s-1OS\s0 X. ) .IP "\(bu" 4 When you need hooks between two plugins, use a builtin command. Make sure to find a name for it that doesn't overload a normal system command. When you need various hooks, see if they can be combined in one builtin command using options (see Zoidberg::Utils::GetOpt). Also check if other shell implementations (like bash, tcsh or zsh) have builtins for similar funtions and try to make your interface consistent. .Sp When calling a builtin as a hook the most efficient way is to use the \&\f(CW\*(C`$shell\->builtin($cmd, @args)\*(C'\fR method in a list context. Using this method will cause a lot of parser levels to be skipped, also the command won't be subject to things like the current command mode. Using list context makes the method return directly without bothering with overloaded objects. .PP \fIPluginConf\fR .IX Subsection "PluginConf" .PP A plugin configuration file can use the following keys: .IP "module" 4 .IX Item "module" The class to bless the plugin object in. .IP "config" 4 .IX Item "config" Hash with plugin specific config stuff. For plugins that inherit from Zoidberg::Fish this will automatically become the \f(CW\*(C`{config}\*(C'\fR attribute. .IP "commands" 4 .IX Item "commands" Hash linking command names to subroutines. See Zoidberg::DispatchTable for the string format used in this hash. .IP "export" 4 .IX Item "export" Array with commands automatically linking to a subroutine of the same name in the plugin object. .IP "events" 4 .IX Item "events" Like \f(CW\*(C`commands\*(C'\fR but used for events. .IP "import" 4 .IX Item "import" Like \f(CW\*(C`export\*(C'\fR but used for events. .IP "settings" 4 .IX Item "settings" Supply some default settings. Used for global settings, plugin settings should be in the 'config' hash. .IP "aliases" 4 .IX Item "aliases" Supply some default aliases. .IP "context" 4 .IX Item "context" Add context hooks. .PP If you want your plugin to be loaded as soon as possible, you can use the loadrc event to load your plugin. For plugins inheriting from Zoidberg::Fish \f(CW\*(C`loadrc => 'plug'\*(C'\fR will work. .PP Custom contexts .IX Subsection "Custom contexts" .PP Typically you'll want to set a custom context from a plugin. To do this you either provide some context hooks in the PluginConf or you set a loadrc event to load your plugin and then setup the context parser and handlers routines from the plugin's \f(CW\*(C`init()\*(C'\fR routine, using the \f(CW\*(C`add_context()\*(C'\fR method in \f(CW\*(C`Zoidberg::Fish\*(C'\fR. If you defined a word_list or filter hook it makes sense to use the second method. The plugin would be loaded anyway when the first command is parsed. .PP A context config hash can contain the following routines: .PP \&\s-1FIXME\s0 more verbose description .IP "word_list \s-1BLOCK\s0" 4 .IX Item "word_list BLOCK" If you want your context to work with words you should have this hook to recognize and list commands. On wantarray it should return a list of possible completions for the word in \f(CW$$block[1]\fR; else it should check whether the word is a recognized command and return true on success. In both cases it is also allowed to return a block ref, this is for the more advanced options. .IP "parser \s-1BLOCK\s0" 4 .IX Item "parser BLOCK" Here you can set options like for example \f(CW\*(C`fork_job\*(C'\fR or \f(CW\*(C`no_words\*(C'\fR for your context. .IP "handler \s-1BLOCK\s0" 4 .IX Item "handler BLOCK" This is the part where your command gets executed. .IP "completion_function \s-1WORD\s0, \s-1LINE\s0, \s-1START\s0, \s-1END\s0" 4 .IX Item "completion_function WORD, LINE, START, END" Hook used by the Intel plugin for custom completion. .IP "intel \s-1BLOCK\s0" 4 .IX Item "intel BLOCK" Hook used by the Intel plugin for custom completion. .IP "filter \s-1BLOCK\s0" 4 .IX Item "filter BLOCK" Hook to filter blocks before they are parsed, this can be used for example for custom redirection code. .Sp Be aware that the a block might be filtered twice with the same meta hash, the second time should reset any meta fields set by the first time. .IP "word_expansion \s-1BLOCK\s0" 4 .IX Item "word_expansion BLOCK" Hook extra expansions into the parser. .PP \fI\*(L"Hello World\*(R" plugin\fR .IX Subsection "Hello World plugin" .PP Here follows an example to create a simple plugin with the \*(L"hello_world\*(R" builtin. .PP First create a dir \fI~/.zoid/plugins/HelloWorld\fR. .PP Next create a module, for example : .PP .Vb 1 \& package HelloWorldZoid; .Ve .PP .Vb 3 \& # Zoidberg::Fish is the base class for plugins \& use Zoidberg::Fish; \& our @ISA = qw/Zoidberg::Fish/; .Ve .PP .Vb 2 \& # Zoidberg::Utils provides the output method \& use Zoidberg::Utils; .Ve .PP .Vb 2 \& # no need for a constructor, bootstrap with init \& sub init { $$_[0]{config}{string} ||= "Hello world !" } .Ve .PP .Vb 2 \& # and in this sub we actually print the string \& sub hello_world { output $$_[0]{config}{string} } .Ve .PP .Vb 2 \& # this will be called when the plugin is unloaded \& sub round_up { output "someone help me" } .Ve .PP .Vb 1 \& 1; # keep require happy .Ve .PP Save the module as \fI~/.zoid/plugins/HelloWorld/HelloWorldFish.pm\fR. .PP Then create a config file, this is just a perl script returning a config hash. .PP .Vb 9 \& { \& module => q/HelloWorldFish/, \& config => { \& # This hash will be both accessible as $shell->{settings}{HelloWorld} \& # and as $shell->HelloWorld->{config} \& string => q/Hello cruel world !/ \& }, \& export => ['hello_world'], \& } .Ve .PP Save the config file as \fI~/.zoid/plugins/HelloWorld/PluginConf.pl\fR. .PP After restarting zoid, you should have a builtin command \*(L"hello_world\*(R" that prints the string \*(L"Hello cruel world !\*(R", and an object called \*(L"HelloWorld\*(R". Of course you guessed already that you can control the string that will be printed from the config file, and also that it defaults to \*(L"Hello world !\*(R". On run-time this string is available under \f(CW\*(C`$shell\->{settings}{HelloWorld}{string}\*(C'\fR, it can be changed at any time. .SH "ENVIRONMENT" .IX Header "ENVIRONMENT" The following environment variables are used be Zoidberg. .IP "\s-1ZOIDPID\s0" 4 .IX Item "ZOIDPID" Contains the process id of a parent zoidberg shell, intended to be used for an \&\s-1IPC\s0 mechanism. .IP "\s-1ZOIDREF\s0" 4 .IX Item "ZOIDREF" In forked child processes this variable contains a stringyfied version of the current Zoidberg object in charge. The parent process has a global hash \&\f(CW%Zoidberg::OBJECTS\fR which maps these strings to the original references. It is intended that an \s-1IPC\s0 mechanism uses this hash to convert strings back to references. .Sp This value should correspond to the object stored in the global \&\f(CW$Zoidberg::CURRENT\fR at the time of forking. .Sp In secondary scripts it is better to use \f(CW\*(C`Zoidberg::Shell\->current()\*(C'\fR. .Sp \&\s-1TODO\s0 this mechanism seems to have some problems .IP "\s-1ZOIDCMD\s0" 4 .IX Item "ZOIDCMD" Contains the string that caused the current command to be executed. Can be used by a command to inspect its arguments as they were before path expansions etc.. .SH "SEE ALSO" .IX Header "SEE ALSO" perl(1),