Home |  Download/Install |  Documentation |  Contact

Documentation

tako is a command language and shell, based on Python 3, with additional syntax to make starting processes, manipulating the environment, and dealing with the filesystem easy. In fact, it is a strict superset of Python (3.4+), so any command that is valid Python is also a valid tako command; as a result, you can use tako purely as an interactive Python interpreter if you don't need any of the additional syntax (though in a few situations, the semantics are slightly different). This page will not focus on Python, but rather on using tako as an interactive command prompt and customizing it to fit your needs.

This page is based on the xonsh "tutorial," and pieces have been copied verbatim.

Table of Contents

01) Basics
02) Interacting with Environment Variables
03) Environment Mapping
04) Environment Variables of Interest
05) Running Commands
06) Modes (Python vs Subprocess Mode)
07) Pipes
08) Input/Output Redirection
    08.1) Redirecting stdout
    08.2) Redirecting stderr
    08.3) Combining Streams
    08.4) Redirecting stdin
    08.5) Combining I/O Redirects
09) Background Jobs
10) Job Control
11) Logical Subprocess And/Or
12) Python Evaluation in Subprocess Mode with @()
13) String Literals in Subprocess Mode
14) Captured Subprocess with $() and !()
15) Uncaptured Subprocess with $[] and ![]
16) Command Substitution with @$()
17) Nesting Subprocesses
18) Searching History
19) Tab Completion
    19.1) Bash Completion
20) Path Search with ``
    20.1) Regular Expression Globbing
    20.2) Normal Globbing (with Brace Expansion)
    20.3) Custom Path Search
21) Commands and Scripts
22) Importing From Tako Scripts (*.tako)
23) Run Control Files
24) Customizing the Prompt
25) Aliases
    25.1) "Simple" Process Proxy
    25.2) "Streaming" Process Proxy
    25.3) Adding Aliases
26) Event Hooks
27) Other Settings
    27.1) General
    27.2) cd Behavior
    27.3) Interpreter
    27.4) Interactive Prompt
    27.5) Tab Completion
28) Plugins
    28.1) Writing Plugins
29) Programmable Tab Completion
    29.1) Structure
    29.2) List of Active Completers
    29.3) Writing a New Completer
    29.4) Registering a Completer
    29.5) Removing a Completer

01) Basics

The tako language is based on Python, and the tako shell uses Python to interpret any input it receives. This makes simple things, like arithmetic, simple:
~ $ 1+1
2
One place where tako differs from Python is in its handling of numbers. When dividing integers, tako keeps an exact representation of a number rather than converting to a float (it will only convert to a float if necessary). For example:
~ $ 3.1
3.1
~ $ 2 / 3
2/3
~ $ 2.0/3
0.6666666666666666
(You can turn this behavior off and revert to Python's regular handling of numbers by setting $TAKO_SETTINGS.number_mode = 'python'. You can cause tako to convert decimals to rationals as well by setting $TAKO_SETTINGS.number_mode = 'exact').

Since tako is a superset of Python, you are able import modules, print values, and use other built-in Python functionality directly from the command prompt:

~ $ import sys
~ $ print(sys.version)
3.5.2 (default, Aug 26 2016, 06:23:54)
[GCC 4.9.2]
If you have third-party Python modules installed, you can use those as well:
~ $ import numpy
~ $ print(numpy.mean(range(4)))
1.5
You can also create and use literal data types, such as ints, floats, lists, sets, and dictionaries. Everything that you are used to if you already know Python is there:
>>> d = {'tako': True}
>>> d.get('bash', False)
False
Like many interactive Python prompts, tako also supports multi-line input for more advanced flow control. The multi-line mode is automatically entered whenever the first line of input is not syntactically valid on its own. Multi-line mode is then exited when enter (or return) is pressed when the cursor is in the first column.
~ $ if True:
...     print(1)
... else:
...     print(2)
...
1
Flow control, of course, includes for and while loops:
~ $ for i, x in enumerate('tako'):
...     print(i, x)
...
0 t
1 a
2 k
3 o
Functions and classes can also be defined directly from the command prompt:
~ $ def f():
...     return "tako"
...
~ $ f()
'tako'

02) Interacting with Environment Variables

