API Reference
The API Reference explains how to access various match and rewrite information in Comby if you want to integrate or build other tooling (like an editor plugin or grammar fuzzer).
There are three operations for information: match, rewrite, and
substitute.
To perform these operations and access the results, there are three options:
- Use Python bindings for Comby.
- Invoke Comby directly on the command line.
- Use HTTP requests to a persistent server that you run on your machine.
Python Bindings
See the interface.py file that describes the operations and data types when using Python bindings.
Command Line
The command line is a bare-bones interface to perform operations, but useful for understanding the schema–consider using the Python bindings or a server to avoid command line awkwardness.
Match
Retrieve match information by using the -match-only flag. For example:
echo 'printf("hello!");' | comby 'printf(:[arg])' '' .c -stdin -match-only
Note:
combycurrently expects a rewrite template in the second anonymous argument. When using-match-only, simply use an empty string like above.
The -match-only option will only print out the entire matched string on the
command line. Add the -json-lines flag to get all information on matched
ranges and matched holes.
comby 'printf(:[arg])' '' .c -stdin -match-only -json-lines
This outputs JSON information, one line per match (in this case, the printf(...) part). We can make the format more readable by piping the output to python -m json.tool.
Schema example
{
"uri": null,
"matches": [
{
"range": {
"start": {
"offset": 0,
"line": 1,
"column": 1
},
"end": {
"offset": 16,
"line": 1,
"column": 17
}
},
"environment": [
{
"variable": "arg",
"value": "\"hello!\"",
"range": {
"start": {
"offset": 7,
"line": 1,
"column": 8
},
"end": {
"offset": 15,
"line": 1,
"column": 16
}
}
}
],
"matched": "printf(\"hello!\")"
}
]
}
uriis the file path of the document containingmatches(nullforstdin)matchesis a list ofmatches(likeprintf(...). Each item inmatchescontains:matched, the string that was matched by the templaterange, the range spanned bymatchedenvironment, containing a list ofvariable,value, andrangeitems where:variableis the hole identifiervalueis the string value bound tovariablerange, the range spanned byvalue
range contains offset, line, and column where:
☞
offsetstarts at zero☞
lineandcolumnstart at one
Rewrite
The rewrite operation is similar to match. Use the -json-lines flag with a rewrite template as in:
echo 'printf("hello!");' | comby 'printf(:[arg])' 'printf("bye")' .c -stdin -json-lines
Schema summary
{
"uri": null,
"rewritten_source": "printf(\"bye\");\n",
"in_place_substitutions": [
{
"range": {
"start": {
"offset": 0,
"line": -1,
"column": -1
},
"end": {
"offset": 13,
"line": -1,
"column": -1
}
},
"replacement_content": "printf(\"bye\")",
"environment": []
}
],
"diff": "--- /dev/null\n+++ /dev/null\n@@ -1,1 +1,1 @@\n-printf(\"hello!\");\n+printf(\"bye\");"
}
uricorresponds to the changed file (nullforstdin)rewritten_sourceis result of the entire rewritten file (or input forstdin)diffis a patch-compatiblediffof the changein_place_substitionsis a list of substituted fragments where:replacement_contentis the fragment substituted in-place for matchesrange, the range spanned byreplacement_contentenvironment, a list ofvariableandvalueof holes used in this result, with the updatedrange
☞ Adding the
-json-only-diffflag will output thediffvalue of the change (useful if you only care about the resulting diff).
⚠ Current Limitations
Rewrite ranges currently do not report line and column values and are set to -1
If a hole with the same identifier is used multiple times in the rewrite template,
environmentwill currently report only the first range
Substitute
Substitute an environment inside a rewrite template with the -substitute flag. An example invocation is:
comby '' ':[1] :[2]' -substitute '[{"variable":"1","value":"hello"},{"variable":"2","value":"there"}]'
The output is only the rewritten output hello there.
Note:
combycurrently expects a match template in the first anonymous argument. When using-substitute, simply use an empty string like above.
Walked example
One way to effectively use -substitute in scripting is by combining it with other operations. For example, Use jq to extract environments from matches:
echo 'printf("hello", "there")' \
| comby 'printf(":[1]", ":[2]")' '' .c -stdin -json-lines -match-only \
| jq -c '.matches | map(.environment) | .[]'
The environment can be substituted by piping to xargs and using -substitute:
echo 'printf("hello", "there")' \
| comby 'printf(":[1]", ":[2]")' '' .c -stdin -json-lines -match-only \
| jq -c '.matches | map(.environment) | .[]' \
| xargs -0 comby '' ':[1] :[2]. General Kenobi!' -substitute
And we’ll see hello there. General Kenobi!.
Comby server
To use the server, you’ll need to build from source. See the README instructions for comby-server.
The comby server exposes the three HTTP POST endpoints below. These return the
same JSON values as the respective command line operations.
The endpoints accept options like rule and language corresponding to
command line flags.
/match
{"source": "hello there", "match": "hello :[1]", "rule": "where :[1] == \"there\"", "language": ".generic", "id": 0}
sourceshould be the entire source file to rewriteidis an identifier for this request, which will be set in the corresponding response
/rewrite
{"source": "hello there", "match": "hello :[1]", "rule": "where :[1] == \"there\"", "rewrite": "kenobi", "language": ".generic", "substitution_kind": "in_place", "id": 0}
substitution_kind can be one of in_place or newline_separated. When
newline_separated is chosen, rewritten fragments are output one per line,
rather than replaced in-place in the original document.
/substitute
{"rewrite_template": "print(:[1])", "environment": "[{\"variable\":\"1\",\"value\":\"hello\"}]", "id": 0}
Set the DEBUG environment variable to see verbose incoming and outgoing data.