Convert Figma logo to code with AI

comby-tools logocomby

A code rewrite tool for structural search and replace that supports ~every language.

2,366
60
2,366
74

Top Related Projects

2,441

Tools for code analysis, visualizations, or style-preserving source transformation.

10,341

Lightweight static analysis for many languages. Find bug variants with patterns that look like source code.

An incremental parsing system for programming tools

Quick Overview

Comby is a tool for searching and rewriting code. It uses a unique pattern matching language that works across many programming languages and file formats. Comby aims to make structural code changes easier and more reliable than traditional regex-based approaches.

Pros

  • Language-agnostic: Works with many programming languages and file formats
  • Powerful pattern matching: Supports structural matching beyond simple regex
  • Easy to use: Simple syntax for common operations
  • Extensible: Can be integrated into other tools and workflows

Cons

  • Learning curve: Requires learning a new pattern matching syntax
  • Limited to structural changes: Not suitable for complex semantic transformations
  • Performance: May be slower than language-specific tools for large codebases
  • Documentation: Could benefit from more extensive examples and use cases

Code Examples

  1. Basic match and rewrite:
comby 'printf(":[1]");' 'console.log(":[1]");' .js

This command replaces all printf calls with console.log in JavaScript files.

  1. Using hole variables:
comby 'function :[name](:[args]) { :[body] }' 'const :[name] = (:[args]) => { :[body] }' .js

This transforms traditional function declarations into arrow functions.

  1. Using where clauses:
comby 'if (:[condition]) { :[then_branch] } else { :[else_branch] }' ':[condition] ? :[then_branch] : :[else_branch]' .js -match-only 'where :[then_branch] != "..."'

This converts if-else statements to ternary operators, but only when the then branch is not a block.

Getting Started

To get started with Comby:

  1. Install Comby:

    bash <(curl -sL get.comby.dev)
    
  2. Run a basic match and rewrite:

    comby 'foo(:[1])' 'bar(:[1])' .py
    
  3. For more advanced usage, refer to the official documentation at https://comby.dev/docs/

Competitor Comparisons

2,441

Tools for code analysis, visualizations, or style-preserving source transformation.

Pros of pfff

  • More comprehensive static analysis toolset with support for multiple languages
  • Includes advanced features like type inference and dataflow analysis
  • Offers visualization tools for code structure and dependencies

Cons of pfff

  • Less actively maintained (last commit in 2019)
  • Steeper learning curve due to its complexity
  • Limited documentation and community support

Code Comparison

pfff (OCaml):

let parse_program file =
  let ast = Parse_php.parse_program file in
  let ast = Ast_php_simple_build.program ast in
  ast

Comby (Pattern matching):

:[prefix]function :[name](...) {
  :[body]
}

Key Differences

  • pfff is a more comprehensive static analysis tool, while Comby focuses on pattern matching and rewriting
  • pfff is written in OCaml, whereas Comby uses its own pattern matching language
  • Comby is more actively maintained and has better documentation
  • pfff offers deeper analysis capabilities, but Comby is easier to use for quick code transformations

Use Cases

  • Use pfff for in-depth static analysis and visualization of large codebases
  • Choose Comby for quick, language-agnostic code refactoring and pattern matching tasks
10,341

Lightweight static analysis for many languages. Find bug variants with patterns that look like source code.

Pros of Semgrep

  • More extensive language support, covering 30+ languages
  • Advanced features like taint analysis and dataflow tracking
  • Large rule database with community-contributed rules

Cons of Semgrep

  • Steeper learning curve for creating custom rules
  • Slower performance on large codebases compared to Comby
  • More complex setup and configuration process

Code Comparison

Semgrep rule example:

rules:
  - id: detect-eval
    pattern: eval($X)
    message: "Dangerous use of eval()"
    languages: [python]
    severity: WARNING

Comby pattern example:

eval(:[arg])

Both tools aim to improve code quality and security through pattern matching, but they differ in approach and complexity. Semgrep offers more advanced features and broader language support, making it suitable for complex analysis tasks. Comby, on the other hand, provides a simpler, faster solution for basic pattern matching across multiple languages.