Environment variables are written as a dollar sign ($) followed by a name. For example, $HOME, $PWD, and $PATH are all references to environment variables. You can interact with these values just like you would any other variables in Python: You can set (and export) environment variables like you would set any other variable in Python. The same is true for deleting them too.
~ $ $HOME
'/home/takofan123'
~ $ print($PATH)
['/usr/local/bin', '/usr/bin', '/bin', '/usr/games']
Note that environment variables are typed, unlike in some other shells. $PATH, for example, is an object much like a Python list, and you can interact with it in the same way you would a list. For example:
~ $ $PATH.append('~/bin')
~ $ print($PATH)
['/usr/local/bin', '/usr/bin', '/bin', '/usr/games', '/home/takofan123/bin']
~ $ $PATH = $PATH[:-1]
~ $ print($PATH)
['/usr/local/bin', '/usr/bin', '/bin', '/usr/games']
One other thing to note is that environment variables in tako are automatically exported. If you want a local variable (that is not shared with subprocesses), you can just use a normal Python variable (with no $). tako will automatically convert back and forth to untyped (string-only) representations of the environment as needed (mostly by subprocess commands). From the command prompt, you'll always have the typed version.

03) Environment Mapping

Internally, the environment is stored as a mapping (much like a regular Python dictionary, but with some additional mechanisms to make sure environment variables have the proper types). The normal way to interact with this mapping is with the syntax described above (variable names starting with $), but sometimes that is not enough. It is also possible to look up values using the ${<expr>} syntax; when using this form, <expr> is first evaluated in the Python context, and the resulting value is used as a key into the mapping. It is also possible to access the entire mapping by looking up an ellipsis ${...}, which allows for different kinds of programmatic access:
~ $ x = 'TH'
~ $ ${'PA' + x}
['/usr/local/bin', '/usr/bin', '/bin', '/usr/games']
~ $ ${...}['PATH'].append('~/bin')
['/usr/local/bin', '/usr/bin', '/bin', '/usr/games']
~ $ 'PATH' in ${...}
True
~ $ myenv = ${...}
~ $ myenv['PATH']
['/usr/local/bin', '/usr/bin', '/bin', '/usr/games', '/home/takofan123/bin']
(Note that this is three "dots" in a row, rather than an actual ellipsis character)

04) Environment Variables of Interest

tako sets a few environment variables: tako also stores many of its settings in the $TAKO_SETTINGS object, which, despite having a name that makes it look like an environment variable, is not passed to subprocesses (see sections farther down the page for more information about this object).

05) Running Commands

tako builds on Python's syntax to make running other programs easy. In general, running other programs works very much like it would in any other shell.

~/tako $ echo "howdy there"
howdy there
~/tako $ cd tako
~/t/tako $ git status
On branch master
Your branch is up-to-date with 'origin/master'.
nothing to commit, working directory clean
~/t/tako $ exit

06) Modes (Python vs Subprocess Mode)

When working with tako, it is important to make the distinction between lines that operate in pure Python mode and those that use shell-specific syntax to run commands.

Unfortunately, it is not always clear from the syntax alone what mode is desired. This ambiguity stems from most command line utilities looking a lot like Python operators.

Take the case of ls -l. This is valid Python code, though it could have also been written as ls - l or ls-l. So we need a way to determine whether this was intended as a command or as a Python expression.

For any given line that only contains an expression statement, tako will treat it as a Python expression if all of the included variables are defined in the current scope. If not, tako will try to parse the line as a subprocess-mode command instead. In the example above, the expression ls -l will be treated as a Python-mode expression if and only if ls and l are both variables defined in the current scope. Otherwise, it will be run as a command (executing the ls program with the -l flag).

~ $ # this will be in subprocess-mode, because ls is not defined
~ $ ls -l
total 0
-rw-rw-r-- 1 takofan123 takofan123 0 Mar  8 15:46 tako
~ $ # set ls and l variables to force python-mode
~ $ ls = 44
~ $ l = 2
~ $ ls -l
42
~ $ # deleting ls will return us to supbroc-mode
~ $ del ls
~ $ ls -l
total 0
-rw-rw-r-- 1 takofan123 takofan123 0 Mar  8 15:46 tako

If you absolutely want to run a command in subprocess mode, you can always force tako to do so with the $(), $[], !(), and ![] operators discussed in later sections.

07) Pipes

In subprocess-mode, tako allows you to use the | character to pipe together commands, as may be familiar from other shells. Doing so connects one process's output (stdout) directly to the next process's input (stdin).
~ $ env | uniq | sort | grep PATH
DATAPATH=/usr/share/MCNPX/v260/Data/
DEFAULTS_PATH=/usr/share/gconf/awesome-gnome.default.path
LD_LIBRARY_PATH=/home/snail/.local/lib:
MANDATORY_PATH=/usr/share/gconf/awesome-gnome.mandatory.path
PATH=/home/snail/.local/bin:/home/snail/sandbox/bin:/usr/local/bin
XDG_SEAT_PATH=/org/freedesktop/DisplayManager/Seat0
XDG_SESSION_PATH=/org/freedesktop/DisplayManager/Session0
This is only available in subprocess-mode because | is otherwise a Python operator.

