Metadata-Version: 2.4
Name: snip-stitch
Version: 1.0.2
Summary: Idempotently manage marked snippets inside shell-like text files
Author-email: Zoran Simic <zoran@simicweb.com>
License-Expression: MIT
Project-URL: Source, https://github.com/zsimic/snip-stitch
Classifier: Development Status :: 5 - Production/Stable
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: System Administrators
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Topic :: System :: Systems Administration
Classifier: Topic :: Text Processing
Classifier: Topic :: Utilities
Requires-Python: >=3.10
Description-Content-Type: text/x-rst
License-File: LICENSE.txt
Dynamic: license-file

snip-stitch
===========

.. image:: https://img.shields.io/pypi/v/snip-stitch.svg
    :target: https://pypi.org/project/snip-stitch/
    :alt: Version on pypi

.. image:: https://github.com/zsimic/snip-stitch/workflows/Tests/badge.svg
    :target: https://github.com/zsimic/snip-stitch/actions
    :alt: Tested with Github Actions

.. image:: https://img.shields.io/pypi/pyversions/snip-stitch.svg
    :target: https://github.com/zsimic/snip-stitch
    :alt: Python versions tested


Idempotently add, update, or remove managed snippets inside shell-like text files.

Installers love to append lines to your shell profile.
Uninstallers... don't.

``snip-stitch`` fixes this by wrapping each snippet in marker lines, so future runs can find,
update, or cleanly remove exactly that section -- and leave everything else alone.

::

    # ---8<- nvm -- managed section, avoid editing
    export NVM_DIR="$HOME/.nvm"
    [ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh"
    # -8<--- nvm --

No dependencies. Idempotent by design. One file, one job.


Installation
============

Run directly (no install required)::

    uvx snip-stitch --help

It can also be ``pip``-installed, or ran ad-hoc (it uses std lib only).


Commands
========

Every invocation follows the same shape::

    snip-stitch [options] <command> <tag> <target> [content]

- **tag** -- identifies the managed section (3-32 lowercase chars: ``[a-z][a-z0-9._-]{2,31}``)
- **target** -- the file to modify (e.g. ``~/.bashrc``, ``~/.ssh/config``)
- **content** -- the snippet source (meaning depends on the command)


``text`` -- inline snippet
--------------------------

Pass the snippet directly as a string. Handy for one-liners::

    snip-stitch text rustup ~/.profile \
      '[ -f "$HOME/.cargo/env" ] && . "$HOME/.cargo/env"'

Supports ``\n`` escapes for callers that cannot easily pass literal newlines.


``file`` -- snippet from a file
--------------------------------

Read the snippet from a file on disk.
Useful when the snippet is maintained separately or generated by another tool::

    snip-stitch file sdkman ~/.bashrc sdkman-init.sh

::

    snip-stitch file personal-github ~/.ssh/config personal-git.config


``remove`` -- delete a managed section
---------------------------------------

Remove a previously managed section by its tag. Only two arguments needed::

    snip-stitch remove sdkman ~/.bashrc

The surrounding file content is left untouched.


Options
=======

Options go **before** the command::

    snip-stitch -n --force text mytag ~/.bashrc 'echo hello'

====================  =======================================================
``-n, --dryrun``      Show what would happen without modifying the file
``-v, --verbose``     Print extra detail to stderr
``-f, --force``       Rewrite even if the managed section hasn't changed
``--comment-chars``   Comment character(s) for the target file (default: ``#``)
``--start-comment``   Comment appended to the opening marker line
``--end-comment``     Comment appended to the closing marker line
``--snip-marker``     Marker string (default: ``-8<-``)
====================  =======================================================


How it works
============

Given this command::

    snip-stitch file nvm ~/.zshrc nvm-init.sh

The target file will contain::

    # ---8<- nvm -- managed section, avoid editing
    export NVM_DIR="$HOME/.nvm"
    [ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh"
    # -8<--- nvm --

Run it again with the same content? Nothing happens -- the file is not rewritten.
Change the content? Only the managed section is updated in place.
Use ``remove``? The markers and everything between them are deleted, the rest stays put.


Use cases
=========

**Shell installers** -- tools like nvm, sdkman, rustup, and Homebrew need to inject
initialization lines into shell profiles. Instead of ``grep ... || echo ... >> ~/.zshrc``
(and hoping for the best at uninstall time), use ``snip-stitch`` for clean ownership.

**Dotfile managers** -- keep your ``~/.bashrc``, ``~/.zprofile``, or ``~/.ssh/config`` tidy
by giving each concern its own tagged section.

**CI/CD and automation** -- any setup script that needs to own a section of a config file
without clobbering the rest of it.

**Package managers** -- npm, Homebrew, and similar tools that modify shell config during
``install`` can use the same tag at ``uninstall`` time to cleanly remove their section.


Guarantees
==========

- Same input produces same file contents (idempotent)
- Unchanged snippet content does not rewrite the file
- Removal leaves surrounding content intact
- Zero runtime dependencies
