- I use this plugin and find it useful.
- N/A
0 voters
KiCommand allows simple command strings to be executed within pcbnew.
Command strings consist of a variety commands that retrieve, filter, and
process Kicad objects. Commands are very easily added with a simple syntax. KiCommand is a stack-based language designed for command line entry.
The KiCommand discussion page is located here. That thread is for asking questions and retaining the history of discussion. This wiki page is honed for up to date information and a tutorial.
Getting Started
The Readme.md file on github should be up to date. It is a great introduction and overview of KiCommand. Read through the Readme.md first to get a general overview. This Tutorial assumes you know about the stack and how to place things on it. In the current document, we’ll walk through the very basics of getting to know KiCommand. We start with the stack, show some examples, and I encourage you to follow along with KiCommand open. Try some commands while reading through this hands-on Tutorial!
In the Readme.md file are the basics, try following steps to install and run KiCommand. If you have trouble, please post on the KiCommand discussion page to get help:
- installation
- run the KiCommand tests to verify installation
- start KiCommand, currently requires selecting “Refresh Plugins” on the “Tools > External Plugins…” menu. The KiCommand window will pop up.
- read overview (stack, capitalization, command structure, calling python)
What the heck is going on?
Entering Commands
Enter commands in the command entry text box and the output, if any, is shown in the window below the text box. You can enter single commands one at a time, or string together many command arguments and commands, each separated by spaces. If an entry is not recognized as a command, it will be placed on the top of the stack to be used as an argument for a future command. Try it!
- clear - clear the stack
- 1 - not a command, so this is placed at the top of the stack
- stack - you should see the (string) value “1” as the only element in the stack.
Now try entering this all at once in the command entry text box:
- clear 1 stack - the results should be identical to the previous example
Now put two items on the stack:
- clear itemA itemB stack - you will see two items on the stack, itemA and itemB.
Get and keep your bearings
Several commands are useful for getting and keeping your bearings while using KiCommand. The “entry point” for getting help is the help command, which also appears on startup. If you get lost, type help in the command window and you’ll see further commands for getting help.
- help - overall help, start here
- All helpcat - list all commands by category
- ’command explain - list specific help for command
- stack - print all elements of the stack. This is the command to show the stack and understand the current state of KiCommand.
- print - print the top element of the stack
Any of these commands can be entered without affecting the stack. Use them liberally.
If you mistype a command and it’s not recognized, try the following commands
- print - verify top element of the stack
- pop - remove the top (mistake) element of the stack
- print - verify (the new) top element of the stack
Working with the stack
You should have already tried basic commands like clear itemA itemB stack to put two items on the stack and view the result. Here we’ll review some basic stack manipulation commands. The primary commands are
- swap - exchange the positions of the top two elements from the stack.
- pop - remove the top item from the stack.
swap
Let’s see these in action!
- clear itemA itemB stack - this will print “itemA itemB”. These are the two items on the stack, with itemB on the “top”.
- swap stack - this will print “itemB itemA”, demonstrating that itemA is now at the top of the stack. They’re swapped!
Now let’s try it all in one:
- clear - clear the stack to prepare for the following commands.
- itemA itemB swap - the stack is now “itemB itemA” with itemA at the top.
- stack - print out the stack to verify the previous command worked!
pop
pop simply removes the top of the stack and throws it away.
- clear itemA itemB stack - prepare the stack and view it
- pop - remove the top item from the stack
- stack - view the resulting stack. It should contain only itemA
And now all in one:
- clear itemA itemB swap pop stack - can you follow what this is doing? Try to determine what this is doing, then verify by running it.
copy and pick
The copy command simply duplicates the top of the stack.
- clear itemA copy stack - prints out “itemA itemA” indicating that itemA is on the stack twice.
If you need to copy something from deeper in the stack, use the pick command. So far, we’ve executing commands that don’t need arguments. pick is different: it requires one argument. How deep from the top of the stack do you want to pick? When executed, the pick command gets and removes the argument from the top of the stack and places the result of the command on the top. As you can see, arguments for a command are put on the stack before the command.
- pick - duplicate an item on the stack and place the duplicate at the top. The 0 item is the top of the stack, 1 is the second from the top, etc.
Let’s try pick:
- 15 14 13 12 11 10 4 pick print - prints “14”
- stack - this shows the full stack as “15 14 13 12 11 10 14”
- notice that the “4” is the argument to pick. It was removed from the stack when pick command ran.
You may have noticed that you could implement the copy command using pick. How would you do it? Take a guess, then see if you were right. Try using 'copy see to look at the definition of copy. Don’t worry if the output doesn’t quite make sense. I’ll explain the output further below under Investigating commands and definitions.
Basic types: string, int, float, list
When you type a command string, it is separated into individual words separated by spaces. Each word is is either an item or a command. items are simply placed on the stack as a string. commands are executed by taking arguments, if any, from the stack, executing the command and placing the result, if any, on the top of the stack.
For example:
- clear stringone stringtwo stringthree stack - this will show three string items on the stack.
- clear 1 2 3 stack - this will also show three strings on the stack.
Most commands will automatically convert arguments to the correct type. But we can also explicitly convert between types.
- clear 2 stack - this will print “2”, which is the string item
- float stack - this will convert the string “2” into a float, and print it out the resulting stack: “2.0”.
Because it is difficult to see the difference between a string and an int on the stack, we use float here so we can see the conversions happening.
When converting from floats to ints, numbers are rounded towards zero (this is known as truncating, aka chopping off the decimal portion):
- 1.6 int - result: 1
- -1.6 int - result: -1
The string command will convert a value to its string representation. For simple objects such as floats and integers, the result is straightforward. And the resulting value can be converted back into an int or float easily. For more complex objects, the string command will output the string representation which usually cannot be converted back into the object. Note that the print command will convert a value to its string representation when printing.
- stringvalue string - doesn’t do anything useful because stringvalue is already a string.
- 1 float string - will output 1.0 as a string.
Lists
Lists are very useful in KiCommand. Many pcb board elements come in lists and many operations work seamlessly with lists as well as individual items. A list can be created from scratch with a comma-separated list of values (no spaces!). Let’s create a list:
- 1,2,3,4,5 int - creates a list of five integers. Remember to not put spaces within the list of numbers.
- 1,2,3,4,5 float - creates a list of five floats.
When printing results, square brackets will surround the list values. For example, “[1,2,3,4,5]” is a list containing five integer values. Generally, a command will be executed for each member of a list and the return value is a list containing the results. A list is simply collection of values, where order matters. A list can be contain any mixture of types.
- 1,2,3,4,5 int - [1, 2, 3, 4, 5] - a list of five ints.
- 1,2,3,4,5 float - [1.0, 2.0, 3.0, 4.0, 5.0] - a list of five floats.
- 1,2,3,4,5 split - [u’1’, u’2’, u’3’, u’4’, u’5’] - a list of five strings.
Most basic operations will convert a comma-separated string value into a list. To convert a comma-separated string value explicitly to a list of strings, use the split command.
- 1,2,3,4,5 split - results in a list of five strings!!
- 1,2,3,4,5 split int - the split here is redundant because int does the split for you prior to the conversion to integers.
concat will concatenate lists and will concatenate strings. It also has the side effect of adding integers, but you should really use the + command for that.
- one two concat - results in onetwo
- 1 2 concat - results in 12.
- 1,2 int 3,4 int concat - results in a list of integers: [1,2,3,4]
append and extend
Two useful commands to manipulate lists are append and extend.
append will append the item at the top of the stack (in this case, the second argument) to the list given as the first argument. extend will add the contents of the list that is the second argument to the list that is the first argument. Note the subtle difference is the commands below:
- 1,2 int 3,4 int extend - [1, 2, 3, 4]
- 1,2 int 3,4 int append - [1, 2, [3, 4]]
- 1,2 int list 3,4 int append - [[1, 2], [3, 4]]
len
Finally, you can use the len command to determine the length of the list. This also has the side effect of giving you the length of a string.
- 1,2 int len - result: 2
- 1,2 split len - result: 2
- 1,2 len - result: 3. Note that this is the length of the string “1,2”. It counts each digit and the comma within the string.
- 1,2 int 3,4 int concat len - result: 4
Numeric operations
Numeric calculations can be used on ints, floats, or lists of ints or floats. The results are pretty straightforward. Add, Subtract, Multiply and Divide are all available using their traditional symbols: +, -, * and /. These commands also automatically convert arguments to float, but will not split comma-separated strings.
- 2 3 + - result: 5
- 2 3 - - result: -1
- 2 3 + - result: 6
- 2 4 / - result: 0.5
Be careful about floating point vs integer math. If you need to make sure you’re using integer math, explicitly convert values to integers.
Try running the following two commands and compare the results.
- 5 3 / 5 3 / + - the result is based on floating point math
- 5 3 / int 5 3 / int + - remember that int will truncate the value (i.e. round towards zero).
Math on lists
Each of the basic numeric operator has a corresponding function that operates on a list of numbers. The operators are followed by a dot “.”:
- +.
- -.
- *.
- /.
- 1,2,3 float 2 *. - result: [2.0, 4.0, 6.0]
These are useful when working with lists of numbers. They also, by default, can handle a variety of input conditions.
When the first operand is a list and the second is a number, each member of the list is operated on using the number as the second operand. When both operands are lists, then the lists are operated on member by member. The second list is repeated and/or truncated to match the length of the first list.
- 1,2,3 float 2,3 float *. - result: [2.0, 6.0, 6.0]
- 7,8,9 float 2,3 float *. print - result: [14.0, 24.0, 18.0]
- 7,8,9,10,11 float 2,3 float *. print - result: [14.0, 24.0, 18.0, 30.0, 22.0]
We’ll use the automatically-repeating list operators when working with pcb elements.
Unit conversion
Numbers within KiCAD commands and objects are usually using the native units: nanometers. You can convert numbers to nanometers with the mm, mil, and mils commands. These can convert single values or lists, and a comma-separated string will automatically be converted into floats.
- 23 mm - results in 23000000.0. 23nm is equal to 23000000nm
- 23 mils - results in 584200.0
- 23 mil - results in 584200.0. The mil and mils commands are identical.
- 1,2,3,4,5 mm - results in [1000000.0, 2000000.0, 3000000.0, 4000000.0, 5000000.0]
Lesson
Now that you have some commands under your belt, try creating a function that converts from native units (nanometers) into millimeters using three functions: multiply list (*.), divide (/), and mm. Note that currently, there is no divide list command (/. does not exist, yet).
Boolean
The bool command converts the argument into True or False. A list of values is converted into a list of True/False values. A False value is an empty string, 0 integer or 0.0 float. Also, any other python value/object that is not None is converted to True.
- ’ bool - results in False. The single quote mark followed by a space creates an empty string.
- 0 bool - results in True!! The “0” by itself is a string and the string is non empty, therefore bool converts it to true!
- 0 int bool - results in False
- 0.0 bool - results in True!!
- 0.0 float bool - results in False
- 0 float bool - results in False. This is the same as the previous since 0 float and 0.0 float both result in the floating point value of 0.0.
- 0,1,0,1,0 bool - results in [True, True, True, True, True]. Remember these are strings until you convert them to int or float!
- 0,1,0,1,0 int bool - results in [False, True, False, True, False]
Filters
Now that you know boolean values, you can use them with the filter command.
- clear 45,76,54,12,15,56,87,16 split copy 1.* regex filter print - get all values that start with “1”.
- 1 list ’ bool list filter - creates an empty list
- zones copy getnetname OLDNAME = filter NEWNAME findnet SetNet callargs - get zones connected to net with OLDNAME, then set them to net with NEWNAME.
Let’s break this last one down. The copy, =, and filter commands are very common together.
- zones - all zone objects
- copy getnetname - make a copy of all zones, get a parallel array of netnames corresponding to each zone. Now on the stack we have a list of zones followed by the list of their corresponding net names.
- OLDNAME = - convert the net names to an array, with True where the net name is equal to OLDNAME and False where it isn’t. After this command, we have the list of zones, the original used when we copied, and a parallel list of true/false values. This could just as easily be any set of commands that results in an array of true/false values corresponding to the list of zones, such as REGEX regex (calling the command regex with argument REGEX), or other commands in the Comparison category.
- filter - this takes the top two elements of the stack and filters the first one using the true/false values in the second argument. The result of this is a list of zones with a net name corresponding to OLDNAME.
- NEWNAME findnet - is the command to find the NETINFO object of the net with name NEWNAME. Now on the stack we have the list of zones with netname matching OLDNAME followed by the NETINFO object of the net with NEWNAME.
- SetNet callargs - finally, this calls the SetNet command with the NETINFO object as the argument on each of the zones in the list.
This is a common method to get a filtered list of items.
- get a full list of items
- copy the list of items, then get an attribute of the items
- filter the list of items based on the value of the attribute.
- repeat steps 2 and 3 as many times as desired.
- do something with the filtered list of items.
Advanced types: dict(ionary), list of lists
Python dictionaries can be built with two parallel lists using the dict command.
- one,two,three split 1,2,3 int dict print - result: {u’three’: 3, u’two’: 2, u’one’: 1}
Then you can extract one value using sindex:
- two sindex print - result: 2
The sindex command is string index and allows you to get a member of a dictionary using a string index value, much like index does for lists in python.
A List Of Lists argument is necessary for some commands, such as callargs. The simplest List Of Lists is a list containing a single-item list (this looks like [[1]]) and can be created with the command list. To create a list of lists containing a single list which contains a single integer, you would use the following command:
- 1 int list list - create a list containing a list containing an integer.
The int command converts the string “1” to an integer. The first list command puts that integer into a single list. The second list command wraps that into another list. If we wanted to create a list of integers in another list, we use
- 1,2 int list - create a single list as the only item within another list.
Note that in this case, the int command itself creates the first list, when the argument to int is a comma-separated string with integers in it.
Once you have the first list, you can append another list to it.
- 1,2 int list 3,4 int append 5,6 int append - [[1,2],[3,4],[5,6]]
list. (list with a dot after it)
To take each element within a list, and convert it to a list, use the list. command. This will allow you to work with callargs more effectively. If the function you use in callargs takes a single argument and you want to call the function multiple times, each with an element of the argument list, you will need to create a list of lists from the single list.
- 1,2,3,4,5 int list. print - [[1], [2], [3], [4], [5]]
pairwise
To collect each list in a list of lists into pairs of values, use pairwise. The primary purpose of pairwise is to transform a list of point lists into x/y coordinates. For this reason, pairwise requires a list of lists to start and ends with a list of list of point pairs. This is a little cumbersome if you only have a single list of numbers, but can work if you need it.
- 1,2,3,4,5,6 int pairwise print - this is an error, the argument needs to be a list of lists, not just a single list. To do what is intended here, do the following:
- 1,2,3,4,5,6 int list pairwise print - [[(1, 2), (3, 4), (5, 6)]]
- 1,2,3,4,5,6 int list 7,8,9,10,11,12 int append pairwise print - [[(1, 2), (3, 4), (5, 6)], [(7, 8), (9, 10), (11, 12)]]
Useful command for manipulating lists and list of lists include zip, zip2
zip takes one argument and will join the first elements of each list into the first element of the result, and so on with second elements, etc.
- zip - run right after the previous command, the result is [[1,3,5],[2,4,6]]
Note that zip is its own inverse: run it again to return the original list.
-
zip - run again to return the original list [[1,2],[3,4],[5,6]]
-
zip2 - takes two arguments, and treats it as a two-element list for zip. Technically, this is the same as swap list swap append zip.
Finally, you can undo a listoflists into a single list using flatlist
- 1,2 int list 3,4 int append 5,6 int append - [[1,2],[3,4],[5,6]]
- flatlist - [1,2,3,4,5,6]