08) Input/Output Redirection

tako also allows you to redirect stdin, stdout, and/or stderr, allowing you to control where the output of a command is sent, and where it receives its input from.

The basic operations for I/O redirection are "write to" (>), "append to" (>>), and "read from" (<). The details of these are perhaps best explained through examples.

08.1) Redirecting stdout

All of the following examples will execute COMMAND and write its regular output (stdout) to a file called output.txt, creating it if it does not exist:
~ $ COMMAND > output.txt
~ $ COMMAND out> output.txt
~ $ COMMAND o> output.txt

These can be made to append to output.txt instead of overwriting its contents by replacing > with > (note that > will still create the file if it does not exist).

08.2) Redirecting stderr

All of the following examples will execute COMMAND and write its error output (stderr) to a file called errors.txt, creating it if it does not exist:
~ $ COMMAND err> errors.txt
~ $ COMMAND e> errors.txt
As above, replacing > with >> will cause the error output to be appended to errors.txt rather than replacing its contents.

08.3) Combining Streams

It is possible to send all of COMMAND's output (both regular output and error output) to the same location. All of the following examples accomplish that task:
~ $ COMMAND all> combined.txt
~ $ COMMAND a> combined.txt
It is also possible to explicitly merge stderr into stdout so that error messages are reported to the same location as regular output. You can do this with the following syntax:
~ $ COMMAND err>out
~ $ COMMAND err>o
~ $ COMMAND e>out
~ $ COMMAND e>o
This merge can be combined with other redirections, including pipes (see the section on Pipes above):
~ $ COMMAND err>out | COMMAND2
~ $ COMMAND e>o > combined.txt
It is worth noting that this last example is equivalent to: COMMAND a> combined.txt

08.4) Redirecting stdin

It is also possible to have a command read its input from a file, rather than from stdin. The following examples demonstrate two ways to accomplish this:
~ $ COMMAND < input.txt
~ $ < input.txt COMMAND

08.5) Combining I/O Redirects

It is worth noting that all of these redirections can be combined. Below is one example of a complicated redirect.
~ $ COMMAND1 e>o < input.txt | COMMAND2 > output.txt e>> errors.txt
This line will run COMMAND1 with the contents of input.txt fed in as input, and it will pipe all output (stdout and stderr) to COMMAND2; the regular output of COMMAND2 will be redirected to output.txt, and the error output will be appended to errors.txt.

09) Background Jobs

Typically, when you start a program running in tako, tako itself will pause and wait for that program to terminate. Sometimes, though, you may want to continue giving commands to tako while that program is running. In subprocess mode, you can start a process "in the background" (i.e., in a way that allows continued use of the shell) by adding an ampersand (&) to the end of your command. Background jobs are very useful when running programs with graphical user interfaces. The following shows an example with gvim:
~ $ gvim really_interesting_file.txt &
~ $
Note that the prompt is returned to you after gvim is started.

10) Job Control

If you start a program in the foreground (with no ampersand), you can suspend that program's execution and return to the command prompt by pressing Control-Z. This will give control of the terminal back to tako, and will keep the program paused in the background.

To unpause the program and bring it back to the foreground, you can use the fg command. To unpause the program have it continue in the background (giving you continued access to the tako prompt), you can use the bg command.

You can get a listing of all currently running jobs with the jobs command.

Each job has a unique identifier (starting with 1 and counting upward). By default, the fg and bg commands operate on the job that was started most recently. You can bring older jobs to the foreground or background by specifying the appropriate ID; for example, fg 1 brings the job with ID 1 to the foreground.

11) Logical Subprocess And/Or

Subprocess-mode also allows you to use the and operator to chain together subprocess commands. The truth value of a command is evaluated as whether its return code is zero (i.e. proc.returncode == 0). Like in Python and in many other shells, this operator "short circuits"; if a command evaluates to False, subsequent commands will not be executed. For example, suppose we want to lists files that may or may not exist:
~ $ touch exists
~ $ ls exists and ls doesnt
exists
/bin/ls: cannot access doesnt: No such file or directory
However, if you list the file that doesn't exist first, you would have only seen the error (because ls exists would not run):
~ $ ls doesnt and ls exists
/bin/ls: cannot access doesnt: No such file or directory

