srgn: v0.13.0
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
andinterface
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
lambda
s (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
insideclass
) (4779d69) - python: Scope function definitions (
def
) (10ef4d5) - python: Scope global aka module-level variable (assignments) (fc5c027)
- python: Scope methods (
def
insideclass
) (e151d9a) - python: Scope staticmethods (
[@staticmethod](https://github.com/staticmethod) def
insideclass
) (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
andfail-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
eq
uality (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 ause
(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)