Semgrep's rule-based approach allows for more nuanced and context-aware checks, while Comby's lightweight design enables quick and easy pattern matching without the need for language-specific parsing.

Choose Semgrep for comprehensive, language-aware analysis in large projects, and Comby for rapid, language-agnostic pattern matching and transformation tasks in smaller codebases or specific use cases.

An incremental parsing system for programming tools

Pros of Tree-sitter

  • More robust parsing with full syntax trees
  • Supports incremental parsing for better performance
  • Wider language support out-of-the-box

Cons of Tree-sitter

  • Steeper learning curve for creating and modifying grammars
  • Requires more setup and integration effort
  • Less flexible for quick, pattern-based searches

Code Comparison

Tree-sitter grammar example:

module {
  rules {
    source_file: $ => repeat($._definition),

    _definition: $ => choice(
      $.function_definition,
      $.variable_declaration
    ),

    function_definition: $ => seq(
      'func',
      $.identifier,
      $.parameter_list,
      $.block
    )
  }
}

Comby pattern example:

func :[name](...) {
  :[body]
}

Tree-sitter provides a more comprehensive parsing solution, generating full syntax trees for supported languages. It offers better performance for large codebases and incremental parsing capabilities. However, it requires more setup and has a steeper learning curve for creating custom grammars.

Comby, on the other hand, focuses on simpler pattern-based matching and rewriting. It's more flexible for quick searches and transformations but may not handle complex language constructs as accurately as Tree-sitter.

Convert Figma logo designs to code with AI

Visual Copilot

Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.

Try Visual Copilot

README

comby

Apache-2.0 codecov Downloads Commit

See the usage documentation.

A short example below shows how comby simplifies matching and rewriting compared to regex approaches like sed.

Comby supports interactive review mode (click here to see it in action).

Install (pre-built binaries)

Mac OS X

  • brew install comby

Ubuntu Linux

  • bash <(curl -sL get-comby.netlify.app)

  • Other Linux distributions: The PCRE library is dynamically linked in the Ubuntu binary. For other distributions like Arch Linux, a fixup is needed: sudo ln -s /usr/lib/libpcre.so /usr/lib/libpcre.so.3. On Fedora, use sudo ln -s /usr/lib64/libpcre.so /usr/lib64/libpcre.so.3. Alternatively, consider building from source.

Windows

Docker

  • docker pull comby/comby
click to expand an example invocation for the docker image

Running with docker on stdin:

docker run -a stdin -a stdout -a stderr -i comby/comby '(:[emoji] hi)' 'bye :[emoji]' lisp -stdin <<< '(👋 hi)'

Or try it live.

Isn't a regex approach like sed good enough?

Sometimes, yes. But often, small changes and refactorings are complicated by nested expressions, comments, or strings. Consider the following C-like snippet. Say the challenge is to rewrite the two if conditions to the value 1. Can you write a regular expression that matches the contents of the two if condition expressions, and only those two? Feel free to share your pattern with @rvtond on Twitter.

if (fgets(line, 128, file_pointer) == Null) // 1) if (...) returns 0
      return 0;
...
if (scanf("%d) %d", &x, &y) == 2) // 2) if (scanf("%d) %d", &x, &y) == 2) returns 0
      return 0;

To match these with comby, all you need to write is if (:[condition]), and specify one flag that this language is C-like. The replacement is if (1). See the live example.

Build from source

  • Install opam. TL;DR do sh <(curl -sL https://raw.githubusercontent.com/ocaml/opam/master/shell/install.sh)

  • Run this if you don't have OCaml installed (it bootstraps the OCaml compiler):

opam init
opam switch create 4.11.0 4.11.0
  • Run eval $(opam env)

  • Install OS dependencies:

    • Linux: sudo apt-get install autoconf libpcre3-dev pkg-config zlib1g-dev m4 libgmp-dev libev4 libsqlite3-dev

    • Mac: brew install pkg-config gmp pcre libev

  • Then install the library dependencies:

git clone https://github.com/comby-tools/comby
cd comby 
opam install . --deps-only
  • Build and test
make
make test
  • Install comby on your PATH by running
make install