Much like with and, you can use the or operator to chain together subprocess commands. The difference is that subsequent commands will be executed if the return code is non-zero (i.e. a failure). Using the file example from above:

~ $ ls exists or ls doesnt
exists
This doesn't even try to list the non-existent file, because ls exists suceeded). However, if you list the file that doesn't exist first, you will see the error and then the file that does exist:
~ $ ls doesnt or ls exists
/bin/ls: cannot access doesnt: No such file or directory
exists

You can also use the more conventional && in place of and, and || in place of or, if you prefer.

12) Python Evaluation in Subprocess Mode with @()

The @(<expr>) operator form works in subprocess mode, and evaluates arbitrary Python code. The result is appended to the subprocess command list. If the result is a string, it is appended to the argument list. If the result is a list or other non-string sequence, the contents are converted to strings and appended to the argument list in order. Otherwise, the result is automatically converted to a string. For example,
~ $ x = 'tako'
~ $ y = 'tuesday'
~ $ echo @(x + ' ' + y)
tako tuesday
~ $ echo @(2+2)
4
~ $ echo @([42, 'hello'])
42 hello
Thus, @() allows us to create complex commands in Python-mode and then feed them to a subprocess as needed. For example:
for i in range(20):
    touch @('file%02d' % i)

13) String Literals in Subprocess Mode

Strings can be used to escape special characters in subprocess-mode. The contents of the string are passed directly to the subprocess command as a single argument. So whenever you are in doubt, or if there is a syntax error because of a filename, just wrap the offending portion in a string.

A common use case for this is files with spaces in their names.
~ $/tako $ touch "sp ace"
~ $/tako $ ls -l
total 0
-rw-rw-r-- 1 takofan123 takofan123 0 Mar  8 17:50 sp ace
-rw-rw-r-- 1 takofan123 takofan123 0 Mar  8 15:46 tako
By default, the name of an environment variable inside a string will be replaced by the contents of that variable (in subprocess mode only). For example:
~/tako $ $ print("my home is $HOME")
my home is $HOME
~tako $ echo "my home is $HOME"
my home is /home/takofan123
You can avoid this expansion within a particular command by forcing the strings to be evaluated in Python mode using the @() syntax:
~/tako $ echo "my home is $HOME"
my home is /home/takofan123
~/tako $ echo @("my home is $HOME")
my home is $HOME

14) Captured Subprocess with $() and !()

The $(<expr>) operator in tako executes a subprocess command and captures some information about that command.

The $() syntax captures and returns the standard output stream as a string (with trailing newlines removed), which should be equivalent to how $() performs in Bash. For example:

~/tako $ $(ls -l)
'total 0\n-rw-rw-r-- 1 takofan123 takofan123 0 Mar  8 15:46 tako'

The !(<expr>) syntax captures more information about the command, as an instance of a class called CompletedCommand, which contains information about the result of the given command, including the return code, the process id, the standard output and standard error streams, and information about how input and output were redirected. For example:

~ $ !(ls nonexistent_directory)
CompletedCommand(stdin=None, stdout='', stderr='/bin/ls: cannot access nonexistent_directory: No such file or directory\n', pid=1862, returncode=2, args=['ls', 'nonexistent_directory'], alias=['ls', '--color=auto'], stdin_redirect=None, stdout_redirect=None, stderr_redirect=None)
This object will be "truthy" if its return code was 0, and it is equal (via ==) to its return code. It also hashes to its return code. This allows for some interesting kinds of interactions with subprocess commands, for example:
def check_file(file):
    if !(test -e @(file)):
        if !(test -f @(file)) or !(test -d @(file)):
            print("File is a regular file or directory")
        else:
            print("File is not a regular file or directory")
    else:
        print("File does not exist")

def wait_until_google_responds():
    while not !(ping -c 1 google.com):
        sleep 1
Iterating over the object will yield a string for each line in stdout.

The $() and !() operators are expressions themselves. This means that you can assign the results to a variable, or manipulate them in other ways as you would any other Python expression.

~/tako $ x = $(ls -l)
~/tako $ print(x.upper())
TOTAL 0
-RW-RW-R-- 1 TAKOFAN123 TAKOFAN123 0 MAR  8 15:46 TAKO
~/tako $ y = !(ls -l)
~/tako $ print(y.returncode)
0
~/tako $ print(y.rtn)  # alias to returncode
0
Note that job control is not implemented for captured subprocesses. While in subprocess-mode or inside of a captured subprocess, you can still query the environment with $NAME variables or the ${} syntax:
~/tako $ $(echo $HOME)[0]
'/home/takofan123'

15) Uncaptured Subprocess with $[] and ![]

