Skip to content

srgn: v0.13.0

Compare
Choose a tag to compare
@alexpovel-ci-machine alexpovel-ci-machine released this 18 Aug 14:26
b3fb9fa

0.13.0 (2024-08-18)

Highlights

srgn is a tool for precise search and manipulation of text, with special support for source code in a number of languages (Rust, Python, Go and more). The main highlight in this release is a new search mode. Think of it like (rip)grep, which this is modeled after, with an additional understanding of source code syntax (and an option for manipulating, not just displaying findings). Search mode is entered when no manipulation is requested and a programming language is specified. For example, searching the pydantic repo:

$ srgn --python class --python doc-strings 'github\.com'
pydantic/networks.py
381:            [`email-validator`](https://github.com/JoshData/python-email-validator) package:
426:        [`email-validator`](https://github.com/JoshData/python-email-validator) package:

pydantic/config.py
732:    See [#6737](https://github.com/pydantic/pydantic/pull/6737) for details.
744:    serialization. See [#7209](https://github.com/pydantic/pydantic/issues/7209) for more details.

<SNIP>

The regex github\.com was sought and found only within docstrings within class bodies (aka, intersection works left-to-right), in all Python source code files of the working directory, recursively. Docstrings outside of class bodies were not considered. Relevant files are found by consulting file extensions and shebang lines, a heuristic that can optionally be overwritten by a custom glob.

Variables

As another example, with the support for variables also landing as part of this release, one could rewrite GitHub issue links in only docstrings and comments (and not, for example, in "literal strings" of source code) with an invocation of

$ srgn --join-language-scopes --python comments --python doc-strings ' (https://github\.com/(\w+)/(\w+)/issues/(\d+)/?) ' ' [issue $2/$3/$4]($1) '
pydantic/fields.py
pydantic/_internal/_model_construction.py
pydantic/_internal/_generics.py
pydantic/mypy.py
pydantic/v1/typing.py
pydantic/v1/validators.py
pydantic/v1/mypy.py
tests/test_edge_cases.py

turning them into into Markdown-formatted links (srgn prints names of processed files to stdout), e.g.

-    See https://github.com/pydantic/pydantic/issues/6763 for context.
+    See [issue pydantic/pydantic/6763](https://github.com/pydantic/pydantic/issues/6763) for context.

The variables ($1, ...) in the replacement string are populated from regex capture groups. The --join-language-scopes flag configures comments and doc-strings to be jointly considered (and not just "doc-strings inside comments" as before, which would probably come up empty).

Focus

srgn builds on top of the excellent tree-sitter family of parsers. Its main focus is on search with just that little bit of extra precision regular expressions cannot offer on their own (in the context of language grammars). For large-scale, demanding refactoring efforts, consider one of the various similar tools: srgn is focused on simplicity, with very obvious mechanisms and good discoverability. For example, it will give you a list of available options if an invalid one is specified:

$ srgn --rust class
error: invalid value 'class' for '--rust <RUST>'
  [possible values: comments, doc-comments, uses, strings, attribute, struct, priv-struct, pub-struct, pub-crate-struct, pub-self-struct, pub-super-struct, enum, priv-enum, pub-enum, pub-crate-enum, pub-self-enum, pub-super-enum, enum-variant, fn, impl-fn, priv-fn, pub-fn, pub-crate-fn, pub-self-fn, pub-super-fn, const-fn, async-fn, unsafe-fn, extern-fn, test-fn, trait, impl, impl-type, impl-trait, mod, mod-tests, type-def, identifier, type-identifier, closure]

For more information, try '--help'.

In other words: there is no query language to learn. If you know regex and the basics of your language of choice, you are golden. Shell completions then make writing srgn invocations quick and easy.

Performance

Lastly, srgn is designed for performance: all processing happens in fast, native code (either C via tree-sitter or Rust). For example, running in the enormous kubernetes repo, the following completes in just 1 second (on M3 Pro, warm cache), finding about 9000 results of struct tags containing omitempty markers:

srgn --go struct-tags 'omitempty'

⚠ BREAKING CHANGES

  • grep-like, recursive search mode
  • Update tree-sitter & bindings
  • Adjust IGNORE pattern
  • Variables for replacement action
  • Ranges

Features

  • grep-like, recursive search mode (d55b28f)
  • Ranges (bd8b0bc)
  • c#: Scope class definitions (f65137d)
  • c#: Scope enum definitions (31dc2cb)
  • c#: Scope interface definitions (338b5f4)
  • c#: Scope struct definitions (5b53286)
  • c#: Scope attribute names (c3fe051)
  • c#: Scope constructor definitions (d8b5e7a)
  • c#: Scope destructor definitions (6f9677b)
  • c#: Scope field definitions (3f2d919)
  • c#: Scope identifier names (0267196)
  • c#: Scope method definitions (5b530a1)
  • c#: Scope property definitions (769ffef)
  • c#: Scope variable declarations (09879ea)
  • cli: -j aka --join-language-scopes flag (2c1b9e8)
  • go: Ignore file paths containing vendor (0be56d0)
  • go: Scope (any) type definitions (bf2e90c)
  • go: Scope const assignments/specifications (61232b9)
  • go: Scope defer blocks (76a91b8)
  • go: Scope func init() definitions (106c4a6)
  • go: Scope func definitions (all, free, methods) (707e95a)
  • go: Scope go blocks (c38c5c3)
  • go: Scope goto statements (4133575)
  • go: Scope select blocks (ddbf9d9)
  • go: Scope struct and interface type definitions (392330f)
  • go: Scope switch blocks (61f5e08)
  • go: Scope type aliases (a1d707a)
  • go: Scope var assignments/specifications (367191d)
  • go: Scope labeled statements (308e28f)
  • go: Scope type aka generic parameters (891aa11)
  • HCL (HashiCorp Configuration Language) (814a592)
  • hcl: Scope data blocks (dc38287)
  • hcl: Scope locals blocks (c22c475)
  • hcl: Scope module blocks (84965ed)
  • hcl: Scope output blocks (9627961)
  • hcl: Scope provider blocks (a77e603)
  • hcl: Scope resource blocks (963d9a4)
  • hcl: Scope terraform blocks (a60a754)
  • hcl: Scope variable blocks (6b8dcdc)
  • language-scoping: Specify multiple language scopes (ce0db6f), closes #104
  • python: Scope lambdas (94894c0)
  • python: Scope try blocks (107d87f)
  • python: Scope with blocks (b0f9825)
  • python: Scope async function definitions (async def) (4debfff)
  • python: Scope classmethods ([@classmethod](https://github.com/classmethod) def inside class) (4779d69)
  • python: Scope function definitions (def) (10ef4d5)
  • python: Scope global aka module-level variable (assignments) (fc5c027)
  • python: Scope methods (def inside class) (e151d9a)
  • python: Scope staticmethods ([@staticmethod](https://github.com/staticmethod) def inside class) (8f53aa5)
  • python: Scope type hints (5dc106f)
  • python: Scope variable names (from their assignment) (0fb549c)
  • rust: Scope "private" (non-pub) function, struct, enum definitions (fab1bc3)
  • rust: Scope "test" functions (functions with any attribute containing test) (1c264fb)
  • rust: Scope {,pub({crate,self,super})} enum definitions (019bacb)
  • rust: Scope {,pub({crate,self,super})} struct definitions (8c922bf)
  • rust: Scope impl blocks (f96d0dd)
  • rust: Scope impl blocks for types and traits specifically (d51290c)
  • rust: Scope pub({crate,self,super}) function definitions (0e90ed5)
  • rust: Scope pub function definitions (2ebcd15)
  • rust: Scope trait definitions (7a1ad3d)
  • rust: Scope attributes (b9c03a3)
  • rust: Scope closure definitions (83473c3)
  • rust: Scope contents of mod tests blocks (fc0a9db)
  • rust: Scope contents of mod blocks (08278bc)
  • rust: Scope function definitions (c2dd0c3)
  • rust: Scope function definitions marked async (156f34c)
  • rust: Scope function definitions marked const (0cd4ac4)
  • rust: Scope function definitions marked extern (fd08b7d)
  • rust: Scope function definitions marked unsafe (c54fe4d)
  • rust: Scope functions inside impl blocks (e9c3c16)
  • rust: Scope identifiers (007f0be)
  • rust: Scope individual variants of enums (07f4eb9)
  • rust: Scope type definitions (struct, enum, union) (33fc03b)
  • rust: Scope type identifiers (4caefdb)
  • typescript: Scope class definitions (f5c3b6f)
  • typescript: Scope constructor method definitions (afafbbf)
  • typescript: Scope enum definitions (91afb9f)
  • typescript: Scope export blocks (bb73080)
  • typescript: Scope function definitions (async, sync, or both) (3edc8f0)
  • typescript: Scope interface definitions (05f3257)
  • typescript: Scope let, const, var variable declarations (9bd04d8)
  • typescript: Scope namespace blocks (aeb5d41)
  • typescript: Scope try/catch/finally blocks (4c19dd9)
  • typescript: Scope type alias declarations (ba3c726)
  • typescript: Scope method definitions (f5ddc52)
  • typescript: Scope type parameters (449d12e)
  • typescript: Scope variable declarations (5be5abc)
  • Variables for replacement action (7f6cfcb)

Bug Fixes

  • fail-any, fail-none and fail-empty-glob flags (9673678)
  • cli: Exit gracefully on broken pipe in search mode (d47b901)
  • go: String scoping no longer scopes parts of imports/field decl. (f4796c0)
  • hcl: Check blocks for exact identifier equality (1f26d56)
  • hcl: Exclude count metavariable from {resource,data}-names (6ff7a05)
  • hcl: Scopes exclude quotes (df30f9e)
  • language-scoping: Construct TSQuery only once (084df95), closes #76
  • logging: Logs display timestamps again (70ffd1c)
  • python: Scoping docstrings and strings no longer includes quotes (2a743c8)
  • rust: uses scope only scopes things actually behind a use (ea1a734)
  • rust: uses scopes to its entire argument (0ca45a1)
  • rust: doc comments match //!-style (a910e82)
  • rust: Scoping strings no longer includes quotes (8fb5da8)
  • typescript: Scoping strings no longer includes quotes (f1626d7)

Miscellaneous Chores

  • Adjust IGNORE pattern (96d4d4c)
  • Update tree-sitter & bindings (5debd0e)