Uncaptured subprocesses are denoted with the $[<expr>] and ![<expr>] operators. They are the same as $() captured subprocesses in almost every way. The only difference is that the subprocess's stdout passes directly to the screen rather than being captured.

In the following, we can see that the results of $[] are automatically printed, and the return value is not a string:

~/tako $ x = $[ls -l]
total 0
-rw-rw-r-- 1 takofan123 takofan123 0 Mar  8 15:46 tako
~/tako $ x is None
True

The ![] operator is similar to !() in that it returns an object containing information about the result of executing the given command. However, its standard output and standard error streams are directed to the terminal, and the resulting object is not displayed. For example:

~/tako $ x = ![ls -l] and ![echo "hi"]
total 0
-rw-rw-r-- 1 takofan123 takofan123 0 Mar  8 15:46 tako
hi

Previously when we automatically entered subprocess-mode, uncaptured subprocesses were used automatically. Thus ls -l and ![ls -l] are usually equivalent (and, in fact, the former is transformed to the latter internally when ls -l is determined to be a subprocess-mode command).

16) Command Substitution with @$()

A common use of the @() and $() operators is allowing the output of a command to replace the command itself (command substitution): @([i.strip() for i in $(cmd).split()]). tako also offers a short-hand syntax for this operation: @$(cmd).

Consider the following example:

~ $ # this returns a string representing stdout
~ $ $(which ls)
'ls --color=auto\n'
~ $ # this attempts to run the command, but as one argument
~ $ # (looks in $PATH for 'ls --color=auto\n' with spaces and newline)
~ $ @($(which ls).strip())
tako: subprocess mode: command not found: ls --color=auto
~ $ # this actually executes the intended command
~ $ @([i.strip() for i in $(which ls).split()])
some_file  some_other_file
~ $ # this does the same thing, but is much more concise
~ $ @$(which ls)
some_file  some_other_file

17) Nesting Subprocesses

It is possible to nest the subprocess operators that we have seen so far ($(), $[], ${}, !(), ![], @(), @$()). Nesting these subprocess operators inside of $(), !(), $[], and/or ![] works because the contents of those operators are executed in subprocess mode. Since @() and ${} run their contents in Python mode, it is not possible to nest other subprocess operators inside of them (they can only contain Python expressions).

18) Searching History

The up and down keys search history matching from the start of the line, much like they do in the IPython shell. tako also supports reverse incremental search with Ctrl-r.

19) Tab Completion

Tab completion is present as well. By default, in Python-mode you are able to complete based on the variable names in the current builtins; globals; and locals; as well as tako language keywords and operators; files and directories; and environment variable names. In subprocess-mode, you additionally complete on the names of executable files on your $PATH, and aliases.

19.1) Bash Completion

It is also possible to make tako to use Bash to provide auxiliary tab completion for a number of commands, provided you have Bash installed. In order to use this functionality, run the following command:

~ $ completer bash enable

The first time this command runs, it will be a bit slow, as it builds up a cache of the Bash completion functions available on your system, but it should be much faster on subsequent runs. If you want these completions to be available every time, add the above line to your ~/.config/tako/config.tako file.

The tab completion itself is fully customizable, so you can remove completers that are included by default, or implement your own. See the section below on programmable tab completion for more information.

20) Path Search with ``

tako offers additional ways to find path names beyond regular globbing, both in Python mode and in subprocess mode, via special string that use backticks (`) instead of quotes.

Note that backticks have a very different meaning in tako, versus Bash.

20.1) Regular Expression Globbing

By default, these backtick strings are interpreted as a regular expression, against which filenames are matched. Like with regular globbing, a list of successful matches is returned. Note that this works both in Python mode and in subprocess mode. In Python mode, the result is a list of strings. In subprocess mode, each filename becomes its own argument to the subprocess command. Let's see a demonstration with some simple filenames:
~ $ touch a aa aaa aba abba aab aabb abcba
~ $ ls `a(a+|b+)a`
aaa  aba  abba
~ $ print(`a(a+|b+)a`)
['aaa', 'aba', 'abba']
~ $ len(`a(a+|b+)a`)
3
This same kind of search is performed if the backticks are prefaced with r. So the following expresions are equivalent: `test` and r`test`.

20.2) Normal Globbing (with Brace Expansion)

In subprocess mode, normal globbing happens without any special syntax. However, the backtick syntax has a few additional features:

Similarly to regex globbing, normal globbing can be performed (either in Python mode or subprocess mode) by using the g`` syntax:

~ $ touch a aa aaa aba abba aab aabb abcba
~ $ ls a*b*
aab  aabb  aba  abba  abcba
~ $ ls g`a*b*`
aab  aabb  aba  abba  abcba
~ $ print(g`a*b*`)
['aab', 'aabb', 'abba', 'abcba', 'aba']
~ $ len(g`a*b*`)
5
~ $ len(g`a{b,bb}a`)
2

20.3) Custom Path Search

In addition, if normal globbing and regular expression globbing are not enough, tako allows you to specify your own search functions. A search function is defined as a function of a single argument (a string) that returns a list of possible matches to that string. Search functions can then be used with backticks with the following syntax: @`test` The following example shows the form of these functions:
~ $ def foo(s):
...     return [i for i in os.listdir('.') if i.startswith(s)]
~ $ @foo`aa`
['aa', 'aaa', 'aab', 'aabb']

21) Commands and Scripts

When started with the -c flag and a command, tako will execute that command and exit, instead of entering the command loop (note that the -s flag can be used to suppress the welcome message).
bash $ tako -s -c "echo @(7+3)"
10
Longer scripts can be run either by specifying a filename containing the script, or by feeding them to tako via stdin. For example, consider the following script, stored in test.tako:
#!/usr/bin/env tako

ls

print('removing files')
rm `file\d+.txt`

ls

print('adding files')
# This is a comment
for i, x in enumerate("tako"):
    echo @(x) > @("file{0}.txt".format(i))

print(' '.join(!(ls)))

This script could be run by piping its contents to tako:

bash $ cat test.tako | tako -s
file0.txt  file1.txt  file2.txt  file3.txt  test.tako
removing files
test.tako
adding files
file0.txt file1.txt file2.txt file3.txt test.tako
or by invoking tako with its filename as an argument:
bash $ tako -s test.tako
file0.txt  file1.txt  file2.txt  file3.txt  test.tako
removing files
test.tako
adding files
file0.txt file1.txt file2.txt file3.txt test.tako

tako scripts can also accept arguments. These arguments are made available to the script in two different ways:

  1. In either mode, as individual variables $<n> (e.g., $1)
  2. In Python mode only, as a list $ARGS

For example, consider a slight variation of the example script from above that operates on a given argument, rather than on the string 'tako' (notice how $ARGS and $1 are used):

#!/usr/bin/env tako

print($ARGS)

ls

print('removing files')
rm `file\d+.txt`

ls

print('adding files')
# This is a comment
for i, x in enumerate($1):
    echo @(x) > @("file{0}.txt".format(i))

print(' '.join(!(ls)))
print()
bash $ tako test2.tako hello
['test2.tako', 'hello']
file0.txt  file1.txt  file2.txt  file3.txt  file4.txt  test2.tako
removing files
test2.tako
adding files
file0.txt file1.txt file2.txt file3.txt file4.txt test2.tako

~ $ echo @(' '.join($(cat @('file%d.txt' % i)) for i in range(5)))
h e l l o

22) Importing From Tako Scripts (*.tako)

You can import tako source files with the *.tako file extension using the normal Python syntax. Say you had a file called mine.tako, you could, therefore, perform a Bash-like source into your current shell with the following:

from mine import *
You can also use source to run a .tako file in the current environment.

23) Run Control Files

tako uses a few run control files, which are executed in the following order:
  1. ~/.config/tako/preload.tako is run before the shell is initialized,
  2. /etc/takorc is run after the shell is initialized, and
  3. ~/.config/tako/config.tako is run immediately afterward.
Most users will only need to modify ~/.config/tako/config.tako, and any commands that are included there will be run when tako starts up. Any of the customization options below can be added to one's config.tako file in order to make the changes persist across terminal sessions.

24) Customizing the Prompt

Customizing the prompt by modifying $TAKO_SETTINGS.prompt is probably the most common reason for changing the settings.

$TAKO_SETTINGS.prompt can be a string, or it can be a function (of no arguments) that returns a string. The result can contain keyword arguments, which will be replaced automatically:

~ $ $TAKO_SETTINGS.prompt = '{user}@{hostname}:{cwd} > '
takofan123@home:~ > # it works!
takofan123@home:~ > $TAKO_SETTINGS.prompt = lambda: '{user}@{hostname}:{cwd} >> '
takofan123@home:~ >> # so does that!

By default, the following variables are available for use:

You can also color your prompt easily by inserting keywords such as {GREEN} or {BOLD_BLUE}. Colors have the form shown below:

You can make use of additional variables beyond these by adding them to the $TAKO_SETTINGS.prompt_fields variable. The values in this dictionary should be strings (which will be inserted into the prompt verbatim), or functions of no arguments (which will be called each time the prompt is generated, and the results of those calls will be inserted into the prompt). For example:

~ $ $TAKO_SETTINGS.prompt_fields['test'] = "hey"
~ $ $TAKO_SETTINGS.prompt = "{test} {cwd} $ "
hey ~ $
hey ~ $ import random
hey ~ $ $TAKO_SETTINGS.prompt_fields['test'] = lambda: random.randint(1,9)
3 ~ $
5 ~ $
2 ~ $
8 ~ $

If a function in $TAKO_SETTINGS.prompt_fields returns None, the None will be interpreted as an empty string.

Environment variables and functions are also available with the $ prefix. For example:

~ $ $TAKO_SETTINGS.prompt = "{$LANG} >"
en_US.utf8 >

25) Aliases

Another important tako built-in is the $TAKO_SETTINGS.aliases mapping. This is like a dictionary that affects how subprocess commands are run. If you are familiar with the Bash alias built-in, this is similar.

The keys of $TAKO_SETTINGS.aliases are strings that act as commands in subprocess-mode. The values are lists of strings, where the first element is the command, and the rest are the arguments. You can also set the value to a string, in which case it will be converted to a list automatically.

For example, the following creates several aliases for the git version control system. Both styles (list of strings and single string) are shown:

~ $ $TAKO_SETTINGS.aliases['g'] = 'git status -sb'
~ $ $TAKO_SETTINGS.aliases['gco'] = 'git checkout'
~ $ $TAKO_SETTINGS.aliases['gp'] = ['git', 'pull']

If you were to run gco mybranch with the above aliases in effect, the command would reduce to ['git', 'checkout', 'mybranch'] before being executed.

Lastly, if an alias value is a function (or other callable), then this function is called with particular arguments instead of going to a subprocess command. Such functions can take one of two forms, detailed below.

25.1) "Simple" Process Proxy

The "simple" Python function alias takes two arguments: This function should return either: Note also that values that are printed inside the function will also be a part of the command's standard output. For example:
def _mycmd(args, stdin=None):
    print('I go to stdout and will be printed or piped')
    return (None, "I failed", 2)

25.2) "Streaming" Process Proxy

Note that the form above does not allow for streaming of its input or output; rather, it assumes that its entire input comes in as one chunk, and that its entire output should be produced as a single chunk as well.

However, there is an alternate form that allows for this kind of streaming. This kind of Python function alias takes 4 arguments:

The function should return a single integer representing its return code.

Here is a simple example:

def _echo(args, stdin, stdout, stderr):
    x = stdin.read(1024)
    stdout.write(x)
    stderr.write(x)
    return 0

25.3) Adding Aliases

We can dynamically alter the aliases present simply by modifying the built-in mapping. Here is an example using a function value:
~ $ def _foo(args, stdin=None):
...     return 'The arguments were: %s' % ' '.join(args)
~ $ $TAKO_SETTINGS.aliases['foo'] = _foo
~ $ foo bar baz
The arguments were: bar baz
~ # foo bar baz | grep baz # pipes, I/O redirection, etc, still work!
The arguments were: bar baz

Alias functions should generally be defined with a leading underscore. Otherwise, they may shadow the alias itself, as Python variables take precedence over aliases when tako executes commands.

26) Event Hooks

It is possible to register functions to be run in response to particular events in tako. These "hooks" are maintained in $TAKO_SETTINGS.hooks, which is a dictionary mapping hook event names to lists of functions to be called in response to that event. The following hooks are currently supported: For example:
~ $ $TAKO_SETTINGS.hooks['on_chdir'].append(lambda new, old: print('we moved to %s!' % new))
~ $ cd tako
we moved to /home/takofan123/tako!
~/tako $ cd
we moved to /home/takofan123!
~ $
~ $ $TAKO_SETTINGS.hooks['post_command'].append(lambda result: print(':)' if result else ':('))
~ $ cd
we moved to /home/takofan123!
:)
~ $ ls nonexistent
/bin/ls: cannot access 'nonexistent': No such file or directory
:(

27) Other Settings

The following other values can also be set inside the $TAKO_SETTINGS object:

27.1) General

27.2) cd Behavior

27.3) Interpreter

27.4) Interactive Prompt

27.5) Tab Completion

28) Plugins

As of version 0.2.0, tako also provides an interface for plug-ins, which can be used to extend or modify the base features of tako. Each plugin takes the form of a single .tako file. To install a plugin, simply place that .tako file in ~/.config/tako/plugins.

A small number of "official" plugins are available from the Git repository at git://hz.mit.edu/tako-plugins.git. Some may be available from third parties, as well (but please only install plugins from trusted sources and perform an audit of the code yourself where possible, since plugins can execute arbitrary code on your machine).

Plugins' configurations options are available from the $TAKO_SETTINGS.plugins object. For example, to configure the frecency plugin, one can modify $TAKO_SETTINGS.plugins.frecency.frecency_max_items.

28.1) Writing Plugins

In addition to installing plugins from other sources, it is of course also possible to create plugins of your own. Note, though, that, due to tako's license, plugins are almost certainly required to be licensed under the same terms as tako itself (the GPLv3+).

Plugins take the form of a single .tako file, which is executed just before the user's main run control file. A plugin can contain arbitrary code (and so can be used to modify features of tako itself), but it is executed in a separate environment (so, for example, variables set in the plugin's file are not directly accessible from the global tako environment).

Plugins are provided with a special PLUGIN_SETTINGS variable, which can be used for storage of relevant state and/or configuration options specific to the plugin. In addition, plugins can register their own aliases and hooks by adding functions to the PLUGIN_SETTINGS.aliases and PLUGIN_SETTINGS.hooks mappings (whose interfaces are the same as their counterparts in $TAKO_SETTINGS. The PLUGIN_SETTINGS object is accessible from the global tako environment as $TAKO_SETTINGS.plugins.your_plugin_name.

For reference, a few example plugins are available in the Git repository at git://hz.mit.edu/tako-plugins.git

29) Programmable Tab Completion

tako also provides a mechanism by which the results of a tab completion can be customized (i.e., new completions can be generated, or a subset of the built-in completions can be ignored).

This section details the internal structure of tako's completion system and includes instructions for implementing new tab completion functions.

29.1) Structure

tako's built-in completers live in the tako.completers package, and they are managed through an instance of OrderedDict (__tako_completers__) that maps unique identifiers to completion functions.

When the "tab" key is pressed, tako loops over the completion functions in order, calling each one in turn until it reaches one that returns a non-empty set of completion for the current line. This set is then displayed to the user.

29.2) List of Active Completers

A list of the active completers can be viewed by running the completer list command. This command will display names and descriptions of the currently-active completers, in the order in which they will be checked.

29.3) Writing a New Completer

Completers are implemented as Python functions that take five arguments:
  1. prefix: the string to be matched (the last whitespace-separated token in the current line)
  2. line: a string representing the entire current line
  3. begidx: the index at which prefix starts in line
  4. endidx: the index at which prefix ends in line
  5. ctx: the current Python environment, as a dictionary mapping names to values

This function should return a Python set of possible completions for prefix in the current context. If the completer should not be used in this case, it should return None or an empty set, which will cause tako to move on and try to use the next completer. If a completer raises StopIteration, then following completers will not be tested, and an empty set of results will be returned.

The docstring of a completer should contain a brief description of its functionality, which will be displayed by completer list.

Three examples follow. For more examples, see the source code of the completers tako actually uses, in the tako.completers module.

def dummy_completer(prefix, line, begidx, endidx, ctx):
    '''
    Completes everything with options "hardshell" and "softshell",
    regardless of the value of prefix.
    '''
    return {"hardshell", "softshell"}
def python_context_completer(prefix, line, begidx, endidx, ctx):
    '''
    Completes based on the names in the current Python environment
    '''
    return {i for i in ctx if i.startswith(prefix)}

29.4) Registering a Completer

Once you have created a completion function, you can add it to the list of active completers via the completer add command:
Usage:
    completer add NAME FUNC [POS]

where NAME is a unique name to use in the listing, FUNC is the name of a completer function to use, and POS (optional) is a position into the list of completers at which the new completer should be added. POS can be one of the following values:

If POS is not provided, it defaults to "start".

Note: It is also possible to manipulate __tako_completers__ directly if that is easier.

29.5) Removing a Completer

To remove a completer from the list of active completers, run completer remove NAME, where NAME is the unique identifier associated with the completer you wish to remove.

 

 ____ 
( oo )
_||||_

Creative Commons License
The contents of this page are licensed under a
Creative Commons Attribution-ShareAlike 4.0 International License.

The web site is available online at https://takoshell.org, or as a Tor "onion service" at http://takoezpr7wxrc7d6.onion or http://tehbemfqolualhxwkyimu3bdob5s4hkrfuwbwxzbblncjy2j2owgolqd.onion.

The source code for the web site is available in a git repository: git clone git://hz.mit.edu/takoshell.org.git.