CINXE.COM

GitHub - alexpovel/srgn: A grep-like tool which understands source code syntax and allows for manipulation in addition to search

<!DOCTYPE html> <html lang="en" data-color-mode="auto" data-light-theme="light" data-dark-theme="dark" data-a11y-animated-images="system" data-a11y-link-underlines="true" > <head> <meta charset="utf-8"> <link rel="dns-prefetch" href="https://github.githubassets.com"> <link rel="dns-prefetch" href="https://avatars.githubusercontent.com"> <link rel="dns-prefetch" href="https://github-cloud.s3.amazonaws.com"> <link rel="dns-prefetch" href="https://user-images.githubusercontent.com/"> <link rel="preconnect" href="https://github.githubassets.com" crossorigin> <link rel="preconnect" href="https://avatars.githubusercontent.com"> <link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/light-74231a1f3bbb.css" /><link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/dark-8a995f0bacd4.css" /><link data-color-theme="dark_dimmed" crossorigin="anonymous" media="all" rel="stylesheet" data-href="https://github.githubassets.com/assets/dark_dimmed-f37fb7684b1f.css" /><link data-color-theme="dark_high_contrast" crossorigin="anonymous" media="all" rel="stylesheet" data-href="https://github.githubassets.com/assets/dark_high_contrast-9ac301c3ebe5.css" /><link data-color-theme="dark_colorblind" crossorigin="anonymous" media="all" rel="stylesheet" data-href="https://github.githubassets.com/assets/dark_colorblind-cd826e8636dc.css" /><link data-color-theme="light_colorblind" crossorigin="anonymous" media="all" rel="stylesheet" data-href="https://github.githubassets.com/assets/light_colorblind-f91b0f603451.css" /><link data-color-theme="light_high_contrast" crossorigin="anonymous" media="all" rel="stylesheet" data-href="https://github.githubassets.com/assets/light_high_contrast-83beb16e0ecf.css" /><link data-color-theme="light_tritanopia" crossorigin="anonymous" media="all" rel="stylesheet" data-href="https://github.githubassets.com/assets/light_tritanopia-6e122dab64fc.css" /><link data-color-theme="dark_tritanopia" crossorigin="anonymous" media="all" rel="stylesheet" data-href="https://github.githubassets.com/assets/dark_tritanopia-18119e682df0.css" /> <link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/primer-primitives-225433424a87.css" /> <link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/primer-aaa714e5674d.css" /> <link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/global-0a3c53b9d1c2.css" /> <link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/github-ea73c9cb5377.css" /> <link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/repository-4fce88777fa8.css" /> <link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/code-0210be90f4d3.css" /> <script type="application/json" id="client-env">{"locale":"en","featureFlags":["copilot_immersive_issue_preview","copilot_new_references_ui","copilot_chat_repo_custom_instructions_preview","copilot_no_floating_button","copilot_topics_as_references","copilot_read_shared_conversation","copilot_duplicate_thread","copilot_buffered_streaming","dotcom_chat_client_side_skills","experimentation_azure_variant_endpoint","failbot_handle_non_errors","geojson_azure_maps","ghost_pilot_confidence_truncation_25","ghost_pilot_confidence_truncation_40","github_models_gateway_parse_params","github_models_o3_mini_streaming","insert_before_patch","issues_react_remove_placeholders","issues_react_blur_item_picker_on_close","marketing_pages_search_explore_provider","primer_react_css_modules_ga","react_data_router_pull_requests","react_override_default_key","remove_child_patch","sample_network_conn_type","swp_enterprise_contact_form","site_proxima_australia_update","viewscreen_sandbox","issues_react_create_milestone","issues_react_cache_fix_workaround","lifecycle_label_name_updates","copilot_task_oriented_assistive_prompts","issue_types_prevent_private_type_creation","refresh_image_video_src","react_router_dispose_on_disconnect","codespaces_prebuild_region_target_update","turbo_app_id_restore","copilot_code_review_sign_up_closed"]}</script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/wp-runtime-a05c883d32f9.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/vendors-node_modules_oddbird_popover-polyfill_dist_popover_js-9da652f58479.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/vendors-node_modules_github_arianotify-polyfill_ariaNotify-polyfill_js-node_modules_github_mi-3abb8f-46b9f4874d95.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/ui_packages_failbot_failbot_ts-75968cfb5298.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/environment-f04cb2a9fc8c.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/vendors-node_modules_primer_behaviors_dist_esm_index_mjs-0dbb79f97f8f.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/vendors-node_modules_github_selector-observer_dist_index_esm_js-f690fd9ae3d5.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/vendors-node_modules_github_relative-time-element_dist_index_js-62d275b7ddd9.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/vendors-node_modules_github_text-expander-element_dist_index_js-78748950cb0c.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/vendors-node_modules_github_auto-complete-element_dist_index_js-node_modules_github_catalyst_-8e9f78-a90ac05d2469.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/vendors-node_modules_github_filter-input-element_dist_index_js-node_modules_github_remote-inp-b5f1d7-a1760ffda83d.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/vendors-node_modules_github_markdown-toolbar-element_dist_index_js-ceef33f593fa.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/vendors-node_modules_github_file-attachment-element_dist_index_js-node_modules_primer_view-co-c44a69-efa32db3a345.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/github-elements-394f8eb34f19.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/element-registry-25113a65b77f.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/vendors-node_modules_braintree_browser-detection_dist_browser-detection_js-node_modules_githu-2906d7-2a07a295af40.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/vendors-node_modules_lit-html_lit-html_js-be8cb88f481b.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/vendors-node_modules_github_mini-throttle_dist_index_js-node_modules_morphdom_dist_morphdom-e-7c534c-a4a1922eb55f.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/vendors-node_modules_github_turbo_dist_turbo_es2017-esm_js-a03ee12d659a.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/vendors-node_modules_github_remote-form_dist_index_js-node_modules_delegated-events_dist_inde-893f9f-b6294cf703b7.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/vendors-node_modules_color-convert_index_js-e3180fe3bcb3.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/vendors-node_modules_github_quote-selection_dist_index_js-node_modules_github_session-resume_-947061-e7a6c4a19f98.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/ui_packages_updatable-content_updatable-content_ts-eb3147a21e96.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/app_assets_modules_github_behaviors_task-list_ts-app_assets_modules_github_sso_ts-ui_packages-900dde-768abe60b1f8.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/app_assets_modules_github_sticky-scroll-into-view_ts-3e000c5d31a9.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/app_assets_modules_github_behaviors_ajax-error_ts-app_assets_modules_github_behaviors_include-87a4ae-4c160a67a3f8.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/app_assets_modules_github_behaviors_commenting_edit_ts-app_assets_modules_github_behaviors_ht-83c235-e429cff6ceb1.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/behaviors-124f4ce2c2c0.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/vendors-node_modules_delegated-events_dist_index_js-node_modules_github_catalyst_lib_index_js-f6223d90c7ba.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/notifications-global-01e85cd1be94.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/vendors-node_modules_virtualized-list_es_index_js-node_modules_github_template-parts_lib_index_js-94dc7a2157c1.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/vendors-node_modules_github_remote-form_dist_index_js-node_modules_delegated-events_dist_inde-70450e-4b93df70b903.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/app_assets_modules_github_ref-selector_ts-3e9d848bab5f.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/codespaces-f76fb2dd7b91.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/vendors-node_modules_github_filter-input-element_dist_index_js-node_modules_github_remote-inp-3eebbd-0763620ad7bf.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/vendors-node_modules_github_mini-throttle_dist_decorators_js-node_modules_delegated-events_di-e161aa-9d41fb1b6c9e.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/vendors-node_modules_github_file-attachment-element_dist_index_js-node_modules_github_remote--3c9c82-b71ef90fbdc7.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/repositories-e6e7c7ff47a3.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/vendors-node_modules_github_mini-throttle_dist_index_js-node_modules_github_catalyst_lib_inde-dbbea9-26cce2010167.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/code-menu-1c0aedc134b1.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/primer-react-602097a4b0db.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/react-core-0bc17999cb79.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/react-lib-f1bca44e0926.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/octicons-react-cf2f2ab8dab4.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/vendors-node_modules_emotion_is-prop-valid_dist_emotion-is-prop-valid_esm_js-node_modules_emo-62da9f-2df2f32ec596.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/vendors-node_modules_github_mini-throttle_dist_index_js-node_modules_stacktrace-parser_dist_s-e7dcdd-9a233856b02c.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/vendors-node_modules_oddbird_popover-polyfill_dist_popover-fn_js-55fea94174bf.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/notifications-subscriptions-menu-57956eade845.js"></script> <link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/primer-react.8157a56b30ae88a1b356.module.css" /> <link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/notifications-subscriptions-menu.1bcff9205c241e99cff2.module.css" /> <link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/primer-react.8157a56b30ae88a1b356.module.css" /> <link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/notifications-subscriptions-menu.1bcff9205c241e99cff2.module.css" /> <title>GitHub - alexpovel/srgn: A grep-like tool which understands source code syntax and allows for manipulation in addition to search</title> <meta name="route-pattern" content="/:user_id/:repository" data-turbo-transient> <meta name="route-controller" content="files" data-turbo-transient> <meta name="route-action" content="disambiguate" data-turbo-transient> <meta name="current-catalog-service-hash" content="f3abb0cc802f3d7b95fc8762b94bdcb13bf39634c40c357301c4aa1d67a256fb"> <meta name="request-id" content="EBF4:E1C7F:2450D0:29E047:67EBDFED" data-pjax-transient="true"/><meta name="html-safe-nonce" content="e6b0732d8cffa5ed2db4ecaeffaa8b66edfa8568fb25616873315df715dbe81d" data-pjax-transient="true"/><meta name="visitor-payload" content="eyJyZWZlcnJlciI6IiIsInJlcXVlc3RfaWQiOiJFQkY0OkUxQzdGOjI0NTBEMDoyOUUwNDc6NjdFQkRGRUQiLCJ2aXNpdG9yX2lkIjoiNzg2NzQ1MjM5MjI1OTQ0NDcxNyIsInJlZ2lvbl9lZGdlIjoic291dGhlYXN0YXNpYSIsInJlZ2lvbl9yZW5kZXIiOiJzb3V0aGVhc3Rhc2lhIn0=" data-pjax-transient="true"/><meta name="visitor-hmac" content="8fe2457aeeba68032dfcd52f2a4e2dcd4bcfa33828f6b6c5e50c312baf325885" data-pjax-transient="true"/> <meta name="hovercard-subject-tag" content="repository:641495940" data-turbo-transient> <meta name="github-keyboard-shortcuts" content="repository,copilot" data-turbo-transient="true" /> <meta name="selected-link" value="repo_source" data-turbo-transient> <link rel="assets" href="https://github.githubassets.com/"> <meta name="google-site-verification" content="Apib7-x98H0j5cPqHWwSMm6dNU4GmODRoqxLiDzdx9I"> <meta name="octolytics-url" content="https://collector.github.com/github/collect" /> <meta name="analytics-location" content="/&lt;user-name&gt;/&lt;repo-name&gt;" data-turbo-transient="true" /> <meta name="user-login" content=""> <meta name="viewport" content="width=device-width"> <meta name="description" content="A grep-like tool which understands source code syntax and allows for manipulation in addition to search - alexpovel/srgn"> <link rel="search" type="application/opensearchdescription+xml" href="/opensearch.xml" title="GitHub"> <link rel="fluid-icon" href="https://github.com/fluidicon.png" title="GitHub"> <meta property="fb:app_id" content="1401488693436528"> <meta name="apple-itunes-app" content="app-id=1477376905, app-argument=https://github.com/alexpovel/srgn" /> <meta name="twitter:image" content="https://opengraph.githubassets.com/e832d639ef08c4fd8de00447e03cda2dec6b322d8f54ff69052af2a1e34155ca/alexpovel/srgn" /><meta name="twitter:site" content="@github" /><meta name="twitter:card" content="summary_large_image" /><meta name="twitter:title" content="GitHub - alexpovel/srgn: A grep-like tool which understands source code syntax and allows for manipulation in addition to search" /><meta name="twitter:description" content="A grep-like tool which understands source code syntax and allows for manipulation in addition to search - alexpovel/srgn" /> <meta property="og:image" content="https://opengraph.githubassets.com/e832d639ef08c4fd8de00447e03cda2dec6b322d8f54ff69052af2a1e34155ca/alexpovel/srgn" /><meta property="og:image:alt" content="A grep-like tool which understands source code syntax and allows for manipulation in addition to search - alexpovel/srgn" /><meta property="og:image:width" content="1200" /><meta property="og:image:height" content="600" /><meta property="og:site_name" content="GitHub" /><meta property="og:type" content="object" /><meta property="og:title" content="GitHub - alexpovel/srgn: A grep-like tool which understands source code syntax and allows for manipulation in addition to search" /><meta property="og:url" content="https://github.com/alexpovel/srgn" /><meta property="og:description" content="A grep-like tool which understands source code syntax and allows for manipulation in addition to search - alexpovel/srgn" /> <meta name="hostname" content="github.com"> <meta name="expected-hostname" content="github.com"> <meta http-equiv="x-pjax-version" content="ce3daf97e8d99e74294e5992d4d61ba885e5722e00e3d3ccf57fe176158751d2" data-turbo-track="reload"> <meta http-equiv="x-pjax-csp-version" content="e26f9f0ba624ee85cc7ac057d8faa8618a4f25a85eab052c33d018ac0f6b1a46" data-turbo-track="reload"> <meta http-equiv="x-pjax-css-version" content="159e03504eed5183f9787c72780a7d8c1460af30746ab09d728b048c41719efa" data-turbo-track="reload"> <meta http-equiv="x-pjax-js-version" content="242e065aec432bdaf96efecc2301783ca2b1af8421b97829999907d8f1c90c56" data-turbo-track="reload"> <meta name="turbo-cache-control" content="no-preview" data-turbo-transient=""> <meta data-hydrostats="publish"> <meta name="go-import" content="github.com/alexpovel/srgn git https://github.com/alexpovel/srgn.git"> <meta name="octolytics-dimension-user_id" content="48824213" /><meta name="octolytics-dimension-user_login" content="alexpovel" /><meta name="octolytics-dimension-repository_id" content="641495940" /><meta name="octolytics-dimension-repository_nwo" content="alexpovel/srgn" /><meta name="octolytics-dimension-repository_public" content="true" /><meta name="octolytics-dimension-repository_is_fork" content="false" /><meta name="octolytics-dimension-repository_network_root_id" content="641495940" /><meta name="octolytics-dimension-repository_network_root_nwo" content="alexpovel/srgn" /> <link rel="canonical" href="https://github.com/alexpovel/srgn" data-turbo-transient> <meta name="turbo-body-classes" content="logged-out env-production page-responsive"> <meta name="browser-stats-url" content="https://api.github.com/_private/browser/stats"> <meta name="browser-errors-url" content="https://api.github.com/_private/browser/errors"> <meta name="release" content="85a1a8f0595fde008b33c23b769a01c024a21704"> <link rel="mask-icon" href="https://github.githubassets.com/assets/pinned-octocat-093da3e6fa40.svg" color="#000000"> <link rel="alternate icon" class="js-site-favicon" type="image/png" href="https://github.githubassets.com/favicons/favicon.png"> <link rel="icon" class="js-site-favicon" type="image/svg+xml" href="https://github.githubassets.com/favicons/favicon.svg" data-base-href="https://github.githubassets.com/favicons/favicon"> <meta name="theme-color" content="#1e2327"> <meta name="color-scheme" content="light dark" /> <link rel="manifest" href="/manifest.json" crossOrigin="use-credentials"> </head> <body class="logged-out env-production page-responsive" style="word-wrap: break-word;"> <div data-turbo-body class="logged-out env-production page-responsive" style="word-wrap: break-word;"> <div class="position-relative header-wrapper js-header-wrapper "> <a href="#start-of-content" data-skip-target-assigned="false" class="px-2 py-4 color-bg-accent-emphasis color-fg-on-emphasis show-on-focus js-skip-to-content">Skip to content</a> <span data-view-component="true" class="progress-pjax-loader Progress position-fixed width-full"> <span style="width: 0%;" data-view-component="true" class="Progress-item progress-pjax-loader-bar left-0 top-0 color-bg-accent-emphasis"></span> </span> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/ui_packages_ui-commands_ui-commands_ts-2ea4e93613c0.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/keyboard-shortcuts-dialog-79d6a754ebf9.js"></script> <link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/primer-react.8157a56b30ae88a1b356.module.css" /> <react-partial partial-name="keyboard-shortcuts-dialog" data-ssr="false" data-attempted-ssr="false" > <script type="application/json" data-target="react-partial.embeddedData">{"props":{"docsUrl":"https://docs.github.com/get-started/accessibility/keyboard-shortcuts"}}</script> <div data-target="react-partial.reactRoot"></div> </react-partial> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/vendors-node_modules_github_remote-form_dist_index_js-node_modules_delegated-events_dist_inde-94fd67-4898d1bf4b51.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/sessions-730dca81d0a2.js"></script> <header class="HeaderMktg header-logged-out js-details-container js-header Details f4 py-3" role="banner" data-is-top="true" data-color-mode=light data-light-theme=light data-dark-theme=dark> <h2 class="sr-only">Navigation Menu</h2> <button type="button" class="HeaderMktg-backdrop d-lg-none border-0 position-fixed top-0 left-0 width-full height-full js-details-target" aria-label="Toggle navigation"> <span class="d-none">Toggle navigation</span> </button> <div class="d-flex flex-column flex-lg-row flex-items-center px-3 px-md-4 px-lg-5 height-full position-relative z-1"> <div class="d-flex flex-justify-between flex-items-center width-full width-lg-auto"> <div class="flex-1"> <button aria-label="Toggle navigation" aria-expanded="false" type="button" data-view-component="true" class="js-details-target js-nav-padding-recalculate js-header-menu-toggle Button--link Button--medium Button d-lg-none color-fg-inherit p-1"> <span class="Button-content"> <span class="Button-label"><div class="HeaderMenu-toggle-bar rounded my-1"></div> <div class="HeaderMenu-toggle-bar rounded my-1"></div> <div class="HeaderMenu-toggle-bar rounded my-1"></div></span> </span> </button> </div> <a class="mr-lg-3 color-fg-inherit flex-order-2 js-prevent-focus-on-mobile-nav" href="/" aria-label="Homepage" data-analytics-event="{&quot;category&quot;:&quot;Marketing nav&quot;,&quot;action&quot;:&quot;click to go to homepage&quot;,&quot;label&quot;:&quot;ref_page:Marketing;ref_cta:Logomark;ref_loc:Header&quot;}"> <svg height="32" aria-hidden="true" viewBox="0 0 24 24" version="1.1" width="32" data-view-component="true" class="octicon octicon-mark-github"> <path d="M12 1C5.9225 1 1 5.9225 1 12C1 16.8675 4.14875 20.9787 8.52125 22.4362C9.07125 22.5325 9.2775 22.2025 9.2775 21.9137C9.2775 21.6525 9.26375 20.7862 9.26375 19.865C6.5 20.3737 5.785 19.1912 5.565 18.5725C5.44125 18.2562 4.905 17.28 4.4375 17.0187C4.0525 16.8125 3.5025 16.3037 4.42375 16.29C5.29 16.2762 5.90875 17.0875 6.115 17.4175C7.105 19.0812 8.68625 18.6137 9.31875 18.325C9.415 17.61 9.70375 17.1287 10.02 16.8537C7.5725 16.5787 5.015 15.63 5.015 11.4225C5.015 10.2262 5.44125 9.23625 6.1425 8.46625C6.0325 8.19125 5.6475 7.06375 6.2525 5.55125C6.2525 5.55125 7.17375 5.2625 9.2775 6.67875C10.1575 6.43125 11.0925 6.3075 12.0275 6.3075C12.9625 6.3075 13.8975 6.43125 14.7775 6.67875C16.8813 5.24875 17.8025 5.55125 17.8025 5.55125C18.4075 7.06375 18.0225 8.19125 17.9125 8.46625C18.6138 9.23625 19.04 10.2125 19.04 11.4225C19.04 15.6437 16.4688 16.5787 14.0213 16.8537C14.42 17.1975 14.7638 17.8575 14.7638 18.8887C14.7638 20.36 14.75 21.5425 14.75 21.9137C14.75 22.2025 14.9563 22.5462 15.5063 22.4362C19.8513 20.9787 23 16.8537 23 12C23 5.9225 18.0775 1 12 1Z"></path> </svg> </a> <div class="flex-1 flex-order-2 text-right"> <a href="/login?return_to=https%3A%2F%2Fgithub.com%2Falexpovel%2Fsrgn" class="HeaderMenu-link HeaderMenu-button d-inline-flex d-lg-none flex-order-1 f5 no-underline border color-border-default rounded-2 px-2 py-1 color-fg-inherit js-prevent-focus-on-mobile-nav" data-hydro-click="{&quot;event_type&quot;:&quot;authentication.click&quot;,&quot;payload&quot;:{&quot;location_in_page&quot;:&quot;site header menu&quot;,&quot;repository_id&quot;:null,&quot;auth_type&quot;:&quot;SIGN_UP&quot;,&quot;originating_url&quot;:&quot;https://github.com/alexpovel/srgn&quot;,&quot;user_id&quot;:null}}" data-hydro-click-hmac="357ea8f0477bd5d909f0350e9c55271527254c96d48f5c2d45afd626f73741b6" data-analytics-event="{&quot;category&quot;:&quot;Marketing nav&quot;,&quot;action&quot;:&quot;click to Sign in&quot;,&quot;label&quot;:&quot;ref_page:Marketing;ref_cta:Sign in;ref_loc:Header&quot;}" > Sign in </a> </div> </div> <div class="HeaderMenu js-header-menu height-fit position-lg-relative d-lg-flex flex-column flex-auto top-0"> <div class="HeaderMenu-wrapper d-flex flex-column flex-self-start flex-lg-row flex-auto rounded rounded-lg-0"> <nav class="HeaderMenu-nav" aria-label="Global"> <ul class="d-lg-flex list-style-none"> <li class="HeaderMenu-item position-relative flex-wrap flex-justify-between flex-items-center d-block d-lg-flex flex-lg-nowrap flex-lg-items-center js-details-container js-header-menu-item"> <button type="button" class="HeaderMenu-link border-0 width-full width-lg-auto px-0 px-lg-2 py-lg-2 no-wrap d-flex flex-items-center flex-justify-between js-details-target" aria-expanded="false"> Product <svg opacity="0.5" aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-chevron-down HeaderMenu-icon ml-1"> <path d="M12.78 5.22a.749.749 0 0 1 0 1.06l-4.25 4.25a.749.749 0 0 1-1.06 0L3.22 6.28a.749.749 0 1 1 1.06-1.06L8 8.939l3.72-3.719a.749.749 0 0 1 1.06 0Z"></path> </svg> </button> <div class="HeaderMenu-dropdown dropdown-menu rounded m-0 p-0 pt-2 pt-lg-4 position-relative position-lg-absolute left-0 left-lg-n3 pb-2 pb-lg-4 d-lg-flex flex-wrap dropdown-menu-wide"> <div class="HeaderMenu-column px-lg-4 border-lg-right mb-4 mb-lg-0 pr-lg-7"> <div class="border-bottom pb-3 pb-lg-0 border-lg-bottom-0"> <ul class="list-style-none f5" > <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary d-flex flex-items-center Link--has-description pb-lg-3" data-analytics-event="{&quot;location&quot;:&quot;navbar&quot;,&quot;action&quot;:&quot;github_copilot&quot;,&quot;context&quot;:&quot;product&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;label&quot;:&quot;github_copilot_link_product_navbar&quot;}" href="https://github.com/features/copilot"> <svg aria-hidden="true" height="24" viewBox="0 0 24 24" version="1.1" width="24" data-view-component="true" class="octicon octicon-copilot color-fg-subtle mr-3"> <path d="M23.922 16.992c-.861 1.495-5.859 5.023-11.922 5.023-6.063 0-11.061-3.528-11.922-5.023A.641.641 0 0 1 0 16.736v-2.869a.841.841 0 0 1 .053-.22c.372-.935 1.347-2.292 2.605-2.656.167-.429.414-1.055.644-1.517a10.195 10.195 0 0 1-.052-1.086c0-1.331.282-2.499 1.132-3.368.397-.406.89-.717 1.474-.952 1.399-1.136 3.392-2.093 6.122-2.093 2.731 0 4.767.957 6.166 2.093.584.235 1.077.546 1.474.952.85.869 1.132 2.037 1.132 3.368 0 .368-.014.733-.052 1.086.23.462.477 1.088.644 1.517 1.258.364 2.233 1.721 2.605 2.656a.832.832 0 0 1 .053.22v2.869a.641.641 0 0 1-.078.256ZM12.172 11h-.344a4.323 4.323 0 0 1-.355.508C10.703 12.455 9.555 13 7.965 13c-1.725 0-2.989-.359-3.782-1.259a2.005 2.005 0 0 1-.085-.104L4 11.741v6.585c1.435.779 4.514 2.179 8 2.179 3.486 0 6.565-1.4 8-2.179v-6.585l-.098-.104s-.033.045-.085.104c-.793.9-2.057 1.259-3.782 1.259-1.59 0-2.738-.545-3.508-1.492a4.323 4.323 0 0 1-.355-.508h-.016.016Zm.641-2.935c.136 1.057.403 1.913.878 2.497.442.544 1.134.938 2.344.938 1.573 0 2.292-.337 2.657-.751.384-.435.558-1.15.558-2.361 0-1.14-.243-1.847-.705-2.319-.477-.488-1.319-.862-2.824-1.025-1.487-.161-2.192.138-2.533.529-.269.307-.437.808-.438 1.578v.021c0 .265.021.562.063.893Zm-1.626 0c.042-.331.063-.628.063-.894v-.02c-.001-.77-.169-1.271-.438-1.578-.341-.391-1.046-.69-2.533-.529-1.505.163-2.347.537-2.824 1.025-.462.472-.705 1.179-.705 2.319 0 1.211.175 1.926.558 2.361.365.414 1.084.751 2.657.751 1.21 0 1.902-.394 2.344-.938.475-.584.742-1.44.878-2.497Z"></path><path d="M14.5 14.25a1 1 0 0 1 1 1v2a1 1 0 0 1-2 0v-2a1 1 0 0 1 1-1Zm-5 0a1 1 0 0 1 1 1v2a1 1 0 0 1-2 0v-2a1 1 0 0 1 1-1Z"></path> </svg> <div> <div class="color-fg-default h4">GitHub Copilot</div> Write better code with AI </div> </a></li> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary d-flex flex-items-center Link--has-description pb-lg-3" data-analytics-event="{&quot;location&quot;:&quot;navbar&quot;,&quot;action&quot;:&quot;security&quot;,&quot;context&quot;:&quot;product&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;label&quot;:&quot;security_link_product_navbar&quot;}" href="https://github.com/features/security"> <svg aria-hidden="true" height="24" viewBox="0 0 24 24" version="1.1" width="24" data-view-component="true" class="octicon octicon-shield-check color-fg-subtle mr-3"> <path d="M16.53 9.78a.75.75 0 0 0-1.06-1.06L11 13.19l-1.97-1.97a.75.75 0 0 0-1.06 1.06l2.5 2.5a.75.75 0 0 0 1.06 0l5-5Z"></path><path d="m12.54.637 8.25 2.675A1.75 1.75 0 0 1 22 4.976V10c0 6.19-3.771 10.704-9.401 12.83a1.704 1.704 0 0 1-1.198 0C5.77 20.705 2 16.19 2 10V4.976c0-.758.489-1.43 1.21-1.664L11.46.637a1.748 1.748 0 0 1 1.08 0Zm-.617 1.426-8.25 2.676a.249.249 0 0 0-.173.237V10c0 5.46 3.28 9.483 8.43 11.426a.199.199 0 0 0 .14 0C17.22 19.483 20.5 15.461 20.5 10V4.976a.25.25 0 0 0-.173-.237l-8.25-2.676a.253.253 0 0 0-.154 0Z"></path> </svg> <div> <div class="color-fg-default h4">Security</div> Find and fix vulnerabilities </div> </a></li> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary d-flex flex-items-center Link--has-description pb-lg-3" data-analytics-event="{&quot;location&quot;:&quot;navbar&quot;,&quot;action&quot;:&quot;actions&quot;,&quot;context&quot;:&quot;product&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;label&quot;:&quot;actions_link_product_navbar&quot;}" href="https://github.com/features/actions"> <svg aria-hidden="true" height="24" viewBox="0 0 24 24" version="1.1" width="24" data-view-component="true" class="octicon octicon-workflow color-fg-subtle mr-3"> <path d="M1 3a2 2 0 0 1 2-2h6.5a2 2 0 0 1 2 2v6.5a2 2 0 0 1-2 2H7v4.063C7 16.355 7.644 17 8.438 17H12.5v-2.5a2 2 0 0 1 2-2H21a2 2 0 0 1 2 2V21a2 2 0 0 1-2 2h-6.5a2 2 0 0 1-2-2v-2.5H8.437A2.939 2.939 0 0 1 5.5 15.562V11.5H3a2 2 0 0 1-2-2Zm2-.5a.5.5 0 0 0-.5.5v6.5a.5.5 0 0 0 .5.5h6.5a.5.5 0 0 0 .5-.5V3a.5.5 0 0 0-.5-.5ZM14.5 14a.5.5 0 0 0-.5.5V21a.5.5 0 0 0 .5.5H21a.5.5 0 0 0 .5-.5v-6.5a.5.5 0 0 0-.5-.5Z"></path> </svg> <div> <div class="color-fg-default h4">Actions</div> Automate any workflow </div> </a></li> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary d-flex flex-items-center Link--has-description pb-lg-3" data-analytics-event="{&quot;location&quot;:&quot;navbar&quot;,&quot;action&quot;:&quot;codespaces&quot;,&quot;context&quot;:&quot;product&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;label&quot;:&quot;codespaces_link_product_navbar&quot;}" href="https://github.com/features/codespaces"> <svg aria-hidden="true" height="24" viewBox="0 0 24 24" version="1.1" width="24" data-view-component="true" class="octicon octicon-codespaces color-fg-subtle mr-3"> <path d="M3.5 3.75C3.5 2.784 4.284 2 5.25 2h13.5c.966 0 1.75.784 1.75 1.75v7.5A1.75 1.75 0 0 1 18.75 13H5.25a1.75 1.75 0 0 1-1.75-1.75Zm-2 12c0-.966.784-1.75 1.75-1.75h17.5c.966 0 1.75.784 1.75 1.75v4a1.75 1.75 0 0 1-1.75 1.75H3.25a1.75 1.75 0 0 1-1.75-1.75ZM5.25 3.5a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h13.5a.25.25 0 0 0 .25-.25v-7.5a.25.25 0 0 0-.25-.25Zm-2 12a.25.25 0 0 0-.25.25v4c0 .138.112.25.25.25h17.5a.25.25 0 0 0 .25-.25v-4a.25.25 0 0 0-.25-.25Z"></path><path d="M10 17.75a.75.75 0 0 1 .75-.75h6.5a.75.75 0 0 1 0 1.5h-6.5a.75.75 0 0 1-.75-.75Zm-4 0a.75.75 0 0 1 .75-.75h.5a.75.75 0 0 1 0 1.5h-.5a.75.75 0 0 1-.75-.75Z"></path> </svg> <div> <div class="color-fg-default h4">Codespaces</div> Instant dev environments </div> </a></li> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary d-flex flex-items-center Link--has-description pb-lg-3" data-analytics-event="{&quot;location&quot;:&quot;navbar&quot;,&quot;action&quot;:&quot;issues&quot;,&quot;context&quot;:&quot;product&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;label&quot;:&quot;issues_link_product_navbar&quot;}" href="https://github.com/features/issues"> <svg aria-hidden="true" height="24" viewBox="0 0 24 24" version="1.1" width="24" data-view-component="true" class="octicon octicon-issue-opened color-fg-subtle mr-3"> <path d="M12 1c6.075 0 11 4.925 11 11s-4.925 11-11 11S1 18.075 1 12 5.925 1 12 1ZM2.5 12a9.5 9.5 0 0 0 9.5 9.5 9.5 9.5 0 0 0 9.5-9.5A9.5 9.5 0 0 0 12 2.5 9.5 9.5 0 0 0 2.5 12Zm9.5 2a2 2 0 1 1-.001-3.999A2 2 0 0 1 12 14Z"></path> </svg> <div> <div class="color-fg-default h4">Issues</div> Plan and track work </div> </a></li> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary d-flex flex-items-center Link--has-description pb-lg-3" data-analytics-event="{&quot;location&quot;:&quot;navbar&quot;,&quot;action&quot;:&quot;code_review&quot;,&quot;context&quot;:&quot;product&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;label&quot;:&quot;code_review_link_product_navbar&quot;}" href="https://github.com/features/code-review"> <svg aria-hidden="true" height="24" viewBox="0 0 24 24" version="1.1" width="24" data-view-component="true" class="octicon octicon-code-review color-fg-subtle mr-3"> <path d="M10.3 6.74a.75.75 0 0 1-.04 1.06l-2.908 2.7 2.908 2.7a.75.75 0 1 1-1.02 1.1l-3.5-3.25a.75.75 0 0 1 0-1.1l3.5-3.25a.75.75 0 0 1 1.06.04Zm3.44 1.06a.75.75 0 1 1 1.02-1.1l3.5 3.25a.75.75 0 0 1 0 1.1l-3.5 3.25a.75.75 0 1 1-1.02-1.1l2.908-2.7-2.908-2.7Z"></path><path d="M1.5 4.25c0-.966.784-1.75 1.75-1.75h17.5c.966 0 1.75.784 1.75 1.75v12.5a1.75 1.75 0 0 1-1.75 1.75h-9.69l-3.573 3.573A1.458 1.458 0 0 1 5 21.043V18.5H3.25a1.75 1.75 0 0 1-1.75-1.75ZM3.25 4a.25.25 0 0 0-.25.25v12.5c0 .138.112.25.25.25h2.5a.75.75 0 0 1 .75.75v3.19l3.72-3.72a.749.749 0 0 1 .53-.22h10a.25.25 0 0 0 .25-.25V4.25a.25.25 0 0 0-.25-.25Z"></path> </svg> <div> <div class="color-fg-default h4">Code Review</div> Manage code changes </div> </a></li> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary d-flex flex-items-center Link--has-description pb-lg-3" data-analytics-event="{&quot;location&quot;:&quot;navbar&quot;,&quot;action&quot;:&quot;discussions&quot;,&quot;context&quot;:&quot;product&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;label&quot;:&quot;discussions_link_product_navbar&quot;}" href="https://github.com/features/discussions"> <svg aria-hidden="true" height="24" viewBox="0 0 24 24" version="1.1" width="24" data-view-component="true" class="octicon octicon-comment-discussion color-fg-subtle mr-3"> <path d="M1.75 1h12.5c.966 0 1.75.784 1.75 1.75v9.5A1.75 1.75 0 0 1 14.25 14H8.061l-2.574 2.573A1.458 1.458 0 0 1 3 15.543V14H1.75A1.75 1.75 0 0 1 0 12.25v-9.5C0 1.784.784 1 1.75 1ZM1.5 2.75v9.5c0 .138.112.25.25.25h2a.75.75 0 0 1 .75.75v2.19l2.72-2.72a.749.749 0 0 1 .53-.22h6.5a.25.25 0 0 0 .25-.25v-9.5a.25.25 0 0 0-.25-.25H1.75a.25.25 0 0 0-.25.25Z"></path><path d="M22.5 8.75a.25.25 0 0 0-.25-.25h-3.5a.75.75 0 0 1 0-1.5h3.5c.966 0 1.75.784 1.75 1.75v9.5A1.75 1.75 0 0 1 22.25 20H21v1.543a1.457 1.457 0 0 1-2.487 1.03L15.939 20H10.75A1.75 1.75 0 0 1 9 18.25v-1.465a.75.75 0 0 1 1.5 0v1.465c0 .138.112.25.25.25h5.5a.75.75 0 0 1 .53.22l2.72 2.72v-2.19a.75.75 0 0 1 .75-.75h2a.25.25 0 0 0 .25-.25v-9.5Z"></path> </svg> <div> <div class="color-fg-default h4">Discussions</div> Collaborate outside of code </div> </a></li> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary d-flex flex-items-center Link--has-description" data-analytics-event="{&quot;location&quot;:&quot;navbar&quot;,&quot;action&quot;:&quot;code_search&quot;,&quot;context&quot;:&quot;product&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;label&quot;:&quot;code_search_link_product_navbar&quot;}" href="https://github.com/features/code-search"> <svg aria-hidden="true" height="24" viewBox="0 0 24 24" version="1.1" width="24" data-view-component="true" class="octicon octicon-code-square color-fg-subtle mr-3"> <path d="M10.3 8.24a.75.75 0 0 1-.04 1.06L7.352 12l2.908 2.7a.75.75 0 1 1-1.02 1.1l-3.5-3.25a.75.75 0 0 1 0-1.1l3.5-3.25a.75.75 0 0 1 1.06.04Zm3.44 1.06a.75.75 0 1 1 1.02-1.1l3.5 3.25a.75.75 0 0 1 0 1.1l-3.5 3.25a.75.75 0 1 1-1.02-1.1l2.908-2.7-2.908-2.7Z"></path><path d="M2 3.75C2 2.784 2.784 2 3.75 2h16.5c.966 0 1.75.784 1.75 1.75v16.5A1.75 1.75 0 0 1 20.25 22H3.75A1.75 1.75 0 0 1 2 20.25Zm1.75-.25a.25.25 0 0 0-.25.25v16.5c0 .138.112.25.25.25h16.5a.25.25 0 0 0 .25-.25V3.75a.25.25 0 0 0-.25-.25Z"></path> </svg> <div> <div class="color-fg-default h4">Code Search</div> Find more, search less </div> </a></li> </ul> </div> </div> <div class="HeaderMenu-column px-lg-4"> <div class="border-bottom pb-3 pb-lg-0 border-lg-bottom-0 border-bottom-0"> <span class="d-block h4 color-fg-default my-1" id="product-explore-heading">Explore</span> <ul class="list-style-none f5" aria-labelledby="product-explore-heading"> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary" data-analytics-event="{&quot;location&quot;:&quot;navbar&quot;,&quot;action&quot;:&quot;all_features&quot;,&quot;context&quot;:&quot;product&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;label&quot;:&quot;all_features_link_product_navbar&quot;}" href="https://github.com/features"> All features </a></li> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary Link--external" target="_blank" data-analytics-event="{&quot;location&quot;:&quot;navbar&quot;,&quot;action&quot;:&quot;documentation&quot;,&quot;context&quot;:&quot;product&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;label&quot;:&quot;documentation_link_product_navbar&quot;}" href="https://docs.github.com"> Documentation <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-link-external HeaderMenu-external-icon color-fg-subtle"> <path d="M3.75 2h3.5a.75.75 0 0 1 0 1.5h-3.5a.25.25 0 0 0-.25.25v8.5c0 .138.112.25.25.25h8.5a.25.25 0 0 0 .25-.25v-3.5a.75.75 0 0 1 1.5 0v3.5A1.75 1.75 0 0 1 12.25 14h-8.5A1.75 1.75 0 0 1 2 12.25v-8.5C2 2.784 2.784 2 3.75 2Zm6.854-1h4.146a.25.25 0 0 1 .25.25v4.146a.25.25 0 0 1-.427.177L13.03 4.03 9.28 7.78a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042l3.75-3.75-1.543-1.543A.25.25 0 0 1 10.604 1Z"></path> </svg> </a></li> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary Link--external" target="_blank" data-analytics-event="{&quot;location&quot;:&quot;navbar&quot;,&quot;action&quot;:&quot;github_skills&quot;,&quot;context&quot;:&quot;product&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;label&quot;:&quot;github_skills_link_product_navbar&quot;}" href="https://skills.github.com"> GitHub Skills <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-link-external HeaderMenu-external-icon color-fg-subtle"> <path d="M3.75 2h3.5a.75.75 0 0 1 0 1.5h-3.5a.25.25 0 0 0-.25.25v8.5c0 .138.112.25.25.25h8.5a.25.25 0 0 0 .25-.25v-3.5a.75.75 0 0 1 1.5 0v3.5A1.75 1.75 0 0 1 12.25 14h-8.5A1.75 1.75 0 0 1 2 12.25v-8.5C2 2.784 2.784 2 3.75 2Zm6.854-1h4.146a.25.25 0 0 1 .25.25v4.146a.25.25 0 0 1-.427.177L13.03 4.03 9.28 7.78a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042l3.75-3.75-1.543-1.543A.25.25 0 0 1 10.604 1Z"></path> </svg> </a></li> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary Link--external" target="_blank" data-analytics-event="{&quot;location&quot;:&quot;navbar&quot;,&quot;action&quot;:&quot;blog&quot;,&quot;context&quot;:&quot;product&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;label&quot;:&quot;blog_link_product_navbar&quot;}" href="https://github.blog"> Blog <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-link-external HeaderMenu-external-icon color-fg-subtle"> <path d="M3.75 2h3.5a.75.75 0 0 1 0 1.5h-3.5a.25.25 0 0 0-.25.25v8.5c0 .138.112.25.25.25h8.5a.25.25 0 0 0 .25-.25v-3.5a.75.75 0 0 1 1.5 0v3.5A1.75 1.75 0 0 1 12.25 14h-8.5A1.75 1.75 0 0 1 2 12.25v-8.5C2 2.784 2.784 2 3.75 2Zm6.854-1h4.146a.25.25 0 0 1 .25.25v4.146a.25.25 0 0 1-.427.177L13.03 4.03 9.28 7.78a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042l3.75-3.75-1.543-1.543A.25.25 0 0 1 10.604 1Z"></path> </svg> </a></li> </ul> </div> </div> </div> </li> <li class="HeaderMenu-item position-relative flex-wrap flex-justify-between flex-items-center d-block d-lg-flex flex-lg-nowrap flex-lg-items-center js-details-container js-header-menu-item"> <button type="button" class="HeaderMenu-link border-0 width-full width-lg-auto px-0 px-lg-2 py-lg-2 no-wrap d-flex flex-items-center flex-justify-between js-details-target" aria-expanded="false"> Solutions <svg opacity="0.5" aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-chevron-down HeaderMenu-icon ml-1"> <path d="M12.78 5.22a.749.749 0 0 1 0 1.06l-4.25 4.25a.749.749 0 0 1-1.06 0L3.22 6.28a.749.749 0 1 1 1.06-1.06L8 8.939l3.72-3.719a.749.749 0 0 1 1.06 0Z"></path> </svg> </button> <div class="HeaderMenu-dropdown dropdown-menu rounded m-0 p-0 pt-2 pt-lg-4 position-relative position-lg-absolute left-0 left-lg-n3 d-lg-flex flex-wrap dropdown-menu-wide"> <div class="HeaderMenu-column px-lg-4 border-lg-right mb-4 mb-lg-0 pr-lg-7"> <div class="border-bottom pb-3 pb-lg-0 border-lg-bottom-0 pb-lg-3 mb-3 mb-lg-0"> <span class="d-block h4 color-fg-default my-1" id="solutions-by-company-size-heading">By company size</span> <ul class="list-style-none f5" aria-labelledby="solutions-by-company-size-heading"> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary" data-analytics-event="{&quot;location&quot;:&quot;navbar&quot;,&quot;action&quot;:&quot;enterprises&quot;,&quot;context&quot;:&quot;solutions&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;label&quot;:&quot;enterprises_link_solutions_navbar&quot;}" href="https://github.com/enterprise"> Enterprises </a></li> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary" data-analytics-event="{&quot;location&quot;:&quot;navbar&quot;,&quot;action&quot;:&quot;small_and_medium_teams&quot;,&quot;context&quot;:&quot;solutions&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;label&quot;:&quot;small_and_medium_teams_link_solutions_navbar&quot;}" href="https://github.com/team"> Small and medium teams </a></li> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary" data-analytics-event="{&quot;location&quot;:&quot;navbar&quot;,&quot;action&quot;:&quot;startups&quot;,&quot;context&quot;:&quot;solutions&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;label&quot;:&quot;startups_link_solutions_navbar&quot;}" href="https://github.com/enterprise/startups"> Startups </a></li> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary" data-analytics-event="{&quot;location&quot;:&quot;navbar&quot;,&quot;action&quot;:&quot;nonprofits&quot;,&quot;context&quot;:&quot;solutions&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;label&quot;:&quot;nonprofits_link_solutions_navbar&quot;}" href="/solutions/industry/nonprofits"> Nonprofits </a></li> </ul> </div> <div class="border-bottom pb-3 pb-lg-0 border-lg-bottom-0"> <span class="d-block h4 color-fg-default my-1" id="solutions-by-use-case-heading">By use case</span> <ul class="list-style-none f5" aria-labelledby="solutions-by-use-case-heading"> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary" data-analytics-event="{&quot;location&quot;:&quot;navbar&quot;,&quot;action&quot;:&quot;devsecops&quot;,&quot;context&quot;:&quot;solutions&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;label&quot;:&quot;devsecops_link_solutions_navbar&quot;}" href="/solutions/use-case/devsecops"> DevSecOps </a></li> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary" data-analytics-event="{&quot;location&quot;:&quot;navbar&quot;,&quot;action&quot;:&quot;devops&quot;,&quot;context&quot;:&quot;solutions&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;label&quot;:&quot;devops_link_solutions_navbar&quot;}" href="/solutions/use-case/devops"> DevOps </a></li> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary" data-analytics-event="{&quot;location&quot;:&quot;navbar&quot;,&quot;action&quot;:&quot;ci_cd&quot;,&quot;context&quot;:&quot;solutions&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;label&quot;:&quot;ci_cd_link_solutions_navbar&quot;}" href="/solutions/use-case/ci-cd"> CI/CD </a></li> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary" data-analytics-event="{&quot;location&quot;:&quot;navbar&quot;,&quot;action&quot;:&quot;view_all_use_cases&quot;,&quot;context&quot;:&quot;solutions&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;label&quot;:&quot;view_all_use_cases_link_solutions_navbar&quot;}" href="/solutions/use-case"> View all use cases </a></li> </ul> </div> </div> <div class="HeaderMenu-column px-lg-4"> <div class="border-bottom pb-3 pb-lg-0 border-lg-bottom-0"> <span class="d-block h4 color-fg-default my-1" id="solutions-by-industry-heading">By industry</span> <ul class="list-style-none f5" aria-labelledby="solutions-by-industry-heading"> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary" data-analytics-event="{&quot;location&quot;:&quot;navbar&quot;,&quot;action&quot;:&quot;healthcare&quot;,&quot;context&quot;:&quot;solutions&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;label&quot;:&quot;healthcare_link_solutions_navbar&quot;}" href="/solutions/industry/healthcare"> Healthcare </a></li> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary" data-analytics-event="{&quot;location&quot;:&quot;navbar&quot;,&quot;action&quot;:&quot;financial_services&quot;,&quot;context&quot;:&quot;solutions&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;label&quot;:&quot;financial_services_link_solutions_navbar&quot;}" href="/solutions/industry/financial-services"> Financial services </a></li> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary" data-analytics-event="{&quot;location&quot;:&quot;navbar&quot;,&quot;action&quot;:&quot;manufacturing&quot;,&quot;context&quot;:&quot;solutions&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;label&quot;:&quot;manufacturing_link_solutions_navbar&quot;}" href="/solutions/industry/manufacturing"> Manufacturing </a></li> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary" data-analytics-event="{&quot;location&quot;:&quot;navbar&quot;,&quot;action&quot;:&quot;government&quot;,&quot;context&quot;:&quot;solutions&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;label&quot;:&quot;government_link_solutions_navbar&quot;}" href="/solutions/industry/government"> Government </a></li> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary" data-analytics-event="{&quot;location&quot;:&quot;navbar&quot;,&quot;action&quot;:&quot;view_all_industries&quot;,&quot;context&quot;:&quot;solutions&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;label&quot;:&quot;view_all_industries_link_solutions_navbar&quot;}" href="/solutions/industry"> View all industries </a></li> </ul> </div> </div> <div class="HeaderMenu-trailing-link rounded-bottom-2 flex-shrink-0 mt-lg-4 px-lg-4 py-4 py-lg-3 f5 text-semibold"> <a href="/solutions"> View all solutions <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-chevron-right HeaderMenu-trailing-link-icon"> <path d="M6.22 3.22a.75.75 0 0 1 1.06 0l4.25 4.25a.75.75 0 0 1 0 1.06l-4.25 4.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042L9.94 8 6.22 4.28a.75.75 0 0 1 0-1.06Z"></path> </svg> </a> </div> </div> </li> <li class="HeaderMenu-item position-relative flex-wrap flex-justify-between flex-items-center d-block d-lg-flex flex-lg-nowrap flex-lg-items-center js-details-container js-header-menu-item"> <button type="button" class="HeaderMenu-link border-0 width-full width-lg-auto px-0 px-lg-2 py-lg-2 no-wrap d-flex flex-items-center flex-justify-between js-details-target" aria-expanded="false"> Resources <svg opacity="0.5" aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-chevron-down HeaderMenu-icon ml-1"> <path d="M12.78 5.22a.749.749 0 0 1 0 1.06l-4.25 4.25a.749.749 0 0 1-1.06 0L3.22 6.28a.749.749 0 1 1 1.06-1.06L8 8.939l3.72-3.719a.749.749 0 0 1 1.06 0Z"></path> </svg> </button> <div class="HeaderMenu-dropdown dropdown-menu rounded m-0 p-0 pt-2 pt-lg-4 position-relative position-lg-absolute left-0 left-lg-n3 pb-2 pb-lg-4 d-lg-flex flex-wrap dropdown-menu-wide"> <div class="HeaderMenu-column px-lg-4 border-lg-right mb-4 mb-lg-0 pr-lg-7"> <div class="border-bottom pb-3 pb-lg-0 border-lg-bottom-0"> <span class="d-block h4 color-fg-default my-1" id="resources-topics-heading">Topics</span> <ul class="list-style-none f5" aria-labelledby="resources-topics-heading"> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary" data-analytics-event="{&quot;location&quot;:&quot;navbar&quot;,&quot;action&quot;:&quot;ai&quot;,&quot;context&quot;:&quot;resources&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;label&quot;:&quot;ai_link_resources_navbar&quot;}" href="/resources/articles/ai"> AI </a></li> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary" data-analytics-event="{&quot;location&quot;:&quot;navbar&quot;,&quot;action&quot;:&quot;devops&quot;,&quot;context&quot;:&quot;resources&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;label&quot;:&quot;devops_link_resources_navbar&quot;}" href="/resources/articles/devops"> DevOps </a></li> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary" data-analytics-event="{&quot;location&quot;:&quot;navbar&quot;,&quot;action&quot;:&quot;security&quot;,&quot;context&quot;:&quot;resources&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;label&quot;:&quot;security_link_resources_navbar&quot;}" href="/resources/articles/security"> Security </a></li> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary" data-analytics-event="{&quot;location&quot;:&quot;navbar&quot;,&quot;action&quot;:&quot;software_development&quot;,&quot;context&quot;:&quot;resources&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;label&quot;:&quot;software_development_link_resources_navbar&quot;}" href="/resources/articles/software-development"> Software Development </a></li> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary" data-analytics-event="{&quot;location&quot;:&quot;navbar&quot;,&quot;action&quot;:&quot;view_all&quot;,&quot;context&quot;:&quot;resources&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;label&quot;:&quot;view_all_link_resources_navbar&quot;}" href="/resources/articles"> View all </a></li> </ul> </div> </div> <div class="HeaderMenu-column px-lg-4"> <div class="border-bottom pb-3 pb-lg-0 border-lg-bottom-0 border-bottom-0"> <span class="d-block h4 color-fg-default my-1" id="resources-explore-heading">Explore</span> <ul class="list-style-none f5" aria-labelledby="resources-explore-heading"> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary Link--external" target="_blank" data-analytics-event="{&quot;location&quot;:&quot;navbar&quot;,&quot;action&quot;:&quot;learning_pathways&quot;,&quot;context&quot;:&quot;resources&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;label&quot;:&quot;learning_pathways_link_resources_navbar&quot;}" href="https://resources.github.com/learn/pathways"> Learning Pathways <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-link-external HeaderMenu-external-icon color-fg-subtle"> <path d="M3.75 2h3.5a.75.75 0 0 1 0 1.5h-3.5a.25.25 0 0 0-.25.25v8.5c0 .138.112.25.25.25h8.5a.25.25 0 0 0 .25-.25v-3.5a.75.75 0 0 1 1.5 0v3.5A1.75 1.75 0 0 1 12.25 14h-8.5A1.75 1.75 0 0 1 2 12.25v-8.5C2 2.784 2.784 2 3.75 2Zm6.854-1h4.146a.25.25 0 0 1 .25.25v4.146a.25.25 0 0 1-.427.177L13.03 4.03 9.28 7.78a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042l3.75-3.75-1.543-1.543A.25.25 0 0 1 10.604 1Z"></path> </svg> </a></li> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary Link--external" target="_blank" data-analytics-event="{&quot;location&quot;:&quot;navbar&quot;,&quot;action&quot;:&quot;events_amp_webinars&quot;,&quot;context&quot;:&quot;resources&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;label&quot;:&quot;events_amp_webinars_link_resources_navbar&quot;}" href="https://resources.github.com"> Events &amp; Webinars <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-link-external HeaderMenu-external-icon color-fg-subtle"> <path d="M3.75 2h3.5a.75.75 0 0 1 0 1.5h-3.5a.25.25 0 0 0-.25.25v8.5c0 .138.112.25.25.25h8.5a.25.25 0 0 0 .25-.25v-3.5a.75.75 0 0 1 1.5 0v3.5A1.75 1.75 0 0 1 12.25 14h-8.5A1.75 1.75 0 0 1 2 12.25v-8.5C2 2.784 2.784 2 3.75 2Zm6.854-1h4.146a.25.25 0 0 1 .25.25v4.146a.25.25 0 0 1-.427.177L13.03 4.03 9.28 7.78a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042l3.75-3.75-1.543-1.543A.25.25 0 0 1 10.604 1Z"></path> </svg> </a></li> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary" data-analytics-event="{&quot;location&quot;:&quot;navbar&quot;,&quot;action&quot;:&quot;ebooks_amp_whitepapers&quot;,&quot;context&quot;:&quot;resources&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;label&quot;:&quot;ebooks_amp_whitepapers_link_resources_navbar&quot;}" href="https://github.com/resources/whitepapers"> Ebooks &amp; Whitepapers </a></li> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary" data-analytics-event="{&quot;location&quot;:&quot;navbar&quot;,&quot;action&quot;:&quot;customer_stories&quot;,&quot;context&quot;:&quot;resources&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;label&quot;:&quot;customer_stories_link_resources_navbar&quot;}" href="https://github.com/customer-stories"> Customer Stories </a></li> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary Link--external" target="_blank" data-analytics-event="{&quot;location&quot;:&quot;navbar&quot;,&quot;action&quot;:&quot;partners&quot;,&quot;context&quot;:&quot;resources&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;label&quot;:&quot;partners_link_resources_navbar&quot;}" href="https://partner.github.com"> Partners <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-link-external HeaderMenu-external-icon color-fg-subtle"> <path d="M3.75 2h3.5a.75.75 0 0 1 0 1.5h-3.5a.25.25 0 0 0-.25.25v8.5c0 .138.112.25.25.25h8.5a.25.25 0 0 0 .25-.25v-3.5a.75.75 0 0 1 1.5 0v3.5A1.75 1.75 0 0 1 12.25 14h-8.5A1.75 1.75 0 0 1 2 12.25v-8.5C2 2.784 2.784 2 3.75 2Zm6.854-1h4.146a.25.25 0 0 1 .25.25v4.146a.25.25 0 0 1-.427.177L13.03 4.03 9.28 7.78a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042l3.75-3.75-1.543-1.543A.25.25 0 0 1 10.604 1Z"></path> </svg> </a></li> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary" data-analytics-event="{&quot;location&quot;:&quot;navbar&quot;,&quot;action&quot;:&quot;executive_insights&quot;,&quot;context&quot;:&quot;resources&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;label&quot;:&quot;executive_insights_link_resources_navbar&quot;}" href="https://github.com/solutions/executive-insights"> Executive Insights </a></li> </ul> </div> </div> </div> </li> <li class="HeaderMenu-item position-relative flex-wrap flex-justify-between flex-items-center d-block d-lg-flex flex-lg-nowrap flex-lg-items-center js-details-container js-header-menu-item"> <button type="button" class="HeaderMenu-link border-0 width-full width-lg-auto px-0 px-lg-2 py-lg-2 no-wrap d-flex flex-items-center flex-justify-between js-details-target" aria-expanded="false"> Open Source <svg opacity="0.5" aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-chevron-down HeaderMenu-icon ml-1"> <path d="M12.78 5.22a.749.749 0 0 1 0 1.06l-4.25 4.25a.749.749 0 0 1-1.06 0L3.22 6.28a.749.749 0 1 1 1.06-1.06L8 8.939l3.72-3.719a.749.749 0 0 1 1.06 0Z"></path> </svg> </button> <div class="HeaderMenu-dropdown dropdown-menu rounded m-0 p-0 pt-2 pt-lg-4 position-relative position-lg-absolute left-0 left-lg-n3 pb-2 pb-lg-4 px-lg-4"> <div class="HeaderMenu-column"> <div class="border-bottom pb-3 pb-lg-0 pb-lg-3 mb-3 mb-lg-0 mb-lg-3"> <ul class="list-style-none f5" > <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary d-flex flex-items-center Link--has-description" data-analytics-event="{&quot;location&quot;:&quot;navbar&quot;,&quot;action&quot;:&quot;github_sponsors&quot;,&quot;context&quot;:&quot;open_source&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;label&quot;:&quot;github_sponsors_link_open_source_navbar&quot;}" href="/sponsors"> <div> <div class="color-fg-default h4">GitHub Sponsors</div> Fund open source developers </div> </a></li> </ul> </div> <div class="border-bottom pb-3 pb-lg-0 pb-lg-3 mb-3 mb-lg-0 mb-lg-3"> <ul class="list-style-none f5" > <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary d-flex flex-items-center Link--has-description" data-analytics-event="{&quot;location&quot;:&quot;navbar&quot;,&quot;action&quot;:&quot;the_readme_project&quot;,&quot;context&quot;:&quot;open_source&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;label&quot;:&quot;the_readme_project_link_open_source_navbar&quot;}" href="https://github.com/readme"> <div> <div class="color-fg-default h4">The ReadME Project</div> GitHub community articles </div> </a></li> </ul> </div> <div class="border-bottom pb-3 pb-lg-0 border-bottom-0"> <span class="d-block h4 color-fg-default my-1" id="open-source-repositories-heading">Repositories</span> <ul class="list-style-none f5" aria-labelledby="open-source-repositories-heading"> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary" data-analytics-event="{&quot;location&quot;:&quot;navbar&quot;,&quot;action&quot;:&quot;topics&quot;,&quot;context&quot;:&quot;open_source&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;label&quot;:&quot;topics_link_open_source_navbar&quot;}" href="https://github.com/topics"> Topics </a></li> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary" data-analytics-event="{&quot;location&quot;:&quot;navbar&quot;,&quot;action&quot;:&quot;trending&quot;,&quot;context&quot;:&quot;open_source&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;label&quot;:&quot;trending_link_open_source_navbar&quot;}" href="https://github.com/trending"> Trending </a></li> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary" data-analytics-event="{&quot;location&quot;:&quot;navbar&quot;,&quot;action&quot;:&quot;collections&quot;,&quot;context&quot;:&quot;open_source&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;label&quot;:&quot;collections_link_open_source_navbar&quot;}" href="https://github.com/collections"> Collections </a></li> </ul> </div> </div> </div> </li> <li class="HeaderMenu-item position-relative flex-wrap flex-justify-between flex-items-center d-block d-lg-flex flex-lg-nowrap flex-lg-items-center js-details-container js-header-menu-item"> <button type="button" class="HeaderMenu-link border-0 width-full width-lg-auto px-0 px-lg-2 py-lg-2 no-wrap d-flex flex-items-center flex-justify-between js-details-target" aria-expanded="false"> Enterprise <svg opacity="0.5" aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-chevron-down HeaderMenu-icon ml-1"> <path d="M12.78 5.22a.749.749 0 0 1 0 1.06l-4.25 4.25a.749.749 0 0 1-1.06 0L3.22 6.28a.749.749 0 1 1 1.06-1.06L8 8.939l3.72-3.719a.749.749 0 0 1 1.06 0Z"></path> </svg> </button> <div class="HeaderMenu-dropdown dropdown-menu rounded m-0 p-0 pt-2 pt-lg-4 position-relative position-lg-absolute left-0 left-lg-n3 pb-2 pb-lg-4 px-lg-4"> <div class="HeaderMenu-column"> <div class="border-bottom pb-3 pb-lg-0 pb-lg-3 mb-3 mb-lg-0 mb-lg-3"> <ul class="list-style-none f5" > <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary d-flex flex-items-center Link--has-description" data-analytics-event="{&quot;location&quot;:&quot;navbar&quot;,&quot;action&quot;:&quot;enterprise_platform&quot;,&quot;context&quot;:&quot;enterprise&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;label&quot;:&quot;enterprise_platform_link_enterprise_navbar&quot;}" href="/enterprise"> <svg aria-hidden="true" height="24" viewBox="0 0 24 24" version="1.1" width="24" data-view-component="true" class="octicon octicon-stack color-fg-subtle mr-3"> <path d="M11.063 1.456a1.749 1.749 0 0 1 1.874 0l8.383 5.316a1.751 1.751 0 0 1 0 2.956l-8.383 5.316a1.749 1.749 0 0 1-1.874 0L2.68 9.728a1.751 1.751 0 0 1 0-2.956Zm1.071 1.267a.25.25 0 0 0-.268 0L3.483 8.039a.25.25 0 0 0 0 .422l8.383 5.316a.25.25 0 0 0 .268 0l8.383-5.316a.25.25 0 0 0 0-.422Z"></path><path d="M1.867 12.324a.75.75 0 0 1 1.035-.232l8.964 5.685a.25.25 0 0 0 .268 0l8.964-5.685a.75.75 0 0 1 .804 1.267l-8.965 5.685a1.749 1.749 0 0 1-1.874 0l-8.965-5.685a.75.75 0 0 1-.231-1.035Z"></path><path d="M1.867 16.324a.75.75 0 0 1 1.035-.232l8.964 5.685a.25.25 0 0 0 .268 0l8.964-5.685a.75.75 0 0 1 .804 1.267l-8.965 5.685a1.749 1.749 0 0 1-1.874 0l-8.965-5.685a.75.75 0 0 1-.231-1.035Z"></path> </svg> <div> <div class="color-fg-default h4">Enterprise platform</div> AI-powered developer platform </div> </a></li> </ul> </div> <div class="border-bottom pb-3 pb-lg-0 border-bottom-0"> <span class="d-block h4 color-fg-default my-1" id="enterprise-available-add-ons-heading">Available add-ons</span> <ul class="list-style-none f5" aria-labelledby="enterprise-available-add-ons-heading"> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary d-flex flex-items-center Link--has-description pb-lg-3" data-analytics-event="{&quot;location&quot;:&quot;navbar&quot;,&quot;action&quot;:&quot;advanced_security&quot;,&quot;context&quot;:&quot;enterprise&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;label&quot;:&quot;advanced_security_link_enterprise_navbar&quot;}" href="https://github.com/enterprise/advanced-security"> <svg aria-hidden="true" height="24" viewBox="0 0 24 24" version="1.1" width="24" data-view-component="true" class="octicon octicon-shield-check color-fg-subtle mr-3"> <path d="M16.53 9.78a.75.75 0 0 0-1.06-1.06L11 13.19l-1.97-1.97a.75.75 0 0 0-1.06 1.06l2.5 2.5a.75.75 0 0 0 1.06 0l5-5Z"></path><path d="m12.54.637 8.25 2.675A1.75 1.75 0 0 1 22 4.976V10c0 6.19-3.771 10.704-9.401 12.83a1.704 1.704 0 0 1-1.198 0C5.77 20.705 2 16.19 2 10V4.976c0-.758.489-1.43 1.21-1.664L11.46.637a1.748 1.748 0 0 1 1.08 0Zm-.617 1.426-8.25 2.676a.249.249 0 0 0-.173.237V10c0 5.46 3.28 9.483 8.43 11.426a.199.199 0 0 0 .14 0C17.22 19.483 20.5 15.461 20.5 10V4.976a.25.25 0 0 0-.173-.237l-8.25-2.676a.253.253 0 0 0-.154 0Z"></path> </svg> <div> <div class="color-fg-default h4">Advanced Security</div> Enterprise-grade security features </div> </a></li> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary d-flex flex-items-center Link--has-description pb-lg-3" data-analytics-event="{&quot;location&quot;:&quot;navbar&quot;,&quot;action&quot;:&quot;copilot_for_business&quot;,&quot;context&quot;:&quot;enterprise&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;label&quot;:&quot;copilot_for_business_link_enterprise_navbar&quot;}" href="/features/copilot/copilot-business"> <svg aria-hidden="true" height="24" viewBox="0 0 24 24" version="1.1" width="24" data-view-component="true" class="octicon octicon-copilot color-fg-subtle mr-3"> <path d="M23.922 16.992c-.861 1.495-5.859 5.023-11.922 5.023-6.063 0-11.061-3.528-11.922-5.023A.641.641 0 0 1 0 16.736v-2.869a.841.841 0 0 1 .053-.22c.372-.935 1.347-2.292 2.605-2.656.167-.429.414-1.055.644-1.517a10.195 10.195 0 0 1-.052-1.086c0-1.331.282-2.499 1.132-3.368.397-.406.89-.717 1.474-.952 1.399-1.136 3.392-2.093 6.122-2.093 2.731 0 4.767.957 6.166 2.093.584.235 1.077.546 1.474.952.85.869 1.132 2.037 1.132 3.368 0 .368-.014.733-.052 1.086.23.462.477 1.088.644 1.517 1.258.364 2.233 1.721 2.605 2.656a.832.832 0 0 1 .053.22v2.869a.641.641 0 0 1-.078.256ZM12.172 11h-.344a4.323 4.323 0 0 1-.355.508C10.703 12.455 9.555 13 7.965 13c-1.725 0-2.989-.359-3.782-1.259a2.005 2.005 0 0 1-.085-.104L4 11.741v6.585c1.435.779 4.514 2.179 8 2.179 3.486 0 6.565-1.4 8-2.179v-6.585l-.098-.104s-.033.045-.085.104c-.793.9-2.057 1.259-3.782 1.259-1.59 0-2.738-.545-3.508-1.492a4.323 4.323 0 0 1-.355-.508h-.016.016Zm.641-2.935c.136 1.057.403 1.913.878 2.497.442.544 1.134.938 2.344.938 1.573 0 2.292-.337 2.657-.751.384-.435.558-1.15.558-2.361 0-1.14-.243-1.847-.705-2.319-.477-.488-1.319-.862-2.824-1.025-1.487-.161-2.192.138-2.533.529-.269.307-.437.808-.438 1.578v.021c0 .265.021.562.063.893Zm-1.626 0c.042-.331.063-.628.063-.894v-.02c-.001-.77-.169-1.271-.438-1.578-.341-.391-1.046-.69-2.533-.529-1.505.163-2.347.537-2.824 1.025-.462.472-.705 1.179-.705 2.319 0 1.211.175 1.926.558 2.361.365.414 1.084.751 2.657.751 1.21 0 1.902-.394 2.344-.938.475-.584.742-1.44.878-2.497Z"></path><path d="M14.5 14.25a1 1 0 0 1 1 1v2a1 1 0 0 1-2 0v-2a1 1 0 0 1 1-1Zm-5 0a1 1 0 0 1 1 1v2a1 1 0 0 1-2 0v-2a1 1 0 0 1 1-1Z"></path> </svg> <div> <div class="color-fg-default h4">Copilot for business</div> Enterprise-grade AI features </div> </a></li> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary d-flex flex-items-center Link--has-description" data-analytics-event="{&quot;location&quot;:&quot;navbar&quot;,&quot;action&quot;:&quot;premium_support&quot;,&quot;context&quot;:&quot;enterprise&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;label&quot;:&quot;premium_support_link_enterprise_navbar&quot;}" href="/premium-support"> <svg aria-hidden="true" height="24" viewBox="0 0 24 24" version="1.1" width="24" data-view-component="true" class="octicon octicon-comment-discussion color-fg-subtle mr-3"> <path d="M1.75 1h12.5c.966 0 1.75.784 1.75 1.75v9.5A1.75 1.75 0 0 1 14.25 14H8.061l-2.574 2.573A1.458 1.458 0 0 1 3 15.543V14H1.75A1.75 1.75 0 0 1 0 12.25v-9.5C0 1.784.784 1 1.75 1ZM1.5 2.75v9.5c0 .138.112.25.25.25h2a.75.75 0 0 1 .75.75v2.19l2.72-2.72a.749.749 0 0 1 .53-.22h6.5a.25.25 0 0 0 .25-.25v-9.5a.25.25 0 0 0-.25-.25H1.75a.25.25 0 0 0-.25.25Z"></path><path d="M22.5 8.75a.25.25 0 0 0-.25-.25h-3.5a.75.75 0 0 1 0-1.5h3.5c.966 0 1.75.784 1.75 1.75v9.5A1.75 1.75 0 0 1 22.25 20H21v1.543a1.457 1.457 0 0 1-2.487 1.03L15.939 20H10.75A1.75 1.75 0 0 1 9 18.25v-1.465a.75.75 0 0 1 1.5 0v1.465c0 .138.112.25.25.25h5.5a.75.75 0 0 1 .53.22l2.72 2.72v-2.19a.75.75 0 0 1 .75-.75h2a.25.25 0 0 0 .25-.25v-9.5Z"></path> </svg> <div> <div class="color-fg-default h4">Premium Support</div> Enterprise-grade 24/7 support </div> </a></li> </ul> </div> </div> </div> </li> <li class="HeaderMenu-item position-relative flex-wrap flex-justify-between flex-items-center d-block d-lg-flex flex-lg-nowrap flex-lg-items-center js-details-container js-header-menu-item"> <a class="HeaderMenu-link no-underline px-0 px-lg-2 py-3 py-lg-2 d-block d-lg-inline-block" data-analytics-event="{&quot;location&quot;:&quot;navbar&quot;,&quot;action&quot;:&quot;pricing&quot;,&quot;context&quot;:&quot;global&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;label&quot;:&quot;pricing_link_global_navbar&quot;}" href="https://github.com/pricing">Pricing</a> </li> </ul> </nav> <div class="d-flex flex-column flex-lg-row width-full flex-justify-end flex-lg-items-center text-center mt-3 mt-lg-0 text-lg-left ml-lg-3"> <qbsearch-input class="search-input" data-scope="repo:alexpovel/srgn" data-custom-scopes-path="/search/custom_scopes" data-delete-custom-scopes-csrf="-hcpYUkIgACRFe6PFi5FA3Y898_UK_VRWPcxwaE-O1UYhcybRbi0PWvClfXq1p_naCbNVmFOB7KUh_GbDZ7GRw" data-max-custom-scopes="10" data-header-redesign-enabled="false" data-initial-value="" data-blackbird-suggestions-path="/search/suggestions" data-jump-to-suggestions-path="/_graphql/GetSuggestedNavigationDestinations" data-current-repository="alexpovel/srgn" data-current-org="" data-current-owner="alexpovel" data-logged-in="false" data-copilot-chat-enabled="false" data-nl-search-enabled="false" data-retain-scroll-position="true"> <div class="search-input-container search-with-dialog position-relative d-flex flex-row flex-items-center mr-4 rounded" data-action="click:qbsearch-input#searchInputContainerClicked" > <button type="button" class="header-search-button placeholder input-button form-control d-flex flex-1 flex-self-stretch flex-items-center no-wrap width-full py-0 pl-2 pr-0 text-left border-0 box-shadow-none" data-target="qbsearch-input.inputButton" aria-label="Search or jump to…" aria-haspopup="dialog" placeholder="Search or jump to..." data-hotkey=s,/ autocapitalize="off" data-analytics-event="{&quot;location&quot;:&quot;navbar&quot;,&quot;action&quot;:&quot;searchbar&quot;,&quot;context&quot;:&quot;global&quot;,&quot;tag&quot;:&quot;input&quot;,&quot;label&quot;:&quot;searchbar_input_global_navbar&quot;}" data-action="click:qbsearch-input#handleExpand" > <div class="mr-2 color-fg-muted"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-search"> <path d="M10.68 11.74a6 6 0 0 1-7.922-8.982 6 6 0 0 1 8.982 7.922l3.04 3.04a.749.749 0 0 1-.326 1.275.749.749 0 0 1-.734-.215ZM11.5 7a4.499 4.499 0 1 0-8.997 0A4.499 4.499 0 0 0 11.5 7Z"></path> </svg> </div> <span class="flex-1" data-target="qbsearch-input.inputButtonText">Search or jump to...</span> <div class="d-flex" data-target="qbsearch-input.hotkeyIndicator"> <svg xmlns="http://www.w3.org/2000/svg" width="22" height="20" aria-hidden="true" class="mr-1"><path fill="none" stroke="#979A9C" opacity=".4" d="M3.5.5h12c1.7 0 3 1.3 3 3v13c0 1.7-1.3 3-3 3h-12c-1.7 0-3-1.3-3-3v-13c0-1.7 1.3-3 3-3z"></path><path fill="#979A9C" d="M11.8 6L8 15.1h-.9L10.8 6h1z"></path></svg> </div> </button> <input type="hidden" name="type" class="js-site-search-type-field"> <div class="Overlay--hidden " data-modal-dialog-overlay> <modal-dialog data-action="close:qbsearch-input#handleClose cancel:qbsearch-input#handleClose" data-target="qbsearch-input.searchSuggestionsDialog" role="dialog" id="search-suggestions-dialog" aria-modal="true" aria-labelledby="search-suggestions-dialog-header" data-view-component="true" class="Overlay Overlay--width-large Overlay--height-auto"> <h1 id="search-suggestions-dialog-header" class="sr-only">Search code, repositories, users, issues, pull requests...</h1> <div class="Overlay-body Overlay-body--paddingNone"> <div data-view-component="true"> <div class="search-suggestions position-fixed width-full color-shadow-large border color-fg-default color-bg-default overflow-hidden d-flex flex-column query-builder-container" style="border-radius: 12px;" data-target="qbsearch-input.queryBuilderContainer" hidden > <!-- '"` --><!-- </textarea></xmp> --></option></form><form id="query-builder-test-form" action="" accept-charset="UTF-8" method="get"> <query-builder data-target="qbsearch-input.queryBuilder" id="query-builder-query-builder-test" data-filter-key=":" data-view-component="true" class="QueryBuilder search-query-builder"> <div class="FormControl FormControl--fullWidth"> <label id="query-builder-test-label" for="query-builder-test" class="FormControl-label sr-only"> Search </label> <div class="QueryBuilder-StyledInput width-fit " data-target="query-builder.styledInput" > <span id="query-builder-test-leadingvisual-wrap" class="FormControl-input-leadingVisualWrap QueryBuilder-leadingVisualWrap"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-search FormControl-input-leadingVisual"> <path d="M10.68 11.74a6 6 0 0 1-7.922-8.982 6 6 0 0 1 8.982 7.922l3.04 3.04a.749.749 0 0 1-.326 1.275.749.749 0 0 1-.734-.215ZM11.5 7a4.499 4.499 0 1 0-8.997 0A4.499 4.499 0 0 0 11.5 7Z"></path> </svg> </span> <div data-target="query-builder.styledInputContainer" class="QueryBuilder-StyledInputContainer"> <div aria-hidden="true" class="QueryBuilder-StyledInputContent" data-target="query-builder.styledInputContent" ></div> <div class="QueryBuilder-InputWrapper"> <div aria-hidden="true" class="QueryBuilder-Sizer" data-target="query-builder.sizer"></div> <input id="query-builder-test" name="query-builder-test" value="" autocomplete="off" type="text" role="combobox" spellcheck="false" aria-expanded="false" aria-describedby="validation-157bdd63-cc6a-457e-8ab3-f26f4381e362" data-target="query-builder.input" data-action=" input:query-builder#inputChange blur:query-builder#inputBlur keydown:query-builder#inputKeydown focus:query-builder#inputFocus " data-view-component="true" class="FormControl-input QueryBuilder-Input FormControl-medium" /> </div> </div> <span class="sr-only" id="query-builder-test-clear">Clear</span> <button role="button" id="query-builder-test-clear-button" aria-labelledby="query-builder-test-clear query-builder-test-label" data-target="query-builder.clearButton" data-action=" click:query-builder#clear focus:query-builder#clearButtonFocus blur:query-builder#clearButtonBlur " variant="small" hidden="hidden" type="button" data-view-component="true" class="Button Button--iconOnly Button--invisible Button--medium mr-1 px-2 py-0 d-flex flex-items-center rounded-1 color-fg-muted"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-x-circle-fill Button-visual"> <path d="M2.343 13.657A8 8 0 1 1 13.658 2.343 8 8 0 0 1 2.343 13.657ZM6.03 4.97a.751.751 0 0 0-1.042.018.751.751 0 0 0-.018 1.042L6.94 8 4.97 9.97a.749.749 0 0 0 .326 1.275.749.749 0 0 0 .734-.215L8 9.06l1.97 1.97a.749.749 0 0 0 1.275-.326.749.749 0 0 0-.215-.734L9.06 8l1.97-1.97a.749.749 0 0 0-.326-1.275.749.749 0 0 0-.734.215L8 6.94Z"></path> </svg> </button> </div> <template id="search-icon"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-search"> <path d="M10.68 11.74a6 6 0 0 1-7.922-8.982 6 6 0 0 1 8.982 7.922l3.04 3.04a.749.749 0 0 1-.326 1.275.749.749 0 0 1-.734-.215ZM11.5 7a4.499 4.499 0 1 0-8.997 0A4.499 4.499 0 0 0 11.5 7Z"></path> </svg> </template> <template id="code-icon"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-code"> <path d="m11.28 3.22 4.25 4.25a.75.75 0 0 1 0 1.06l-4.25 4.25a.749.749 0 0 1-1.275-.326.749.749 0 0 1 .215-.734L13.94 8l-3.72-3.72a.749.749 0 0 1 .326-1.275.749.749 0 0 1 .734.215Zm-6.56 0a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042L2.06 8l3.72 3.72a.749.749 0 0 1-.326 1.275.749.749 0 0 1-.734-.215L.47 8.53a.75.75 0 0 1 0-1.06Z"></path> </svg> </template> <template id="file-code-icon"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-file-code"> <path d="M4 1.75C4 .784 4.784 0 5.75 0h5.586c.464 0 .909.184 1.237.513l2.914 2.914c.329.328.513.773.513 1.237v8.586A1.75 1.75 0 0 1 14.25 15h-9a.75.75 0 0 1 0-1.5h9a.25.25 0 0 0 .25-.25V6h-2.75A1.75 1.75 0 0 1 10 4.25V1.5H5.75a.25.25 0 0 0-.25.25v2.5a.75.75 0 0 1-1.5 0Zm1.72 4.97a.75.75 0 0 1 1.06 0l2 2a.75.75 0 0 1 0 1.06l-2 2a.749.749 0 0 1-1.275-.326.749.749 0 0 1 .215-.734l1.47-1.47-1.47-1.47a.75.75 0 0 1 0-1.06ZM3.28 7.78 1.81 9.25l1.47 1.47a.751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018l-2-2a.75.75 0 0 1 0-1.06l2-2a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042Zm8.22-6.218V4.25c0 .138.112.25.25.25h2.688l-.011-.013-2.914-2.914-.013-.011Z"></path> </svg> </template> <template id="history-icon"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-history"> <path d="m.427 1.927 1.215 1.215a8.002 8.002 0 1 1-1.6 5.685.75.75 0 1 1 1.493-.154 6.5 6.5 0 1 0 1.18-4.458l1.358 1.358A.25.25 0 0 1 3.896 6H.25A.25.25 0 0 1 0 5.75V2.104a.25.25 0 0 1 .427-.177ZM7.75 4a.75.75 0 0 1 .75.75v2.992l2.028.812a.75.75 0 0 1-.557 1.392l-2.5-1A.751.751 0 0 1 7 8.25v-3.5A.75.75 0 0 1 7.75 4Z"></path> </svg> </template> <template id="repo-icon"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-repo"> <path d="M2 2.5A2.5 2.5 0 0 1 4.5 0h8.75a.75.75 0 0 1 .75.75v12.5a.75.75 0 0 1-.75.75h-2.5a.75.75 0 0 1 0-1.5h1.75v-2h-8a1 1 0 0 0-.714 1.7.75.75 0 1 1-1.072 1.05A2.495 2.495 0 0 1 2 11.5Zm10.5-1h-8a1 1 0 0 0-1 1v6.708A2.486 2.486 0 0 1 4.5 9h8ZM5 12.25a.25.25 0 0 1 .25-.25h3.5a.25.25 0 0 1 .25.25v3.25a.25.25 0 0 1-.4.2l-1.45-1.087a.249.249 0 0 0-.3 0L5.4 15.7a.25.25 0 0 1-.4-.2Z"></path> </svg> </template> <template id="bookmark-icon"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-bookmark"> <path d="M3 2.75C3 1.784 3.784 1 4.75 1h6.5c.966 0 1.75.784 1.75 1.75v11.5a.75.75 0 0 1-1.227.579L8 11.722l-3.773 3.107A.751.751 0 0 1 3 14.25Zm1.75-.25a.25.25 0 0 0-.25.25v9.91l3.023-2.489a.75.75 0 0 1 .954 0l3.023 2.49V2.75a.25.25 0 0 0-.25-.25Z"></path> </svg> </template> <template id="plus-circle-icon"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-plus-circle"> <path d="M8 0a8 8 0 1 1 0 16A8 8 0 0 1 8 0ZM1.5 8a6.5 6.5 0 1 0 13 0 6.5 6.5 0 0 0-13 0Zm7.25-3.25v2.5h2.5a.75.75 0 0 1 0 1.5h-2.5v2.5a.75.75 0 0 1-1.5 0v-2.5h-2.5a.75.75 0 0 1 0-1.5h2.5v-2.5a.75.75 0 0 1 1.5 0Z"></path> </svg> </template> <template id="circle-icon"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-dot-fill"> <path d="M8 4a4 4 0 1 1 0 8 4 4 0 0 1 0-8Z"></path> </svg> </template> <template id="trash-icon"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-trash"> <path d="M11 1.75V3h2.25a.75.75 0 0 1 0 1.5H2.75a.75.75 0 0 1 0-1.5H5V1.75C5 .784 5.784 0 6.75 0h2.5C10.216 0 11 .784 11 1.75ZM4.496 6.675l.66 6.6a.25.25 0 0 0 .249.225h5.19a.25.25 0 0 0 .249-.225l.66-6.6a.75.75 0 0 1 1.492.149l-.66 6.6A1.748 1.748 0 0 1 10.595 15h-5.19a1.75 1.75 0 0 1-1.741-1.575l-.66-6.6a.75.75 0 1 1 1.492-.15ZM6.5 1.75V3h3V1.75a.25.25 0 0 0-.25-.25h-2.5a.25.25 0 0 0-.25.25Z"></path> </svg> </template> <template id="team-icon"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-people"> <path d="M2 5.5a3.5 3.5 0 1 1 5.898 2.549 5.508 5.508 0 0 1 3.034 4.084.75.75 0 1 1-1.482.235 4 4 0 0 0-7.9 0 .75.75 0 0 1-1.482-.236A5.507 5.507 0 0 1 3.102 8.05 3.493 3.493 0 0 1 2 5.5ZM11 4a3.001 3.001 0 0 1 2.22 5.018 5.01 5.01 0 0 1 2.56 3.012.749.749 0 0 1-.885.954.752.752 0 0 1-.549-.514 3.507 3.507 0 0 0-2.522-2.372.75.75 0 0 1-.574-.73v-.352a.75.75 0 0 1 .416-.672A1.5 1.5 0 0 0 11 5.5.75.75 0 0 1 11 4Zm-5.5-.5a2 2 0 1 0-.001 3.999A2 2 0 0 0 5.5 3.5Z"></path> </svg> </template> <template id="project-icon"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-project"> <path d="M1.75 0h12.5C15.216 0 16 .784 16 1.75v12.5A1.75 1.75 0 0 1 14.25 16H1.75A1.75 1.75 0 0 1 0 14.25V1.75C0 .784.784 0 1.75 0ZM1.5 1.75v12.5c0 .138.112.25.25.25h12.5a.25.25 0 0 0 .25-.25V1.75a.25.25 0 0 0-.25-.25H1.75a.25.25 0 0 0-.25.25ZM11.75 3a.75.75 0 0 1 .75.75v7.5a.75.75 0 0 1-1.5 0v-7.5a.75.75 0 0 1 .75-.75Zm-8.25.75a.75.75 0 0 1 1.5 0v5.5a.75.75 0 0 1-1.5 0ZM8 3a.75.75 0 0 1 .75.75v3.5a.75.75 0 0 1-1.5 0v-3.5A.75.75 0 0 1 8 3Z"></path> </svg> </template> <template id="pencil-icon"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-pencil"> <path d="M11.013 1.427a1.75 1.75 0 0 1 2.474 0l1.086 1.086a1.75 1.75 0 0 1 0 2.474l-8.61 8.61c-.21.21-.47.364-.756.445l-3.251.93a.75.75 0 0 1-.927-.928l.929-3.25c.081-.286.235-.547.445-.758l8.61-8.61Zm.176 4.823L9.75 4.81l-6.286 6.287a.253.253 0 0 0-.064.108l-.558 1.953 1.953-.558a.253.253 0 0 0 .108-.064Zm1.238-3.763a.25.25 0 0 0-.354 0L10.811 3.75l1.439 1.44 1.263-1.263a.25.25 0 0 0 0-.354Z"></path> </svg> </template> <template id="copilot-icon"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-copilot"> <path d="M7.998 15.035c-4.562 0-7.873-2.914-7.998-3.749V9.338c.085-.628.677-1.686 1.588-2.065.013-.07.024-.143.036-.218.029-.183.06-.384.126-.612-.201-.508-.254-1.084-.254-1.656 0-.87.128-1.769.693-2.484.579-.733 1.494-1.124 2.724-1.261 1.206-.134 2.262.034 2.944.765.05.053.096.108.139.165.044-.057.094-.112.143-.165.682-.731 1.738-.899 2.944-.765 1.23.137 2.145.528 2.724 1.261.566.715.693 1.614.693 2.484 0 .572-.053 1.148-.254 1.656.066.228.098.429.126.612.012.076.024.148.037.218.924.385 1.522 1.471 1.591 2.095v1.872c0 .766-3.351 3.795-8.002 3.795Zm0-1.485c2.28 0 4.584-1.11 5.002-1.433V7.862l-.023-.116c-.49.21-1.075.291-1.727.291-1.146 0-2.059-.327-2.71-.991A3.222 3.222 0 0 1 8 6.303a3.24 3.24 0 0 1-.544.743c-.65.664-1.563.991-2.71.991-.652 0-1.236-.081-1.727-.291l-.023.116v4.255c.419.323 2.722 1.433 5.002 1.433ZM6.762 2.83c-.193-.206-.637-.413-1.682-.297-1.019.113-1.479.404-1.713.7-.247.312-.369.789-.369 1.554 0 .793.129 1.171.308 1.371.162.181.519.379 1.442.379.853 0 1.339-.235 1.638-.54.315-.322.527-.827.617-1.553.117-.935-.037-1.395-.241-1.614Zm4.155-.297c-1.044-.116-1.488.091-1.681.297-.204.219-.359.679-.242 1.614.091.726.303 1.231.618 1.553.299.305.784.54 1.638.54.922 0 1.28-.198 1.442-.379.179-.2.308-.578.308-1.371 0-.765-.123-1.242-.37-1.554-.233-.296-.693-.587-1.713-.7Z"></path><path d="M6.25 9.037a.75.75 0 0 1 .75.75v1.501a.75.75 0 0 1-1.5 0V9.787a.75.75 0 0 1 .75-.75Zm4.25.75v1.501a.75.75 0 0 1-1.5 0V9.787a.75.75 0 0 1 1.5 0Z"></path> </svg> </template> <template id="copilot-error-icon"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-copilot-error"> <path d="M16 11.24c0 .112-.072.274-.21.467L13 9.688V7.862l-.023-.116c-.49.21-1.075.291-1.727.291-.198 0-.388-.009-.571-.029L6.833 5.226a4.01 4.01 0 0 0 .17-.782c.117-.935-.037-1.395-.241-1.614-.193-.206-.637-.413-1.682-.297-.683.076-1.115.231-1.395.415l-1.257-.91c.579-.564 1.413-.877 2.485-.996 1.206-.134 2.262.034 2.944.765.05.053.096.108.139.165.044-.057.094-.112.143-.165.682-.731 1.738-.899 2.944-.765 1.23.137 2.145.528 2.724 1.261.566.715.693 1.614.693 2.484 0 .572-.053 1.148-.254 1.656.066.228.098.429.126.612.012.076.024.148.037.218.924.385 1.522 1.471 1.591 2.095Zm-5.083-8.707c-1.044-.116-1.488.091-1.681.297-.204.219-.359.679-.242 1.614.091.726.303 1.231.618 1.553.299.305.784.54 1.638.54.922 0 1.28-.198 1.442-.379.179-.2.308-.578.308-1.371 0-.765-.123-1.242-.37-1.554-.233-.296-.693-.587-1.713-.7Zm2.511 11.074c-1.393.776-3.272 1.428-5.43 1.428-4.562 0-7.873-2.914-7.998-3.749V9.338c.085-.628.677-1.686 1.588-2.065.013-.07.024-.143.036-.218.029-.183.06-.384.126-.612-.18-.455-.241-.963-.252-1.475L.31 4.107A.747.747 0 0 1 0 3.509V3.49a.748.748 0 0 1 .625-.73c.156-.026.306.047.435.139l14.667 10.578a.592.592 0 0 1 .227.264.752.752 0 0 1 .046.249v.022a.75.75 0 0 1-1.19.596Zm-1.367-.991L5.635 7.964a5.128 5.128 0 0 1-.889.073c-.652 0-1.236-.081-1.727-.291l-.023.116v4.255c.419.323 2.722 1.433 5.002 1.433 1.539 0 3.089-.505 4.063-.934Z"></path> </svg> </template> <template id="workflow-icon"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-workflow"> <path d="M0 1.75C0 .784.784 0 1.75 0h3.5C6.216 0 7 .784 7 1.75v3.5A1.75 1.75 0 0 1 5.25 7H4v4a1 1 0 0 0 1 1h4v-1.25C9 9.784 9.784 9 10.75 9h3.5c.966 0 1.75.784 1.75 1.75v3.5A1.75 1.75 0 0 1 14.25 16h-3.5A1.75 1.75 0 0 1 9 14.25v-.75H5A2.5 2.5 0 0 1 2.5 11V7h-.75A1.75 1.75 0 0 1 0 5.25Zm1.75-.25a.25.25 0 0 0-.25.25v3.5c0 .138.112.25.25.25h3.5a.25.25 0 0 0 .25-.25v-3.5a.25.25 0 0 0-.25-.25Zm9 9a.25.25 0 0 0-.25.25v3.5c0 .138.112.25.25.25h3.5a.25.25 0 0 0 .25-.25v-3.5a.25.25 0 0 0-.25-.25Z"></path> </svg> </template> <template id="book-icon"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-book"> <path d="M0 1.75A.75.75 0 0 1 .75 1h4.253c1.227 0 2.317.59 3 1.501A3.743 3.743 0 0 1 11.006 1h4.245a.75.75 0 0 1 .75.75v10.5a.75.75 0 0 1-.75.75h-4.507a2.25 2.25 0 0 0-1.591.659l-.622.621a.75.75 0 0 1-1.06 0l-.622-.621A2.25 2.25 0 0 0 5.258 13H.75a.75.75 0 0 1-.75-.75Zm7.251 10.324.004-5.073-.002-2.253A2.25 2.25 0 0 0 5.003 2.5H1.5v9h3.757a3.75 3.75 0 0 1 1.994.574ZM8.755 4.75l-.004 7.322a3.752 3.752 0 0 1 1.992-.572H14.5v-9h-3.495a2.25 2.25 0 0 0-2.25 2.25Z"></path> </svg> </template> <template id="code-review-icon"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-code-review"> <path d="M1.75 1h12.5c.966 0 1.75.784 1.75 1.75v8.5A1.75 1.75 0 0 1 14.25 13H8.061l-2.574 2.573A1.458 1.458 0 0 1 3 14.543V13H1.75A1.75 1.75 0 0 1 0 11.25v-8.5C0 1.784.784 1 1.75 1ZM1.5 2.75v8.5c0 .138.112.25.25.25h2a.75.75 0 0 1 .75.75v2.19l2.72-2.72a.749.749 0 0 1 .53-.22h6.5a.25.25 0 0 0 .25-.25v-8.5a.25.25 0 0 0-.25-.25H1.75a.25.25 0 0 0-.25.25Zm5.28 1.72a.75.75 0 0 1 0 1.06L5.31 7l1.47 1.47a.751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018l-2-2a.75.75 0 0 1 0-1.06l2-2a.75.75 0 0 1 1.06 0Zm2.44 0a.75.75 0 0 1 1.06 0l2 2a.75.75 0 0 1 0 1.06l-2 2a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042L10.69 7 9.22 5.53a.75.75 0 0 1 0-1.06Z"></path> </svg> </template> <template id="codespaces-icon"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-codespaces"> <path d="M0 11.25c0-.966.784-1.75 1.75-1.75h12.5c.966 0 1.75.784 1.75 1.75v3A1.75 1.75 0 0 1 14.25 16H1.75A1.75 1.75 0 0 1 0 14.25Zm2-9.5C2 .784 2.784 0 3.75 0h8.5C13.216 0 14 .784 14 1.75v5a1.75 1.75 0 0 1-1.75 1.75h-8.5A1.75 1.75 0 0 1 2 6.75Zm1.75-.25a.25.25 0 0 0-.25.25v5c0 .138.112.25.25.25h8.5a.25.25 0 0 0 .25-.25v-5a.25.25 0 0 0-.25-.25Zm-2 9.5a.25.25 0 0 0-.25.25v3c0 .138.112.25.25.25h12.5a.25.25 0 0 0 .25-.25v-3a.25.25 0 0 0-.25-.25Z"></path><path d="M7 12.75a.75.75 0 0 1 .75-.75h4.5a.75.75 0 0 1 0 1.5h-4.5a.75.75 0 0 1-.75-.75Zm-4 0a.75.75 0 0 1 .75-.75h.5a.75.75 0 0 1 0 1.5h-.5a.75.75 0 0 1-.75-.75Z"></path> </svg> </template> <template id="comment-icon"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-comment"> <path d="M1 2.75C1 1.784 1.784 1 2.75 1h10.5c.966 0 1.75.784 1.75 1.75v7.5A1.75 1.75 0 0 1 13.25 12H9.06l-2.573 2.573A1.458 1.458 0 0 1 4 13.543V12H2.75A1.75 1.75 0 0 1 1 10.25Zm1.75-.25a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h2a.75.75 0 0 1 .75.75v2.19l2.72-2.72a.749.749 0 0 1 .53-.22h4.5a.25.25 0 0 0 .25-.25v-7.5a.25.25 0 0 0-.25-.25Z"></path> </svg> </template> <template id="comment-discussion-icon"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-comment-discussion"> <path d="M1.75 1h8.5c.966 0 1.75.784 1.75 1.75v5.5A1.75 1.75 0 0 1 10.25 10H7.061l-2.574 2.573A1.458 1.458 0 0 1 2 11.543V10h-.25A1.75 1.75 0 0 1 0 8.25v-5.5C0 1.784.784 1 1.75 1ZM1.5 2.75v5.5c0 .138.112.25.25.25h1a.75.75 0 0 1 .75.75v2.19l2.72-2.72a.749.749 0 0 1 .53-.22h3.5a.25.25 0 0 0 .25-.25v-5.5a.25.25 0 0 0-.25-.25h-8.5a.25.25 0 0 0-.25.25Zm13 2a.25.25 0 0 0-.25-.25h-.5a.75.75 0 0 1 0-1.5h.5c.966 0 1.75.784 1.75 1.75v5.5A1.75 1.75 0 0 1 14.25 12H14v1.543a1.458 1.458 0 0 1-2.487 1.03L9.22 12.28a.749.749 0 0 1 .326-1.275.749.749 0 0 1 .734.215l2.22 2.22v-2.19a.75.75 0 0 1 .75-.75h1a.25.25 0 0 0 .25-.25Z"></path> </svg> </template> <template id="organization-icon"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-organization"> <path d="M1.75 16A1.75 1.75 0 0 1 0 14.25V1.75C0 .784.784 0 1.75 0h8.5C11.216 0 12 .784 12 1.75v12.5c0 .085-.006.168-.018.25h2.268a.25.25 0 0 0 .25-.25V8.285a.25.25 0 0 0-.111-.208l-1.055-.703a.749.749 0 1 1 .832-1.248l1.055.703c.487.325.779.871.779 1.456v5.965A1.75 1.75 0 0 1 14.25 16h-3.5a.766.766 0 0 1-.197-.026c-.099.017-.2.026-.303.026h-3a.75.75 0 0 1-.75-.75V14h-1v1.25a.75.75 0 0 1-.75.75Zm-.25-1.75c0 .138.112.25.25.25H4v-1.25a.75.75 0 0 1 .75-.75h2.5a.75.75 0 0 1 .75.75v1.25h2.25a.25.25 0 0 0 .25-.25V1.75a.25.25 0 0 0-.25-.25h-8.5a.25.25 0 0 0-.25.25ZM3.75 6h.5a.75.75 0 0 1 0 1.5h-.5a.75.75 0 0 1 0-1.5ZM3 3.75A.75.75 0 0 1 3.75 3h.5a.75.75 0 0 1 0 1.5h-.5A.75.75 0 0 1 3 3.75Zm4 3A.75.75 0 0 1 7.75 6h.5a.75.75 0 0 1 0 1.5h-.5A.75.75 0 0 1 7 6.75ZM7.75 3h.5a.75.75 0 0 1 0 1.5h-.5a.75.75 0 0 1 0-1.5ZM3 9.75A.75.75 0 0 1 3.75 9h.5a.75.75 0 0 1 0 1.5h-.5A.75.75 0 0 1 3 9.75ZM7.75 9h.5a.75.75 0 0 1 0 1.5h-.5a.75.75 0 0 1 0-1.5Z"></path> </svg> </template> <template id="rocket-icon"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-rocket"> <path d="M14.064 0h.186C15.216 0 16 .784 16 1.75v.186a8.752 8.752 0 0 1-2.564 6.186l-.458.459c-.314.314-.641.616-.979.904v3.207c0 .608-.315 1.172-.833 1.49l-2.774 1.707a.749.749 0 0 1-1.11-.418l-.954-3.102a1.214 1.214 0 0 1-.145-.125L3.754 9.816a1.218 1.218 0 0 1-.124-.145L.528 8.717a.749.749 0 0 1-.418-1.11l1.71-2.774A1.748 1.748 0 0 1 3.31 4h3.204c.288-.338.59-.665.904-.979l.459-.458A8.749 8.749 0 0 1 14.064 0ZM8.938 3.623h-.002l-.458.458c-.76.76-1.437 1.598-2.02 2.5l-1.5 2.317 2.143 2.143 2.317-1.5c.902-.583 1.74-1.26 2.499-2.02l.459-.458a7.25 7.25 0 0 0 2.123-5.127V1.75a.25.25 0 0 0-.25-.25h-.186a7.249 7.249 0 0 0-5.125 2.123ZM3.56 14.56c-.732.732-2.334 1.045-3.005 1.148a.234.234 0 0 1-.201-.064.234.234 0 0 1-.064-.201c.103-.671.416-2.273 1.15-3.003a1.502 1.502 0 1 1 2.12 2.12Zm6.94-3.935c-.088.06-.177.118-.266.175l-2.35 1.521.548 1.783 1.949-1.2a.25.25 0 0 0 .119-.213ZM3.678 8.116 5.2 5.766c.058-.09.117-.178.176-.266H3.309a.25.25 0 0 0-.213.119l-1.2 1.95ZM12 5a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z"></path> </svg> </template> <template id="shield-check-icon"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-shield-check"> <path d="m8.533.133 5.25 1.68A1.75 1.75 0 0 1 15 3.48V7c0 1.566-.32 3.182-1.303 4.682-.983 1.498-2.585 2.813-5.032 3.855a1.697 1.697 0 0 1-1.33 0c-2.447-1.042-4.049-2.357-5.032-3.855C1.32 10.182 1 8.566 1 7V3.48a1.75 1.75 0 0 1 1.217-1.667l5.25-1.68a1.748 1.748 0 0 1 1.066 0Zm-.61 1.429.001.001-5.25 1.68a.251.251 0 0 0-.174.237V7c0 1.36.275 2.666 1.057 3.859.784 1.194 2.121 2.342 4.366 3.298a.196.196 0 0 0 .154 0c2.245-.957 3.582-2.103 4.366-3.297C13.225 9.666 13.5 8.358 13.5 7V3.48a.25.25 0 0 0-.174-.238l-5.25-1.68a.25.25 0 0 0-.153 0ZM11.28 6.28l-3.5 3.5a.75.75 0 0 1-1.06 0l-1.5-1.5a.749.749 0 0 1 .326-1.275.749.749 0 0 1 .734.215l.97.97 2.97-2.97a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042Z"></path> </svg> </template> <template id="heart-icon"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-heart"> <path d="m8 14.25.345.666a.75.75 0 0 1-.69 0l-.008-.004-.018-.01a7.152 7.152 0 0 1-.31-.17 22.055 22.055 0 0 1-3.434-2.414C2.045 10.731 0 8.35 0 5.5 0 2.836 2.086 1 4.25 1 5.797 1 7.153 1.802 8 3.02 8.847 1.802 10.203 1 11.75 1 13.914 1 16 2.836 16 5.5c0 2.85-2.045 5.231-3.885 6.818a22.066 22.066 0 0 1-3.744 2.584l-.018.01-.006.003h-.002ZM4.25 2.5c-1.336 0-2.75 1.164-2.75 3 0 2.15 1.58 4.144 3.365 5.682A20.58 20.58 0 0 0 8 13.393a20.58 20.58 0 0 0 3.135-2.211C12.92 9.644 14.5 7.65 14.5 5.5c0-1.836-1.414-3-2.75-3-1.373 0-2.609.986-3.029 2.456a.749.749 0 0 1-1.442 0C6.859 3.486 5.623 2.5 4.25 2.5Z"></path> </svg> </template> <template id="server-icon"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-server"> <path d="M1.75 1h12.5c.966 0 1.75.784 1.75 1.75v4c0 .372-.116.717-.314 1 .198.283.314.628.314 1v4a1.75 1.75 0 0 1-1.75 1.75H1.75A1.75 1.75 0 0 1 0 12.75v-4c0-.358.109-.707.314-1a1.739 1.739 0 0 1-.314-1v-4C0 1.784.784 1 1.75 1ZM1.5 2.75v4c0 .138.112.25.25.25h12.5a.25.25 0 0 0 .25-.25v-4a.25.25 0 0 0-.25-.25H1.75a.25.25 0 0 0-.25.25Zm.25 5.75a.25.25 0 0 0-.25.25v4c0 .138.112.25.25.25h12.5a.25.25 0 0 0 .25-.25v-4a.25.25 0 0 0-.25-.25ZM7 4.75A.75.75 0 0 1 7.75 4h4.5a.75.75 0 0 1 0 1.5h-4.5A.75.75 0 0 1 7 4.75ZM7.75 10h4.5a.75.75 0 0 1 0 1.5h-4.5a.75.75 0 0 1 0-1.5ZM3 4.75A.75.75 0 0 1 3.75 4h.5a.75.75 0 0 1 0 1.5h-.5A.75.75 0 0 1 3 4.75ZM3.75 10h.5a.75.75 0 0 1 0 1.5h-.5a.75.75 0 0 1 0-1.5Z"></path> </svg> </template> <template id="globe-icon"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-globe"> <path d="M8 0a8 8 0 1 1 0 16A8 8 0 0 1 8 0ZM5.78 8.75a9.64 9.64 0 0 0 1.363 4.177c.255.426.542.832.857 1.215.245-.296.551-.705.857-1.215A9.64 9.64 0 0 0 10.22 8.75Zm4.44-1.5a9.64 9.64 0 0 0-1.363-4.177c-.307-.51-.612-.919-.857-1.215a9.927 9.927 0 0 0-.857 1.215A9.64 9.64 0 0 0 5.78 7.25Zm-5.944 1.5H1.543a6.507 6.507 0 0 0 4.666 5.5c-.123-.181-.24-.365-.352-.552-.715-1.192-1.437-2.874-1.581-4.948Zm-2.733-1.5h2.733c.144-2.074.866-3.756 1.58-4.948.12-.197.237-.381.353-.552a6.507 6.507 0 0 0-4.666 5.5Zm10.181 1.5c-.144 2.074-.866 3.756-1.58 4.948-.12.197-.237.381-.353.552a6.507 6.507 0 0 0 4.666-5.5Zm2.733-1.5a6.507 6.507 0 0 0-4.666-5.5c.123.181.24.365.353.552.714 1.192 1.436 2.874 1.58 4.948Z"></path> </svg> </template> <template id="issue-opened-icon"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-issue-opened"> <path d="M8 9.5a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3Z"></path><path d="M8 0a8 8 0 1 1 0 16A8 8 0 0 1 8 0ZM1.5 8a6.5 6.5 0 1 0 13 0 6.5 6.5 0 0 0-13 0Z"></path> </svg> </template> <template id="device-mobile-icon"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-device-mobile"> <path d="M3.75 0h8.5C13.216 0 14 .784 14 1.75v12.5A1.75 1.75 0 0 1 12.25 16h-8.5A1.75 1.75 0 0 1 2 14.25V1.75C2 .784 2.784 0 3.75 0ZM3.5 1.75v12.5c0 .138.112.25.25.25h8.5a.25.25 0 0 0 .25-.25V1.75a.25.25 0 0 0-.25-.25h-8.5a.25.25 0 0 0-.25.25ZM8 13a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z"></path> </svg> </template> <template id="package-icon"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-package"> <path d="m8.878.392 5.25 3.045c.54.314.872.89.872 1.514v6.098a1.75 1.75 0 0 1-.872 1.514l-5.25 3.045a1.75 1.75 0 0 1-1.756 0l-5.25-3.045A1.75 1.75 0 0 1 1 11.049V4.951c0-.624.332-1.201.872-1.514L7.122.392a1.75 1.75 0 0 1 1.756 0ZM7.875 1.69l-4.63 2.685L8 7.133l4.755-2.758-4.63-2.685a.248.248 0 0 0-.25 0ZM2.5 5.677v5.372c0 .09.047.171.125.216l4.625 2.683V8.432Zm6.25 8.271 4.625-2.683a.25.25 0 0 0 .125-.216V5.677L8.75 8.432Z"></path> </svg> </template> <template id="credit-card-icon"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-credit-card"> <path d="M10.75 9a.75.75 0 0 0 0 1.5h1.5a.75.75 0 0 0 0-1.5h-1.5Z"></path><path d="M0 3.75C0 2.784.784 2 1.75 2h12.5c.966 0 1.75.784 1.75 1.75v8.5A1.75 1.75 0 0 1 14.25 14H1.75A1.75 1.75 0 0 1 0 12.25ZM14.5 6.5h-13v5.75c0 .138.112.25.25.25h12.5a.25.25 0 0 0 .25-.25Zm0-2.75a.25.25 0 0 0-.25-.25H1.75a.25.25 0 0 0-.25.25V5h13Z"></path> </svg> </template> <template id="play-icon"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-play"> <path d="M8 0a8 8 0 1 1 0 16A8 8 0 0 1 8 0ZM1.5 8a6.5 6.5 0 1 0 13 0 6.5 6.5 0 0 0-13 0Zm4.879-2.773 4.264 2.559a.25.25 0 0 1 0 .428l-4.264 2.559A.25.25 0 0 1 6 10.559V5.442a.25.25 0 0 1 .379-.215Z"></path> </svg> </template> <template id="gift-icon"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-gift"> <path d="M2 2.75A2.75 2.75 0 0 1 4.75 0c.983 0 1.873.42 2.57 1.232.268.318.497.668.68 1.042.183-.375.411-.725.68-1.044C9.376.42 10.266 0 11.25 0a2.75 2.75 0 0 1 2.45 4h.55c.966 0 1.75.784 1.75 1.75v2c0 .698-.409 1.301-1 1.582v4.918A1.75 1.75 0 0 1 13.25 16H2.75A1.75 1.75 0 0 1 1 14.25V9.332C.409 9.05 0 8.448 0 7.75v-2C0 4.784.784 4 1.75 4h.55c-.192-.375-.3-.8-.3-1.25ZM7.25 9.5H2.5v4.75c0 .138.112.25.25.25h4.5Zm1.5 0v5h4.5a.25.25 0 0 0 .25-.25V9.5Zm0-4V8h5.5a.25.25 0 0 0 .25-.25v-2a.25.25 0 0 0-.25-.25Zm-7 0a.25.25 0 0 0-.25.25v2c0 .138.112.25.25.25h5.5V5.5h-5.5Zm3-4a1.25 1.25 0 0 0 0 2.5h2.309c-.233-.818-.542-1.401-.878-1.793-.43-.502-.915-.707-1.431-.707ZM8.941 4h2.309a1.25 1.25 0 0 0 0-2.5c-.516 0-1 .205-1.43.707-.337.392-.646.975-.879 1.793Z"></path> </svg> </template> <template id="code-square-icon"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-code-square"> <path d="M0 1.75C0 .784.784 0 1.75 0h12.5C15.216 0 16 .784 16 1.75v12.5A1.75 1.75 0 0 1 14.25 16H1.75A1.75 1.75 0 0 1 0 14.25Zm1.75-.25a.25.25 0 0 0-.25.25v12.5c0 .138.112.25.25.25h12.5a.25.25 0 0 0 .25-.25V1.75a.25.25 0 0 0-.25-.25Zm7.47 3.97a.75.75 0 0 1 1.06 0l2 2a.75.75 0 0 1 0 1.06l-2 2a.749.749 0 0 1-1.275-.326.749.749 0 0 1 .215-.734L10.69 8 9.22 6.53a.75.75 0 0 1 0-1.06ZM6.78 6.53 5.31 8l1.47 1.47a.749.749 0 0 1-.326 1.275.749.749 0 0 1-.734-.215l-2-2a.75.75 0 0 1 0-1.06l2-2a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042Z"></path> </svg> </template> <template id="device-desktop-icon"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-device-desktop"> <path d="M14.25 1c.966 0 1.75.784 1.75 1.75v7.5A1.75 1.75 0 0 1 14.25 12h-3.727c.099 1.041.52 1.872 1.292 2.757A.752.752 0 0 1 11.25 16h-6.5a.75.75 0 0 1-.565-1.243c.772-.885 1.192-1.716 1.292-2.757H1.75A1.75 1.75 0 0 1 0 10.25v-7.5C0 1.784.784 1 1.75 1ZM1.75 2.5a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h12.5a.25.25 0 0 0 .25-.25v-7.5a.25.25 0 0 0-.25-.25ZM9.018 12H6.982a5.72 5.72 0 0 1-.765 2.5h3.566a5.72 5.72 0 0 1-.765-2.5Z"></path> </svg> </template> <div class="position-relative"> <ul role="listbox" class="ActionListWrap QueryBuilder-ListWrap" aria-label="Suggestions" data-action=" combobox-commit:query-builder#comboboxCommit mousedown:query-builder#resultsMousedown " data-target="query-builder.resultsList" data-persist-list=false id="query-builder-test-results" ></ul> </div> <div class="FormControl-inlineValidation" id="validation-157bdd63-cc6a-457e-8ab3-f26f4381e362" hidden="hidden"> <span class="FormControl-inlineValidation--visual"> <svg aria-hidden="true" height="12" viewBox="0 0 12 12" version="1.1" width="12" data-view-component="true" class="octicon octicon-alert-fill"> <path d="M4.855.708c.5-.896 1.79-.896 2.29 0l4.675 8.351a1.312 1.312 0 0 1-1.146 1.954H1.33A1.313 1.313 0 0 1 .183 9.058ZM7 7V3H5v4Zm-1 3a1 1 0 1 0 0-2 1 1 0 0 0 0 2Z"></path> </svg> </span> <span></span> </div> </div> <div data-target="query-builder.screenReaderFeedback" aria-live="polite" aria-atomic="true" class="sr-only"></div> </query-builder></form> <div class="d-flex flex-row color-fg-muted px-3 text-small color-bg-default search-feedback-prompt"> <a target="_blank" href="https://docs.github.com/search-github/github-code-search/understanding-github-code-search-syntax" data-view-component="true" class="Link color-fg-accent text-normal ml-2">Search syntax tips</a> <div class="d-flex flex-1"></div> </div> </div> </div> </div> </modal-dialog></div> </div> <div data-action="click:qbsearch-input#retract" class="dark-backdrop position-fixed" hidden data-target="qbsearch-input.darkBackdrop"></div> <div class="color-fg-default"> <dialog-helper> <dialog data-target="qbsearch-input.feedbackDialog" data-action="close:qbsearch-input#handleDialogClose cancel:qbsearch-input#handleDialogClose" id="feedback-dialog" aria-modal="true" aria-labelledby="feedback-dialog-title" aria-describedby="feedback-dialog-description" data-view-component="true" class="Overlay Overlay-whenNarrow Overlay--size-medium Overlay--motion-scaleFade Overlay--disableScroll"> <div data-view-component="true" class="Overlay-header"> <div class="Overlay-headerContentWrap"> <div class="Overlay-titleWrap"> <h1 class="Overlay-title " id="feedback-dialog-title"> Provide feedback </h1> </div> <div class="Overlay-actionWrap"> <button data-close-dialog-id="feedback-dialog" aria-label="Close" type="button" data-view-component="true" class="close-button Overlay-closeButton"><svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-x"> <path d="M3.72 3.72a.75.75 0 0 1 1.06 0L8 6.94l3.22-3.22a.749.749 0 0 1 1.275.326.749.749 0 0 1-.215.734L9.06 8l3.22 3.22a.749.749 0 0 1-.326 1.275.749.749 0 0 1-.734-.215L8 9.06l-3.22 3.22a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042L6.94 8 3.72 4.78a.75.75 0 0 1 0-1.06Z"></path> </svg></button> </div> </div> </div> <scrollable-region data-labelled-by="feedback-dialog-title"> <div data-view-component="true" class="Overlay-body"> <!-- '"` --><!-- </textarea></xmp> --></option></form><form id="code-search-feedback-form" data-turbo="false" action="/search/feedback" accept-charset="UTF-8" method="post"><input type="hidden" data-csrf="true" name="authenticity_token" value="lefplVugps3ZhylAX/qEIK42HaP+kzhDYQby3YUsNUoaQmrdGmecPir5eVxjLgzRA+HLKoNFqA1Ll1Bw6yjgwA==" /> <p>We read every piece of feedback, and take your input very seriously.</p> <textarea name="feedback" class="form-control width-full mb-2" style="height: 120px" id="feedback"></textarea> <input name="include_email" id="include_email" aria-label="Include my email address so I can be contacted" class="form-control mr-2" type="checkbox"> <label for="include_email" style="font-weight: normal">Include my email address so I can be contacted</label> </form></div> </scrollable-region> <div data-view-component="true" class="Overlay-footer Overlay-footer--alignEnd"> <button data-close-dialog-id="feedback-dialog" type="button" data-view-component="true" class="btn"> Cancel </button> <button form="code-search-feedback-form" data-action="click:qbsearch-input#submitFeedback" type="submit" data-view-component="true" class="btn-primary btn"> Submit feedback </button> </div> </dialog></dialog-helper> <custom-scopes data-target="qbsearch-input.customScopesManager"> <dialog-helper> <dialog data-target="custom-scopes.customScopesModalDialog" data-action="close:qbsearch-input#handleDialogClose cancel:qbsearch-input#handleDialogClose" id="custom-scopes-dialog" aria-modal="true" aria-labelledby="custom-scopes-dialog-title" aria-describedby="custom-scopes-dialog-description" data-view-component="true" class="Overlay Overlay-whenNarrow Overlay--size-medium Overlay--motion-scaleFade Overlay--disableScroll"> <div data-view-component="true" class="Overlay-header Overlay-header--divided"> <div class="Overlay-headerContentWrap"> <div class="Overlay-titleWrap"> <h1 class="Overlay-title " id="custom-scopes-dialog-title"> Saved searches </h1> <h2 id="custom-scopes-dialog-description" class="Overlay-description">Use saved searches to filter your results more quickly</h2> </div> <div class="Overlay-actionWrap"> <button data-close-dialog-id="custom-scopes-dialog" aria-label="Close" type="button" data-view-component="true" class="close-button Overlay-closeButton"><svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-x"> <path d="M3.72 3.72a.75.75 0 0 1 1.06 0L8 6.94l3.22-3.22a.749.749 0 0 1 1.275.326.749.749 0 0 1-.215.734L9.06 8l3.22 3.22a.749.749 0 0 1-.326 1.275.749.749 0 0 1-.734-.215L8 9.06l-3.22 3.22a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042L6.94 8 3.72 4.78a.75.75 0 0 1 0-1.06Z"></path> </svg></button> </div> </div> </div> <scrollable-region data-labelled-by="custom-scopes-dialog-title"> <div data-view-component="true" class="Overlay-body"> <div data-target="custom-scopes.customScopesModalDialogFlash"></div> <div hidden class="create-custom-scope-form" data-target="custom-scopes.createCustomScopeForm"> <!-- '"` --><!-- </textarea></xmp> --></option></form><form id="custom-scopes-dialog-form" data-turbo="false" action="/search/custom_scopes" accept-charset="UTF-8" method="post"><input type="hidden" data-csrf="true" name="authenticity_token" value="cYmEWR83i7cfL1x5nFNGn/fbF1Mf2K12GwU9o4MaN6hRT9KsBhqnUAindQnf9o9tYv5ByQ2tKskg8McioK66pg==" /> <div data-target="custom-scopes.customScopesModalDialogFlash"></div> <input type="hidden" id="custom_scope_id" name="custom_scope_id" data-target="custom-scopes.customScopesIdField"> <div class="form-group"> <label for="custom_scope_name">Name</label> <auto-check src="/search/custom_scopes/check_name" required only-validate-on-blur="false"> <input type="text" name="custom_scope_name" id="custom_scope_name" data-target="custom-scopes.customScopesNameField" class="form-control" autocomplete="off" placeholder="github-ruby" required maxlength="50"> <input type="hidden" data-csrf="true" value="wfqXZDAA9fN+9jRUZzUdLFX7m/ZAVXyaaiwyTwSqtjwxA0z/sqysP+J/Kj+4OIQIJ9EptAhw5UgzzSC/UN+a4A==" /> </auto-check> </div> <div class="form-group"> <label for="custom_scope_query">Query</label> <input type="text" name="custom_scope_query" id="custom_scope_query" data-target="custom-scopes.customScopesQueryField" class="form-control" autocomplete="off" placeholder="(repo:mona/a OR repo:mona/b) AND lang:python" required maxlength="500"> </div> <p class="text-small color-fg-muted"> To see all available qualifiers, see our <a class="Link--inTextBlock" href="https://docs.github.com/search-github/github-code-search/understanding-github-code-search-syntax">documentation</a>. </p> </form> </div> <div data-target="custom-scopes.manageCustomScopesForm"> <div data-target="custom-scopes.list"></div> </div> </div> </scrollable-region> <div data-view-component="true" class="Overlay-footer Overlay-footer--alignEnd Overlay-footer--divided"> <button data-action="click:custom-scopes#customScopesCancel" type="button" data-view-component="true" class="btn"> Cancel </button> <button form="custom-scopes-dialog-form" data-action="click:custom-scopes#customScopesSubmit" data-target="custom-scopes.customScopesSubmitButton" type="submit" data-view-component="true" class="btn-primary btn"> Create saved search </button> </div> </dialog></dialog-helper> </custom-scopes> </div> </qbsearch-input> <div class="position-relative HeaderMenu-link-wrap d-lg-inline-block"> <a href="/login?return_to=https%3A%2F%2Fgithub.com%2Falexpovel%2Fsrgn" class="HeaderMenu-link HeaderMenu-link--sign-in HeaderMenu-button flex-shrink-0 no-underline d-none d-lg-inline-flex border border-lg-0 rounded rounded-lg-0 px-2 py-1" style="margin-left: 12px;" data-hydro-click="{&quot;event_type&quot;:&quot;authentication.click&quot;,&quot;payload&quot;:{&quot;location_in_page&quot;:&quot;site header menu&quot;,&quot;repository_id&quot;:null,&quot;auth_type&quot;:&quot;SIGN_UP&quot;,&quot;originating_url&quot;:&quot;https://github.com/alexpovel/srgn&quot;,&quot;user_id&quot;:null}}" data-hydro-click-hmac="357ea8f0477bd5d909f0350e9c55271527254c96d48f5c2d45afd626f73741b6" data-analytics-event="{&quot;category&quot;:&quot;Marketing nav&quot;,&quot;action&quot;:&quot;click to go to homepage&quot;,&quot;label&quot;:&quot;ref_page:Marketing;ref_cta:Sign in;ref_loc:Header&quot;}" > Sign in </a> </div> <a href="/signup?ref_cta=Sign+up&amp;ref_loc=header+logged+out&amp;ref_page=%2F%3Cuser-name%3E%2F%3Crepo-name%3E&amp;source=header-repo&amp;source_repo=alexpovel%2Fsrgn" class="HeaderMenu-link HeaderMenu-link--sign-up HeaderMenu-button flex-shrink-0 d-flex d-lg-inline-flex no-underline border color-border-default rounded px-2 py-1" data-hydro-click="{&quot;event_type&quot;:&quot;authentication.click&quot;,&quot;payload&quot;:{&quot;location_in_page&quot;:&quot;site header menu&quot;,&quot;repository_id&quot;:null,&quot;auth_type&quot;:&quot;SIGN_UP&quot;,&quot;originating_url&quot;:&quot;https://github.com/alexpovel/srgn&quot;,&quot;user_id&quot;:null}}" data-hydro-click-hmac="357ea8f0477bd5d909f0350e9c55271527254c96d48f5c2d45afd626f73741b6" data-analytics-event="{&quot;category&quot;:&quot;Sign up&quot;,&quot;action&quot;:&quot;click to sign up for account&quot;,&quot;label&quot;:&quot;ref_page:/&lt;user-name&gt;/&lt;repo-name&gt;;ref_cta:Sign up;ref_loc:header logged out&quot;}" > Sign up </a> <button type="button" class="sr-only js-header-menu-focus-trap d-block d-lg-none">Reseting focus</button> </div> </div> </div> </div> </header> <div hidden="hidden" data-view-component="true" class="js-stale-session-flash stale-session-flash flash flash-warn flash-full"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-alert"> <path d="M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z"></path> </svg> <span class="js-stale-session-flash-signed-in" hidden>You signed in with another tab or window. <a class="Link--inTextBlock" href="">Reload</a> to refresh your session.</span> <span class="js-stale-session-flash-signed-out" hidden>You signed out in another tab or window. <a class="Link--inTextBlock" href="">Reload</a> to refresh your session.</span> <span class="js-stale-session-flash-switched" hidden>You switched accounts on another tab or window. <a class="Link--inTextBlock" href="">Reload</a> to refresh your session.</span> <button id="icon-button-ee97664d-8b81-4fd7-a7de-2107e0831e55" aria-labelledby="tooltip-4ef86aac-a725-4b99-8170-82203af4c03e" type="button" data-view-component="true" class="Button Button--iconOnly Button--invisible Button--medium flash-close js-flash-close"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-x Button-visual"> <path d="M3.72 3.72a.75.75 0 0 1 1.06 0L8 6.94l3.22-3.22a.749.749 0 0 1 1.275.326.749.749 0 0 1-.215.734L9.06 8l3.22 3.22a.749.749 0 0 1-.326 1.275.749.749 0 0 1-.734-.215L8 9.06l-3.22 3.22a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042L6.94 8 3.72 4.78a.75.75 0 0 1 0-1.06Z"></path> </svg> </button><tool-tip id="tooltip-4ef86aac-a725-4b99-8170-82203af4c03e" for="icon-button-ee97664d-8b81-4fd7-a7de-2107e0831e55" popover="manual" data-direction="s" data-type="label" data-view-component="true" class="sr-only position-absolute">Dismiss alert</tool-tip> </div> </div> <div id="start-of-content" class="show-on-focus"></div> <div id="js-flash-container" class="flash-container" data-turbo-replace> <template class="js-flash-template"> <div class="flash flash-full {{ className }}"> <div > <button autofocus class="flash-close js-flash-close" type="button" aria-label="Dismiss this message"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-x"> <path d="M3.72 3.72a.75.75 0 0 1 1.06 0L8 6.94l3.22-3.22a.749.749 0 0 1 1.275.326.749.749 0 0 1-.215.734L9.06 8l3.22 3.22a.749.749 0 0 1-.326 1.275.749.749 0 0 1-.734-.215L8 9.06l-3.22 3.22a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042L6.94 8 3.72 4.78a.75.75 0 0 1 0-1.06Z"></path> </svg> </button> <div aria-atomic="true" role="alert" class="js-flash-alert"> <div>{{ message }}</div> </div> </div> </div> </template> </div> <div class="application-main " data-commit-hovercards-enabled data-discussion-hovercards-enabled data-issue-and-pr-hovercards-enabled data-project-hovercards-enabled > <div itemscope itemtype="http://schema.org/SoftwareSourceCode" class=""> <main id="js-repo-pjax-container" > <div id="repository-container-header" class="pt-3 hide-full-screen" style="background-color: var(--page-header-bgColor, var(--color-page-header-bg));" data-turbo-replace> <div class="d-flex flex-nowrap flex-justify-end mb-3 px-3 px-lg-5" style="gap: 1rem;"> <div class="flex-auto min-width-0 width-fit"> <div class=" d-flex flex-wrap flex-items-center wb-break-word f3 text-normal"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-repo color-fg-muted mr-2"> <path d="M2 2.5A2.5 2.5 0 0 1 4.5 0h8.75a.75.75 0 0 1 .75.75v12.5a.75.75 0 0 1-.75.75h-2.5a.75.75 0 0 1 0-1.5h1.75v-2h-8a1 1 0 0 0-.714 1.7.75.75 0 1 1-1.072 1.05A2.495 2.495 0 0 1 2 11.5Zm10.5-1h-8a1 1 0 0 0-1 1v6.708A2.486 2.486 0 0 1 4.5 9h8ZM5 12.25a.25.25 0 0 1 .25-.25h3.5a.25.25 0 0 1 .25.25v3.25a.25.25 0 0 1-.4.2l-1.45-1.087a.249.249 0 0 0-.3 0L5.4 15.7a.25.25 0 0 1-.4-.2Z"></path> </svg> <span class="author flex-self-stretch" itemprop="author"> <a class="url fn" rel="author" data-hovercard-type="user" data-hovercard-url="/users/alexpovel/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="/alexpovel"> alexpovel </a> </span> <span class="mx-1 flex-self-stretch color-fg-muted">/</span> <strong itemprop="name" class="mr-2 flex-self-stretch"> <a data-pjax="#repo-content-pjax-container" data-turbo-frame="repo-content-turbo-frame" href="/alexpovel/srgn">srgn</a> </strong> <span></span><span class="Label Label--secondary v-align-middle mr-1">Public</span> </div> </div> <div id="repository-details-container" class="flex-shrink-0" data-turbo-replace style="max-width: 70%;"> <ul class="pagehead-actions flex-shrink-0 d-none d-md-inline" style="padding: 2px 0;"> <li> <a href="/login?return_to=%2Falexpovel%2Fsrgn" rel="nofollow" id="repository-details-watch-button" data-hydro-click="{&quot;event_type&quot;:&quot;authentication.click&quot;,&quot;payload&quot;:{&quot;location_in_page&quot;:&quot;notification subscription menu watch&quot;,&quot;repository_id&quot;:null,&quot;auth_type&quot;:&quot;LOG_IN&quot;,&quot;originating_url&quot;:&quot;https://github.com/alexpovel/srgn&quot;,&quot;user_id&quot;:null}}" data-hydro-click-hmac="25f72cd2a86cb3042a9530629dfa3358f46060a4a8b78eb62ff2f91f3fa604c8" aria-label="You must be signed in to change notification settings" data-view-component="true" class="btn-sm btn"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-bell mr-2"> <path d="M8 16a2 2 0 0 0 1.985-1.75c.017-.137-.097-.25-.235-.25h-3.5c-.138 0-.252.113-.235.25A2 2 0 0 0 8 16ZM3 5a5 5 0 0 1 10 0v2.947c0 .05.015.098.042.139l1.703 2.555A1.519 1.519 0 0 1 13.482 13H2.518a1.516 1.516 0 0 1-1.263-2.36l1.703-2.554A.255.255 0 0 0 3 7.947Zm5-3.5A3.5 3.5 0 0 0 4.5 5v2.947c0 .346-.102.683-.294.97l-1.703 2.556a.017.017 0 0 0-.003.01l.001.006c0 .002.002.004.004.006l.006.004.007.001h10.964l.007-.001.006-.004.004-.006.001-.007a.017.017 0 0 0-.003-.01l-1.703-2.554a1.745 1.745 0 0 1-.294-.97V5A3.5 3.5 0 0 0 8 1.5Z"></path> </svg>Notifications </a> <tool-tip id="tooltip-ae8e7a8b-46af-4ca1-89ea-77faa0915af6" for="repository-details-watch-button" popover="manual" data-direction="s" data-type="description" data-view-component="true" class="sr-only position-absolute">You must be signed in to change notification settings</tool-tip> </li> <li> <a icon="repo-forked" id="fork-button" href="/login?return_to=%2Falexpovel%2Fsrgn" rel="nofollow" data-hydro-click="{&quot;event_type&quot;:&quot;authentication.click&quot;,&quot;payload&quot;:{&quot;location_in_page&quot;:&quot;repo details fork button&quot;,&quot;repository_id&quot;:641495940,&quot;auth_type&quot;:&quot;LOG_IN&quot;,&quot;originating_url&quot;:&quot;https://github.com/alexpovel/srgn&quot;,&quot;user_id&quot;:null}}" data-hydro-click-hmac="ade10893725bd67bcb298a2016fccbb6d3b8d0b19f5659d827183ff2c23cac22" data-view-component="true" class="btn-sm btn"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-repo-forked mr-2"> <path d="M5 5.372v.878c0 .414.336.75.75.75h4.5a.75.75 0 0 0 .75-.75v-.878a2.25 2.25 0 1 1 1.5 0v.878a2.25 2.25 0 0 1-2.25 2.25h-1.5v2.128a2.251 2.251 0 1 1-1.5 0V8.5h-1.5A2.25 2.25 0 0 1 3.5 6.25v-.878a2.25 2.25 0 1 1 1.5 0ZM5 3.25a.75.75 0 1 0-1.5 0 .75.75 0 0 0 1.5 0Zm6.75.75a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5Zm-3 8.75a.75.75 0 1 0-1.5 0 .75.75 0 0 0 1.5 0Z"></path> </svg>Fork <span id="repo-network-counter" data-pjax-replace="true" data-turbo-replace="true" title="9" data-view-component="true" class="Counter">9</span> </a> </li> <li> <div data-view-component="true" class="BtnGroup d-flex"> <a href="/login?return_to=%2Falexpovel%2Fsrgn" rel="nofollow" data-hydro-click="{&quot;event_type&quot;:&quot;authentication.click&quot;,&quot;payload&quot;:{&quot;location_in_page&quot;:&quot;star button&quot;,&quot;repository_id&quot;:641495940,&quot;auth_type&quot;:&quot;LOG_IN&quot;,&quot;originating_url&quot;:&quot;https://github.com/alexpovel/srgn&quot;,&quot;user_id&quot;:null}}" data-hydro-click-hmac="ff12a677794ce97e2d42ebc420af732d9a1d0e30a8e8271d47542d342b4c46c3" aria-label="You must be signed in to star a repository" data-view-component="true" class="tooltipped tooltipped-sw btn-sm btn"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-star v-align-text-bottom d-inline-block mr-2"> <path d="M8 .25a.75.75 0 0 1 .673.418l1.882 3.815 4.21.612a.75.75 0 0 1 .416 1.279l-3.046 2.97.719 4.192a.751.751 0 0 1-1.088.791L8 12.347l-3.766 1.98a.75.75 0 0 1-1.088-.79l.72-4.194L.818 6.374a.75.75 0 0 1 .416-1.28l4.21-.611L7.327.668A.75.75 0 0 1 8 .25Zm0 2.445L6.615 5.5a.75.75 0 0 1-.564.41l-3.097.45 2.24 2.184a.75.75 0 0 1 .216.664l-.528 3.084 2.769-1.456a.75.75 0 0 1 .698 0l2.77 1.456-.53-3.084a.75.75 0 0 1 .216-.664l2.24-2.183-3.096-.45a.75.75 0 0 1-.564-.41L8 2.694Z"></path> </svg><span data-view-component="true" class="d-inline"> Star </span> <span id="repo-stars-counter-star" aria-label="722 users starred this repository" data-singular-suffix="user starred this repository" data-plural-suffix="users starred this repository" data-turbo-replace="true" title="722" data-view-component="true" class="Counter js-social-count">722</span> </a></div> </li> </ul> </div> </div> <div id="responsive-meta-container" data-turbo-replace> <div class="d-block d-md-none mb-2 px-3 px-md-4 px-lg-5"> <p class="f4 mb-3 "> A grep-like tool which understands source code syntax and allows for manipulation in addition to search </p> <div class="mb-2 d-flex flex-items-center Link--secondary"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-link flex-shrink-0 mr-2"> <path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path> </svg> <span class="flex-auto min-width-0 css-truncate css-truncate-target width-fit"> <a title="https://crates.io/crates/srgn/" role="link" target="_blank" class="text-bold" rel="noopener noreferrer" href="https://crates.io/crates/srgn/">crates.io/crates/srgn/</a> </span> </div> <h3 class="sr-only">License</h3> <details class="details-reset details-overlay details-overlay-dark lh-default color-fg-default d-inline mb-2"> <summary class="Link--muted" > <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-law mr-2"> <path d="M8.75.75V2h.985c.304 0 .603.08.867.231l1.29.736c.038.022.08.033.124.033h2.234a.75.75 0 0 1 0 1.5h-.427l2.111 4.692a.75.75 0 0 1-.154.838l-.53-.53.529.531-.001.002-.002.002-.006.006-.006.005-.01.01-.045.04c-.21.176-.441.327-.686.45C14.556 10.78 13.88 11 13 11a4.498 4.498 0 0 1-2.023-.454 3.544 3.544 0 0 1-.686-.45l-.045-.04-.016-.015-.006-.006-.004-.004v-.001a.75.75 0 0 1-.154-.838L12.178 4.5h-.162c-.305 0-.604-.079-.868-.231l-1.29-.736a.245.245 0 0 0-.124-.033H8.75V13h2.5a.75.75 0 0 1 0 1.5h-6.5a.75.75 0 0 1 0-1.5h2.5V3.5h-.984a.245.245 0 0 0-.124.033l-1.289.737c-.265.15-.564.23-.869.23h-.162l2.112 4.692a.75.75 0 0 1-.154.838l-.53-.53.529.531-.001.002-.002.002-.006.006-.016.015-.045.04c-.21.176-.441.327-.686.45C4.556 10.78 3.88 11 3 11a4.498 4.498 0 0 1-2.023-.454 3.544 3.544 0 0 1-.686-.45l-.045-.04-.016-.015-.006-.006-.004-.004v-.001a.75.75 0 0 1-.154-.838L2.178 4.5H1.75a.75.75 0 0 1 0-1.5h2.234a.249.249 0 0 0 .125-.033l1.288-.737c.265-.15.564-.23.869-.23h.984V.75a.75.75 0 0 1 1.5 0Zm2.945 8.477c.285.135.718.273 1.305.273s1.02-.138 1.305-.273L13 6.327Zm-10 0c.285.135.718.273 1.305.273s1.02-.138 1.305-.273L3 6.327Z"></path> </svg> Apache-2.0, MIT licenses found </summary> <details-dialog class="Box Box--overlay d-flex flex-column anim-fade-in fast" aria-label="Licenses found"> <div class="Box-header"> <button type="button" class="Box-btn-octicon btn-octicon float-right" data-action="toggle" data-close-dialog aria-label="Close licenses dialog"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-x"> <path d="M3.72 3.72a.75.75 0 0 1 1.06 0L8 6.94l3.22-3.22a.749.749 0 0 1 1.275.326.749.749 0 0 1-.215.734L9.06 8l3.22 3.22a.749.749 0 0 1-.326 1.275.749.749 0 0 1-.734-.215L8 9.06l-3.22 3.22a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042L6.94 8 3.72 4.78a.75.75 0 0 1 0-1.06Z"></path> </svg> </button> <h3 class="Box-title">Licenses found</h3> </div> <a class="Link--primary no-underline" aria-label="Apache-2.0 license" href="/alexpovel/srgn/blob/main/./LICENSE-APACHE"> <div class="Box-row Box-row--hover-gray border-top rounded-0"> <div class="text-bold">Apache-2.0</div> <span class="f6 color-fg-muted">LICENSE-APACHE</span> </div> </a> <a class="Link--primary no-underline" aria-label="MIT license" href="/alexpovel/srgn/blob/main/./LICENSE-MIT"> <div class="Box-row Box-row--hover-gray border-top rounded-0"> <div class="text-bold">MIT</div> <span class="f6 color-fg-muted">LICENSE-MIT</span> </div> </a> </details-dialog> </details> <div class="mb-3"> <a class="Link--secondary no-underline mr-3" href="/alexpovel/srgn/stargazers"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-star mr-1"> <path d="M8 .25a.75.75 0 0 1 .673.418l1.882 3.815 4.21.612a.75.75 0 0 1 .416 1.279l-3.046 2.97.719 4.192a.751.751 0 0 1-1.088.791L8 12.347l-3.766 1.98a.75.75 0 0 1-1.088-.79l.72-4.194L.818 6.374a.75.75 0 0 1 .416-1.28l4.21-.611L7.327.668A.75.75 0 0 1 8 .25Zm0 2.445L6.615 5.5a.75.75 0 0 1-.564.41l-3.097.45 2.24 2.184a.75.75 0 0 1 .216.664l-.528 3.084 2.769-1.456a.75.75 0 0 1 .698 0l2.77 1.456-.53-3.084a.75.75 0 0 1 .216-.664l2.24-2.183-3.096-.45a.75.75 0 0 1-.564-.41L8 2.694Z"></path> </svg> <span class="text-bold">722</span> stars </a> <a class="Link--secondary no-underline mr-3" href="/alexpovel/srgn/forks"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-repo-forked mr-1"> <path d="M5 5.372v.878c0 .414.336.75.75.75h4.5a.75.75 0 0 0 .75-.75v-.878a2.25 2.25 0 1 1 1.5 0v.878a2.25 2.25 0 0 1-2.25 2.25h-1.5v2.128a2.251 2.251 0 1 1-1.5 0V8.5h-1.5A2.25 2.25 0 0 1 3.5 6.25v-.878a2.25 2.25 0 1 1 1.5 0ZM5 3.25a.75.75 0 1 0-1.5 0 .75.75 0 0 0 1.5 0Zm6.75.75a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5Zm-3 8.75a.75.75 0 1 0-1.5 0 .75.75 0 0 0 1.5 0Z"></path> </svg> <span class="text-bold">9</span> forks </a> <a class="Link--secondary no-underline mr-3 d-inline-block" href="/alexpovel/srgn/branches"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-git-branch mr-1"> <path d="M9.5 3.25a2.25 2.25 0 1 1 3 2.122V6A2.5 2.5 0 0 1 10 8.5H6a1 1 0 0 0-1 1v1.128a2.251 2.251 0 1 1-1.5 0V5.372a2.25 2.25 0 1 1 1.5 0v1.836A2.493 2.493 0 0 1 6 7h4a1 1 0 0 0 1-1v-.628A2.25 2.25 0 0 1 9.5 3.25Zm-6 0a.75.75 0 1 0 1.5 0 .75.75 0 0 0-1.5 0Zm8.25-.75a.75.75 0 1 0 0 1.5.75.75 0 0 0 0-1.5ZM4.25 12a.75.75 0 1 0 0 1.5.75.75 0 0 0 0-1.5Z"></path> </svg> <span>Branches</span> </a> <a class="Link--secondary no-underline d-inline-block" href="/alexpovel/srgn/tags"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-tag mr-1"> <path d="M1 7.775V2.75C1 1.784 1.784 1 2.75 1h5.025c.464 0 .91.184 1.238.513l6.25 6.25a1.75 1.75 0 0 1 0 2.474l-5.026 5.026a1.75 1.75 0 0 1-2.474 0l-6.25-6.25A1.752 1.752 0 0 1 1 7.775Zm1.5 0c0 .066.026.13.073.177l6.25 6.25a.25.25 0 0 0 .354 0l5.025-5.025a.25.25 0 0 0 0-.354l-6.25-6.25a.25.25 0 0 0-.177-.073H2.75a.25.25 0 0 0-.25.25ZM6 5a1 1 0 1 1 0 2 1 1 0 0 1 0-2Z"></path> </svg> <span>Tags</span> </a> <a class="Link--secondary no-underline d-inline-block" href="/alexpovel/srgn/activity"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-pulse mr-1"> <path d="M6 2c.306 0 .582.187.696.471L10 10.731l1.304-3.26A.751.751 0 0 1 12 7h3.25a.75.75 0 0 1 0 1.5h-2.742l-1.812 4.528a.751.751 0 0 1-1.392 0L6 4.77 4.696 8.03A.75.75 0 0 1 4 8.5H.75a.75.75 0 0 1 0-1.5h2.742l1.812-4.529A.751.751 0 0 1 6 2Z"></path> </svg> <span>Activity</span> </a> </div> <div class="d-flex flex-wrap gap-2"> <div class="flex-1"> <div data-view-component="true" class="BtnGroup d-flex"> <a href="/login?return_to=%2Falexpovel%2Fsrgn" rel="nofollow" data-hydro-click="{&quot;event_type&quot;:&quot;authentication.click&quot;,&quot;payload&quot;:{&quot;location_in_page&quot;:&quot;star button&quot;,&quot;repository_id&quot;:641495940,&quot;auth_type&quot;:&quot;LOG_IN&quot;,&quot;originating_url&quot;:&quot;https://github.com/alexpovel/srgn&quot;,&quot;user_id&quot;:null}}" data-hydro-click-hmac="ff12a677794ce97e2d42ebc420af732d9a1d0e30a8e8271d47542d342b4c46c3" aria-label="You must be signed in to star a repository" data-view-component="true" class="tooltipped tooltipped-sw btn-sm btn btn-block"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-star v-align-text-bottom d-inline-block mr-2"> <path d="M8 .25a.75.75 0 0 1 .673.418l1.882 3.815 4.21.612a.75.75 0 0 1 .416 1.279l-3.046 2.97.719 4.192a.751.751 0 0 1-1.088.791L8 12.347l-3.766 1.98a.75.75 0 0 1-1.088-.79l.72-4.194L.818 6.374a.75.75 0 0 1 .416-1.28l4.21-.611L7.327.668A.75.75 0 0 1 8 .25Zm0 2.445L6.615 5.5a.75.75 0 0 1-.564.41l-3.097.45 2.24 2.184a.75.75 0 0 1 .216.664l-.528 3.084 2.769-1.456a.75.75 0 0 1 .698 0l2.77 1.456-.53-3.084a.75.75 0 0 1 .216-.664l2.24-2.183-3.096-.45a.75.75 0 0 1-.564-.41L8 2.694Z"></path> </svg><span data-view-component="true" class="d-inline"> Star </span> </a></div> </div> <div class="flex-1"> <a href="/login?return_to=%2Falexpovel%2Fsrgn" rel="nofollow" id="files-overview-watch-button" data-hydro-click="{&quot;event_type&quot;:&quot;authentication.click&quot;,&quot;payload&quot;:{&quot;location_in_page&quot;:&quot;notification subscription menu watch&quot;,&quot;repository_id&quot;:null,&quot;auth_type&quot;:&quot;LOG_IN&quot;,&quot;originating_url&quot;:&quot;https://github.com/alexpovel/srgn&quot;,&quot;user_id&quot;:null}}" data-hydro-click-hmac="25f72cd2a86cb3042a9530629dfa3358f46060a4a8b78eb62ff2f91f3fa604c8" aria-label="You must be signed in to change notification settings" data-view-component="true" class="btn-sm btn btn-block"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-bell mr-2"> <path d="M8 16a2 2 0 0 0 1.985-1.75c.017-.137-.097-.25-.235-.25h-3.5c-.138 0-.252.113-.235.25A2 2 0 0 0 8 16ZM3 5a5 5 0 0 1 10 0v2.947c0 .05.015.098.042.139l1.703 2.555A1.519 1.519 0 0 1 13.482 13H2.518a1.516 1.516 0 0 1-1.263-2.36l1.703-2.554A.255.255 0 0 0 3 7.947Zm5-3.5A3.5 3.5 0 0 0 4.5 5v2.947c0 .346-.102.683-.294.97l-1.703 2.556a.017.017 0 0 0-.003.01l.001.006c0 .002.002.004.004.006l.006.004.007.001h10.964l.007-.001.006-.004.004-.006.001-.007a.017.017 0 0 0-.003-.01l-1.703-2.554a1.745 1.745 0 0 1-.294-.97V5A3.5 3.5 0 0 0 8 1.5Z"></path> </svg>Notifications </a> <tool-tip id="tooltip-ecd04f9c-8fe4-4408-9faf-a5467b578636" for="files-overview-watch-button" popover="manual" data-direction="s" data-type="description" data-view-component="true" class="sr-only position-absolute">You must be signed in to change notification settings</tool-tip> </div> <span> </span> </div> </div> </div> <nav data-pjax="#js-repo-pjax-container" aria-label="Repository" data-view-component="true" class="js-repo-nav js-sidenav-container-pjax js-responsive-underlinenav overflow-hidden UnderlineNav px-3 px-md-4 px-lg-5"> <ul data-view-component="true" class="UnderlineNav-body list-style-none"> <li data-view-component="true" class="d-inline-flex"> <a id="code-tab" href="/alexpovel/srgn" data-tab-item="i0code-tab" data-selected-links="repo_source repo_downloads repo_commits repo_releases repo_tags repo_branches repo_packages repo_deployments repo_attestations /alexpovel/srgn" data-pjax="#repo-content-pjax-container" data-turbo-frame="repo-content-turbo-frame" data-hotkey="g c" data-analytics-event="{&quot;category&quot;:&quot;Underline navbar&quot;,&quot;action&quot;:&quot;Click tab&quot;,&quot;label&quot;:&quot;Code&quot;,&quot;target&quot;:&quot;UNDERLINE_NAV.TAB&quot;}" aria-current="page" data-view-component="true" class="UnderlineNav-item no-wrap js-responsive-underlinenav-item js-selected-navigation-item selected"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-code UnderlineNav-octicon d-none d-sm-inline"> <path d="m11.28 3.22 4.25 4.25a.75.75 0 0 1 0 1.06l-4.25 4.25a.749.749 0 0 1-1.275-.326.749.749 0 0 1 .215-.734L13.94 8l-3.72-3.72a.749.749 0 0 1 .326-1.275.749.749 0 0 1 .734.215Zm-6.56 0a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042L2.06 8l3.72 3.72a.749.749 0 0 1-.326 1.275.749.749 0 0 1-.734-.215L.47 8.53a.75.75 0 0 1 0-1.06Z"></path> </svg> <span data-content="Code">Code</span> <span id="code-repo-tab-count" data-pjax-replace="" data-turbo-replace="" title="Not available" data-view-component="true" class="Counter"></span> </a></li> <li data-view-component="true" class="d-inline-flex"> <a id="issues-tab" href="/alexpovel/srgn/issues" data-tab-item="i1issues-tab" data-selected-links="repo_issues repo_labels repo_milestones /alexpovel/srgn/issues" data-pjax="#repo-content-pjax-container" data-turbo-frame="repo-content-turbo-frame" data-hotkey="g i" data-analytics-event="{&quot;category&quot;:&quot;Underline navbar&quot;,&quot;action&quot;:&quot;Click tab&quot;,&quot;label&quot;:&quot;Issues&quot;,&quot;target&quot;:&quot;UNDERLINE_NAV.TAB&quot;}" data-view-component="true" class="UnderlineNav-item no-wrap js-responsive-underlinenav-item js-selected-navigation-item"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-issue-opened UnderlineNav-octicon d-none d-sm-inline"> <path d="M8 9.5a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3Z"></path><path d="M8 0a8 8 0 1 1 0 16A8 8 0 0 1 8 0ZM1.5 8a6.5 6.5 0 1 0 13 0 6.5 6.5 0 0 0-13 0Z"></path> </svg> <span data-content="Issues">Issues</span> <span id="issues-repo-tab-count" data-pjax-replace="" data-turbo-replace="" title="5" data-view-component="true" class="Counter">5</span> </a></li> <li data-view-component="true" class="d-inline-flex"> <a id="pull-requests-tab" href="/alexpovel/srgn/pulls" data-tab-item="i2pull-requests-tab" data-selected-links="repo_pulls checks /alexpovel/srgn/pulls" data-pjax="#repo-content-pjax-container" data-turbo-frame="repo-content-turbo-frame" data-hotkey="g p" data-analytics-event="{&quot;category&quot;:&quot;Underline navbar&quot;,&quot;action&quot;:&quot;Click tab&quot;,&quot;label&quot;:&quot;Pull requests&quot;,&quot;target&quot;:&quot;UNDERLINE_NAV.TAB&quot;}" data-view-component="true" class="UnderlineNav-item no-wrap js-responsive-underlinenav-item js-selected-navigation-item"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-git-pull-request UnderlineNav-octicon d-none d-sm-inline"> <path d="M1.5 3.25a2.25 2.25 0 1 1 3 2.122v5.256a2.251 2.251 0 1 1-1.5 0V5.372A2.25 2.25 0 0 1 1.5 3.25Zm5.677-.177L9.573.677A.25.25 0 0 1 10 .854V2.5h1A2.5 2.5 0 0 1 13.5 5v5.628a2.251 2.251 0 1 1-1.5 0V5a1 1 0 0 0-1-1h-1v1.646a.25.25 0 0 1-.427.177L7.177 3.427a.25.25 0 0 1 0-.354ZM3.75 2.5a.75.75 0 1 0 0 1.5.75.75 0 0 0 0-1.5Zm0 9.5a.75.75 0 1 0 0 1.5.75.75 0 0 0 0-1.5Zm8.25.75a.75.75 0 1 0 1.5 0 .75.75 0 0 0-1.5 0Z"></path> </svg> <span data-content="Pull requests">Pull requests</span> <span id="pull-requests-repo-tab-count" data-pjax-replace="" data-turbo-replace="" title="9" data-view-component="true" class="Counter">9</span> </a></li> <li data-view-component="true" class="d-inline-flex"> <a id="actions-tab" href="/alexpovel/srgn/actions" data-tab-item="i3actions-tab" data-selected-links="repo_actions /alexpovel/srgn/actions" data-pjax="#repo-content-pjax-container" data-turbo-frame="repo-content-turbo-frame" data-hotkey="g a" data-analytics-event="{&quot;category&quot;:&quot;Underline navbar&quot;,&quot;action&quot;:&quot;Click tab&quot;,&quot;label&quot;:&quot;Actions&quot;,&quot;target&quot;:&quot;UNDERLINE_NAV.TAB&quot;}" data-view-component="true" class="UnderlineNav-item no-wrap js-responsive-underlinenav-item js-selected-navigation-item"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-play UnderlineNav-octicon d-none d-sm-inline"> <path d="M8 0a8 8 0 1 1 0 16A8 8 0 0 1 8 0ZM1.5 8a6.5 6.5 0 1 0 13 0 6.5 6.5 0 0 0-13 0Zm4.879-2.773 4.264 2.559a.25.25 0 0 1 0 .428l-4.264 2.559A.25.25 0 0 1 6 10.559V5.442a.25.25 0 0 1 .379-.215Z"></path> </svg> <span data-content="Actions">Actions</span> <span id="actions-repo-tab-count" data-pjax-replace="" data-turbo-replace="" title="Not available" data-view-component="true" class="Counter"></span> </a></li> <li data-view-component="true" class="d-inline-flex"> <a id="security-tab" href="/alexpovel/srgn/security" data-tab-item="i4security-tab" data-selected-links="security overview alerts policy token_scanning code_scanning /alexpovel/srgn/security" data-pjax="#repo-content-pjax-container" data-turbo-frame="repo-content-turbo-frame" data-hotkey="g s" data-analytics-event="{&quot;category&quot;:&quot;Underline navbar&quot;,&quot;action&quot;:&quot;Click tab&quot;,&quot;label&quot;:&quot;Security&quot;,&quot;target&quot;:&quot;UNDERLINE_NAV.TAB&quot;}" data-view-component="true" class="UnderlineNav-item no-wrap js-responsive-underlinenav-item js-selected-navigation-item"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-shield UnderlineNav-octicon d-none d-sm-inline"> <path d="M7.467.133a1.748 1.748 0 0 1 1.066 0l5.25 1.68A1.75 1.75 0 0 1 15 3.48V7c0 1.566-.32 3.182-1.303 4.682-.983 1.498-2.585 2.813-5.032 3.855a1.697 1.697 0 0 1-1.33 0c-2.447-1.042-4.049-2.357-5.032-3.855C1.32 10.182 1 8.566 1 7V3.48a1.75 1.75 0 0 1 1.217-1.667Zm.61 1.429a.25.25 0 0 0-.153 0l-5.25 1.68a.25.25 0 0 0-.174.238V7c0 1.358.275 2.666 1.057 3.86.784 1.194 2.121 2.34 4.366 3.297a.196.196 0 0 0 .154 0c2.245-.956 3.582-2.104 4.366-3.298C13.225 9.666 13.5 8.36 13.5 7V3.48a.251.251 0 0 0-.174-.237l-5.25-1.68ZM8.75 4.75v3a.75.75 0 0 1-1.5 0v-3a.75.75 0 0 1 1.5 0ZM9 10.5a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z"></path> </svg> <span data-content="Security">Security</span> <include-fragment src="/alexpovel/srgn/security/overall-count" accept="text/fragment+html"></include-fragment> </a></li> <li data-view-component="true" class="d-inline-flex"> <a id="insights-tab" href="/alexpovel/srgn/pulse" data-tab-item="i5insights-tab" data-selected-links="repo_graphs repo_contributors dependency_graph dependabot_updates pulse people community /alexpovel/srgn/pulse" data-pjax="#repo-content-pjax-container" data-turbo-frame="repo-content-turbo-frame" data-analytics-event="{&quot;category&quot;:&quot;Underline navbar&quot;,&quot;action&quot;:&quot;Click tab&quot;,&quot;label&quot;:&quot;Insights&quot;,&quot;target&quot;:&quot;UNDERLINE_NAV.TAB&quot;}" data-view-component="true" class="UnderlineNav-item no-wrap js-responsive-underlinenav-item js-selected-navigation-item"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-graph UnderlineNav-octicon d-none d-sm-inline"> <path d="M1.5 1.75V13.5h13.75a.75.75 0 0 1 0 1.5H.75a.75.75 0 0 1-.75-.75V1.75a.75.75 0 0 1 1.5 0Zm14.28 2.53-5.25 5.25a.75.75 0 0 1-1.06 0L7 7.06 4.28 9.78a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042l3.25-3.25a.75.75 0 0 1 1.06 0L10 7.94l4.72-4.72a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042Z"></path> </svg> <span data-content="Insights">Insights</span> <span id="insights-repo-tab-count" data-pjax-replace="" data-turbo-replace="" title="Not available" data-view-component="true" class="Counter"></span> </a></li> </ul> <div style="visibility:hidden;" data-view-component="true" class="UnderlineNav-actions js-responsive-underlinenav-overflow position-absolute pr-3 pr-md-4 pr-lg-5 right-0"> <action-menu data-select-variant="none" data-view-component="true"> <focus-group direction="vertical" mnemonics retain> <button id="action-menu-8e62b725-a593-4b79-8c73-ce4d8a5a1e59-button" popovertarget="action-menu-8e62b725-a593-4b79-8c73-ce4d8a5a1e59-overlay" aria-controls="action-menu-8e62b725-a593-4b79-8c73-ce4d8a5a1e59-list" aria-haspopup="true" aria-labelledby="tooltip-7d7f6e96-b84d-49e2-9e4d-0cd7e473784d" type="button" data-view-component="true" class="Button Button--iconOnly Button--secondary Button--medium UnderlineNav-item"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-kebab-horizontal Button-visual"> <path d="M8 9a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3ZM1.5 9a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3Zm13 0a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3Z"></path> </svg> </button><tool-tip id="tooltip-7d7f6e96-b84d-49e2-9e4d-0cd7e473784d" for="action-menu-8e62b725-a593-4b79-8c73-ce4d8a5a1e59-button" popover="manual" data-direction="s" data-type="label" data-view-component="true" class="sr-only position-absolute">Additional navigation options</tool-tip> <anchored-position data-target="action-menu.overlay" id="action-menu-8e62b725-a593-4b79-8c73-ce4d8a5a1e59-overlay" anchor="action-menu-8e62b725-a593-4b79-8c73-ce4d8a5a1e59-button" align="start" side="outside-bottom" anchor-offset="normal" popover="auto" data-view-component="true"> <div data-view-component="true" class="Overlay Overlay--size-auto"> <div data-view-component="true" class="Overlay-body Overlay-body--paddingNone"> <action-list> <div data-view-component="true"> <ul aria-labelledby="action-menu-8e62b725-a593-4b79-8c73-ce4d8a5a1e59-button" id="action-menu-8e62b725-a593-4b79-8c73-ce4d8a5a1e59-list" role="menu" data-view-component="true" class="ActionListWrap--inset ActionListWrap"> <li hidden="hidden" data-menu-item="i0code-tab" data-targets="action-list.items" role="none" data-view-component="true" class="ActionListItem"> <a tabindex="-1" id="item-b51de94a-a1df-4912-be73-3271e0e16055" href="/alexpovel/srgn" role="menuitem" data-view-component="true" class="ActionListContent ActionListContent--visual16"> <span class="ActionListItem-visual ActionListItem-visual--leading"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-code"> <path d="m11.28 3.22 4.25 4.25a.75.75 0 0 1 0 1.06l-4.25 4.25a.749.749 0 0 1-1.275-.326.749.749 0 0 1 .215-.734L13.94 8l-3.72-3.72a.749.749 0 0 1 .326-1.275.749.749 0 0 1 .734.215Zm-6.56 0a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042L2.06 8l3.72 3.72a.749.749 0 0 1-.326 1.275.749.749 0 0 1-.734-.215L.47 8.53a.75.75 0 0 1 0-1.06Z"></path> </svg> </span> <span data-view-component="true" class="ActionListItem-label"> Code </span> </a> </li> <li hidden="hidden" data-menu-item="i1issues-tab" data-targets="action-list.items" role="none" data-view-component="true" class="ActionListItem"> <a tabindex="-1" id="item-30fc95e0-5a79-485a-af87-b93ef4e6faa0" href="/alexpovel/srgn/issues" role="menuitem" data-view-component="true" class="ActionListContent ActionListContent--visual16"> <span class="ActionListItem-visual ActionListItem-visual--leading"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-issue-opened"> <path d="M8 9.5a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3Z"></path><path d="M8 0a8 8 0 1 1 0 16A8 8 0 0 1 8 0ZM1.5 8a6.5 6.5 0 1 0 13 0 6.5 6.5 0 0 0-13 0Z"></path> </svg> </span> <span data-view-component="true" class="ActionListItem-label"> Issues </span> </a> </li> <li hidden="hidden" data-menu-item="i2pull-requests-tab" data-targets="action-list.items" role="none" data-view-component="true" class="ActionListItem"> <a tabindex="-1" id="item-987bd745-d2d8-427a-9b0c-8f6f9bd313c7" href="/alexpovel/srgn/pulls" role="menuitem" data-view-component="true" class="ActionListContent ActionListContent--visual16"> <span class="ActionListItem-visual ActionListItem-visual--leading"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-git-pull-request"> <path d="M1.5 3.25a2.25 2.25 0 1 1 3 2.122v5.256a2.251 2.251 0 1 1-1.5 0V5.372A2.25 2.25 0 0 1 1.5 3.25Zm5.677-.177L9.573.677A.25.25 0 0 1 10 .854V2.5h1A2.5 2.5 0 0 1 13.5 5v5.628a2.251 2.251 0 1 1-1.5 0V5a1 1 0 0 0-1-1h-1v1.646a.25.25 0 0 1-.427.177L7.177 3.427a.25.25 0 0 1 0-.354ZM3.75 2.5a.75.75 0 1 0 0 1.5.75.75 0 0 0 0-1.5Zm0 9.5a.75.75 0 1 0 0 1.5.75.75 0 0 0 0-1.5Zm8.25.75a.75.75 0 1 0 1.5 0 .75.75 0 0 0-1.5 0Z"></path> </svg> </span> <span data-view-component="true" class="ActionListItem-label"> Pull requests </span> </a> </li> <li hidden="hidden" data-menu-item="i3actions-tab" data-targets="action-list.items" role="none" data-view-component="true" class="ActionListItem"> <a tabindex="-1" id="item-7e50a32c-517b-400b-9703-6f62b26b1819" href="/alexpovel/srgn/actions" role="menuitem" data-view-component="true" class="ActionListContent ActionListContent--visual16"> <span class="ActionListItem-visual ActionListItem-visual--leading"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-play"> <path d="M8 0a8 8 0 1 1 0 16A8 8 0 0 1 8 0ZM1.5 8a6.5 6.5 0 1 0 13 0 6.5 6.5 0 0 0-13 0Zm4.879-2.773 4.264 2.559a.25.25 0 0 1 0 .428l-4.264 2.559A.25.25 0 0 1 6 10.559V5.442a.25.25 0 0 1 .379-.215Z"></path> </svg> </span> <span data-view-component="true" class="ActionListItem-label"> Actions </span> </a> </li> <li hidden="hidden" data-menu-item="i4security-tab" data-targets="action-list.items" role="none" data-view-component="true" class="ActionListItem"> <a tabindex="-1" id="item-bc15a435-2934-4619-b199-32ea27e8436b" href="/alexpovel/srgn/security" role="menuitem" data-view-component="true" class="ActionListContent ActionListContent--visual16"> <span class="ActionListItem-visual ActionListItem-visual--leading"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-shield"> <path d="M7.467.133a1.748 1.748 0 0 1 1.066 0l5.25 1.68A1.75 1.75 0 0 1 15 3.48V7c0 1.566-.32 3.182-1.303 4.682-.983 1.498-2.585 2.813-5.032 3.855a1.697 1.697 0 0 1-1.33 0c-2.447-1.042-4.049-2.357-5.032-3.855C1.32 10.182 1 8.566 1 7V3.48a1.75 1.75 0 0 1 1.217-1.667Zm.61 1.429a.25.25 0 0 0-.153 0l-5.25 1.68a.25.25 0 0 0-.174.238V7c0 1.358.275 2.666 1.057 3.86.784 1.194 2.121 2.34 4.366 3.297a.196.196 0 0 0 .154 0c2.245-.956 3.582-2.104 4.366-3.298C13.225 9.666 13.5 8.36 13.5 7V3.48a.251.251 0 0 0-.174-.237l-5.25-1.68ZM8.75 4.75v3a.75.75 0 0 1-1.5 0v-3a.75.75 0 0 1 1.5 0ZM9 10.5a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z"></path> </svg> </span> <span data-view-component="true" class="ActionListItem-label"> Security </span> </a> </li> <li hidden="hidden" data-menu-item="i5insights-tab" data-targets="action-list.items" role="none" data-view-component="true" class="ActionListItem"> <a tabindex="-1" id="item-87b22efb-ff41-4486-a2f8-f646c45a06c3" href="/alexpovel/srgn/pulse" role="menuitem" data-view-component="true" class="ActionListContent ActionListContent--visual16"> <span class="ActionListItem-visual ActionListItem-visual--leading"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-graph"> <path d="M1.5 1.75V13.5h13.75a.75.75 0 0 1 0 1.5H.75a.75.75 0 0 1-.75-.75V1.75a.75.75 0 0 1 1.5 0Zm14.28 2.53-5.25 5.25a.75.75 0 0 1-1.06 0L7 7.06 4.28 9.78a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042l3.25-3.25a.75.75 0 0 1 1.06 0L10 7.94l4.72-4.72a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042Z"></path> </svg> </span> <span data-view-component="true" class="ActionListItem-label"> Insights </span> </a> </li> </ul> </div></action-list> </div> </div></anchored-position> </focus-group> </action-menu></div> </nav> </div> <turbo-frame id="repo-content-turbo-frame" target="_top" data-turbo-action="advance" class=""> <div id="repo-content-pjax-container" class="repository-content " > <h1 class='sr-only'>alexpovel/srgn</h1> <div class="clearfix container-xl px-md-4 px-lg-5 px-3"> <div> <div style="max-width: 100%" data-view-component="true" class="Layout Layout--flowRow-until-md react-repos-overview-margin Layout--sidebarPosition-end Layout--sidebarPosition-flowRow-end"> <div data-view-component="true" class="Layout-main"> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/vendors-node_modules_dompurify_dist_purify_es_mjs-dd1d3ea6a436.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/vendors-node_modules_tanstack_query-core_build_modern_queryObserver_js-node_modules_tanstack_-defd52-843b41414e0e.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/ui_packages_aria-live_aria-live_ts-ui_packages_history_history_ts-ui_packages_promise-with-re-01dc80-134579ff449f.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/ui_packages_paths_index_ts-3adbcf6faa83.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/ui_packages_ref-selector_RefSelector_tsx-7496afc3784d.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/ui_packages_commit-attribution_index_ts-ui_packages_commit-checks-status_index_ts-ui_packages-7094d4-b869a469ca5e.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/ui_packages_hydro-analytics_hydro-analytics_ts-ui_packages_verified-fetch_verified-fetch_ts-u-4672d1-96a19eaeffb7.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/ui_packages_code-view-shared_hooks_use-canonical-object_ts-ui_packages_code-view-shared_hooks-d63960-3a5579c864b4.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/repos-overview-fa360a7b1b46.js"></script> <link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/primer-react.8157a56b30ae88a1b356.module.css" /> <link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/repos-overview.0ee7cac3ab511a65d9f9.module.css" /> <react-partial partial-name="repos-overview" data-ssr="true" data-attempted-ssr="true" > <script type="application/json" data-target="react-partial.embeddedData">{"props":{"initialPayload":{"allShortcutsEnabled":false,"path":"/","repo":{"id":641495940,"defaultBranch":"main","name":"srgn","ownerLogin":"alexpovel","currentUserCanPush":false,"isFork":false,"isEmpty":false,"createdAt":"2023-05-16T15:32:07.000Z","ownerAvatar":"https://avatars.githubusercontent.com/u/48824213?v=4","public":true,"private":false,"isOrgOwned":false},"currentUser":null,"refInfo":{"name":"main","listCacheKey":"v0:1743502020.0","canEdit":false,"refType":"branch","currentOid":"fbacfe3d7ce52304afd40e0278e4325783a99558"},"tree":{"items":[{"name":".github","path":".github","contentType":"directory"},{"name":".vscode","path":".vscode","contentType":"directory"},{"name":"benches","path":"benches","contentType":"directory"},{"name":"data/word-lists","path":"data/word-lists","contentType":"directory","hasSimplifiedPath":true},{"name":"docs","path":"docs","contentType":"directory"},{"name":"src","path":"src","contentType":"directory"},{"name":"tests","path":"tests","contentType":"directory"},{"name":".gitattributes","path":".gitattributes","contentType":"file"},{"name":".gitignore","path":".gitignore","contentType":"file"},{"name":".gitmodules","path":".gitmodules","contentType":"file"},{"name":".markdownlint.yaml","path":".markdownlint.yaml","contentType":"file"},{"name":".markdownlintignore","path":".markdownlintignore","contentType":"file"},{"name":".pre-commit-config.yaml","path":".pre-commit-config.yaml","contentType":"file"},{"name":".release-please-manifest.json","path":".release-please-manifest.json","contentType":"file"},{"name":"CHANGELOG.md","path":"CHANGELOG.md","contentType":"file"},{"name":"CONTRIBUTING.md","path":"CONTRIBUTING.md","contentType":"file"},{"name":"Cargo.lock","path":"Cargo.lock","contentType":"file"},{"name":"Cargo.toml","path":"Cargo.toml","contentType":"file"},{"name":"LICENSE-APACHE","path":"LICENSE-APACHE","contentType":"file"},{"name":"LICENSE-MIT","path":"LICENSE-MIT","contentType":"file"},{"name":"NOTICE","path":"NOTICE","contentType":"file"},{"name":"README.md","path":"README.md","contentType":"file"},{"name":"build.rs","path":"build.rs","contentType":"file"},{"name":"codecov.yml","path":"codecov.yml","contentType":"file"},{"name":"release-please-config.json","path":"release-please-config.json","contentType":"file"},{"name":"rustfmt.toml","path":"rustfmt.toml","contentType":"file"},{"name":"tarpaulin.toml","path":"tarpaulin.toml","contentType":"file"}],"templateDirectorySuggestionUrl":null,"readme":null,"totalCount":27,"showBranchInfobar":false},"fileTree":null,"fileTreeProcessingTime":null,"foldersToFetch":[],"treeExpanded":false,"symbolsExpanded":false,"isOverview":true,"overview":{"banners":{"shouldRecommendReadme":false,"isPersonalRepo":false,"showUseActionBanner":false,"actionSlug":null,"actionId":null,"showProtectBranchBanner":false,"publishBannersInfo":{"dismissActionNoticePath":"/settings/dismiss-notice/publish_action_from_repo","releasePath":"/alexpovel/srgn/releases/new?marketplace=true","showPublishActionBanner":false},"interactionLimitBanner":null,"showInvitationBanner":false,"inviterName":null,"actionsMigrationBannerInfo":{"releaseTags":[],"showImmutableActionsMigrationBanner":false,"initialMigrationStatus":null}},"codeButton":{"contactPath":"/contact","isEnterprise":false,"local":{"protocolInfo":{"httpAvailable":true,"sshAvailable":null,"httpUrl":"https://github.com/alexpovel/srgn.git","showCloneWarning":null,"sshUrl":null,"sshCertificatesRequired":null,"sshCertificatesAvailable":null,"ghCliUrl":"gh repo clone alexpovel/srgn","defaultProtocol":"http","newSshKeyUrl":"/settings/ssh/new","setProtocolPath":"/users/set_protocol"},"platformInfo":{"cloneUrl":"https://desktop.github.com","showVisualStudioCloneButton":false,"visualStudioCloneUrl":"https://windows.github.com","showXcodeCloneButton":false,"xcodeCloneUrl":"xcode://clone?repo=https%3A%2F%2Fgithub.com%2Falexpovel%2Fsrgn","zipballUrl":"/alexpovel/srgn/archive/refs/heads/main.zip"}},"newCodespacePath":"/codespaces/new?hide_repo_select=true\u0026repo=641495940"},"popovers":{"rename":null,"renamedParentRepo":null},"commitCount":"690","overviewFiles":[{"displayName":"README.md","repoName":"srgn","refName":"main","path":"README.md","preferredFileType":"readme","tabName":"README","richText":"\u003carticle class=\"markdown-body entry-content container-lg\" itemprop=\"text\"\u003e\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch1 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003esrgn - a code surgeon\u003c/h1\u003e\u003ca id=\"user-content-srgn---a-code-surgeon\" class=\"anchor\" aria-label=\"Permalink: srgn - a code surgeon\" href=\"#srgn---a-code-surgeon\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eA \u003ccode\u003egrep\u003c/code\u003e-like tool which understands source code syntax and allows for manipulation in\naddition to search.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eLike \u003ccode\u003egrep\u003c/code\u003e, regular expressions are a core primitive. Unlike \u003ccode\u003egrep\u003c/code\u003e, additional\ncapabilities allow for \u003cstrong\u003ehigher precision\u003c/strong\u003e, with \u003cstrong\u003eoptions for manipulation\u003c/strong\u003e. This\nallows \u003ccode\u003esrgn\u003c/code\u003e to operate along dimensions regular expressions and IDE tooling (\u003cem\u003eRename\nall\u003c/em\u003e, \u003cem\u003eFind all references\u003c/em\u003e, ...) alone cannot, complementing them.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003e\u003ccode\u003esrgn\u003c/code\u003e is organized around \u003cem\u003eactions\u003c/em\u003e to take (if any), acting only within precise,\noptionally \u003cstrong\u003elanguage grammar-aware\u003c/strong\u003e \u003cem\u003escopes\u003c/em\u003e. In terms of existing tools, think of it\nas a mix of\n\u003ca href=\"https://www.gnu.org/software/coreutils/manual/html_node/tr-invocation.html#tr-invocation\" rel=\"nofollow\"\u003e\u003ccode\u003etr\u003c/code\u003e\u003c/a\u003e,\n\u003ca href=\"https://www.gnu.org/software/sed/\" rel=\"nofollow\"\u003e\u003ccode\u003esed\u003c/code\u003e\u003c/a\u003e,\n\u003ca href=\"https://github.com/BurntSushi/ripgrep\"\u003eripgrep\u003c/a\u003e and\n\u003ca href=\"https://tree-sitter.github.io/tree-sitter/\" rel=\"nofollow\"\u003e\u003ccode\u003etree-sitter\u003c/code\u003e\u003c/a\u003e, with a design goal of\n\u003cem\u003esimplicity\u003c/em\u003e: if you know regex and the basics of the language you are working with, you\nare good to go.\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp dir=\"auto\"\u003eThe answer to \"What if \u003ccode\u003egrep\u003c/code\u003e, \u003ccode\u003etr\u003c/code\u003e, \u003ccode\u003esed\u003c/code\u003e and \u003ccode\u003etree-sitter\u003c/code\u003e got really drunk one\nnight and had a baby?\"\u003c/p\u003e\n\u003cp dir=\"auto\"\u003e-- \u003ca href=\"https://realpython.com/podcasts/rpp/225/#t=2286\" rel=\"nofollow\"\u003eReal Python Podcast\u003c/a\u003e\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch2 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eQuick walkthrough\u003c/h2\u003e\u003ca id=\"user-content-quick-walkthrough\" class=\"anchor\" aria-label=\"Permalink: Quick walkthrough\" href=\"#quick-walkthrough\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cdiv class=\"markdown-alert markdown-alert-tip\" dir=\"auto\"\u003e\u003cp class=\"markdown-alert-title\" dir=\"auto\"\u003e\u003csvg class=\"octicon octicon-light-bulb mr-2\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"M8 1.5c-2.363 0-4 1.69-4 3.75 0 .984.424 1.625.984 2.304l.214.253c.223.264.47.556.673.848.284.411.537.896.621 1.49a.75.75 0 0 1-1.484.211c-.04-.282-.163-.547-.37-.847a8.456 8.456 0 0 0-.542-.68c-.084-.1-.173-.205-.268-.32C3.201 7.75 2.5 6.766 2.5 5.25 2.5 2.31 4.863 0 8 0s5.5 2.31 5.5 5.25c0 1.516-.701 2.5-1.328 3.259-.095.115-.184.22-.268.319-.207.245-.383.453-.541.681-.208.3-.33.565-.37.847a.751.751 0 0 1-1.485-.212c.084-.593.337-1.078.621-1.489.203-.292.45-.584.673-.848.075-.088.147-.173.213-.253.561-.679.985-1.32.985-2.304 0-2.06-1.637-3.75-4-3.75ZM5.75 12h4.5a.75.75 0 0 1 0 1.5h-4.5a.75.75 0 0 1 0-1.5ZM6 15.25a.75.75 0 0 1 .75-.75h2.5a.75.75 0 0 1 0 1.5h-2.5a.75.75 0 0 1-.75-.75Z\"\u003e\u003c/path\u003e\u003c/svg\u003eTip\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eAll code snippets displayed here are \u003ca href=\"/alexpovel/srgn/blob/main/tests/readme.rs\"\u003everified as part of unit tests\u003c/a\u003e\nusing the actual \u003ccode\u003esrgn\u003c/code\u003e binary. What is showcased here is guaranteed to work.\u003c/p\u003e\n\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eThe most simple \u003ccode\u003esrgn\u003c/code\u003e usage works \u003ca href=\"#comparison-with-tr\"\u003esimilar to \u003ccode\u003etr\u003c/code\u003e\u003c/a\u003e:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-shell notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"$ echo 'Hello World!' | srgn '[wW]orld' 'there' # replacement\nHello there!\"\u003e\u003cpre\u003e$ \u003cspan class=\"pl-c1\"\u003eecho\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003eHello World!\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-k\"\u003e|\u003c/span\u003e srgn \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e[wW]orld\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003ethere\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-c\"\u003e\u003cspan class=\"pl-c\"\u003e#\u003c/span\u003e replacement\u003c/span\u003e\nHello there\u003cspan class=\"pl-k\"\u003e!\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eMatches for the regular expression pattern \u003ccode\u003e'[wW]orld'\u003c/code\u003e (the \u003cem\u003escope\u003c/em\u003e) are replaced (the\n\u003cem\u003eaction\u003c/em\u003e) by the second positional argument. Zero or more actions can be specified:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-shell notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"$ echo 'Hello World!' | srgn '[wW]orld' # zero actions: input returned unchanged\nHello World!\n$ echo 'Hello World!' | srgn --upper '[wW]orld' 'you' # two actions: replacement, afterwards uppercasing\nHello YOU!\"\u003e\u003cpre\u003e$ \u003cspan class=\"pl-c1\"\u003eecho\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003eHello World!\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-k\"\u003e|\u003c/span\u003e srgn \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e[wW]orld\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-c\"\u003e\u003cspan class=\"pl-c\"\u003e#\u003c/span\u003e zero actions: input returned unchanged\u003c/span\u003e\nHello World\u003cspan class=\"pl-k\"\u003e!\u003c/span\u003e\n$ \u003cspan class=\"pl-c1\"\u003eecho\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003eHello World!\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-k\"\u003e|\u003c/span\u003e srgn --upper \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e[wW]orld\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003eyou\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-c\"\u003e\u003cspan class=\"pl-c\"\u003e#\u003c/span\u003e two actions: replacement, afterwards uppercasing\u003c/span\u003e\nHello YOU\u003cspan class=\"pl-k\"\u003e!\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eReplacement is always performed first and specified positionally. Any \u003ca href=\"#actions\"\u003eother\nactions\u003c/a\u003e are applied after and given as command line flags.\u003c/p\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch3 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eMultiple scopes\u003c/h3\u003e\u003ca id=\"user-content-multiple-scopes\" class=\"anchor\" aria-label=\"Permalink: Multiple scopes\" href=\"#multiple-scopes\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eSimilarly, more than one scope can be specified: in addition to the regex pattern, a\n\u003ca href=\"https://tree-sitter.github.io/tree-sitter/\" rel=\"nofollow\"\u003e\u003cstrong\u003elanguage grammar-aware\u003c/strong\u003e\u003c/a\u003e scope can be\ngiven, which scopes to \u003cstrong\u003esyntactical elements of source code\u003c/strong\u003e (think, for example, \"all\nbodies of \u003ccode\u003eclass\u003c/code\u003e definitions in Python\"). If both are given, the regular expression\npattern is then \u003cstrong\u003eonly applied \u003cem\u003ewithin\u003c/em\u003e that first, language scope\u003c/strong\u003e. This enables\nsearch and manipulation at precision not normally possible using plain regular\nexpressions, and serving a dimension different from tools such as \u003cem\u003eRename all\u003c/em\u003e in IDEs.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eFor example, consider this (pointless) Python source file:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-python notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"\u0026quot;\u0026quot;\u0026quot;Module for watching birds and their age.\u0026quot;\u0026quot;\u0026quot;\n\nfrom dataclasses import dataclass\n\n\n@dataclass\nclass Bird:\n \u0026quot;\u0026quot;\u0026quot;A bird!\u0026quot;\u0026quot;\u0026quot;\n\n name: str\n age: int\n\n def celebrate_birthday(self):\n print(\u0026quot;🎉\u0026quot;)\n self.age += 1\n\n @classmethod\n def from_egg(egg):\n \u0026quot;\u0026quot;\u0026quot;Create a bird from an egg.\u0026quot;\u0026quot;\u0026quot;\n pass # No bird here yet!\n\n\ndef register_bird(bird: Bird, db: Db) -\u0026gt; None:\n assert bird.age \u0026gt;= 0\n with db.tx() as tx:\n tx.insert(bird)\"\u003e\u003cpre\u003e\u003cspan class=\"pl-s\"\u003e\"\"\"Module for watching birds and their age.\"\"\"\u003c/span\u003e\n\n\u003cspan class=\"pl-k\"\u003efrom\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003edataclasses\u003c/span\u003e \u003cspan class=\"pl-k\"\u003eimport\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003edataclass\u003c/span\u003e\n\n\n\u003cspan class=\"pl-en\"\u003e@\u003cspan class=\"pl-s1\"\u003edataclass\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"pl-k\"\u003eclass\u003c/span\u003e \u003cspan class=\"pl-v\"\u003eBird\u003c/span\u003e:\n \u003cspan class=\"pl-s\"\u003e\"\"\"A bird!\"\"\"\u003c/span\u003e\n\n \u003cspan class=\"pl-s1\"\u003ename\u003c/span\u003e: \u003cspan class=\"pl-smi\"\u003estr\u003c/span\u003e\n \u003cspan class=\"pl-s1\"\u003eage\u003c/span\u003e: \u003cspan class=\"pl-smi\"\u003eint\u003c/span\u003e\n\n \u003cspan class=\"pl-k\"\u003edef\u003c/span\u003e \u003cspan class=\"pl-en\"\u003ecelebrate_birthday\u003c/span\u003e(\u003cspan class=\"pl-s1\"\u003eself\u003c/span\u003e):\n \u003cspan class=\"pl-en\"\u003eprint\u003c/span\u003e(\u003cspan class=\"pl-s\"\u003e\"🎉\"\u003c/span\u003e)\n \u003cspan class=\"pl-s1\"\u003eself\u003c/span\u003e.\u003cspan class=\"pl-c1\"\u003eage\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e+=\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e1\u003c/span\u003e\n\n \u003cspan class=\"pl-en\"\u003e@\u003cspan class=\"pl-s1\"\u003eclassmethod\u003c/span\u003e\u003c/span\u003e\n \u003cspan class=\"pl-k\"\u003edef\u003c/span\u003e \u003cspan class=\"pl-en\"\u003efrom_egg\u003c/span\u003e(\u003cspan class=\"pl-s1\"\u003eegg\u003c/span\u003e):\n \u003cspan class=\"pl-s\"\u003e\"\"\"Create a bird from an egg.\"\"\"\u003c/span\u003e\n \u003cspan class=\"pl-k\"\u003epass\u003c/span\u003e \u003cspan class=\"pl-c\"\u003e# No bird here yet!\u003c/span\u003e\n\n\n\u003cspan class=\"pl-k\"\u003edef\u003c/span\u003e \u003cspan class=\"pl-en\"\u003eregister_bird\u003c/span\u003e(\u003cspan class=\"pl-s1\"\u003ebird\u003c/span\u003e: \u003cspan class=\"pl-smi\"\u003eBird\u003c/span\u003e, \u003cspan class=\"pl-s1\"\u003edb\u003c/span\u003e: \u003cspan class=\"pl-smi\"\u003eDb\u003c/span\u003e) \u003cspan class=\"pl-c1\"\u003e-\u0026gt;\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003eNone\u003c/span\u003e:\n \u003cspan class=\"pl-k\"\u003eassert\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003ebird\u003c/span\u003e.\u003cspan class=\"pl-c1\"\u003eage\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e\u0026gt;=\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e0\u003c/span\u003e\n \u003cspan class=\"pl-k\"\u003ewith\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003edb\u003c/span\u003e.\u003cspan class=\"pl-c1\"\u003etx\u003c/span\u003e() \u003cspan class=\"pl-k\"\u003eas\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003etx\u003c/span\u003e:\n \u003cspan class=\"pl-s1\"\u003etx\u003c/span\u003e.\u003cspan class=\"pl-c1\"\u003einsert\u003c/span\u003e(\u003cspan class=\"pl-s1\"\u003ebird\u003c/span\u003e)\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003ewhich can be searched using:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-text-shell-session notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"$ cat birds.py | srgn --python 'class' 'age'\n11: age: int\n15: self.age += 1\"\u003e\u003cpre\u003e$ \u003cspan class=\"pl-s1\"\u003ecat birds.py \u003cspan class=\"pl-k\"\u003e|\u003c/span\u003e srgn --python \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003eclass\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003eage\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e11: age: int\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e15: self.age += 1\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eThe string \u003ccode\u003eage\u003c/code\u003e was sought and found \u003cem\u003eonly\u003c/em\u003e within Python \u003ccode\u003eclass\u003c/code\u003e definitions (and not,\nfor example, in function bodies such as \u003ccode\u003eregister_bird\u003c/code\u003e, where \u003ccode\u003eage\u003c/code\u003e also occurs and\nwould be nigh impossible to exclude from consideration in vanilla \u003ccode\u003egrep\u003c/code\u003e). By default,\nthis 'search mode' also prints line numbers. \u003cstrong\u003eSearch mode is entered if no actions are\nspecified\u003c/strong\u003e, and a language such as \u003ccode\u003e--python\u003c/code\u003e is given\u003csup\u003e\u003ca href=\"#user-content-fn-3-b30ce13ed678ccbd6287a3f5e19f11b5\" id=\"user-content-fnref-3-b30ce13ed678ccbd6287a3f5e19f11b5\" data-footnote-ref=\"\" aria-describedby=\"footnote-label\"\u003e1\u003c/a\u003e\u003c/sup\u003e—think of it like\n'\u003ca href=\"https://github.com/BurntSushi/ripgrep\"\u003eripgrep\u003c/a\u003e but with syntactical language\nelements'.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eSearching can also be performed \u003ca href=\"https://docs.rs/regex/1.10.5/regex/index.html#grouping-and-flags\" rel=\"nofollow\"\u003eacross\nlines\u003c/a\u003e, for example to\nfind methods (aka \u003cem\u003e\u003ccode\u003edef\u003c/code\u003e within \u003ccode\u003eclass\u003c/code\u003e\u003c/em\u003e) lacking docstrings:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-text-shell-session notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"$ cat birds.py | srgn --python 'class' 'def .+:\\n\\s+[^\u0026quot;\\s]{3}' # do not try this pattern at home\n13: def celebrate_birthday(self):\n14: print(\u0026quot;🎉\u0026quot;)\"\u003e\u003cpre\u003e$ \u003cspan class=\"pl-s1\"\u003ecat birds.py \u003cspan class=\"pl-k\"\u003e|\u003c/span\u003e srgn --python \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003eclass\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003edef .+:\\n\\s+[^\"\\s]{3}\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-c\"\u003e\u003cspan class=\"pl-c\"\u003e#\u003c/span\u003e do not try this pattern at home\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e13: def celebrate_birthday(self):\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e14: print(\"🎉\")\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eNote how this does not surface either \u003ccode\u003efrom_egg\u003c/code\u003e (has a docstring) or \u003ccode\u003eregister_bird\u003c/code\u003e\n(not a method, \u003cem\u003e\u003ccode\u003edef\u003c/code\u003e outside \u003ccode\u003eclass\u003c/code\u003e\u003c/em\u003e).\u003c/p\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch4 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eMultiple language scopes\u003c/h4\u003e\u003ca id=\"user-content-multiple-language-scopes\" class=\"anchor\" aria-label=\"Permalink: Multiple language scopes\" href=\"#multiple-language-scopes\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eLanguage scopes themselves can be specified multiple times as well. For example, in the\nRust snippet\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-rust notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"pub enum Genre {\n Rock(Subgenre),\n Jazz,\n}\n\nconst MOST_POPULAR_SUBGENRE: Subgenre = Subgenre::Something;\n\npub struct Musician {\n name: String,\n genres: Vec\u0026lt;Subgenre\u0026gt;,\n}\"\u003e\u003cpre\u003e\u003cspan class=\"pl-k\"\u003epub\u003c/span\u003e \u003cspan class=\"pl-k\"\u003eenum\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eGenre\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e{\u003c/span\u003e\n \u003cspan class=\"pl-v\"\u003eRock\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-smi\"\u003eSubgenre\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e,\u003c/span\u003e\n \u003cspan class=\"pl-v\"\u003eJazz\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e,\u003c/span\u003e\n\u003cspan class=\"pl-kos\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"pl-k\"\u003econst\u003c/span\u003e \u003cspan class=\"pl-v\"\u003eMOST_POPULAR_SUBGENRE\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e:\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eSubgenre\u003c/span\u003e = \u003cspan class=\"pl-smi\"\u003eSubgenre\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e::\u003c/span\u003e\u003cspan class=\"pl-v\"\u003eSomething\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e;\u003c/span\u003e\n\n\u003cspan class=\"pl-k\"\u003epub\u003c/span\u003e \u003cspan class=\"pl-k\"\u003estruct\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eMusician\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e{\u003c/span\u003e\n \u003cspan class=\"pl-c1\"\u003ename\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e:\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eString\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e,\u003c/span\u003e\n \u003cspan class=\"pl-c1\"\u003egenres\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e:\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eVec\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"pl-smi\"\u003eSubgenre\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e,\u003c/span\u003e\n\u003cspan class=\"pl-kos\"\u003e}\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003emultiple items can be surgically drilled down into as\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-text-shell-session notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"$ cat music.rs | srgn --rust 'pub-enum' --rust 'type-identifier' 'Subgenre' # AND'ed together\n2: Rock(Subgenre),\"\u003e\u003cpre\u003e$ \u003cspan class=\"pl-s1\"\u003ecat music.rs \u003cspan class=\"pl-k\"\u003e|\u003c/span\u003e srgn --rust \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003epub-enum\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e --rust \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003etype-identifier\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003eSubgenre\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-c\"\u003e\u003cspan class=\"pl-c\"\u003e#\u003c/span\u003e AND'ed together\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e2: Rock(Subgenre),\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003ewhere only lines matching \u003cem\u003eall\u003c/em\u003e criteria are returned, acting like a logical \u003cem\u003eand\u003c/em\u003e\nbetween all conditions. Note that conditions are evaluated left-to-right, precluding\nsome combinations from making sense: for example, searching for a Python \u003ccode\u003eclass\u003c/code\u003e body\n\u003cem\u003einside\u003c/em\u003e of Python \u003ccode\u003edoc-strings\u003c/code\u003e usually returns nothing. The inverse works as expected\nhowever:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-text-shell-session notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"$ cat birds.py | srgn --py 'class' --py 'doc-strings' \n8: \u0026quot;\u0026quot;\u0026quot;A bird!\u0026quot;\u0026quot;\u0026quot;\n19: \u0026quot;\u0026quot;\u0026quot;Create a bird from an egg.\u0026quot;\u0026quot;\u0026quot;\"\u003e\u003cpre\u003e$ \u003cspan class=\"pl-s1\"\u003ecat birds.py \u003cspan class=\"pl-k\"\u003e|\u003c/span\u003e srgn --py \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003eclass\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e --py \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003edoc-strings\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e \u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e8: \"\"\"A bird!\"\"\"\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e19: \"\"\"Create a bird from an egg.\"\"\"\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eNo docstrings outside \u003ccode\u003eclass\u003c/code\u003e bodies are surfaced!\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eThe \u003ca href=\"#help-output\"\u003e\u003ccode\u003e-j\u003c/code\u003e flag\u003c/a\u003e changes this behavior: from intersecting left-to-right, to\nrunning all queries independently and joining their results, allowing you to search\nmultiple ways at once:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-text-shell-session notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"$ cat birds.py | srgn -j --python 'comments' --python 'doc-strings' 'bird[^s]'\n8: \u0026quot;\u0026quot;\u0026quot;A bird!\u0026quot;\u0026quot;\u0026quot;\n19: \u0026quot;\u0026quot;\u0026quot;Create a bird from an egg.\u0026quot;\u0026quot;\u0026quot;\n20: pass # No bird here yet!\"\u003e\u003cpre\u003e$ \u003cspan class=\"pl-s1\"\u003ecat birds.py \u003cspan class=\"pl-k\"\u003e|\u003c/span\u003e srgn -j --python \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003ecomments\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e --python \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003edoc-strings\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003ebird[^s]\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e8: \"\"\"A bird!\"\"\"\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e19: \"\"\"Create a bird from an egg.\"\"\"\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e20: pass # No bird here yet!\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eThe pattern \u003ccode\u003ebird[^s]\u003c/code\u003e was found inside of comments \u003cem\u003eor\u003c/em\u003e docstrings likewise, not just\n\"docstrings \u003cem\u003ewithin\u003c/em\u003e comments\".\u003c/p\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch4 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eWorking recursively\u003c/h4\u003e\u003ca id=\"user-content-working-recursively\" class=\"anchor\" aria-label=\"Permalink: Working recursively\" href=\"#working-recursively\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eIf standard input is not given, \u003ccode\u003esrgn\u003c/code\u003e knows how to find relevant source files\nautomatically, for example in this repository:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-text-shell-session notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"$ srgn --python 'class' 'age'\ndocs/samples/birds\n11: age: int\n15: self.age += 1\n\ndocs/samples/birds.py\n9: age: int\n13: self.age += 1\"\u003e\u003cpre\u003e$ \u003cspan class=\"pl-s1\"\u003esrgn --python \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003eclass\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003eage\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003edocs/samples/birds\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e11: age: int\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e15: self.age += 1\u003c/span\u003e\n\n\u003cspan class=\"pl-c1\"\u003edocs/samples/birds.py\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e9: age: int\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e13: self.age += 1\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eIt recursively walks its current directory, finding files based on \u003ca href=\"/alexpovel/srgn/blob/main/docs/samples/birds.py\"\u003efile\nextensions\u003c/a\u003e and \u003ca href=\"/alexpovel/srgn/blob/main/docs/samples/birds\"\u003eshebang lines\u003c/a\u003e, processing\nat very high speed. For example, \u003ccode\u003esrgn --go strings '\\d+'\u003c/code\u003e finds and prints all ~140,000\nruns of digits in literal Go strings inside the \u003ca href=\"https://github.com/kubernetes/kubernetes/tree/5639f8f848720329f4a9d53555a228891550cb79\"\u003eKubernetes\ncodebase\u003c/a\u003e\nof ~3,000,000 lines of Go code within 3 seconds on 12 cores of M3. For more on working\nwith many files, see \u003ca href=\"#run-against-multiple-files\"\u003ebelow\u003c/a\u003e.\u003c/p\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch3 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eCombining actions and scopes\u003c/h3\u003e\u003ca id=\"user-content-combining-actions-and-scopes\" class=\"anchor\" aria-label=\"Permalink: Combining actions and scopes\" href=\"#combining-actions-and-scopes\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eScopes and actions can be combined almost arbitrarily (though many combinations are not\ngoing to be use- or even meaningful). For example, consider this Python snippet (for\nexamples using other supported languages see\n\u003ca href=\"#prepared-queries\"\u003ebelow\u003c/a\u003e):\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-python notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"\u0026quot;\u0026quot;\u0026quot;GNU module.\u0026quot;\u0026quot;\u0026quot;\n\ndef GNU_says_moo():\n \u0026quot;\u0026quot;\u0026quot;The GNU function -\u0026gt; say moo -\u0026gt; ✅\u0026quot;\u0026quot;\u0026quot;\n\n GNU = \u0026quot;\u0026quot;\u0026quot;\n GNU\n \u0026quot;\u0026quot;\u0026quot; # the GNU...\n\n print(GNU + \u0026quot; says moo\u0026quot;) # ...says moo\"\u003e\u003cpre\u003e\u003cspan class=\"pl-s\"\u003e\"\"\"GNU module.\"\"\"\u003c/span\u003e\n\n\u003cspan class=\"pl-k\"\u003edef\u003c/span\u003e \u003cspan class=\"pl-en\"\u003eGNU_says_moo\u003c/span\u003e():\n \u003cspan class=\"pl-s\"\u003e\"\"\"The GNU function -\u0026gt; say moo -\u0026gt; ✅\"\"\"\u003c/span\u003e\n\n \u003cspan class=\"pl-c1\"\u003eGNU\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e=\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\"\"\"\u003c/span\u003e\n\u003cspan class=\"pl-s\"\u003e GNU\u003c/span\u003e\n\u003cspan class=\"pl-s\"\u003e \"\"\"\u003c/span\u003e \u003cspan class=\"pl-c\"\u003e# the GNU...\u003c/span\u003e\n\n \u003cspan class=\"pl-en\"\u003eprint\u003c/span\u003e(\u003cspan class=\"pl-c1\"\u003eGNU\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e+\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\" says moo\"\u003c/span\u003e) \u003cspan class=\"pl-c\"\u003e# ...says moo\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eagainst which the following command is run:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-shell notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"cat gnu.py | srgn --titlecase --python 'doc-strings' '(?\u0026lt;!The )GNU ([a-z]+)' '$1: GNU 🐂 is not Unix'\"\u003e\u003cpre\u003ecat gnu.py \u003cspan class=\"pl-k\"\u003e|\u003c/span\u003e srgn --titlecase --python \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003edoc-strings\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e(?\u0026lt;!The )GNU ([a-z]+)\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e$1: GNU 🐂 is not Unix\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eThe anatomy of that invocation is:\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003e\u003ccode\u003e--titlecase\u003c/code\u003e (an \u003ca href=\"#character-casing\"\u003eaction\u003c/a\u003e) will Titlecase Everything Found In\nScope\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003e\u003ccode\u003e--python 'doc-strings'\u003c/code\u003e (a \u003ca href=\"#language-grammar-aware-scopes\"\u003escope\u003c/a\u003e) will scope to\n(i.e., only take into consideration) docstrings according to the Python language\ngrammar\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003e\u003ccode\u003e'(?\u0026lt;!The )GNU ([a-z]+)'\u003c/code\u003e (a \u003ca href=\"#scopes\"\u003escope\u003c/a\u003e) sees only what was already scoped by\nthe previous option, and will narrow it down further. It can never extend the previous\nscope. The regular expression scope is applied after any language scope(s).\u003c/p\u003e\n\n\u003cp dir=\"auto\"\u003e\u003ccode\u003e(?\u0026lt;!)\u003c/code\u003e is \u003ca href=\"https://docs.rs/fancy-regex/latest/fancy_regex/#syntax\" rel=\"nofollow\"\u003enegative\nlookbehind\u003c/a\u003e syntax,\ndemonstrating how this advanced feature is available. Strings of \u003ccode\u003eGNU\u003c/code\u003e prefixed by\n\u003ccode\u003eThe \u003c/code\u003e will not be considered.\u003c/p\u003e\n\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003e\u003ccode\u003e'$1: GNU 🐂 is not Unix'\u003c/code\u003e (an \u003ca href=\"#replacement\"\u003eaction\u003c/a\u003e) will \u003cem\u003ereplace\u003c/em\u003e each matched\noccurrence (i.e., each input section found to be in scope) with this string. Matched\noccurrences are patterns of \u003ccode\u003e'(?\u0026lt;!The )GNU ([a-z]+)'\u003c/code\u003e \u003cem\u003eonly within\u003c/em\u003e Python docstrings.\nNotably, this replacement string demonstrates:\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003edynamic \u003ca href=\"#variables\"\u003evariable binding and substitution\u003c/a\u003e using \u003ccode\u003e$1\u003c/code\u003e, which carries\nthe contents captured by the first capturing regex group. That's \u003ccode\u003e([a-z]+)\u003c/code\u003e, as\n\u003ccode\u003e(?\u0026lt;!The )\u003c/code\u003e is not capturing.\u003c/li\u003e\n\u003cli\u003efull Unicode support (🐂).\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp dir=\"auto\"\u003eThe command makes use of multiple scopes (language and regex pattern) and multiple\nactions (replacement and titlecasing). The result then reads\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-python notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"\u0026quot;\u0026quot;\u0026quot;Module: GNU 🐂 Is Not Unix.\u0026quot;\u0026quot;\u0026quot;\n\ndef GNU_says_moo():\n \u0026quot;\u0026quot;\u0026quot;The GNU function -\u0026gt; say moo -\u0026gt; ✅\u0026quot;\u0026quot;\u0026quot;\n\n GNU = \u0026quot;\u0026quot;\u0026quot;\n GNU\n \u0026quot;\u0026quot;\u0026quot; # the GNU...\n\n print(GNU + \u0026quot; says moo\u0026quot;) # ...says moo\"\u003e\u003cpre\u003e\u003cspan class=\"pl-s\"\u003e\"\"\"Module: GNU 🐂 Is Not Unix.\"\"\"\u003c/span\u003e\n\n\u003cspan class=\"pl-k\"\u003edef\u003c/span\u003e \u003cspan class=\"pl-en\"\u003eGNU_says_moo\u003c/span\u003e():\n \u003cspan class=\"pl-s\"\u003e\"\"\"The GNU function -\u0026gt; say moo -\u0026gt; ✅\"\"\"\u003c/span\u003e\n\n \u003cspan class=\"pl-c1\"\u003eGNU\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e=\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\"\"\"\u003c/span\u003e\n\u003cspan class=\"pl-s\"\u003e GNU\u003c/span\u003e\n\u003cspan class=\"pl-s\"\u003e \"\"\"\u003c/span\u003e \u003cspan class=\"pl-c\"\u003e# the GNU...\u003c/span\u003e\n\n \u003cspan class=\"pl-en\"\u003eprint\u003c/span\u003e(\u003cspan class=\"pl-c1\"\u003eGNU\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e+\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\" says moo\"\u003c/span\u003e) \u003cspan class=\"pl-c\"\u003e# ...says moo\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003ewhere the changes are limited to:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-diff notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"- \u0026quot;\u0026quot;\u0026quot;GNU module.\u0026quot;\u0026quot;\u0026quot;\n+ \u0026quot;\u0026quot;\u0026quot;Module: GNU 🐂 Is Not Unix.\u0026quot;\u0026quot;\u0026quot;\n\ndef GNU_says_moo():\n \u0026quot;\u0026quot;\u0026quot;The GNU -\u0026gt; say moo -\u0026gt; ✅\u0026quot;\u0026quot;\u0026quot;\"\u003e\u003cpre\u003e\u003cspan class=\"pl-md\"\u003e\u003cspan class=\"pl-md\"\u003e-\u003c/span\u003e \"\"\"GNU module.\"\"\"\u003c/span\u003e\n\u003cspan class=\"pl-mi1\"\u003e\u003cspan class=\"pl-mi1\"\u003e+\u003c/span\u003e \"\"\"Module: GNU 🐂 Is Not Unix.\"\"\"\u003c/span\u003e\n\ndef GNU_says_moo():\n \"\"\"The GNU -\u0026gt; say moo -\u0026gt; ✅\"\"\"\u003c/pre\u003e\u003c/div\u003e\n\u003cdiv class=\"markdown-alert markdown-alert-warning\" dir=\"auto\"\u003e\u003cp class=\"markdown-alert-title\" dir=\"auto\"\u003e\u003csvg class=\"octicon octicon-alert mr-2\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z\"\u003e\u003c/path\u003e\u003c/svg\u003eWarning\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eWhile \u003ccode\u003esrgn\u003c/code\u003e is in beta (\u003ca href=\"https://semver.org/\" rel=\"nofollow\"\u003emajor version\u003c/a\u003e 0), make sure to only\n(recursively) process files you can safely\n\u003ca href=\"https://git-scm.com/docs/git-restore\" rel=\"nofollow\"\u003erestore\u003c/a\u003e.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eSearch mode does not overwrite files, so is always safe.\u003c/p\u003e\n\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eSee \u003ca href=\"#help-output\"\u003ebelow\u003c/a\u003e for the full help output of the tool.\u003c/p\u003e\n\u003cdiv class=\"markdown-alert markdown-alert-note\" dir=\"auto\"\u003e\u003cp class=\"markdown-alert-title\" dir=\"auto\"\u003e\u003csvg class=\"octicon octicon-info mr-2\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z\"\u003e\u003c/path\u003e\u003c/svg\u003eNote\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eSupported languages are\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003eC\u003c/li\u003e\n\u003cli\u003eC#\u003c/li\u003e\n\u003cli\u003eGo\u003c/li\u003e\n\u003cli\u003eHCL (Terraform)\u003c/li\u003e\n\u003cli\u003ePython\u003c/li\u003e\n\u003cli\u003eRust\u003c/li\u003e\n\u003cli\u003eTypeScript\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/div\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch2 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eInstallation\u003c/h2\u003e\u003ca id=\"user-content-installation\" class=\"anchor\" aria-label=\"Permalink: Installation\" href=\"#installation\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch3 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003ePrebuilt binaries\u003c/h3\u003e\u003ca id=\"user-content-prebuilt-binaries\" class=\"anchor\" aria-label=\"Permalink: Prebuilt binaries\" href=\"#prebuilt-binaries\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eDownload a prebuilt binary from the\n\u003ca href=\"https://github.com/alexpovel/srgn/releases/latest\"\u003ereleases\u003c/a\u003e.\u003c/p\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch3 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003ecargo-binstall\u003c/h3\u003e\u003ca id=\"user-content-cargo-binstall\" class=\"anchor\" aria-label=\"Permalink: cargo-binstall\" href=\"#cargo-binstall\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eThis crate provides its binaries in a format\n\u003ca href=\"https://github.com/cargo-bins/cargo-binstall/blob/9cfc0cd5f97300925ae60f67712b74970a380aca/SUPPORT.md#support-for-cargo-binstall\"\u003ecompatible\u003c/a\u003e\nwith \u003ca href=\"https://github.com/cargo-bins/cargo-binstall\"\u003e\u003ccode\u003ecargo-binstall\u003c/code\u003e\u003c/a\u003e:\u003c/p\u003e\n\u003col dir=\"auto\"\u003e\n\u003cli\u003eInstall the \u003ca href=\"https://www.rust-lang.org/tools/install\" rel=\"nofollow\"\u003eRust toolchain\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003eRun \u003ccode\u003ecargo install cargo-binstall\u003c/code\u003e (might take a while)\u003c/li\u003e\n\u003cli\u003eRun \u003ccode\u003ecargo binstall srgn\u003c/code\u003e (couple seconds, as it downloads \u003ca href=\"#prebuilt-binaries\"\u003eprebuilt\nbinaries\u003c/a\u003e from GitHub)\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp dir=\"auto\"\u003eThese steps are guaranteed to work™, as they are \u003ca href=\"/alexpovel/srgn/blob/main/.github/workflows/main.yml\"\u003etested in\nCI\u003c/a\u003e. They also work if no prebuilt binaries are available\nfor your platform, as the tool will fall back to \u003ca href=\"#cargo-compile-from-source\"\u003ecompiling from\nsource\u003c/a\u003e.\u003c/p\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch3 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eHomebrew\u003c/h3\u003e\u003ca id=\"user-content-homebrew\" class=\"anchor\" aria-label=\"Permalink: Homebrew\" href=\"#homebrew\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eA \u003ca href=\"https://formulae.brew.sh/formula/srgn\" rel=\"nofollow\"\u003eformula\u003c/a\u003e is available via:\u003c/p\u003e\n\u003cdiv class=\"snippet-clipboard-content notranslate position-relative overflow-auto\" data-snippet-clipboard-copy-content=\"brew install srgn\"\u003e\u003cpre lang=\"text\" class=\"notranslate\"\u003e\u003ccode\u003ebrew install srgn\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch3 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eNix\u003c/h3\u003e\u003ca id=\"user-content-nix\" class=\"anchor\" aria-label=\"Permalink: Nix\" href=\"#nix\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eAvailable via \u003ca href=\"https://search.nixos.org/packages?channel=unstable\u0026amp;show=srgn\u0026amp;from=0\u0026amp;size=50\u0026amp;sort=relevance\u0026amp;type=packages\u0026amp;query=srgn\" rel=\"nofollow\"\u003eunstable\u003c/a\u003e:\u003c/p\u003e\n\u003cdiv class=\"snippet-clipboard-content notranslate position-relative overflow-auto\" data-snippet-clipboard-copy-content=\"nix-shell -p srgn\"\u003e\u003cpre lang=\"text\" class=\"notranslate\"\u003e\u003ccode\u003enix-shell -p srgn\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch3 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eArch Linux\u003c/h3\u003e\u003ca id=\"user-content-arch-linux\" class=\"anchor\" aria-label=\"Permalink: Arch Linux\" href=\"#arch-linux\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eAvailable via the \u003ca href=\"https://aur.archlinux.org/cgit/aur.git/tree/PKGBUILD?h=srgn\" rel=\"nofollow\"\u003eAUR\u003c/a\u003e.\u003c/p\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch3 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eMacPorts\u003c/h3\u003e\u003ca id=\"user-content-macports\" class=\"anchor\" aria-label=\"Permalink: MacPorts\" href=\"#macports\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eA \u003ca href=\"https://ports.macports.org/port/srgn/\" rel=\"nofollow\"\u003eport\u003c/a\u003e is available:\u003c/p\u003e\n\u003cdiv class=\"snippet-clipboard-content notranslate position-relative overflow-auto\" data-snippet-clipboard-copy-content=\"sudo port install srgn\"\u003e\u003cpre lang=\"text\" class=\"notranslate\"\u003e\u003ccode\u003esudo port install srgn\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch3 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eCI (GitHub Actions)\u003c/h3\u003e\u003ca id=\"user-content-ci-github-actions\" class=\"anchor\" aria-label=\"Permalink: CI (GitHub Actions)\" href=\"#ci-github-actions\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eAll \u003ca href=\"https://github.com/actions/runner-images/tree/main/images\"\u003eGitHub Actions runner\nimages\u003c/a\u003e come with \u003ccode\u003ecargo\u003c/code\u003e\npreinstalled, and \u003ccode\u003ecargo-binstall\u003c/code\u003e provides a convenient \u003ca href=\"https://github.com/marketplace/actions/install-cargo-binstall\"\u003eGitHub\nAction\u003c/a\u003e:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-yaml notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"jobs:\n srgn:\n name: Install srgn in CI\n # All three major OSes work\n runs-on: ubuntu-latest\n steps:\n - uses: cargo-bins/cargo-binstall@main\n - name: Install binary\n run: \u0026gt;\n cargo binstall\n --no-confirm\n srgn\n - name: Use binary\n run: srgn --version\"\u003e\u003cpre\u003e\u003cspan class=\"pl-ent\"\u003ejobs\u003c/span\u003e:\n \u003cspan class=\"pl-ent\"\u003esrgn\u003c/span\u003e:\n \u003cspan class=\"pl-ent\"\u003ename\u003c/span\u003e: \u003cspan class=\"pl-s\"\u003eInstall srgn in CI\u003c/span\u003e\n \u003cspan class=\"pl-c\"\u003e\u003cspan class=\"pl-c\"\u003e#\u003c/span\u003e All three major OSes work\u003c/span\u003e\n \u003cspan class=\"pl-ent\"\u003eruns-on\u003c/span\u003e: \u003cspan class=\"pl-s\"\u003eubuntu-latest\u003c/span\u003e\n \u003cspan class=\"pl-ent\"\u003esteps\u003c/span\u003e:\n - \u003cspan class=\"pl-ent\"\u003euses\u003c/span\u003e: \u003cspan class=\"pl-s\"\u003ecargo-bins/cargo-binstall@main\u003c/span\u003e\n - \u003cspan class=\"pl-ent\"\u003ename\u003c/span\u003e: \u003cspan class=\"pl-s\"\u003eInstall binary\u003c/span\u003e\n \u003cspan class=\"pl-ent\"\u003erun\u003c/span\u003e: \u003cspan class=\"pl-s\"\u003e\u0026gt;\u003c/span\u003e\n\u003cspan class=\"pl-s\"\u003e cargo binstall\u003c/span\u003e\n\u003cspan class=\"pl-s\"\u003e --no-confirm\u003c/span\u003e\n\u003cspan class=\"pl-s\"\u003e srgn\u003c/span\u003e\n\u003cspan class=\"pl-s\"\u003e\u003c/span\u003e - \u003cspan class=\"pl-ent\"\u003ename\u003c/span\u003e: \u003cspan class=\"pl-s\"\u003eUse binary\u003c/span\u003e\n \u003cspan class=\"pl-ent\"\u003erun\u003c/span\u003e: \u003cspan class=\"pl-s\"\u003esrgn --version\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eThe above concludes in just \u003ca href=\"https://github.com/alexpovel/srgn/actions/runs/6605290729/job/17940329899\"\u003e5 seconds\ntotal\u003c/a\u003e, as no\ncompilation is required. For more context, see \u003ca href=\"https://github.com/cargo-bins/cargo-binstall#can-i-use-it-in-ci\"\u003e\u003ccode\u003ecargo-binstall\u003c/code\u003e's advise on\nCI\u003c/a\u003e.\u003c/p\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch3 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eCargo (compile from source)\u003c/h3\u003e\u003ca id=\"user-content-cargo-compile-from-source\" class=\"anchor\" aria-label=\"Permalink: Cargo (compile from source)\" href=\"#cargo-compile-from-source\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003col dir=\"auto\"\u003e\n\u003cli\u003eInstall the \u003ca href=\"https://www.rust-lang.org/tools/install\" rel=\"nofollow\"\u003eRust toolchain\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003eA C compiler is required:\n\u003col dir=\"auto\"\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003eOn Linux, \u003ccode\u003egcc\u003c/code\u003e works.\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003eOn macOS, use \u003ccode\u003eclang\u003c/code\u003e.\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003eOn Windows, \u003ca href=\"https://visualstudio.microsoft.com/downloads/\" rel=\"nofollow\"\u003eMSVC\u003c/a\u003e works.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eSelect \"Desktop development with C++\" on installation.\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\u003c/li\u003e\n\u003cli\u003eRun \u003ccode\u003ecargo install srgn\u003c/code\u003e\u003c/li\u003e\n\u003c/ol\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch3 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eCargo (as a Rust library)\u003c/h3\u003e\u003ca id=\"user-content-cargo-as-a-rust-library\" class=\"anchor\" aria-label=\"Permalink: Cargo (as a Rust library)\" href=\"#cargo-as-a-rust-library\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cdiv class=\"snippet-clipboard-content notranslate position-relative overflow-auto\" data-snippet-clipboard-copy-content=\"cargo add srgn\"\u003e\u003cpre lang=\"text\" class=\"notranslate\"\u003e\u003ccode\u003ecargo add srgn\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eSee \u003ca href=\"#rust-library\"\u003ehere\u003c/a\u003e for more.\u003c/p\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch3 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eShell completions\u003c/h3\u003e\u003ca id=\"user-content-shell-completions\" class=\"anchor\" aria-label=\"Permalink: Shell completions\" href=\"#shell-completions\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003e\u003ca href=\"https://docs.rs/clap_complete/4.5.1/clap_complete/shells/enum.Shell.html#variants\" rel=\"nofollow\"\u003eVarious\nshells\u003c/a\u003e\nare supported for shell completion scripts. For example, append \u003ccode\u003eeval \"$(srgn --completions zsh)\"\u003c/code\u003e to \u003ccode\u003e~/.zshrc\u003c/code\u003e for completions in ZSH. An interactive session can\nthen look like:\u003c/p\u003e\n\u003cp dir=\"auto\"\u003e\u003ca href=\"https://asciinema.org/a/673473\" rel=\"nofollow\"\u003e\u003cimg src=\"/alexpovel/srgn/raw/main/docs/images/interactive-use-shell-completion.gif\" alt=\"srgn shell completion\" data-animated-image=\"\" style=\"max-width: 100%;\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch2 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eWalkthrough\u003c/h2\u003e\u003ca id=\"user-content-walkthrough\" class=\"anchor\" aria-label=\"Permalink: Walkthrough\" href=\"#walkthrough\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eThe tool is designed around \u003cstrong\u003escopes\u003c/strong\u003e and \u003cstrong\u003eactions\u003c/strong\u003e. Scopes narrow down the parts of\nthe input to process. Actions then perform the processing. Generally, both scopes and\nactions are composable, so more than one of each may be passed. Both are optional (but\ntaking no action is pointless); specifying no scope implies the entire input is in\nscope.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eAt the same time, there is \u003ca href=\"#comparison-with-tr\"\u003econsiderable overlap\u003c/a\u003e with plain\n\u003ca href=\"https://www.gnu.org/software/coreutils/manual/html_node/tr-invocation.html\" rel=\"nofollow\"\u003e\u003ccode\u003etr\u003c/code\u003e\u003c/a\u003e: the tool is designed to have close correspondence in the most common use\ncases, and only go beyond when needed.\u003c/p\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch3 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eActions\u003c/h3\u003e\u003ca id=\"user-content-actions\" class=\"anchor\" aria-label=\"Permalink: Actions\" href=\"#actions\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eThe simplest action is replacement. It is specially accessed (as an argument, not an\noption) for compatibility with \u003ca href=\"https://www.gnu.org/software/coreutils/manual/html_node/tr-invocation.html\" rel=\"nofollow\"\u003e\u003ccode\u003etr\u003c/code\u003e\u003c/a\u003e, and general ergonomics. All other actions are\ngiven as flags, or options should they take a value.\u003c/p\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch4 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eReplacement\u003c/h4\u003e\u003ca id=\"user-content-replacement\" class=\"anchor\" aria-label=\"Permalink: Replacement\" href=\"#replacement\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eFor example, simple, single-character replacements work as in \u003ca href=\"https://www.gnu.org/software/coreutils/manual/html_node/tr-invocation.html\" rel=\"nofollow\"\u003e\u003ccode\u003etr\u003c/code\u003e\u003c/a\u003e:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-text-shell-session notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"$ echo 'Hello, World!' | srgn 'H' 'J'\nJello, World!\"\u003e\u003cpre\u003e$ \u003cspan class=\"pl-s1\"\u003e\u003cspan class=\"pl-c1\"\u003eecho\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003eHello, World!\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-k\"\u003e|\u003c/span\u003e srgn \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003eH\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003eJ\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003eJello, World!\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eThe first argument is the scope (literal \u003ccode\u003eH\u003c/code\u003e in this case). Anything matched by it is\nsubject to processing (replacement by \u003ccode\u003eJ\u003c/code\u003e, the second argument, in this case). However,\nthere is \u003cstrong\u003eno direct concept of character classes\u003c/strong\u003e as in \u003ca href=\"https://www.gnu.org/software/coreutils/manual/html_node/tr-invocation.html\" rel=\"nofollow\"\u003e\u003ccode\u003etr\u003c/code\u003e\u003c/a\u003e. Instead, by\ndefault, the scope is a regular expression pattern, so \u003cem\u003eits\u003c/em\u003e\n\u003ca href=\"https://docs.rs/regex/1.9.5/regex/index.html#character-classes\" rel=\"nofollow\"\u003eclasses\u003c/a\u003e can be used to\nsimilar effect:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-text-shell-session notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"$ echo 'Hello, World!' | srgn '[a-z]' '_'\nH____, W____!\"\u003e\u003cpre\u003e$ \u003cspan class=\"pl-s1\"\u003e\u003cspan class=\"pl-c1\"\u003eecho\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003eHello, World!\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-k\"\u003e|\u003c/span\u003e srgn \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e[a-z]\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e_\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003eH____, W____!\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eThe replacement occurs greedily across the entire match by default (note the \u003ca href=\"https://docs.rs/regex/1.9.5/regex/index.html#ascii-character-classes\" rel=\"nofollow\"\u003eUTS\ncharacter class\u003c/a\u003e,\nreminiscent of \u003ca href=\"https://github.com/coreutils/coreutils/blob/769ace51e8a1129c44ee4e7e209c3b2df2111524/src/tr.c#L322C25-L322C25\"\u003e\u003ccode\u003etr\u003c/code\u003e's\n\u003ccode\u003e[:alnum:]\u003c/code\u003e\u003c/a\u003e):\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-text-shell-session notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"$ echo 'ghp_oHn0As3cr3T!!' | srgn 'ghp_[[:alnum:]]+' '*' # A GitHub token\n*!!\"\u003e\u003cpre\u003e$ \u003cspan class=\"pl-s1\"\u003e\u003cspan class=\"pl-c1\"\u003eecho\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003eghp_oHn0As3cr3T!!\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-k\"\u003e|\u003c/span\u003e srgn \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003eghp_[[:alnum:]]+\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e*\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-c\"\u003e\u003cspan class=\"pl-c\"\u003e#\u003c/span\u003e A GitHub token\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e*!!\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eAdvanced regex features are\n\u003ca href=\"https://docs.rs/fancy-regex/0.11.0/fancy_regex/index.html#syntax\" rel=\"nofollow\"\u003esupported\u003c/a\u003e, for\nexample lookarounds:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-text-shell-session notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"$ echo 'ghp_oHn0As3cr3T' | srgn '(?\u0026lt;=ghp_)[[:alnum:]]+' '*'\nghp_*\"\u003e\u003cpre\u003e$ \u003cspan class=\"pl-s1\"\u003e\u003cspan class=\"pl-c1\"\u003eecho\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003eghp_oHn0As3cr3T\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-k\"\u003e|\u003c/span\u003e srgn \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e(?\u0026lt;=ghp_)[[:alnum:]]+\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e*\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003eghp_*\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eTake care in using these safely, as advanced patterns come without certain \u003ca href=\"https://docs.rs/regex/latest/regex/#untrusted-input\" rel=\"nofollow\"\u003esafety and\nperformance guarantees\u003c/a\u003e. If they\naren't used, \u003ca href=\"https://docs.rs/fancy-regex/0.11.0/fancy_regex/index.html#\" rel=\"nofollow\"\u003eperformance is not\nimpacted\u003c/a\u003e.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eThe replacement is not limited to a single character. It can be any string, for example\nto fix \u003ca href=\"http://regex.info/blog/2006-09-15/247\" rel=\"nofollow\"\u003ethis quote\u003c/a\u003e:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-text-shell-session notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"$ echo '\u0026quot;Using regex, I now have no issues.\u0026quot;' | srgn 'no issues' '2 problems'\n\u0026quot;Using regex, I now have 2 problems.\u0026quot;\"\u003e\u003cpre\u003e$ \u003cspan class=\"pl-s1\"\u003e\u003cspan class=\"pl-c1\"\u003eecho\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\"Using regex, I now have no issues.\"\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-k\"\u003e|\u003c/span\u003e srgn \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003eno issues\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e2 problems\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e\"Using regex, I now have 2 problems.\"\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eThe tool is fully Unicode-aware, with useful support for \u003ca href=\"https://github.com/rust-lang/regex/blob/061ee815ef2c44101dba7b0b124600fcb03c1912/UNICODE.md#rl12-properties\"\u003ecertain advanced\ncharacter\nclasses\u003c/a\u003e:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-text-shell-session notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"$ echo 'Mood: 🙂' | srgn '🙂' '😀'\nMood: 😀\n$ echo 'Mood: 🤮🤒🤧🦠 :(' | srgn '\\p{Emoji_Presentation}' '😷'\nMood: 😷😷😷😷 :(\"\u003e\u003cpre\u003e$ \u003cspan class=\"pl-s1\"\u003e\u003cspan class=\"pl-c1\"\u003eecho\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003eMood: 🙂\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-k\"\u003e|\u003c/span\u003e srgn \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e🙂\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e😀\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003eMood: 😀\u003c/span\u003e\n$ \u003cspan class=\"pl-s1\"\u003e\u003cspan class=\"pl-c1\"\u003eecho\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003eMood: 🤮🤒🤧🦠 :(\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-k\"\u003e|\u003c/span\u003e srgn \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\\p{Emoji_Presentation}\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e😷\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003eMood: 😷😷😷😷 :(\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch5 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eVariables\u003c/h5\u003e\u003ca id=\"user-content-variables\" class=\"anchor\" aria-label=\"Permalink: Variables\" href=\"#variables\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eReplacements are aware of variables, which are made accessible for use through regex\ncapture groups. Capture groups can be numbered, or optionally named. The zeroth capture\ngroup corresponds to the entire match.\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-text-shell-session notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"$ echo 'Swap It' | srgn '(\\w+) (\\w+)' '$2 $1' # Regular, numbered\nIt Swap\n$ echo 'Swap It' | srgn '(\\w+) (\\w+)' '$2 $1$1$1' # Use as many times as you'd like\nIt SwapSwapSwap\n$ echo 'Call +1-206-555-0100!' | srgn 'Call (\\+?\\d\\-\\d{3}\\-\\d{3}\\-\\d{4}).+' 'The phone number in \u0026quot;$0\u0026quot; is: $1.' # Variable `0` is the entire match\nThe phone number in \u0026quot;Call +1-206-555-0100!\u0026quot; is: +1-206-555-0100.\"\u003e\u003cpre\u003e$ \u003cspan class=\"pl-s1\"\u003e\u003cspan class=\"pl-c1\"\u003eecho\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003eSwap It\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-k\"\u003e|\u003c/span\u003e srgn \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e(\\w+) (\\w+)\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e$2 $1\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-c\"\u003e\u003cspan class=\"pl-c\"\u003e#\u003c/span\u003e Regular, numbered\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003eIt Swap\u003c/span\u003e\n$ \u003cspan class=\"pl-s1\"\u003e\u003cspan class=\"pl-c1\"\u003eecho\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003eSwap It\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-k\"\u003e|\u003c/span\u003e srgn \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e(\\w+) (\\w+)\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e$2 $1$1$1\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-c\"\u003e\u003cspan class=\"pl-c\"\u003e#\u003c/span\u003e Use as many times as you'd like\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003eIt SwapSwapSwap\u003c/span\u003e\n$ \u003cspan class=\"pl-s1\"\u003e\u003cspan class=\"pl-c1\"\u003eecho\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003eCall +1-206-555-0100!\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-k\"\u003e|\u003c/span\u003e srgn \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003eCall (\\+?\\d\\-\\d{3}\\-\\d{3}\\-\\d{4}).+\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003eThe phone number in \"$0\" is: $1.\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-c\"\u003e\u003cspan class=\"pl-c\"\u003e#\u003c/span\u003e Variable `0` is the entire match\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003eThe phone number in \"Call +1-206-555-0100!\" is: +1-206-555-0100.\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eA more advanced use case is, for example, code refactoring using named capture groups\n(perhaps you can come up with a more useful one...):\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-text-shell-session notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"$ echo 'let x = 3;' | srgn 'let (?\u0026lt;var\u0026gt;[a-z]+) = (?\u0026lt;expr\u0026gt;.+);' 'const $var$var = $expr + $expr;'\nconst xx = 3 + 3;\"\u003e\u003cpre\u003e$ \u003cspan class=\"pl-s1\"\u003e\u003cspan class=\"pl-c1\"\u003eecho\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003elet x = 3;\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-k\"\u003e|\u003c/span\u003e srgn \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003elet (?\u0026lt;var\u0026gt;[a-z]+) = (?\u0026lt;expr\u0026gt;.+);\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003econst $var$var = $expr + $expr;\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003econst xx = 3 + 3;\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eAs in bash, use curly braces to disambiguate variables from immediately adjacent\ncontent:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-text-shell-session notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"$ echo '12' | srgn '(\\d)(\\d)' '$2${1}1'\n211\n$ echo '12' | srgn '(\\d)(\\d)' '$2$11' # will fail (`11` is unknown)\n$ echo '12' | srgn '(\\d)(\\d)' '$2${11' # will fail (brace was not closed)\"\u003e\u003cpre\u003e$ \u003cspan class=\"pl-s1\"\u003e\u003cspan class=\"pl-c1\"\u003eecho\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e12\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-k\"\u003e|\u003c/span\u003e srgn \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e(\\d)(\\d)\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e$2${1}1\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e211\u003c/span\u003e\n$ \u003cspan class=\"pl-s1\"\u003e\u003cspan class=\"pl-c1\"\u003eecho\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e12\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-k\"\u003e|\u003c/span\u003e srgn \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e(\\d)(\\d)\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e$2$11\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-c\"\u003e\u003cspan class=\"pl-c\"\u003e#\u003c/span\u003e will fail (`11` is unknown)\u003c/span\u003e\u003c/span\u003e\n$ \u003cspan class=\"pl-s1\"\u003e\u003cspan class=\"pl-c1\"\u003eecho\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e12\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-k\"\u003e|\u003c/span\u003e srgn \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e(\\d)(\\d)\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e$2${11\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-c\"\u003e\u003cspan class=\"pl-c\"\u003e#\u003c/span\u003e will fail (brace was not closed)\u003c/span\u003e\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch4 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eBeyond replacement\u003c/h4\u003e\u003ca id=\"user-content-beyond-replacement\" class=\"anchor\" aria-label=\"Permalink: Beyond replacement\" href=\"#beyond-replacement\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eSeeing how the replacement is merely a static string, its usefulness is limited. This is\nwhere \u003ca href=\"https://maizure.org/projects/decoded-gnu-coreutils/tr.html\" rel=\"nofollow\"\u003e\u003ccode\u003etr\u003c/code\u003e's secret sauce\u003c/a\u003e\nordinarily comes into play: using its character classes, which are valid in the second\nposition as well, neatly translating from members of the first to the second. Here,\nthose classes are instead regexes, and only valid in first position (the scope). A\nregular expression being a state machine, it is impossible to match onto a 'list of\ncharacters', which in \u003ccode\u003etr\u003c/code\u003e is the second (optional) argument. That concept is out the\nwindow, and its flexibility lost.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eInstead, the offered actions, all of them \u003cstrong\u003efixed\u003c/strong\u003e, are used. A peek at \u003ca href=\"#use-cases-and-equivalences\"\u003ethe most\ncommon use cases for \u003ccode\u003etr\u003c/code\u003e\u003c/a\u003e reveals that the provided set of\nactions covers virtually all of them! Feel free to file an issue if your use case is not\ncovered.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eOnto the next action.\u003c/p\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch4 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eDeletion\u003c/h4\u003e\u003ca id=\"user-content-deletion\" class=\"anchor\" aria-label=\"Permalink: Deletion\" href=\"#deletion\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eRemoves whatever is found from the input. Same flag name as in \u003ccode\u003etr\u003c/code\u003e.\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-text-shell-session notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"$ echo 'Hello, World!' | srgn -d '(H|W|!)'\nello, orld\"\u003e\u003cpre\u003e$ \u003cspan class=\"pl-s1\"\u003e\u003cspan class=\"pl-c1\"\u003eecho\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003eHello, World!\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-k\"\u003e|\u003c/span\u003e srgn -d \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e(H|W|!)\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003eello, orld\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cdiv class=\"markdown-alert markdown-alert-note\" dir=\"auto\"\u003e\u003cp class=\"markdown-alert-title\" dir=\"auto\"\u003e\u003csvg class=\"octicon octicon-info mr-2\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z\"\u003e\u003c/path\u003e\u003c/svg\u003eNote\u003c/p\u003e\u003cp dir=\"auto\"\u003eAs the default scope is to match the entire input, it is an error to specify\ndeletion without a scope.\u003c/p\u003e\n\u003c/div\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch4 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eSqueezing\u003c/h4\u003e\u003ca id=\"user-content-squeezing\" class=\"anchor\" aria-label=\"Permalink: Squeezing\" href=\"#squeezing\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eSqueezes repeats of characters matching the scope into single occurrences. Same flag\nname as in \u003ccode\u003etr\u003c/code\u003e.\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-text-shell-session notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"$ echo 'Helloooo Woooorld!!!' | srgn -s '(o|!)'\nHello World!\"\u003e\u003cpre\u003e$ \u003cspan class=\"pl-s1\"\u003e\u003cspan class=\"pl-c1\"\u003eecho\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003eHelloooo Woooorld!!!\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-k\"\u003e|\u003c/span\u003e srgn -s \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e(o|!)\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003eHello World!\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eIf a character class is passed, all members of that class are squeezed into whatever\nclass member was encountered first:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-text-shell-session notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"$ echo 'The number is: 3490834' | srgn -s '\\d'\nThe number is: 3\"\u003e\u003cpre\u003e$ \u003cspan class=\"pl-s1\"\u003e\u003cspan class=\"pl-c1\"\u003eecho\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003eThe number is: 3490834\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-k\"\u003e|\u003c/span\u003e srgn -s \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\\d\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003eThe number is: 3\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eGreediness in matching is not modified, so take care:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-text-shell-session notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"$ echo 'Winter is coming... 🌞🌞🌞' | srgn -s '🌞+'\nWinter is coming... 🌞🌞🌞\"\u003e\u003cpre\u003e$ \u003cspan class=\"pl-s1\"\u003e\u003cspan class=\"pl-c1\"\u003eecho\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003eWinter is coming... 🌞🌞🌞\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-k\"\u003e|\u003c/span\u003e srgn -s \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e🌞+\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003eWinter is coming... 🌞🌞🌞\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cdiv class=\"markdown-alert markdown-alert-note\" dir=\"auto\"\u003e\u003cp class=\"markdown-alert-title\" dir=\"auto\"\u003e\u003csvg class=\"octicon octicon-info mr-2\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z\"\u003e\u003c/path\u003e\u003c/svg\u003eNote\u003c/p\u003e\u003cp dir=\"auto\"\u003eThe pattern matched the \u003cem\u003eentire\u003c/em\u003e run of suns, so there's nothing to squeeze. Summer\nprevails.\u003c/p\u003e\n\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eInvert greediness if the use case calls for it:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-text-shell-session notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"$ echo 'Winter is coming... 🌞🌞🌞' | srgn -s '🌞+?' '☃️'\nWinter is coming... ☃️\"\u003e\u003cpre\u003e$ \u003cspan class=\"pl-s1\"\u003e\u003cspan class=\"pl-c1\"\u003eecho\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003eWinter is coming... 🌞🌞🌞\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-k\"\u003e|\u003c/span\u003e srgn -s \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e🌞+?\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e☃️\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003eWinter is coming... ☃️\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cdiv class=\"markdown-alert markdown-alert-note\" dir=\"auto\"\u003e\u003cp class=\"markdown-alert-title\" dir=\"auto\"\u003e\u003csvg class=\"octicon octicon-info mr-2\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z\"\u003e\u003c/path\u003e\u003c/svg\u003eNote\u003c/p\u003e\u003cp dir=\"auto\"\u003eAgain, as with \u003ca href=\"#deletion\"\u003edeletion\u003c/a\u003e, specifying squeezing without an \u003cem\u003eexplicit\u003c/em\u003e scope\nis an error. Otherwise, the entire input is squeezed.\u003c/p\u003e\n\u003c/div\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch4 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eCharacter casing\u003c/h4\u003e\u003ca id=\"user-content-character-casing\" class=\"anchor\" aria-label=\"Permalink: Character casing\" href=\"#character-casing\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eA good chunk of \u003ccode\u003etr\u003c/code\u003e usage \u003ca href=\"#changing-character-casing\"\u003efalls into this category\u003c/a\u003e. It's\nvery straightforward.\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-text-shell-session notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"$ echo 'Hello, World!' | srgn --lower\nhello, world!\n$ echo 'Hello, World!' | srgn --upper\nHELLO, WORLD!\n$ echo 'hello, world!' | srgn --titlecase\nHello, World!\"\u003e\u003cpre\u003e$ \u003cspan class=\"pl-s1\"\u003e\u003cspan class=\"pl-c1\"\u003eecho\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003eHello, World!\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-k\"\u003e|\u003c/span\u003e srgn --lower\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003ehello, world!\u003c/span\u003e\n$ \u003cspan class=\"pl-s1\"\u003e\u003cspan class=\"pl-c1\"\u003eecho\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003eHello, World!\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-k\"\u003e|\u003c/span\u003e srgn --upper\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003eHELLO, WORLD!\u003c/span\u003e\n$ \u003cspan class=\"pl-s1\"\u003e\u003cspan class=\"pl-c1\"\u003eecho\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003ehello, world!\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-k\"\u003e|\u003c/span\u003e srgn --titlecase\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003eHello, World!\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch4 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eNormalization\u003c/h4\u003e\u003ca id=\"user-content-normalization\" class=\"anchor\" aria-label=\"Permalink: Normalization\" href=\"#normalization\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eDecomposes input according to \u003ca href=\"https://en.wikipedia.org/wiki/Unicode_equivalence#Normal_forms\" rel=\"nofollow\"\u003eNormalization Form\nD\u003c/a\u003e, and then discards\ncode points of the \u003ca href=\"https://en.wikipedia.org/wiki/Unicode_character_property#General_Category\" rel=\"nofollow\"\u003eMark\ncategory\u003c/a\u003e\n(see \u003ca href=\"https://www.compart.com/en/unicode/category/Mn\" rel=\"nofollow\"\u003eexamples\u003c/a\u003e). That roughly means:\ntake fancy character, rip off dangly bits, throw those away.\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-text-shell-session notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"$ echo 'Naïve jalapeño ärgert mgła' | srgn -d '\\P{ASCII}' # Naive approach\nNave jalapeo rgert mga\n$ echo 'Naïve jalapeño ärgert mgła' | srgn --normalize # Normalize is smarter\nNaive jalapeno argert mgła\"\u003e\u003cpre\u003e$ \u003cspan class=\"pl-s1\"\u003e\u003cspan class=\"pl-c1\"\u003eecho\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003eNaïve jalapeño ärgert mgła\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-k\"\u003e|\u003c/span\u003e srgn -d \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\\P{ASCII}\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-c\"\u003e\u003cspan class=\"pl-c\"\u003e#\u003c/span\u003e Naive approach\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003eNave jalapeo rgert mga\u003c/span\u003e\n$ \u003cspan class=\"pl-s1\"\u003e\u003cspan class=\"pl-c1\"\u003eecho\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003eNaïve jalapeño ärgert mgła\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-k\"\u003e|\u003c/span\u003e srgn --normalize \u003cspan class=\"pl-c\"\u003e\u003cspan class=\"pl-c\"\u003e#\u003c/span\u003e Normalize is smarter\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003eNaive jalapeno argert mgła\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eNotice how \u003ccode\u003emgła\u003c/code\u003e is out of scope for NFD, as it is \"atomic\" and thus not decomposable\n(at least that's what ChatGPT whispers in my ear).\u003c/p\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch4 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eSymbols\u003c/h4\u003e\u003ca id=\"user-content-symbols\" class=\"anchor\" aria-label=\"Permalink: Symbols\" href=\"#symbols\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eThis action replaces multi-character, ASCII symbols with appropriate single-code point,\nnative Unicode counterparts.\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-text-shell-session notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"$ echo '(A --\u0026gt; B) != C --- obviously' | srgn --symbols\n(A ⟶ B) ≠ C — obviously\"\u003e\u003cpre\u003e$ \u003cspan class=\"pl-s1\"\u003e\u003cspan class=\"pl-c1\"\u003eecho\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e(A --\u0026gt; B) != C --- obviously\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-k\"\u003e|\u003c/span\u003e srgn --symbols\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e(A ⟶ B) ≠ C — obviously\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eAlternatively, if you're only interested in math, make use of scoping:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-text-shell-session notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"$ echo 'A \u0026lt;= B --- More is--obviously--possible' | srgn --symbols '\u0026lt;='\nA ≤ B --- More is--obviously--possible\"\u003e\u003cpre\u003e$ \u003cspan class=\"pl-s1\"\u003e\u003cspan class=\"pl-c1\"\u003eecho\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003eA \u0026lt;= B --- More is--obviously--possible\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-k\"\u003e|\u003c/span\u003e srgn --symbols \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u0026lt;=\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003eA ≤ B --- More is--obviously--possible\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eAs there is a \u003ca href=\"https://en.wikipedia.org/wiki/Bijection\" rel=\"nofollow\"\u003e1:1 correspondence\u003c/a\u003e between an\nASCII symbol and its replacement, the effect is reversible\u003csup\u003e\u003ca href=\"#user-content-fn-1-b30ce13ed678ccbd6287a3f5e19f11b5\" id=\"user-content-fnref-1-b30ce13ed678ccbd6287a3f5e19f11b5\" data-footnote-ref=\"\" aria-describedby=\"footnote-label\"\u003e2\u003c/a\u003e\u003c/sup\u003e:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-text-shell-session notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"$ echo 'A ⇒ B' | srgn --symbols --invert\nA =\u0026gt; B\"\u003e\u003cpre\u003e$ \u003cspan class=\"pl-s1\"\u003e\u003cspan class=\"pl-c1\"\u003eecho\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003eA ⇒ B\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-k\"\u003e|\u003c/span\u003e srgn --symbols --invert\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003eA =\u0026gt; B\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eThere is only a limited set of symbols supported as of right now, but more can be added.\u003c/p\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch4 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eGerman\u003c/h4\u003e\u003ca id=\"user-content-german\" class=\"anchor\" aria-label=\"Permalink: German\" href=\"#german\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eThis action replaces alternative spellings of German special characters (ae, oe, ue, ss)\nwith their native versions (ä, ö, ü, ß)\u003csup\u003e\u003ca href=\"#user-content-fn-2-b30ce13ed678ccbd6287a3f5e19f11b5\" id=\"user-content-fnref-2-b30ce13ed678ccbd6287a3f5e19f11b5\" data-footnote-ref=\"\" aria-describedby=\"footnote-label\"\u003e3\u003c/a\u003e\u003c/sup\u003e.\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-text-shell-session notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"$ echo 'Gruess Gott, Neueroeffnungen, Poeten und Abenteuergruetze!' | srgn --german\nGrüß Gott, Neueröffnungen, Poeten und Abenteuergrütze!\"\u003e\u003cpre\u003e$ \u003cspan class=\"pl-s1\"\u003e\u003cspan class=\"pl-c1\"\u003eecho\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003eGruess Gott, Neueroeffnungen, Poeten und Abenteuergruetze!\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-k\"\u003e|\u003c/span\u003e srgn --german\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003eGrüß Gott, Neueröffnungen, Poeten und Abenteuergrütze!\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eThis action is based on a \u003ca href=\"/alexpovel/srgn/blob/main/data/word-lists/de.txt\"\u003eword list\u003c/a\u003e (compile without\n\u003ccode\u003egerman\u003c/code\u003e feature if this bloats your binary too much). Note the following features about\nthe above example:\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003eempty scope and replacement: the entire input will be processed, and no replacement is\nperformed\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003ePoeten\u003c/code\u003e remained as-is, instead of being naively and mistakenly converted to \u003ccode\u003ePöten\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003eas a (compound) word, \u003ccode\u003eAbenteuergrütze\u003c/code\u003e is not going to be found in \u003ca href=\"https://www.duden.de/suchen/dudenonline/Abenteuergr%C3%BCtze\" rel=\"nofollow\"\u003eany reasonable\nword list\u003c/a\u003e, but was\nhandled properly nonetheless\u003c/li\u003e\n\u003cli\u003ewhile part of a compound word, \u003ccode\u003eAbenteuer\u003c/code\u003e remained as-is as well, instead of being\nincorrectly converted to \u003ccode\u003eAbenteür\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003elastly, \u003ccode\u003eNeueroeffnungen\u003c/code\u003e sneakily forms a \u003ccode\u003eue\u003c/code\u003e element neither constituent word\n(\u003ccode\u003eneu\u003c/code\u003e, \u003ccode\u003eEröffnungen\u003c/code\u003e) possesses, but is still processed correctly (despite the\nmismatched casings as well)\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp dir=\"auto\"\u003eOn request, replacements may be forced, as is potentially useful for names:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-text-shell-session notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"$ echo 'Frau Loetter steht ueber der Mauer.' | srgn --german-naive '(?\u0026lt;=Frau )\\w+'\nFrau Lötter steht ueber der Mauer.\"\u003e\u003cpre\u003e$ \u003cspan class=\"pl-s1\"\u003e\u003cspan class=\"pl-c1\"\u003eecho\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003eFrau Loetter steht ueber der Mauer.\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-k\"\u003e|\u003c/span\u003e srgn --german-naive \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e(?\u0026lt;=Frau )\\w+\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003eFrau Lötter steht ueber der Mauer.\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eThrough positive lookahead, nothing but the salutation was scoped and therefore changed.\n\u003ccode\u003eMauer\u003c/code\u003e correctly remained as-is, but \u003ccode\u003eueber\u003c/code\u003e was not processed. A second pass fixes\nthis:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-text-shell-session notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"$ echo 'Frau Loetter steht ueber der Mauer.' | srgn --german-naive '(?\u0026lt;=Frau )\\w+' | srgn --german\nFrau Lötter steht über der Mauer.\"\u003e\u003cpre\u003e$ \u003cspan class=\"pl-s1\"\u003e\u003cspan class=\"pl-c1\"\u003eecho\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003eFrau Loetter steht ueber der Mauer.\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-k\"\u003e|\u003c/span\u003e srgn --german-naive \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e(?\u0026lt;=Frau )\\w+\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-k\"\u003e|\u003c/span\u003e srgn --german\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003eFrau Lötter steht über der Mauer.\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cdiv class=\"markdown-alert markdown-alert-note\" dir=\"auto\"\u003e\u003cp class=\"markdown-alert-title\" dir=\"auto\"\u003e\u003csvg class=\"octicon octicon-info mr-2\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z\"\u003e\u003c/path\u003e\u003c/svg\u003eNote\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eOptions and flags pertaining to some \"parent\" are prefixed with their parent's name,\nand will \u003cem\u003eimply\u003c/em\u003e their parent when given, such that the latter does not need to be\npassed explicitly. That's why \u003ccode\u003e--german-naive\u003c/code\u003e is named as it is, and \u003ccode\u003e--german\u003c/code\u003e\nneedn't be passed.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eThis behavior might change once \u003ccode\u003eclap\u003c/code\u003e supports \u003ca href=\"https://github.com/clap-rs/clap/issues/2222\" data-hovercard-type=\"issue\" data-hovercard-url=\"/clap-rs/clap/issues/2222/hovercard\"\u003esubcommand\nchaining\u003c/a\u003e.\u003c/p\u003e\n\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eSome branches are undecidable for this modest tool, as it operates without language\ncontext. For example, both \u003ccode\u003eBusse\u003c/code\u003e (busses) and \u003ccode\u003eBuße\u003c/code\u003e (penance) are legal words. By\ndefault, replacements are greedily performed if legal (that's the \u003ca href=\"https://en.wikipedia.org/wiki/Principle_of_least_astonishment\" rel=\"nofollow\"\u003ewhole\npoint\u003c/a\u003e of \u003ccode\u003esrgn\u003c/code\u003e,\nafter all), but there's a flag for toggling this behavior:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-text-shell-session notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"$ echo 'Busse und Geluebte 🙏' | srgn --german\nBuße und Gelübte 🙏\n$ echo 'Busse 🚌 und Fussgaenger 🚶‍♀️' | srgn --german-prefer-original\nBusse 🚌 und Fußgänger 🚶‍♀️\"\u003e\u003cpre\u003e$ \u003cspan class=\"pl-s1\"\u003e\u003cspan class=\"pl-c1\"\u003eecho\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003eBusse und Geluebte 🙏\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-k\"\u003e|\u003c/span\u003e srgn --german\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003eBuße und Gelübte 🙏\u003c/span\u003e\n$ \u003cspan class=\"pl-s1\"\u003e\u003cspan class=\"pl-c1\"\u003eecho\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003eBusse 🚌 und Fussgaenger 🚶‍♀️\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-k\"\u003e|\u003c/span\u003e srgn --german-prefer-original\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003eBusse 🚌 und Fußgänger 🚶‍♀️\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch3 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eCombining Actions\u003c/h3\u003e\u003ca id=\"user-content-combining-actions\" class=\"anchor\" aria-label=\"Permalink: Combining Actions\" href=\"#combining-actions\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eMost actions are composable, unless doing so were nonsensical (like for\n\u003ca href=\"#deletion\"\u003edeletion\u003c/a\u003e). Their order of application is fixed, so the \u003cem\u003eorder\u003c/em\u003e of the flags\ngiven has no influence (piping multiple runs is an alternative, if needed). Replacements\nalways occur first. Generally, the CLI is designed to prevent misuse and\n\u003ca href=\"https://en.wikipedia.org/wiki/Principle_of_least_astonishment\" rel=\"nofollow\"\u003esurprises\u003c/a\u003e: it prefers\ncrashing to doing something unexpected (which is subjective, of course). Note that lots\nof combinations \u003cem\u003eare\u003c/em\u003e technically possible, but might yield nonsensical results.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eCombining actions might look like:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-text-shell-session notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"$ echo 'Koeffizienten != Bruecken...' | srgn -Sgu\nKOEFFIZIENTEN ≠ BRÜCKEN...\"\u003e\u003cpre\u003e$ \u003cspan class=\"pl-s1\"\u003e\u003cspan class=\"pl-c1\"\u003eecho\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003eKoeffizienten != Bruecken...\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-k\"\u003e|\u003c/span\u003e srgn -Sgu\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003eKOEFFIZIENTEN ≠ BRÜCKEN...\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eA more narrow scope can be specified, and will apply to \u003cem\u003eall\u003c/em\u003e actions equally:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-text-shell-session notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"$ echo 'Koeffizienten != Bruecken...' | srgn -Sgu '\\b\\w{1,8}\\b'\nKoeffizienten != BRÜCKEN...\"\u003e\u003cpre\u003e$ \u003cspan class=\"pl-s1\"\u003e\u003cspan class=\"pl-c1\"\u003eecho\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003eKoeffizienten != Bruecken...\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-k\"\u003e|\u003c/span\u003e srgn -Sgu \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\\b\\w{1,8}\\b\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003eKoeffizienten != BRÜCKEN...\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eThe \u003ca href=\"https://www.regular-expressions.info/wordboundaries.html\" rel=\"nofollow\"\u003eword boundaries\u003c/a\u003e are\nrequired as otherwise \u003ccode\u003eKoeffizienten\u003c/code\u003e is matched as \u003ccode\u003eKoeffizi\u003c/code\u003e and \u003ccode\u003eenten\u003c/code\u003e. Note how the\ntrailing periods cannot be, for example, squeezed. The required scope of \u003ccode\u003e\\.\u003c/code\u003e would\ninterfere with the given one. Regular piping solves this:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-text-shell-session notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"$ echo 'Koeffizienten != Bruecken...' | srgn -Sgu '\\b\\w{1,8}\\b' | srgn -s '\\.'\nKoeffizienten != BRÜCKEN.\"\u003e\u003cpre\u003e$ \u003cspan class=\"pl-s1\"\u003e\u003cspan class=\"pl-c1\"\u003eecho\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003eKoeffizienten != Bruecken...\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-k\"\u003e|\u003c/span\u003e srgn -Sgu \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\\b\\w{1,8}\\b\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-k\"\u003e|\u003c/span\u003e srgn -s \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\\.\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003eKoeffizienten != BRÜCKEN.\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eNote: regex escaping (\u003ccode\u003e\\.\u003c/code\u003e) can be circumvent using \u003ca href=\"#literal-scope\"\u003eliteral scoping\u003c/a\u003e.\nThe specially treated replacement action is also composable:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-text-shell-session notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"$ echo 'Mooood: 🤮🤒🤧🦠!!!' | srgn -s '\\p{Emoji}' '😷'\nMooood: 😷!!!\"\u003e\u003cpre\u003e$ \u003cspan class=\"pl-s1\"\u003e\u003cspan class=\"pl-c1\"\u003eecho\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003eMooood: 🤮🤒🤧🦠!!!\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-k\"\u003e|\u003c/span\u003e srgn -s \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\\p{Emoji}\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e😷\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003eMooood: 😷!!!\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eEmojis are first all replaced, then squeezed. Notice how nothing else is squeezed.\u003c/p\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch3 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eScopes\u003c/h3\u003e\u003ca id=\"user-content-scopes\" class=\"anchor\" aria-label=\"Permalink: Scopes\" href=\"#scopes\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eScopes are the second driving concept to \u003ccode\u003esrgn\u003c/code\u003e. In the default case, the main scope is\na regular expression. The \u003ca href=\"#actions\"\u003eactions\u003c/a\u003e section showcased this use case in some\ndetail, so it's not repeated here. It is given as a first positional argument.\u003c/p\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch4 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eLanguage grammar-aware scopes\u003c/h4\u003e\u003ca id=\"user-content-language-grammar-aware-scopes\" class=\"anchor\" aria-label=\"Permalink: Language grammar-aware scopes\" href=\"#language-grammar-aware-scopes\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003e\u003ccode\u003esrgn\u003c/code\u003e extends this through prepared, language grammar-aware scopes, made possible\nthrough the excellent \u003ca href=\"https://tree-sitter.github.io/tree-sitter/\" rel=\"nofollow\"\u003e\u003ccode\u003etree-sitter\u003c/code\u003e\u003c/a\u003e\nlibrary. It offers a\n\u003ca href=\"https://tree-sitter.github.io/tree-sitter/using-parsers#query-syntax\" rel=\"nofollow\"\u003equeries\u003c/a\u003e feature,\nwhich works much like pattern matching against a \u003ca href=\"https://en.wikipedia.org/wiki/Parse_tree\" rel=\"nofollow\"\u003etree data\nstructure\u003c/a\u003e.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003e\u003ccode\u003esrgn\u003c/code\u003e comes bundled with a handful of the most useful of these queries. Through its\ndiscoverable API (either \u003ca href=\"#rust-library\"\u003eas a library\u003c/a\u003e or via CLI, \u003ccode\u003esrgn --help\u003c/code\u003e), one\ncan learn of the supported languages and available, prepared queries. Each supported\nlanguage comes with an escape hatch, allowing you to run your own, custom ad-hoc\nqueries. The hatch comes in the form of \u003ccode\u003e--lang-query \u0026lt;S EXPRESSION\u0026gt;\u003c/code\u003e, where \u003ccode\u003elang\u003c/code\u003e is a\nlanguage such as \u003ccode\u003epython\u003c/code\u003e. See \u003ca href=\"#custom-queries\"\u003ebelow\u003c/a\u003e for more on this advanced topic.\u003c/p\u003e\n\u003cdiv class=\"markdown-alert markdown-alert-note\" dir=\"auto\"\u003e\u003cp class=\"markdown-alert-title\" dir=\"auto\"\u003e\u003csvg class=\"octicon octicon-info mr-2\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z\"\u003e\u003c/path\u003e\u003c/svg\u003eNote\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eLanguage scopes are applied \u003cem\u003efirst\u003c/em\u003e, so whatever regex aka main scope you pass, it\noperates on each matched language construct individually.\u003c/p\u003e\n\u003c/div\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch5 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003ePrepared queries\u003c/h5\u003e\u003ca id=\"user-content-prepared-queries\" class=\"anchor\" aria-label=\"Permalink: Prepared queries\" href=\"#prepared-queries\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eThis section shows examples for some of the \u003cstrong\u003eprepared queries\u003c/strong\u003e.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eMost prepared queries are static, e.g. they always scope \"all comments\", for example.\nVarious language elements are naturally \u003cem\u003enamed\u003c/em\u003e however: functions, classes, structs,\nmodules and more are usually not anonymous, but carry names. Some prepared queries\ntherefore have \u003cem\u003edynamic\u003c/em\u003e variants, where an optional regular expression pattern can\nadditionally be supplied. The pattern then applies to the name of the item, and will\nonly scope those items whose name matches the pattern. This allows for an extra degree\nof freedom for querying. Examples follow.\u003c/p\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch6 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eFinding all structs related to testing (Go)\u003c/h6\u003e\u003ca id=\"user-content-finding-all-structs-related-to-testing-go\" class=\"anchor\" aria-label=\"Permalink: Finding all structs related to testing (Go)\" href=\"#finding-all-structs-related-to-testing-go\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eAn input like\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-go notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"type PublicTestInput struct {\n Name string\n Value int\n}\n\ntype privateTestInput struct {\n name string\n value int\n}\n\ntype ActualDomainType struct {\n Name string\n Value int\n}\"\u003e\u003cpre\u003e\u003cspan class=\"pl-k\"\u003etype\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003ePublicTestInput\u003c/span\u003e \u003cspan class=\"pl-k\"\u003estruct\u003c/span\u003e {\n \u003cspan class=\"pl-c1\"\u003eName\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003estring\u003c/span\u003e\n \u003cspan class=\"pl-c1\"\u003eValue\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eint\u003c/span\u003e\n}\n\n\u003cspan class=\"pl-k\"\u003etype\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eprivateTestInput\u003c/span\u003e \u003cspan class=\"pl-k\"\u003estruct\u003c/span\u003e {\n \u003cspan class=\"pl-c1\"\u003ename\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003estring\u003c/span\u003e\n \u003cspan class=\"pl-c1\"\u003evalue\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eint\u003c/span\u003e\n}\n\n\u003cspan class=\"pl-k\"\u003etype\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eActualDomainType\u003c/span\u003e \u003cspan class=\"pl-k\"\u003estruct\u003c/span\u003e {\n \u003cspan class=\"pl-c1\"\u003eName\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003estring\u003c/span\u003e\n \u003cspan class=\"pl-c1\"\u003eValue\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eint\u003c/span\u003e\n}\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003ecan be searched as\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-text-shell-session notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"$ cat testing.go | srgn --go 'struct~[tT]est'\n1:type PublicTestInput struct {\n2: Name string\n3: Value int\n4:}\n6:type privateTestInput struct {\n7: name string\n8: value int\n9:}\"\u003e\u003cpre\u003e$ \u003cspan class=\"pl-s1\"\u003ecat testing.go \u003cspan class=\"pl-k\"\u003e|\u003c/span\u003e srgn --go \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003estruct~[tT]est\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e1:type PublicTestInput struct {\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e2: Name string\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e3: Value int\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e4:}\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e6:type privateTestInput struct {\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e7: name string\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e8: value int\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e9:}\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003esurfacing only \u003ccode\u003estruct\u003c/code\u003es whose name matches \u003ccode\u003e[tT]est\u003c/code\u003e. The \u003ccode\u003e~\u003c/code\u003e character serves as the\nseparator between the language grammar/node type and pattern. This approach allows\nmanipulation of \u003cem\u003eonly these structs\u003c/em\u003e, e.g.\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-text-shell-session notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"$ cat testing.go | srgn --go 'struct~[tT]est' '(\\s+)Name' '${1}TestName'\ntype PublicTestInput struct {\n TestName string\n Value int\n}\n\ntype privateTestInput struct {\n name string\n value int\n}\n\ntype ActualDomainType struct {\n Name string\n Value int\n}\"\u003e\u003cpre\u003e$ \u003cspan class=\"pl-s1\"\u003ecat testing.go \u003cspan class=\"pl-k\"\u003e|\u003c/span\u003e srgn --go \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003estruct~[tT]est\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e(\\s+)Name\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e${1}TestName\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003etype PublicTestInput struct {\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e TestName string\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e Value int\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"pl-c1\"\u003etype privateTestInput struct {\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e name string\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e value int\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"pl-c1\"\u003etype ActualDomainType struct {\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e Name string\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e Value int\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e}\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch6 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eFinding all \u003ccode\u003eunsafe\u003c/code\u003e code (Rust)\u003c/h6\u003e\u003ca id=\"user-content-finding-all-unsafe-code-rust\" class=\"anchor\" aria-label=\"Permalink: Finding all unsafe code (Rust)\" href=\"#finding-all-unsafe-code-rust\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eOne advantage of the \u003ca href=\"https://doc.rust-lang.org/book/ch19-01-unsafe-rust.html\" rel=\"nofollow\"\u003e\u003ccode\u003eunsafe\u003c/code\u003e keyword in\nRust\u003c/a\u003e is its \"grepability\".\nHowever, an \u003ccode\u003erg 'unsafe'\u003c/code\u003e will of course surface \u003cem\u003eall\u003c/em\u003e string matches (\u003ccode\u003erg '\\bunsafe\\b'\u003c/code\u003e\nhelps to an extent), not just those in of the actual Rust language keyword. \u003ccode\u003esrgn\u003c/code\u003e helps\nmake this more precise. For example:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-rust notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"// Oh no, an unsafe module!\nmod scary_unsafe_operations {\n pub unsafe fn unsafe_array_access(arr: \u0026amp;[i32], index: usize) -\u0026gt; i32 {\n // UNSAFE: This function performs unsafe array access without bounds checking\n *arr.get_unchecked(index)\n }\n\n pub fn call_unsafe_function() {\n let unsafe_numbers = vec![1, 2, 3, 4, 5];\n println!(\u0026quot;About to perform an unsafe operation!\u0026quot;);\n let result = unsafe {\n // Calling an unsafe function\n unsafe_array_access(\u0026amp;unsafe_numbers, 10)\n };\n println!(\u0026quot;Result of unsafe operation: {}\u0026quot;, result);\n }\n}\"\u003e\u003cpre\u003e\u003cspan class=\"pl-c\"\u003e// Oh no, an unsafe module!\u003c/span\u003e\n\u003cspan class=\"pl-k\"\u003emod\u003c/span\u003e scary_unsafe_operations \u003cspan class=\"pl-kos\"\u003e{\u003c/span\u003e\n \u003cspan class=\"pl-k\"\u003epub\u003c/span\u003e \u003cspan class=\"pl-k\"\u003eunsafe\u003c/span\u003e \u003cspan class=\"pl-k\"\u003efn\u003c/span\u003e \u003cspan class=\"pl-en\"\u003eunsafe_array_access\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-s1\"\u003earr\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e:\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e[\u003c/span\u003e\u003cspan class=\"pl-smi\"\u003ei32\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e]\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e,\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003eindex\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e:\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eusize\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e -\u0026gt; \u003cspan class=\"pl-smi\"\u003ei32\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e{\u003c/span\u003e\n \u003cspan class=\"pl-c\"\u003e// UNSAFE: This function performs unsafe array access without bounds checking\u003c/span\u003e\n \u003cspan class=\"pl-c1\"\u003e*\u003c/span\u003earr\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eget_unchecked\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003eindex\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\n \u003cspan class=\"pl-kos\"\u003e}\u003c/span\u003e\n\n \u003cspan class=\"pl-k\"\u003epub\u003c/span\u003e \u003cspan class=\"pl-k\"\u003efn\u003c/span\u003e \u003cspan class=\"pl-en\"\u003ecall_unsafe_function\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e{\u003c/span\u003e\n \u003cspan class=\"pl-k\"\u003elet\u003c/span\u003e unsafe_numbers = \u003cspan class=\"pl-en\"\u003evec\u003c/span\u003e\u003cspan class=\"pl-en\"\u003e!\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e[\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003e1\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e,\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e2\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e,\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e3\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e,\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e4\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e,\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e5\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e]\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e;\u003c/span\u003e\n \u003cspan class=\"pl-en\"\u003eprintln\u003c/span\u003e\u003cspan class=\"pl-en\"\u003e!\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\"About to perform an unsafe operation!\"\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e;\u003c/span\u003e\n \u003cspan class=\"pl-k\"\u003elet\u003c/span\u003e result = \u003cspan class=\"pl-k\"\u003eunsafe\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e{\u003c/span\u003e\n \u003cspan class=\"pl-c\"\u003e// Calling an unsafe function\u003c/span\u003e\n \u003cspan class=\"pl-en\"\u003eunsafe_array_access\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003e\u0026amp;\u003c/span\u003eunsafe_numbers\u003cspan class=\"pl-kos\"\u003e,\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e10\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\n \u003cspan class=\"pl-kos\"\u003e}\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e;\u003c/span\u003e\n \u003cspan class=\"pl-en\"\u003eprintln\u003c/span\u003e\u003cspan class=\"pl-en\"\u003e!\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\"Result of unsafe operation: {}\"\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e,\u003c/span\u003e result\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e;\u003c/span\u003e\n \u003cspan class=\"pl-kos\"\u003e}\u003c/span\u003e\n\u003cspan class=\"pl-kos\"\u003e}\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003ecan be searched as\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-text-shell-session notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"$ cat unsafe.rs | srgn --rs 'unsafe' # Note: no 2nd argument necessary\n3: pub unsafe fn unsafe_array_access(arr: \u0026amp;[i32], index: usize) -\u0026gt; i32 {\n4: // UNSAFE: This function performs unsafe array access without bounds checking\n5: *arr.get_unchecked(index)\n6: }\n11: let result = unsafe {\n12: // Calling an unsafe function\n13: unsafe_array_access(\u0026amp;unsafe_numbers, 10)\n14: };\"\u003e\u003cpre\u003e$ \u003cspan class=\"pl-s1\"\u003ecat unsafe.rs \u003cspan class=\"pl-k\"\u003e|\u003c/span\u003e srgn --rs \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003eunsafe\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-c\"\u003e\u003cspan class=\"pl-c\"\u003e#\u003c/span\u003e Note: no 2nd argument necessary\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e3: pub unsafe fn unsafe_array_access(arr: \u0026amp;[i32], index: usize) -\u0026gt; i32 {\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e4: // UNSAFE: This function performs unsafe array access without bounds checking\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e5: *arr.get_unchecked(index)\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e6: }\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e11: let result = unsafe {\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e12: // Calling an unsafe function\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e13: unsafe_array_access(\u0026amp;unsafe_numbers, 10)\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e14: };\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003esurfacing only truly \u003ccode\u003eunsafe\u003c/code\u003e items (and not comments, strings etc. merely mentioning\nit).\u003csup\u003e\u003ca href=\"#user-content-fn-4-b30ce13ed678ccbd6287a3f5e19f11b5\" id=\"user-content-fnref-4-b30ce13ed678ccbd6287a3f5e19f11b5\" data-footnote-ref=\"\" aria-describedby=\"footnote-label\"\u003e4\u003c/a\u003e\u003c/sup\u003e\u003c/p\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch6 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eReplacing \u003ccode\u003eallow\u003c/code\u003e with \u003ccode\u003eexpect\u003c/code\u003e for lints (Rust)\u003c/h6\u003e\u003ca id=\"user-content-replacing-allow-with-expect-for-lints-rust\" class=\"anchor\" aria-label=\"Permalink: Replacing allow with expect for lints (Rust)\" href=\"#replacing-allow-with-expect-for-lints-rust\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eTaking advantage of the stabilization of the \u003ccode\u003eexpect\u003c/code\u003e lint level in \u003ca href=\"https://blog.rust-lang.org/2024/09/05/Rust-1.81.0.html#expectlint\" rel=\"nofollow\"\u003eRust\n1.81\u003c/a\u003e, one might want\nto migrate from \u003ccode\u003eallow\u003c/code\u003e to \u003ccode\u003eexpect\u003c/code\u003e throughout (cf.\n959a692f1d788d071d5f55376e2bb5ff3c2ae15a in this repo):\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-rust notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"#[allow(unsafe_code)]\nif let Some(env_value) = env_value {\n unsafe {\n env::set_var(DEFAULT_FILTER_ENV, env_value);\n }\n}\"\u003e\u003cpre\u003e\u003cspan class=\"pl-c1\"\u003e#\u003cspan class=\"pl-kos\"\u003e[\u003c/span\u003eallow\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003eunsafe_code\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e]\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"pl-k\"\u003eif\u003c/span\u003e \u003cspan class=\"pl-k\"\u003elet\u003c/span\u003e \u003cspan class=\"pl-v\"\u003eSome\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003eenv_value\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e = env_value \u003cspan class=\"pl-kos\"\u003e{\u003c/span\u003e\n \u003cspan class=\"pl-k\"\u003eunsafe\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e{\u003c/span\u003e\n env\u003cspan class=\"pl-kos\"\u003e::\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eset_var\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-v\"\u003eDEFAULT_FILTER_ENV\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e,\u003c/span\u003e env_value\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e;\u003c/span\u003e\n \u003cspan class=\"pl-kos\"\u003e}\u003c/span\u003e\n\u003cspan class=\"pl-kos\"\u003e}\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003ecan be refactored using\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-shell notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"cat allow.rs | srgn --rust 'attribute' '^allow' 'expect'\"\u003e\u003cpre\u003ecat allow.rs \u003cspan class=\"pl-k\"\u003e|\u003c/span\u003e srgn --rust \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003eattribute\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e^allow\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003eexpect\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003ewhich will yield\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-rust notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"#[expect(unsafe_code)]\nif let Some(env_value) = env_value {\n unsafe {\n env::set_var(DEFAULT_FILTER_ENV, env_value);\n }\n}\"\u003e\u003cpre\u003e\u003cspan class=\"pl-c1\"\u003e#\u003cspan class=\"pl-kos\"\u003e[\u003c/span\u003eexpect\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003eunsafe_code\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e]\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"pl-k\"\u003eif\u003c/span\u003e \u003cspan class=\"pl-k\"\u003elet\u003c/span\u003e \u003cspan class=\"pl-v\"\u003eSome\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003eenv_value\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e = env_value \u003cspan class=\"pl-kos\"\u003e{\u003c/span\u003e\n \u003cspan class=\"pl-k\"\u003eunsafe\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e{\u003c/span\u003e\n env\u003cspan class=\"pl-kos\"\u003e::\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eset_var\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-v\"\u003eDEFAULT_FILTER_ENV\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e,\u003c/span\u003e env_value\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e;\u003c/span\u003e\n \u003cspan class=\"pl-kos\"\u003e}\u003c/span\u003e\n\u003cspan class=\"pl-kos\"\u003e}\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch6 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eMass import (module) renaming (Python, Rust)\u003c/h6\u003e\u003ca id=\"user-content-mass-import-module-renaming-python-rust\" class=\"anchor\" aria-label=\"Permalink: Mass import (module) renaming (Python, Rust)\" href=\"#mass-import-module-renaming-python-rust\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eAs part of a large refactor (say, after an acquisition), imagine all imports of a\nspecific package needed renaming:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-python notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"import math\nfrom pathlib import Path\n\nimport good_company.infra\nimport good_company.aws.auth as aws_auth\nfrom good_company.util.iter import dedupe\nfrom good_company.shopping.cart import * # Ok but don't do this at home!\n\ngood_company = \u0026quot;good_company\u0026quot; # good_company\"\u003e\u003cpre\u003e\u003cspan class=\"pl-k\"\u003eimport\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003emath\u003c/span\u003e\n\u003cspan class=\"pl-k\"\u003efrom\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003epathlib\u003c/span\u003e \u003cspan class=\"pl-k\"\u003eimport\u003c/span\u003e \u003cspan class=\"pl-v\"\u003ePath\u003c/span\u003e\n\n\u003cspan class=\"pl-k\"\u003eimport\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003egood_company\u003c/span\u003e.\u003cspan class=\"pl-s1\"\u003einfra\u003c/span\u003e\n\u003cspan class=\"pl-k\"\u003eimport\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003egood_company\u003c/span\u003e.\u003cspan class=\"pl-s1\"\u003eaws\u003c/span\u003e.\u003cspan class=\"pl-s1\"\u003eauth\u003c/span\u003e \u003cspan class=\"pl-k\"\u003eas\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003eaws_auth\u003c/span\u003e\n\u003cspan class=\"pl-k\"\u003efrom\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003egood_company\u003c/span\u003e.\u003cspan class=\"pl-s1\"\u003eutil\u003c/span\u003e.\u003cspan class=\"pl-s1\"\u003eiter\u003c/span\u003e \u003cspan class=\"pl-k\"\u003eimport\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003ededupe\u003c/span\u003e\n\u003cspan class=\"pl-k\"\u003efrom\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003egood_company\u003c/span\u003e.\u003cspan class=\"pl-s1\"\u003eshopping\u003c/span\u003e.\u003cspan class=\"pl-s1\"\u003ecart\u003c/span\u003e \u003cspan class=\"pl-k\"\u003eimport\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e*\u003c/span\u003e \u003cspan class=\"pl-c\"\u003e# Ok but don't do this at home!\u003c/span\u003e\n\n\u003cspan class=\"pl-s1\"\u003egood_company\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e=\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\"good_company\"\u003c/span\u003e \u003cspan class=\"pl-c\"\u003e# good_company\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eAt the same time, a move to \u003ca href=\"https://packaging.python.org/en/latest/discussions/src-layout-vs-flat-layout/\" rel=\"nofollow\"\u003e\u003ccode\u003esrc/\u003c/code\u003e\nlayout\u003c/a\u003e\nis desired. Achieve this move with:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-shell notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"cat imports.py | srgn --python 'imports' '^good_company' 'src.better_company'\"\u003e\u003cpre\u003ecat imports.py \u003cspan class=\"pl-k\"\u003e|\u003c/span\u003e srgn --python \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003eimports\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e^good_company\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003esrc.better_company\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003ewhich will yield\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-python notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"import math\nfrom pathlib import Path\n\nimport src.better_company.infra\nimport src.better_company.aws.auth as aws_auth\nfrom src.better_company.util.iter import dedupe\nfrom src.better_company.shopping.cart import * # Ok but don't do this at home!\n\ngood_company = \u0026quot;good_company\u0026quot; # good_company\"\u003e\u003cpre\u003e\u003cspan class=\"pl-k\"\u003eimport\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003emath\u003c/span\u003e\n\u003cspan class=\"pl-k\"\u003efrom\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003epathlib\u003c/span\u003e \u003cspan class=\"pl-k\"\u003eimport\u003c/span\u003e \u003cspan class=\"pl-v\"\u003ePath\u003c/span\u003e\n\n\u003cspan class=\"pl-k\"\u003eimport\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003esrc\u003c/span\u003e.\u003cspan class=\"pl-s1\"\u003ebetter_company\u003c/span\u003e.\u003cspan class=\"pl-s1\"\u003einfra\u003c/span\u003e\n\u003cspan class=\"pl-k\"\u003eimport\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003esrc\u003c/span\u003e.\u003cspan class=\"pl-s1\"\u003ebetter_company\u003c/span\u003e.\u003cspan class=\"pl-s1\"\u003eaws\u003c/span\u003e.\u003cspan class=\"pl-s1\"\u003eauth\u003c/span\u003e \u003cspan class=\"pl-k\"\u003eas\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003eaws_auth\u003c/span\u003e\n\u003cspan class=\"pl-k\"\u003efrom\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003esrc\u003c/span\u003e.\u003cspan class=\"pl-s1\"\u003ebetter_company\u003c/span\u003e.\u003cspan class=\"pl-s1\"\u003eutil\u003c/span\u003e.\u003cspan class=\"pl-s1\"\u003eiter\u003c/span\u003e \u003cspan class=\"pl-k\"\u003eimport\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003ededupe\u003c/span\u003e\n\u003cspan class=\"pl-k\"\u003efrom\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003esrc\u003c/span\u003e.\u003cspan class=\"pl-s1\"\u003ebetter_company\u003c/span\u003e.\u003cspan class=\"pl-s1\"\u003eshopping\u003c/span\u003e.\u003cspan class=\"pl-s1\"\u003ecart\u003c/span\u003e \u003cspan class=\"pl-k\"\u003eimport\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e*\u003c/span\u003e \u003cspan class=\"pl-c\"\u003e# Ok but don't do this at home!\u003c/span\u003e\n\n\u003cspan class=\"pl-s1\"\u003egood_company\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e=\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\"good_company\"\u003c/span\u003e \u003cspan class=\"pl-c\"\u003e# good_company\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eNote how the last line remains untouched by this particular operation. To run across\nmany files, see \u003ca href=\"#run-against-multiple-files\"\u003ethe \u003ccode\u003efiles\u003c/code\u003e option\u003c/a\u003e.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eSimilar import-related edits are supported for other languages as well, for example\nRust:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-rust notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"use std::collections::HashMap;\n\nuse good_company::infra;\nuse good_company::aws::auth as aws_auth;\nuse good_company::util::iter::dedupe;\nuse good_company::shopping::cart::*;\n\ngood_company = \u0026quot;good_company\u0026quot;; // good_company\"\u003e\u003cpre\u003e\u003cspan class=\"pl-k\"\u003euse\u003c/span\u003e std\u003cspan class=\"pl-kos\"\u003e::\u003c/span\u003ecollections\u003cspan class=\"pl-kos\"\u003e::\u003c/span\u003e\u003cspan class=\"pl-v\"\u003eHashMap\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e;\u003c/span\u003e\n\n\u003cspan class=\"pl-k\"\u003euse\u003c/span\u003e good_company\u003cspan class=\"pl-kos\"\u003e::\u003c/span\u003einfra\u003cspan class=\"pl-kos\"\u003e;\u003c/span\u003e\n\u003cspan class=\"pl-k\"\u003euse\u003c/span\u003e good_company\u003cspan class=\"pl-kos\"\u003e::\u003c/span\u003eaws\u003cspan class=\"pl-kos\"\u003e::\u003c/span\u003eauth \u003cspan class=\"pl-k\"\u003eas\u003c/span\u003e aws_auth\u003cspan class=\"pl-kos\"\u003e;\u003c/span\u003e\n\u003cspan class=\"pl-k\"\u003euse\u003c/span\u003e good_company\u003cspan class=\"pl-kos\"\u003e::\u003c/span\u003eutil\u003cspan class=\"pl-kos\"\u003e::\u003c/span\u003eiter\u003cspan class=\"pl-kos\"\u003e::\u003c/span\u003ededupe\u003cspan class=\"pl-kos\"\u003e;\u003c/span\u003e\n\u003cspan class=\"pl-k\"\u003euse\u003c/span\u003e good_company\u003cspan class=\"pl-kos\"\u003e::\u003c/span\u003eshopping\u003cspan class=\"pl-kos\"\u003e::\u003c/span\u003ecart\u003cspan class=\"pl-kos\"\u003e::\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003e*\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e;\u003c/span\u003e\n\ngood_company = \u003cspan class=\"pl-s\"\u003e\"good_company\"\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e;\u003c/span\u003e \u003cspan class=\"pl-c\"\u003e// good_company\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003ewhich, using\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-shell notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"cat imports.rs | srgn --rust 'uses' '^good_company' 'better_company'\"\u003e\u003cpre\u003ecat imports.rs \u003cspan class=\"pl-k\"\u003e|\u003c/span\u003e srgn --rust \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003euses\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e^good_company\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003ebetter_company\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003ebecomes\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-rust notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"use std::collections::HashMap;\n\nuse better_company::infra;\nuse better_company::aws::auth as aws_auth;\nuse better_company::util::iter::dedupe;\nuse better_company::shopping::cart::*;\n\ngood_company = \u0026quot;good_company\u0026quot;; // good_company\"\u003e\u003cpre\u003e\u003cspan class=\"pl-k\"\u003euse\u003c/span\u003e std\u003cspan class=\"pl-kos\"\u003e::\u003c/span\u003ecollections\u003cspan class=\"pl-kos\"\u003e::\u003c/span\u003e\u003cspan class=\"pl-v\"\u003eHashMap\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e;\u003c/span\u003e\n\n\u003cspan class=\"pl-k\"\u003euse\u003c/span\u003e better_company\u003cspan class=\"pl-kos\"\u003e::\u003c/span\u003einfra\u003cspan class=\"pl-kos\"\u003e;\u003c/span\u003e\n\u003cspan class=\"pl-k\"\u003euse\u003c/span\u003e better_company\u003cspan class=\"pl-kos\"\u003e::\u003c/span\u003eaws\u003cspan class=\"pl-kos\"\u003e::\u003c/span\u003eauth \u003cspan class=\"pl-k\"\u003eas\u003c/span\u003e aws_auth\u003cspan class=\"pl-kos\"\u003e;\u003c/span\u003e\n\u003cspan class=\"pl-k\"\u003euse\u003c/span\u003e better_company\u003cspan class=\"pl-kos\"\u003e::\u003c/span\u003eutil\u003cspan class=\"pl-kos\"\u003e::\u003c/span\u003eiter\u003cspan class=\"pl-kos\"\u003e::\u003c/span\u003ededupe\u003cspan class=\"pl-kos\"\u003e;\u003c/span\u003e\n\u003cspan class=\"pl-k\"\u003euse\u003c/span\u003e better_company\u003cspan class=\"pl-kos\"\u003e::\u003c/span\u003eshopping\u003cspan class=\"pl-kos\"\u003e::\u003c/span\u003ecart\u003cspan class=\"pl-kos\"\u003e::\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003e*\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e;\u003c/span\u003e\n\ngood_company = \u003cspan class=\"pl-s\"\u003e\"good_company\"\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e;\u003c/span\u003e \u003cspan class=\"pl-c\"\u003e// good_company\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch6 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eAssigning \u003ccode\u003eTODO\u003c/code\u003es (TypeScript)\u003c/h6\u003e\u003ca id=\"user-content-assigning-todos-typescript\" class=\"anchor\" aria-label=\"Permalink: Assigning TODOs (TypeScript)\" href=\"#assigning-todos-typescript\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003ePerhaps you're using a system of \u003ccode\u003eTODO\u003c/code\u003e notes in comments:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-ts notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"class TODOApp {\n // TODO app for writing TODO lists\n addTodo(todo: TODO): void {\n // TODO: everything, actually 🤷‍♀️\n }\n}\"\u003e\u003cpre\u003e\u003cspan class=\"pl-k\"\u003eclass\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eTODOApp\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e{\u003c/span\u003e\n \u003cspan class=\"pl-c\"\u003e// TODO app for writing TODO lists\u003c/span\u003e\n \u003cspan class=\"pl-en\"\u003eaddTodo\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-s1\"\u003etodo\u003c/span\u003e: \u003cspan class=\"pl-smi\"\u003eTODO\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e: \u003cspan class=\"pl-smi\"\u003e\u003cspan class=\"pl-k\"\u003evoid\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e{\u003c/span\u003e\n \u003cspan class=\"pl-c\"\u003e// TODO: everything, actually 🤷‍♀️\u003c/span\u003e\n \u003cspan class=\"pl-kos\"\u003e}\u003c/span\u003e\n\u003cspan class=\"pl-kos\"\u003e}\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eand \u003cem\u003eusually\u003c/em\u003e assign people to each note. It's possible to automate assigning yourself\nto every unassigned note (lucky you!) using\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-shell notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"cat todo.ts | srgn --typescript 'comments' 'TODO(?=:)' 'TODO(@poorguy)'\"\u003e\u003cpre\u003ecat todo.ts \u003cspan class=\"pl-k\"\u003e|\u003c/span\u003e srgn --typescript \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003ecomments\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003eTODO(?=:)\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003eTODO(@poorguy)\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003ewhich in this case gives\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-ts notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"class TODOApp {\n // TODO app for writing TODO lists\n addTodo(todo: TODO): void {\n // TODO(@poorguy): everything, actually 🤷‍♀️\n }\n}\"\u003e\u003cpre\u003e\u003cspan class=\"pl-k\"\u003eclass\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eTODOApp\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e{\u003c/span\u003e\n \u003cspan class=\"pl-c\"\u003e// TODO app for writing TODO lists\u003c/span\u003e\n \u003cspan class=\"pl-en\"\u003eaddTodo\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-s1\"\u003etodo\u003c/span\u003e: \u003cspan class=\"pl-smi\"\u003eTODO\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e: \u003cspan class=\"pl-smi\"\u003e\u003cspan class=\"pl-k\"\u003evoid\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e{\u003c/span\u003e\n \u003cspan class=\"pl-c\"\u003e// TODO(@poorguy): everything, actually 🤷‍♀️\u003c/span\u003e\n \u003cspan class=\"pl-kos\"\u003e}\u003c/span\u003e\n\u003cspan class=\"pl-kos\"\u003e}\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eNotice the \u003ca href=\"https://www.regular-expressions.info/lookaround.html\" rel=\"nofollow\"\u003epositive lookahead\u003c/a\u003e of\n\u003ccode\u003e(?=:)\u003c/code\u003e, ensuring an actual \u003ccode\u003eTODO\u003c/code\u003e note is hit (\u003ccode\u003eTODO:\u003c/code\u003e). Otherwise, the other \u003ccode\u003eTODO\u003c/code\u003es\nmentioned around the comments would be matched as well.\u003c/p\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch6 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eConverting \u003ccode\u003eprint\u003c/code\u003e calls to proper \u003ccode\u003elogging\u003c/code\u003e (Python)\u003c/h6\u003e\u003ca id=\"user-content-converting-print-calls-to-proper-logging-python\" class=\"anchor\" aria-label=\"Permalink: Converting print calls to proper logging (Python)\" href=\"#converting-print-calls-to-proper-logging-python\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eSay there's code making liberal use of \u003ccode\u003eprint\u003c/code\u003e:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-python notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"def print_money():\n \u0026quot;\u0026quot;\u0026quot;Let's print money 💸.\u0026quot;\u0026quot;\u0026quot;\n\n amount = 32\n print(\u0026quot;Got here.\u0026quot;)\n\n print_more = lambda s: print(f\u0026quot;Printed {s}\u0026quot;)\n print_more(23) # print the stuff\n\nprint_money()\nprint(\u0026quot;Done.\u0026quot;)\"\u003e\u003cpre\u003e\u003cspan class=\"pl-k\"\u003edef\u003c/span\u003e \u003cspan class=\"pl-en\"\u003eprint_money\u003c/span\u003e():\n \u003cspan class=\"pl-s\"\u003e\"\"\"Let's print money 💸.\"\"\"\u003c/span\u003e\n\n \u003cspan class=\"pl-s1\"\u003eamount\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e=\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e32\u003c/span\u003e\n \u003cspan class=\"pl-en\"\u003eprint\u003c/span\u003e(\u003cspan class=\"pl-s\"\u003e\"Got here.\"\u003c/span\u003e)\n\n \u003cspan class=\"pl-s1\"\u003eprint_more\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e=\u003c/span\u003e \u003cspan class=\"pl-k\"\u003elambda\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003es\u003c/span\u003e: \u003cspan class=\"pl-en\"\u003eprint\u003c/span\u003e(\u003cspan class=\"pl-s\"\u003ef\"Printed \u003cspan class=\"pl-s1\"\u003e\u003cspan class=\"pl-kos\"\u003e{\u003c/span\u003e\u003cspan class=\"pl-s1\"\u003es\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e}\u003c/span\u003e\u003c/span\u003e\"\u003c/span\u003e)\n \u003cspan class=\"pl-en\"\u003eprint_more\u003c/span\u003e(\u003cspan class=\"pl-c1\"\u003e23\u003c/span\u003e) \u003cspan class=\"pl-c\"\u003e# print the stuff\u003c/span\u003e\n\n\u003cspan class=\"pl-en\"\u003eprint_money\u003c/span\u003e()\n\u003cspan class=\"pl-en\"\u003eprint\u003c/span\u003e(\u003cspan class=\"pl-s\"\u003e\"Done.\"\u003c/span\u003e)\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eand a move to \u003ca href=\"https://docs.python.org/3/library/logging.html\" rel=\"nofollow\"\u003e\u003ccode\u003elogging\u003c/code\u003e\u003c/a\u003e is desired.\nThat's fully automated by a call of\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-shell notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"cat money.py | srgn --python 'function-calls' '^print$' 'logging.info'\"\u003e\u003cpre\u003ecat money.py \u003cspan class=\"pl-k\"\u003e|\u003c/span\u003e srgn --python \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003efunction-calls\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e^print$\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003elogging.info\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eyielding\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-python notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"def print_money():\n \u0026quot;\u0026quot;\u0026quot;Let's print money 💸.\u0026quot;\u0026quot;\u0026quot;\n\n amount = 32\n logging.info(\u0026quot;Got here.\u0026quot;)\n\n print_more = lambda s: logging.info(f\u0026quot;Printed {s}\u0026quot;)\n print_more(23) # print the stuff\n\nprint_money()\nlogging.info(\u0026quot;Done.\u0026quot;)\"\u003e\u003cpre\u003e\u003cspan class=\"pl-k\"\u003edef\u003c/span\u003e \u003cspan class=\"pl-en\"\u003eprint_money\u003c/span\u003e():\n \u003cspan class=\"pl-s\"\u003e\"\"\"Let's print money 💸.\"\"\"\u003c/span\u003e\n\n \u003cspan class=\"pl-s1\"\u003eamount\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e=\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e32\u003c/span\u003e\n \u003cspan class=\"pl-s1\"\u003elogging\u003c/span\u003e.\u003cspan class=\"pl-c1\"\u003einfo\u003c/span\u003e(\u003cspan class=\"pl-s\"\u003e\"Got here.\"\u003c/span\u003e)\n\n \u003cspan class=\"pl-s1\"\u003eprint_more\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e=\u003c/span\u003e \u003cspan class=\"pl-k\"\u003elambda\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003es\u003c/span\u003e: \u003cspan class=\"pl-s1\"\u003elogging\u003c/span\u003e.\u003cspan class=\"pl-c1\"\u003einfo\u003c/span\u003e(\u003cspan class=\"pl-s\"\u003ef\"Printed \u003cspan class=\"pl-s1\"\u003e\u003cspan class=\"pl-kos\"\u003e{\u003c/span\u003e\u003cspan class=\"pl-s1\"\u003es\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e}\u003c/span\u003e\u003c/span\u003e\"\u003c/span\u003e)\n \u003cspan class=\"pl-en\"\u003eprint_more\u003c/span\u003e(\u003cspan class=\"pl-c1\"\u003e23\u003c/span\u003e) \u003cspan class=\"pl-c\"\u003e# print the stuff\u003c/span\u003e\n\n\u003cspan class=\"pl-en\"\u003eprint_money\u003c/span\u003e()\n\u003cspan class=\"pl-s1\"\u003elogging\u003c/span\u003e.\u003cspan class=\"pl-c1\"\u003einfo\u003c/span\u003e(\u003cspan class=\"pl-s\"\u003e\"Done.\"\u003c/span\u003e)\u003c/pre\u003e\u003c/div\u003e\n\u003cdiv class=\"markdown-alert markdown-alert-note\" dir=\"auto\"\u003e\u003cp class=\"markdown-alert-title\" dir=\"auto\"\u003e\u003csvg class=\"octicon octicon-info mr-2\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z\"\u003e\u003c/path\u003e\u003c/svg\u003eNote\u003c/p\u003e\u003cp dir=\"auto\"\u003eNote the \u003ca href=\"https://www.regular-expressions.info/anchors.html\" rel=\"nofollow\"\u003eanchors\u003c/a\u003e: \u003ccode\u003eprint_more\u003c/code\u003e is\na function call as well, but \u003ccode\u003e^print$\u003c/code\u003e ensures it's not matched.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eThe regular expression applies \u003cem\u003eafter\u003c/em\u003e grammar scoping, so operates entirely within\nthe already-scoped context.\u003c/p\u003e\n\u003c/div\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch6 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eRemove all comments (C#)\u003c/h6\u003e\u003ca id=\"user-content-remove-all-comments-c\" class=\"anchor\" aria-label=\"Permalink: Remove all comments (C#)\" href=\"#remove-all-comments-c\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eOverdone, comments can turn into \u003ca href=\"https://refactoring.guru/smells/comments\" rel=\"nofollow\"\u003esmells\u003c/a\u003e. If\nnot tended to, they might very well start lying:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-cs notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"using System.Linq;\n\npublic class UserService\n{\n private readonly AppDbContext _dbContext;\n\n /// \u0026lt;summary\u0026gt;\n /// Initializes a new instance of the \u0026lt;see cref=\u0026quot;FileService\u0026quot;/\u0026gt; class.\n /// \u0026lt;/summary\u0026gt;\n /// \u0026lt;param name=\u0026quot;dbContext\u0026quot;\u0026gt;The configuration for manipulating text.\u0026lt;/param\u0026gt;\n public UserService(AppDbContext dbContext)\n {\n _dbContext /* the logging context */ = dbContext;\n }\n\n /// \u0026lt;summary\u0026gt;\n /// Uploads a file to the server.\n /// \u0026lt;/summary\u0026gt;\n // Method to log users out of the system\n public void DoWork()\n {\n _dbContext.Database.EnsureCreated(); // Ensure the database schema is deleted\n\n _dbContext.Users.Add(new User /* the car */ { Name = \u0026quot;Alice\u0026quot; });\n\n /* Begin reading file */\n _dbContext.SaveChanges();\n\n var user = _dbContext.Users.Where(/* fetch products */ u =\u0026gt; u.Name == \u0026quot;Alice\u0026quot;).FirstOrDefault();\n\n /// Delete all records before proceeding\n if (user /* the product */ != null)\n {\n System.Console.WriteLine($\u0026quot;Found user with ID: {user.Id}\u0026quot;);\n }\n }\n}\"\u003e\u003cpre\u003e\u003cspan class=\"pl-k\"\u003eusing\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003eSystem\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-s1\"\u003eLinq\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e;\u003c/span\u003e\n\n\u003cspan class=\"pl-k\"\u003epublic\u003c/span\u003e \u003cspan class=\"pl-k\"\u003eclass\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eUserService\u003c/span\u003e\n\u003cspan class=\"pl-kos\"\u003e{\u003c/span\u003e\n \u003cspan class=\"pl-k\"\u003eprivate\u003c/span\u003e \u003cspan class=\"pl-k\"\u003ereadonly\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eAppDbContext\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003e_dbContext\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e;\u003c/span\u003e\n\n \u003cspan class=\"pl-c\"\u003e/// \u0026lt;summary\u0026gt;\u003c/span\u003e\n \u003cspan class=\"pl-c\"\u003e/// Initializes a new instance of the \u0026lt;see cref=\"FileService\"/\u0026gt; class.\u003c/span\u003e\n \u003cspan class=\"pl-c\"\u003e/// \u0026lt;/summary\u0026gt;\u003c/span\u003e\n \u003cspan class=\"pl-c\"\u003e/// \u0026lt;param name=\"dbContext\"\u0026gt;The configuration for manipulating text.\u0026lt;/param\u0026gt;\u003c/span\u003e\n \u003cspan class=\"pl-k\"\u003epublic\u003c/span\u003e \u003cspan class=\"pl-v\"\u003eUserService\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-smi\"\u003eAppDbContext\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003edbContext\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\n \u003cspan class=\"pl-kos\"\u003e{\u003c/span\u003e\n \u003cspan class=\"pl-s1\"\u003e_dbContext\u003c/span\u003e \u003cspan class=\"pl-c\"\u003e/* the logging context */\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e=\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003edbContext\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e;\u003c/span\u003e\n \u003cspan class=\"pl-kos\"\u003e}\u003c/span\u003e\n\n \u003cspan class=\"pl-c\"\u003e/// \u0026lt;summary\u0026gt;\u003c/span\u003e\n \u003cspan class=\"pl-c\"\u003e/// Uploads a file to the server.\u003c/span\u003e\n \u003cspan class=\"pl-c\"\u003e/// \u0026lt;/summary\u0026gt;\u003c/span\u003e\n \u003cspan class=\"pl-c\"\u003e// Method to log users out of the system\u003c/span\u003e\n \u003cspan class=\"pl-k\"\u003epublic\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003evoid\u003c/span\u003e \u003cspan class=\"pl-en\"\u003eDoWork\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\n \u003cspan class=\"pl-kos\"\u003e{\u003c/span\u003e\n \u003cspan class=\"pl-s1\"\u003e_dbContext\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-s1\"\u003eDatabase\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eEnsureCreated\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e;\u003c/span\u003e \u003cspan class=\"pl-c\"\u003e// Ensure the database schema is deleted\u003c/span\u003e\n\n \u003cspan class=\"pl-s1\"\u003e_dbContext\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-s1\"\u003eUsers\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eAdd\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-k\"\u003enew\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eUser\u003c/span\u003e \u003cspan class=\"pl-c\"\u003e/* the car */\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e{\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003eName\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e=\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\"Alice\"\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e}\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e;\u003c/span\u003e\n\n \u003cspan class=\"pl-c\"\u003e/* Begin reading file */\u003c/span\u003e\n \u003cspan class=\"pl-s1\"\u003e_dbContext\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eSaveChanges\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e;\u003c/span\u003e\n\n \u003cspan class=\"pl-k\"\u003evar\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003euser\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e=\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003e_dbContext\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-s1\"\u003eUsers\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eWhere\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-c\"\u003e/* fetch products */\u003c/span\u003e u \u003cspan class=\"pl-c1\"\u003e=\u0026gt;\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003eu\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-s1\"\u003eName\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e==\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\"Alice\"\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eFirstOrDefault\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e;\u003c/span\u003e\n\n \u003cspan class=\"pl-c\"\u003e/// Delete all records before proceeding\u003c/span\u003e\n \u003cspan class=\"pl-k\"\u003eif\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-s1\"\u003euser\u003c/span\u003e \u003cspan class=\"pl-c\"\u003e/* the product */\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e!=\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003enull\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\n \u003cspan class=\"pl-kos\"\u003e{\u003c/span\u003e\n \u003cspan class=\"pl-s1\"\u003eSystem\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-s1\"\u003eConsole\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eWriteLine\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-s\"\u003e$\u003c/span\u003e\"Found user with ID: \u003cspan class=\"pl-kos\"\u003e{\u003c/span\u003e\u003cspan class=\"pl-s1\"\u003euser\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-s1\"\u003eId\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e}\u003c/span\u003e\"\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e;\u003c/span\u003e\n \u003cspan class=\"pl-kos\"\u003e}\u003c/span\u003e\n \u003cspan class=\"pl-kos\"\u003e}\u003c/span\u003e\n\u003cspan class=\"pl-kos\"\u003e}\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eSo, should you count purging comments among your fetishes, more power to you:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-shell notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"cat UserService.cs | srgn --csharp 'comments' -d '.*' | srgn -d '[[:blank:]]+\\n'\"\u003e\u003cpre\u003ecat UserService.cs \u003cspan class=\"pl-k\"\u003e|\u003c/span\u003e srgn --csharp \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003ecomments\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e -d \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e.*\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-k\"\u003e|\u003c/span\u003e srgn -d \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e[[:blank:]]+\\n\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eThe result is a tidy, yet taciturn:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-cs notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"using System.Linq;\n\npublic class UserService\n{\n private readonly AppDbContext _dbContext;\n\n public UserService(AppDbContext dbContext)\n {\n _dbContext = dbContext;\n }\n\n public void DoWork()\n {\n _dbContext.Database.EnsureCreated();\n _dbContext.Users.Add(new User { Name = \u0026quot;Alice\u0026quot; });\n\n _dbContext.SaveChanges();\n\n var user = _dbContext.Users.Where( u =\u0026gt; u.Name == \u0026quot;Alice\u0026quot;).FirstOrDefault();\n\n if (user != null)\n {\n System.Console.WriteLine($\u0026quot;Found user with ID: {user.Id}\u0026quot;);\n }\n }\n}\"\u003e\u003cpre\u003e\u003cspan class=\"pl-k\"\u003eusing\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003eSystem\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-s1\"\u003eLinq\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e;\u003c/span\u003e\n\n\u003cspan class=\"pl-k\"\u003epublic\u003c/span\u003e \u003cspan class=\"pl-k\"\u003eclass\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eUserService\u003c/span\u003e\n\u003cspan class=\"pl-kos\"\u003e{\u003c/span\u003e\n \u003cspan class=\"pl-k\"\u003eprivate\u003c/span\u003e \u003cspan class=\"pl-k\"\u003ereadonly\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eAppDbContext\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003e_dbContext\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e;\u003c/span\u003e\n\n \u003cspan class=\"pl-k\"\u003epublic\u003c/span\u003e \u003cspan class=\"pl-v\"\u003eUserService\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-smi\"\u003eAppDbContext\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003edbContext\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\n \u003cspan class=\"pl-kos\"\u003e{\u003c/span\u003e\n \u003cspan class=\"pl-s1\"\u003e_dbContext\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e=\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003edbContext\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e;\u003c/span\u003e\n \u003cspan class=\"pl-kos\"\u003e}\u003c/span\u003e\n\n \u003cspan class=\"pl-k\"\u003epublic\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003evoid\u003c/span\u003e \u003cspan class=\"pl-en\"\u003eDoWork\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\n \u003cspan class=\"pl-kos\"\u003e{\u003c/span\u003e\n \u003cspan class=\"pl-s1\"\u003e_dbContext\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-s1\"\u003eDatabase\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eEnsureCreated\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e;\u003c/span\u003e\n \u003cspan class=\"pl-s1\"\u003e_dbContext\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-s1\"\u003eUsers\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eAdd\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-k\"\u003enew\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eUser\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e{\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003eName\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e=\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\"Alice\"\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e}\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e;\u003c/span\u003e\n\n \u003cspan class=\"pl-s1\"\u003e_dbContext\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eSaveChanges\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e;\u003c/span\u003e\n\n \u003cspan class=\"pl-k\"\u003evar\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003euser\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e=\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003e_dbContext\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-s1\"\u003eUsers\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eWhere\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e u \u003cspan class=\"pl-c1\"\u003e=\u0026gt;\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003eu\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-s1\"\u003eName\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e==\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\"Alice\"\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eFirstOrDefault\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e;\u003c/span\u003e\n\n \u003cspan class=\"pl-k\"\u003eif\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-s1\"\u003euser\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e!=\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003enull\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\n \u003cspan class=\"pl-kos\"\u003e{\u003c/span\u003e\n \u003cspan class=\"pl-s1\"\u003eSystem\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-s1\"\u003eConsole\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eWriteLine\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-s\"\u003e$\u003c/span\u003e\"Found user with ID: \u003cspan class=\"pl-kos\"\u003e{\u003c/span\u003e\u003cspan class=\"pl-s1\"\u003euser\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-s1\"\u003eId\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e}\u003c/span\u003e\"\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e;\u003c/span\u003e\n \u003cspan class=\"pl-kos\"\u003e}\u003c/span\u003e\n \u003cspan class=\"pl-kos\"\u003e}\u003c/span\u003e\n\u003cspan class=\"pl-kos\"\u003e}\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eNote how all\n\u003ca href=\"https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/tokens/comments\" rel=\"nofollow\"\u003edifferent\u003c/a\u003e\n\u003ca href=\"https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/xmldoc/\" rel=\"nofollow\"\u003esorts\u003c/a\u003e of\ncomments were identified and removed. The second pass removes all leftover dangling\nlines (\u003ccode\u003e[:blank:]\u003c/code\u003e is \u003ca href=\"https://docs.rs/regex/latest/regex/#ascii-character-classes\" rel=\"nofollow\"\u003etabs and\nspaces\u003c/a\u003e).\u003c/p\u003e\n\u003cdiv class=\"markdown-alert markdown-alert-note\" dir=\"auto\"\u003e\u003cp class=\"markdown-alert-title\" dir=\"auto\"\u003e\u003csvg class=\"octicon octicon-info mr-2\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z\"\u003e\u003c/path\u003e\u003c/svg\u003eNote\u003c/p\u003e\u003cp dir=\"auto\"\u003eWhen deleting (\u003ccode\u003e-d\u003c/code\u003e), for reasons of safety and sanity, a scope is \u003cem\u003erequired\u003c/em\u003e.\u003c/p\u003e\n\u003c/div\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch6 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eUpgrade VM size (Terraform)\u003c/h6\u003e\u003ca id=\"user-content-upgrade-vm-size-terraform\" class=\"anchor\" aria-label=\"Permalink: Upgrade VM size (Terraform)\" href=\"#upgrade-vm-size-terraform\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eSay you'd like to upgrade the instance size you're using:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-hcl notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"data \u0026quot;aws_ec2_instance_type\u0026quot; \u0026quot;tiny\u0026quot; {\n instance_type = \u0026quot;t2.micro\u0026quot;\n}\n\nresource \u0026quot;aws_instance\u0026quot; \u0026quot;main\u0026quot; {\n ami = \u0026quot;ami-022f20bb44daf4c86\u0026quot;\n instance_type = data.aws_ec2_instance_type.tiny.instance_type\n}\"\u003e\u003cpre\u003e\u003cspan class=\"pl-en\"\u003edata\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003e\"aws_ec2_instance_type\"\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003e\"tiny\"\u003c/span\u003e {\n \u003cspan class=\"pl-v\"\u003e\u003cspan class=\"pl-smi\"\u003einstance_type\u003c/span\u003e \u003cspan class=\"pl-k\"\u003e=\u003c/span\u003e \u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003et2.micro\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003c/span\u003e\n}\n\n\u003cspan class=\"pl-en\"\u003eresource\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003e\"aws_instance\"\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003e\"main\"\u003c/span\u003e {\n \u003cspan class=\"pl-v\"\u003e\u003cspan class=\"pl-smi\"\u003eami\u003c/span\u003e \u003cspan class=\"pl-k\"\u003e=\u003c/span\u003e \u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003eami-022f20bb44daf4c86\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003c/span\u003e\n \u003cspan class=\"pl-v\"\u003e\u003cspan class=\"pl-smi\"\u003einstance_type\u003c/span\u003e \u003cspan class=\"pl-k\"\u003e=\u003c/span\u003e \u003c/span\u003edata\u003cspan class=\"pl-k\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-smi\"\u003eaws_ec2_instance_type\u003c/span\u003e\u003cspan class=\"pl-k\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-smi\"\u003etiny\u003c/span\u003e\u003cspan class=\"pl-k\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-smi\"\u003einstance_type\u003c/span\u003e\n}\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003ewith\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-shell notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"cat ec2.tf | srgn --hcl 'strings' '^t2\\.(\\w+)$' 't3.$1' | srgn --hcl 'data-names' 'tiny' 'small'\"\u003e\u003cpre\u003ecat ec2.tf \u003cspan class=\"pl-k\"\u003e|\u003c/span\u003e srgn --hcl \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003estrings\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e^t2\\.(\\w+)$\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003et3.$1\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-k\"\u003e|\u003c/span\u003e srgn --hcl \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003edata-names\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003etiny\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003esmall\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003ewill give\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-hcl notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"data \u0026quot;aws_ec2_instance_type\u0026quot; \u0026quot;small\u0026quot; {\n instance_type = \u0026quot;t3.micro\u0026quot;\n}\n\nresource \u0026quot;aws_instance\u0026quot; \u0026quot;main\u0026quot; {\n ami = \u0026quot;ami-022f20bb44daf4c86\u0026quot;\n instance_type = data.aws_ec2_instance_type.small.instance_type\n}\"\u003e\u003cpre\u003e\u003cspan class=\"pl-en\"\u003edata\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003e\"aws_ec2_instance_type\"\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003e\"small\"\u003c/span\u003e {\n \u003cspan class=\"pl-v\"\u003e\u003cspan class=\"pl-smi\"\u003einstance_type\u003c/span\u003e \u003cspan class=\"pl-k\"\u003e=\u003c/span\u003e \u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003et3.micro\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003c/span\u003e\n}\n\n\u003cspan class=\"pl-en\"\u003eresource\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003e\"aws_instance\"\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003e\"main\"\u003c/span\u003e {\n \u003cspan class=\"pl-v\"\u003e\u003cspan class=\"pl-smi\"\u003eami\u003c/span\u003e \u003cspan class=\"pl-k\"\u003e=\u003c/span\u003e \u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003eami-022f20bb44daf4c86\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003c/span\u003e\n \u003cspan class=\"pl-v\"\u003e\u003cspan class=\"pl-smi\"\u003einstance_type\u003c/span\u003e \u003cspan class=\"pl-k\"\u003e=\u003c/span\u003e \u003c/span\u003edata\u003cspan class=\"pl-k\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-smi\"\u003eaws_ec2_instance_type\u003c/span\u003e\u003cspan class=\"pl-k\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-smi\"\u003esmall\u003c/span\u003e\u003cspan class=\"pl-k\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-smi\"\u003einstance_type\u003c/span\u003e\n}\u003c/pre\u003e\u003c/div\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch6 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eRename function (C)\u003c/h6\u003e\u003ca id=\"user-content-rename-function-c\" class=\"anchor\" aria-label=\"Permalink: Rename function (C)\" href=\"#rename-function-c\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eYou can rename a function:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-c notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"void old_function_name(void) {\n ///\n int variable_in_old_function_name;\n ///\n}\n\nint main(void) {\n old_function_name();\n}\"\u003e\u003cpre\u003e\u003cspan class=\"pl-smi\"\u003evoid\u003c/span\u003e \u003cspan class=\"pl-en\"\u003eold_function_name\u003c/span\u003e(\u003cspan class=\"pl-smi\"\u003evoid\u003c/span\u003e) {\n \u003cspan class=\"pl-c\"\u003e///\u003c/span\u003e\n \u003cspan class=\"pl-smi\"\u003eint\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003evariable_in_old_function_name\u003c/span\u003e;\n \u003cspan class=\"pl-c\"\u003e///\u003c/span\u003e\n}\n\n\u003cspan class=\"pl-smi\"\u003eint\u003c/span\u003e \u003cspan class=\"pl-en\"\u003emain\u003c/span\u003e(\u003cspan class=\"pl-smi\"\u003evoid\u003c/span\u003e) {\n \u003cspan class=\"pl-en\"\u003eold_function_name\u003c/span\u003e();\n}\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eusing\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-shell notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"cat function.c | srgn --c 'function' 'old_function_name' 'new_function_name'\"\u003e\u003cpre\u003ecat function.c \u003cspan class=\"pl-k\"\u003e|\u003c/span\u003e srgn --c \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003efunction\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003eold_function_name\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003enew_function_name\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003ewhich will give\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-c notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"void new_function_name(void) {\n ///\n int variable_in_old_function_name;\n ///\n}\n\nint main(void) {\n new_function_name();\n}\"\u003e\u003cpre\u003e\u003cspan class=\"pl-smi\"\u003evoid\u003c/span\u003e \u003cspan class=\"pl-en\"\u003enew_function_name\u003c/span\u003e(\u003cspan class=\"pl-smi\"\u003evoid\u003c/span\u003e) {\n \u003cspan class=\"pl-c\"\u003e///\u003c/span\u003e\n \u003cspan class=\"pl-smi\"\u003eint\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003evariable_in_old_function_name\u003c/span\u003e;\n \u003cspan class=\"pl-c\"\u003e///\u003c/span\u003e\n}\n\n\u003cspan class=\"pl-smi\"\u003eint\u003c/span\u003e \u003cspan class=\"pl-en\"\u003emain\u003c/span\u003e(\u003cspan class=\"pl-smi\"\u003evoid\u003c/span\u003e) {\n \u003cspan class=\"pl-en\"\u003enew_function_name\u003c/span\u003e();\n}\u003c/pre\u003e\u003c/div\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch5 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eCustom queries\u003c/h5\u003e\u003ca id=\"user-content-custom-queries\" class=\"anchor\" aria-label=\"Permalink: Custom queries\" href=\"#custom-queries\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eCustom queries allow you to create ad-hoc scopes. These might be useful, for example, to\ncreate small, ad-hoc, tailor-made linters, for example to catch code such as:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-python notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"if x:\n return left\nelse:\n return right\"\u003e\u003cpre\u003e\u003cspan class=\"pl-k\"\u003eif\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003ex\u003c/span\u003e:\n \u003cspan class=\"pl-k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003eleft\u003c/span\u003e\n\u003cspan class=\"pl-k\"\u003eelse\u003c/span\u003e:\n \u003cspan class=\"pl-k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003eright\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003ewith an invocation of\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-shell notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"cat cond.py | srgn --python-query '(if_statement consequence: (block (return_statement (identifier))) alternative: (else_clause body: (block (return_statement (identifier))))) @cond' --fail-any # will fail\"\u003e\u003cpre\u003ecat cond.py \u003cspan class=\"pl-k\"\u003e|\u003c/span\u003e srgn --python-query \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e(if_statement consequence: (block (return_statement (identifier))) alternative: (else_clause body: (block (return_statement (identifier))))) @cond\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e --fail-any \u003cspan class=\"pl-c\"\u003e\u003cspan class=\"pl-c\"\u003e#\u003c/span\u003e will fail\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eto hint that the code can be more idiomatically rewritten as \u003ccode\u003ereturn left if x else right\u003c/code\u003e. Another example, this one in Go, is ensuring sensitive fields are not\nserialized:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-go notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"package main\n\ntype User struct {\n Name string `json:\u0026quot;name\u0026quot;`\n Token string `json:\u0026quot;token\u0026quot;`\n}\"\u003e\u003cpre\u003e\u003cspan class=\"pl-k\"\u003epackage\u003c/span\u003e main\n\n\u003cspan class=\"pl-k\"\u003etype\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eUser\u003c/span\u003e \u003cspan class=\"pl-k\"\u003estruct\u003c/span\u003e {\n \u003cspan class=\"pl-c1\"\u003eName\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003estring\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e`json:\"name\"`\u003c/span\u003e\n \u003cspan class=\"pl-c1\"\u003eToken\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003estring\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e`json:\"token\"`\u003c/span\u003e\n}\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003ewhich can be caught as:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-shell notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"cat sensitive.go | srgn --go-query '(field_declaration name: (field_identifier) @name tag: (raw_string_literal) @tag (#match? @name \u0026quot;[tT]oken\u0026quot;) (#not-eq? @tag \u0026quot;`json:\\\u0026quot;-\\\u0026quot;`\u0026quot;))' --fail-any # will fail\"\u003e\u003cpre\u003ecat sensitive.go \u003cspan class=\"pl-k\"\u003e|\u003c/span\u003e srgn --go-query \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e(field_declaration name: (field_identifier) @name tag: (raw_string_literal) @tag (#match? @name \"[tT]oken\") (#not-eq? @tag \"`json:\\\"-\\\"`\"))\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e --fail-any \u003cspan class=\"pl-c\"\u003e\u003cspan class=\"pl-c\"\u003e#\u003c/span\u003e will fail\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch5 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eCustom queries from file\u003c/h5\u003e\u003ca id=\"user-content-custom-queries-from-file\" class=\"anchor\" aria-label=\"Permalink: Custom queries from file\" href=\"#custom-queries-from-file\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eTyping out tree-sitter queries at the CLI can be unwieldy. To mitigate this you can read queries from \u003ca href=\"/alexpovel/srgn/blob/main/docs/python_cond_query.scm\"\u003efile\u003c/a\u003e.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eBelow we use the same Python file from the previous section with an invocation of\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-shell notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"cat cond.py | srgn --python-query-file 'docs/python_cond_query.scm'\n1:if x:\n2: return left\n3:else:\n4: return right\"\u003e\u003cpre\u003ecat cond.py \u003cspan class=\"pl-k\"\u003e|\u003c/span\u003e srgn --python-query-file \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003edocs/python_cond_query.scm\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e\n1:if x:\n2: \u003cspan class=\"pl-k\"\u003ereturn\u003c/span\u003e left\n3:else:\n4: \u003cspan class=\"pl-k\"\u003ereturn\u003c/span\u003e right\u003c/pre\u003e\u003c/div\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch6 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eIgnoring parts of matches\u003c/h6\u003e\u003ca id=\"user-content-ignoring-parts-of-matches\" class=\"anchor\" aria-label=\"Permalink: Ignoring parts of matches\" href=\"#ignoring-parts-of-matches\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eOccassionally, parts of a match need to be ignored, for example when no suitable\ntree-sitter node type is available. For example, say we'd like to replace the \u003ccode\u003eerror\u003c/code\u003e\nwith \u003ccode\u003ewrong\u003c/code\u003e inside the string of the macro body:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-rust notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"fn wrong() {\n let wrong = \u0026quot;wrong\u0026quot;;\n error!(\u0026quot;This went error\u0026quot;);\n}\"\u003e\u003cpre\u003e\u003cspan class=\"pl-k\"\u003efn\u003c/span\u003e \u003cspan class=\"pl-en\"\u003ewrong\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e{\u003c/span\u003e\n \u003cspan class=\"pl-k\"\u003elet\u003c/span\u003e wrong = \u003cspan class=\"pl-s\"\u003e\"wrong\"\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e;\u003c/span\u003e\n \u003cspan class=\"pl-en\"\u003eerror\u003c/span\u003e\u003cspan class=\"pl-en\"\u003e!\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\"This went error\"\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e;\u003c/span\u003e\n\u003cspan class=\"pl-kos\"\u003e}\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eLet's assume there's a node type for matching \u003cem\u003eentire\u003c/em\u003e macros (\u003ccode\u003emacro_invocation\u003c/code\u003e) and\none to match macro \u003cem\u003enames\u003c/em\u003e (\u003ccode\u003e((macro_invocation macro: (identifier) @name))\u003c/code\u003e), but\n\u003cem\u003enone\u003c/em\u003e to match macro \u003cem\u003econtents\u003c/em\u003e (this is wrong, tree-sitter offers this in the form of\n\u003ccode\u003etoken_tree\u003c/code\u003e, but let's imagine...). To match just \u003ccode\u003e\"This went error\"\u003c/code\u003e, the entire macro\nwould need to be matched, with the name part ignored. Any capture name starting with\n\u003ccode\u003e_SRGN_IGNORE\u003c/code\u003e will provide just that:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-shell notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"cat wrong.rs | srgn --rust-query '((macro_invocation macro: (identifier) @_SRGN_IGNORE_name) @macro)' 'error' 'wrong'\"\u003e\u003cpre\u003ecat wrong.rs \u003cspan class=\"pl-k\"\u003e|\u003c/span\u003e srgn --rust-query \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e((macro_invocation macro: (identifier) @_SRGN_IGNORE_name) @macro)\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003eerror\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003ewrong\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cdiv class=\"highlight highlight-source-rust notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"fn wrong() {\n let wrong = \u0026quot;wrong\u0026quot;;\n error!(\u0026quot;This went wrong\u0026quot;);\n}\"\u003e\u003cpre\u003e\u003cspan class=\"pl-k\"\u003efn\u003c/span\u003e \u003cspan class=\"pl-en\"\u003ewrong\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e{\u003c/span\u003e\n \u003cspan class=\"pl-k\"\u003elet\u003c/span\u003e wrong = \u003cspan class=\"pl-s\"\u003e\"wrong\"\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e;\u003c/span\u003e\n \u003cspan class=\"pl-en\"\u003eerror\u003c/span\u003e\u003cspan class=\"pl-en\"\u003e!\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\"This went wrong\"\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e;\u003c/span\u003e\n\u003cspan class=\"pl-kos\"\u003e}\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eIf it weren't ignored, the result would read \u003ccode\u003ewrong!(\"This went wrong\");\u003c/code\u003e.\u003c/p\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch6 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eFurther reading\u003c/h6\u003e\u003ca id=\"user-content-further-reading\" class=\"anchor\" aria-label=\"Permalink: Further reading\" href=\"#further-reading\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eThese matching expressions are a mouthful. A couple resources exist for getting started\nwith your own queries:\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003ethe \u003ca href=\"https://tree-sitter.github.io/tree-sitter/using-parsers#pattern-matching-with-queries\" rel=\"nofollow\"\u003eofficial docs on\nquerying\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003ethe great \u003ca href=\"https://tree-sitter.github.io/tree-sitter/playground\" rel=\"nofollow\"\u003eofficial playground\u003c/a\u003e\nfor interactive use, which makes developing queries a breeze. For example, the above\nGo sample looks like:\u003c/p\u003e\n\u003cp dir=\"auto\"\u003e\u003ca target=\"_blank\" rel=\"noopener noreferrer\" href=\"/alexpovel/srgn/blob/main/docs/images/tree-sitter-playground-go-example.png\"\u003e\u003cimg src=\"/alexpovel/srgn/raw/main/docs/images/tree-sitter-playground-go-example.png\" alt=\"tree-sitter playground go example\" style=\"max-width: 100%;\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003e\u003ca href=\"https://siraben.dev/2022/03/22/tree-sitter-linter.html\" rel=\"nofollow\"\u003e\u003cem\u003eHow to write a linter using tree-sitter in an\nhour\u003c/em\u003e\u003c/a\u003e, a great introduction\nto the topic in general\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003ethe official \u003ca href=\"https://github.com/tree-sitter/tree-sitter/blob/master/cli/README.md\"\u003e\u003ccode\u003etree-sitter\u003c/code\u003e\nCLI\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003eusing \u003ccode\u003esrgn\u003c/code\u003e with high verbosity (\u003ccode\u003e-vvvv\u003c/code\u003e) is supposed to grant detailed insights into\nwhat's happening to your input, including a \u003ca href=\"https://docs.rs/tree-sitter/latest/tree_sitter/struct.Node.html#method.to_sexp\" rel=\"nofollow\"\u003erepresentation of the parsed\ntree\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch4 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eRun against multiple files\u003c/h4\u003e\u003ca id=\"user-content-run-against-multiple-files\" class=\"anchor\" aria-label=\"Permalink: Run against multiple files\" href=\"#run-against-multiple-files\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eUse the \u003ccode\u003e--glob\u003c/code\u003e option to run against multiple files, in-place. This option accepts a\n\u003ca href=\"https://docs.rs/glob/0.3.1/glob/struct.Pattern.html\" rel=\"nofollow\"\u003eglob pattern\u003c/a\u003e. The glob is\nprocessed \u003cem\u003ewithin \u003ccode\u003esrgn\u003c/code\u003e\u003c/em\u003e: it must be quoted to prevent premature shell interpretation.\nThe \u003ccode\u003e--glob\u003c/code\u003e option takes precedence over the heuristics of language scoping. For\nexample,\u003c/p\u003e\n\n\u003cdiv class=\"highlight highlight-text-shell-session notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"$ srgn --go 'comments' --glob 'tests/langs/go/fizz*.go' '\\w+'\ntests/langs/go/fizzbuzz.go\n5:// fizzBuzz prints the numbers from 1 to a specified limit.\n6:// For multiples of 3, it prints \u0026quot;Fizz\u0026quot; instead of the number,\n7:// for multiples of 5, it prints \u0026quot;Buzz\u0026quot;, and for multiples of both 3 and 5,\n8:// it prints \u0026quot;FizzBuzz\u0026quot;.\n25:\t// Run the FizzBuzz function for numbers from 1 to 100\"\u003e\u003cpre\u003e$ \u003cspan class=\"pl-s1\"\u003esrgn --go \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003ecomments\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e --glob \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003etests/langs/go/fizz*.go\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\\w+\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003etests/langs/go/fizzbuzz.go\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e5:// fizzBuzz prints the numbers from 1 to a specified limit.\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e6:// For multiples of 3, it prints \"Fizz\" instead of the number,\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e7:// for multiples of 5, it prints \"Buzz\", and for multiples of both 3 and 5,\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e8:// it prints \"FizzBuzz\".\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e25:\t// Run the FizzBuzz function for numbers from 1 to 100\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\n\u003cp dir=\"auto\"\u003efinds only what's matched by the (narrow) glob, even though \u003ccode\u003e--go\u003c/code\u003e queries by themselves\nwould match much more.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003e\u003ccode\u003esrgn\u003c/code\u003e will process results fully parallel, using all available threads. For example,\n\u003cstrong\u003e\u003ca href=\"/alexpovel/srgn/blob/main/benches/django\"\u003e450k lines of Python\u003c/a\u003e are processed in about a second\u003c/strong\u003e, altering\nover 1000 lines across a couple hundred files:\u003c/p\u003e\n\u003cp dir=\"auto\"\u003e\u003ca target=\"_blank\" rel=\"noopener noreferrer\" href=\"/alexpovel/srgn/blob/main/docs/images/files-benchmarks.png\"\u003e\u003cimg src=\"/alexpovel/srgn/raw/main/docs/images/files-benchmarks.png\" alt=\"hyperfine benchmarks for files option\" style=\"max-width: 100%;\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eRun the \u003ca href=\"/alexpovel/srgn/blob/main/benches/bench-files.sh\"\u003ebenchmarks\u003c/a\u003e too see performance for your own system.\u003c/p\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch4 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eExplicit failure for (mis)matches\u003c/h4\u003e\u003ca id=\"user-content-explicit-failure-for-mismatches\" class=\"anchor\" aria-label=\"Permalink: Explicit failure for (mis)matches\" href=\"#explicit-failure-for-mismatches\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eAfter all scopes are applied, it might turn out no matches were found. The default\nbehavior is to silently succeed:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-text-shell-session notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"$ echo 'Some input...' | srgn --delete '\\d'\nSome input...\"\u003e\u003cpre\u003e$ \u003cspan class=\"pl-s1\"\u003e\u003cspan class=\"pl-c1\"\u003eecho\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003eSome input...\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-k\"\u003e|\u003c/span\u003e srgn --delete \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\\d\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003eSome input...\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eThe output matches the specification: all digits are removed. There just happened to be\nnone. No matter how many actions are applied, \u003cstrong\u003ethe input is returned unprocessed\u003c/strong\u003e once\nthis situation is detected. Hence, no unnecessary work is done.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eOne might prefer receiving explicit feedback (exit code other than zero) on failure:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-shell notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"echo 'Some input...' | srgn --delete --fail-none '\\d' # will fail\"\u003e\u003cpre\u003e\u003cspan class=\"pl-c1\"\u003eecho\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003eSome input...\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-k\"\u003e|\u003c/span\u003e srgn --delete --fail-none \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\\d\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-c\"\u003e\u003cspan class=\"pl-c\"\u003e#\u003c/span\u003e will fail\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eThe inverse scenario is also supported: \u003cstrong\u003efailing if anything matched\u003c/strong\u003e. This is useful\nfor checks (for example, in CI) against \"undesirable\" content. This works much like a\ncustom, ad-hoc linter.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eTake for example \"old-style\" Python code, where type hints are not yet \u003ca href=\"https://docs.python.org/3/library/typing.html\" rel=\"nofollow\"\u003esurfaced to the\nsyntax-level\u003c/a\u003e:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-python notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"def square(a):\n \u0026quot;\u0026quot;\u0026quot;Squares a number.\n\n :param a: The number (type: int or float)\n \u0026quot;\u0026quot;\u0026quot;\n\n return a**2\"\u003e\u003cpre\u003e\u003cspan class=\"pl-k\"\u003edef\u003c/span\u003e \u003cspan class=\"pl-en\"\u003esquare\u003c/span\u003e(\u003cspan class=\"pl-s1\"\u003ea\u003c/span\u003e):\n \u003cspan class=\"pl-s\"\u003e\"\"\"Squares a number.\u003c/span\u003e\n\u003cspan class=\"pl-s\"\u003e\u003c/span\u003e\n\u003cspan class=\"pl-s\"\u003e :param a: The number (type: int or float)\u003c/span\u003e\n\u003cspan class=\"pl-s\"\u003e \"\"\"\u003c/span\u003e\n\n \u003cspan class=\"pl-k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003ea\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003e**\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003e2\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eThis style can be checked against and \"forbidden\" using:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-shell notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"cat oldtyping.py | srgn --python 'doc-strings' --fail-any 'param.+type' # will fail\"\u003e\u003cpre\u003ecat oldtyping.py \u003cspan class=\"pl-k\"\u003e|\u003c/span\u003e srgn --python \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003edoc-strings\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e --fail-any \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003eparam.+type\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-c\"\u003e\u003cspan class=\"pl-c\"\u003e#\u003c/span\u003e will fail\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch4 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eLiteral scope\u003c/h4\u003e\u003ca id=\"user-content-literal-scope\" class=\"anchor\" aria-label=\"Permalink: Literal scope\" href=\"#literal-scope\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eThis causes whatever was passed as the regex scope to be interpreted literally. Useful\nfor scopes containing lots of special characters that otherwise would need to be\nescaped:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-text-shell-session notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"$ echo 'stuff...' | srgn -d --literal-string '.'\nstuff\"\u003e\u003cpre\u003e$ \u003cspan class=\"pl-s1\"\u003e\u003cspan class=\"pl-c1\"\u003eecho\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003estuff...\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-k\"\u003e|\u003c/span\u003e srgn -d --literal-string \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e.\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003estuff\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch3 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eHelp output\u003c/h3\u003e\u003ca id=\"user-content-help-output\" class=\"anchor\" aria-label=\"Permalink: Help output\" href=\"#help-output\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eFor reference, the full help output with all available options is given below. As with\nall other snippets, the output is validated for correctness as part of \u003ca href=\"/alexpovel/srgn/blob/main/tests/readme.rs\"\u003eunit\ntests\u003c/a\u003e. Checkout git tags to view help output of specific versions.\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-text-shell-session notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"$ srgn --help\nA grep-like tool which understands source code syntax and allows for manipulation in\naddition to search\n\nUsage: srgn [OPTIONS] [SCOPE] [REPLACEMENT]\n\nArguments:\n [SCOPE]\n Scope to apply to, as a regular expression pattern.\n \n If string literal mode is requested, will be interpreted as a literal\n string.\n \n Actions will apply their transformations within this scope only.\n \n The default is the global scope, matching the entire input. Where that\n default is meaningless or dangerous (e.g., deletion), this argument is\n required.\n \n [default: .*]\n\nOptions:\n --completions \u0026lt;SHELL\u0026gt;\n Print shell completions for the given shell.\n \n [possible values: bash, elvish, fish, powershell, zsh]\n\n -h, --help\n Print help (see a summary with '-h')\n\n -V, --version\n Print version\n\nComposable Actions:\n -u, --upper\n Uppercase anything in scope.\n \n [env: UPPER=]\n\n -l, --lower\n Lowercase anything in scope.\n \n [env: LOWER=]\n\n -t, --titlecase\n Titlecase anything in scope.\n \n [env: TITLECASE=]\n\n -n, --normalize\n Normalize (Normalization Form D) anything in scope, and throw away marks.\n \n [env: NORMALIZE=]\n\n -g, --german\n Perform substitutions on German words, such as 'Abenteuergruesse' to\n 'Abenteuergrüße', for anything in scope.\n \n ASCII spellings for Umlauts (ae, oe, ue) and Eszett (ss) are replaced by\n their respective native Unicode (ä, ö, ü, ß).\n \n Arbitrary compound words are supported.\n \n Words legally containing alternative spellings are not modified.\n \n Words require correct spelling to be detected.\n\n -S, --symbols\n Perform substitutions on symbols, such as '!=' to '≠', '-\u0026gt;' to '→', on\n anything in scope.\n \n Helps translate 'ASCII art' into native Unicode representations.\n\n [REPLACEMENT]\n Replace anything in scope with this value.\n \n Variables are supported: if a regex pattern was used for scoping and\n captured content in named or numbered capture groups, access these in the\n replacement value using `$1` etc. for numbered, `$NAME` etc. for named\n capture groups.\n \n This action is specially treated as a positional argument for ergonomics and\n compatibility with `tr`.\n \n If given, will run before any other action.\n \n [env: REPLACE=]\n\nStandalone Actions (only usable alone):\n -d, --delete\n Delete anything in scope.\n \n Cannot be used with any other action: there is no point in deleting and\n performing any other processing. Sibling actions would either receive empty\n input or have their work wiped.\n\n -s, --squeeze\n Squeeze consecutive occurrences of scope into one.\n \n [env: SQUEEZE=]\n [aliases: squeeze-repeats]\n\nOptions (global):\n -G, --glob \u0026lt;GLOB\u0026gt;\n Glob of files to work on (instead of reading stdin).\n \n If actions are applied, they overwrite files in-place.\n \n For supported glob syntax, see:\n \u0026lt;https://docs.rs/glob/0.3.1/glob/struct.Pattern.html\u0026gt;\n \n Names of processed files are written to stdout.\n\n --fail-no-files\n Fail if working on files (e.g. globbing is requested) but none are found.\n \n Processing no files is not an error condition in itself, but might be an\n unexpected outcome in some contexts. This flag makes the condition explicit.\n\n --dry-run\n Do not destructively overwrite files, instead print rich diff only.\n \n The diff details the names of files which would be modified, alongside all\n changes inside those files which would be performed outside of dry running.\n It is similar to git diff with word diffing enabled.\n\n -i, --invert\n Undo the effects of passed actions, where applicable.\n \n Requires a 1:1 mapping between replacements and original, which is currently\n available only for:\n \n - symbols: '≠' \u0026lt;-\u0026gt; '!=' etc.\n \n Other actions:\n \n - german: inverting e.g. 'Ä' is ambiguous (can be 'Ae' or 'AE')\n \n - upper, lower, deletion, squeeze: inversion is impossible as information is\n lost\n \n These may still be passed, but will be ignored for inversion and applied\n normally.\n \n [env: INVERT=]\n\n -L, --literal-string\n Do not interpret the scope as a regex. Instead, interpret it as a literal\n string. Will require a scope to be passed.\n \n [env: LITERAL_STRING=]\n\n --fail-any\n If anything at all is found to be in scope, fail.\n \n The default is to continue processing normally.\n\n --fail-none\n If nothing is found to be in scope, fail.\n \n The default is to return the input unchanged (without failure).\n\n -j, --join-language-scopes\n Join (logical 'OR') multiple language scopes, instead of intersecting them.\n \n The default when multiple language scopes are given is to intersect their\n scopes, left to right. For example, `--go func --go strings` will first\n scope down to `func` bodies, then look for strings only within those. This\n flag instead joins (in the set logic sense) all scopes. The example would\n then scope any `func` bodies, and any strings, anywhere. Language scopers\n can then also be given in any order.\n \n No effect if only a single language scope is given. Also does not affect\n non-language scopers (regex pattern etc.), which always intersect.\n\n -H, --hidden\n Do not ignore hidden files and directories.\n\n --gitignored\n Do not ignore `.gitignore`d files and directories.\n\n --sorted\n Process files in lexicographically sorted order, by file path.\n \n In search mode, this emits results in sorted order. Otherwise, it processes\n files in sorted order.\n \n Sorted processing disables parallel processing.\n\n --threads \u0026lt;THREADS\u0026gt;\n Number of threads to run processing on, when working with files.\n \n If not specified, will default to available parallelism. Set to 1 for\n sequential, deterministic (but not sorted) output.\n\n -v, --verbose...\n Increase log verbosity level.\n \n The base log level to use is read from the `RUST_LOG` environment variable\n (if unspecified, defaults to 'error'), and increased according to the number\n of times this flag is given, maxing out at 'trace' verbosity.\n\nLanguage scopes:\n --c \u0026lt;C\u0026gt;\n Scope C code using a prepared query.\n \n [env: C=]\n\n Possible values:\n - comments: Comments (single- and multi-line)\n - strings: Strings\n - includes: Includes\n - type-def: Type definitions\n - enum: `enum` definitions\n - struct: `struct` type definitions\n - variable: Variable definitions\n - function: All functions usages (declarations and calls)\n - function-def: Function definitions\n - function-decl: Function declaration\n - switch: `switch` blocks\n - if: `if` blocks\n - for: `for` blocks\n - while: `while` blocks\n - do: `do` blocks\n - union: `union` blocks\n - identifier: Identifier\n - declaration: Declaration\n - call-expression: Call expression\n\n --c-query \u0026lt;TREE-SITTER-QUERY-VALUE\u0026gt;\n Scope C code using a custom tree-sitter query.\n \n [env: C_QUERY=]\n\n --c-query-file \u0026lt;TREE-SITTER-QUERY-FILENAME\u0026gt;\n Scope C code using a custom tree-sitter query from file.\n \n [env: C_QUERY_FILE=]\n\n --csharp \u0026lt;CSHARP\u0026gt;\n Scope C# code using a prepared query.\n \n [env: CSHARP=]\n [aliases: cs]\n\n Possible values:\n - comments: Comments (including XML, inline, doc comments)\n - strings: Strings (incl. verbatim, interpolated; incl. quotes,\n except for interpolated)\n - usings: `using` directives (including periods)\n - struct: `struct` definitions (in their entirety)\n - enum: `enum` definitions (in their entirety)\n - interface: `interface` definitions (in their entirety)\n - class: `class` definitions (in their entirety)\n - method: Method definitions (in their entirety)\n - variable-declaration: Variable declarations (in their entirety)\n - property: Property definitions (in their entirety)\n - constructor: Constructor definitions (in their entirety)\n - destructor: Destructor definitions (in their entirety)\n - field: Field definitions on types (in their entirety)\n - attribute: Attribute names\n - identifier: Identifier names\n\n --csharp-query \u0026lt;TREE-SITTER-QUERY-VALUE\u0026gt;\n Scope C# code using a custom tree-sitter query.\n \n [env: CSHARP_QUERY=]\n\n --csharp-query-file \u0026lt;TREE-SITTER-QUERY-FILENAME\u0026gt;\n Scope C# code using a custom tree-sitter query from file.\n \n [env: CSHARP_QUERY_FILE=]\n\n --go \u0026lt;GO\u0026gt;\n Scope Go code using a prepared query.\n \n [env: GO=]\n\n Possible values:\n - comments: Comments (single- and multi-line)\n - strings: Strings (interpreted and raw; excluding struct tags)\n - imports: Imports\n - expression: Expressions (all of them!)\n - type-def: Type definitions\n - type-alias: Type alias assignments\n - struct: `struct` type definitions\n - struct~\u0026lt;PATTERN\u0026gt;: Like struct, but only considers items whose name matches\n PATTERN.\n - interface: `interface` type definitions\n - interface~\u0026lt;PATTERN\u0026gt;: Like interface, but only considers items whose name\n matches PATTERN.\n - const: `const` specifications\n - var: `var` specifications\n - func: `func` definitions\n - func~\u0026lt;PATTERN\u0026gt;: Like func, but only considers items whose name matches\n PATTERN.\n - method: Method `func` definitions (`func (recv Recv) SomeFunc()`)\n - free-func: Free `func` definitions (`func SomeFunc()`)\n - init-func: `func init()` definitions\n - type-params: Type parameters (generics)\n - defer: `defer` blocks\n - select: `select` blocks\n - go: `go` blocks\n - switch: `switch` blocks\n - labeled: Labeled statements\n - goto: `goto` statements\n - struct-tags: Struct tags\n\n --go-query \u0026lt;TREE-SITTER-QUERY-VALUE\u0026gt;\n Scope Go code using a custom tree-sitter query.\n \n [env: GO_QUERY=]\n\n --go-query-file \u0026lt;TREE-SITTER-QUERY-FILENAME\u0026gt;\n Scope Go code using a custom tree-sitter query from file.\n \n [env: GO_QUERY_FILE=]\n\n --hcl \u0026lt;HCL\u0026gt;\n Scope HashiCorp Configuration Language code using a prepared query.\n \n [env: HCL=]\n\n Possible values:\n - variable: `variable` blocks (in their entirety)\n - resource: `resource` blocks (in their entirety)\n - data: `data` blocks (in their entirety)\n - output: `output` blocks (in their entirety)\n - provider: `provider` blocks (in their entirety)\n - terraform: `terraform` blocks (in their entirety)\n - locals: `locals` blocks (in their entirety)\n - module: `module` blocks (in their entirety)\n - variables: Variable declarations and usages\n - resource-names: `resource` name declarations and usages\n - resource-types: `resource` type declarations and usages\n - data-names: `data` name declarations and usages\n - data-sources: `data` source declarations and usages\n - comments: Comments\n - strings: Literal strings\n\n --hcl-query \u0026lt;TREE-SITTER-QUERY-VALUE\u0026gt;\n Scope HashiCorp Configuration Language code using a custom tree-sitter query.\n \n [env: HCL_QUERY=]\n\n --hcl-query-file \u0026lt;TREE-SITTER-QUERY-FILENAME\u0026gt;\n Scope HashiCorp Configuration Language code using a custom tree-sitter query\n from file.\n \n [env: HCL_QUERY_FILE=]\n\n --python \u0026lt;PYTHON\u0026gt;\n Scope Python code using a prepared query.\n \n [env: PYTHON=]\n [aliases: py]\n\n Possible values:\n - comments: Comments\n - strings: Strings (raw, byte, f-strings; interpolation not\n included)\n - imports: Module names in imports (incl. periods; excl.\n `import`/`from`/`as`/`*`)\n - doc-strings: Docstrings (not including multi-line strings)\n - function-names: Function names, at the definition site\n - function-calls: Function calls\n - class: Class definitions (in their entirety)\n - def: Function definitions (*all* `def` block in their\n entirety)\n - async-def: Async function definitions (*all* `async def` block in\n their entirety)\n - methods: Function definitions inside `class` bodies\n - class-methods: Function definitions decorated as `classmethod` (excl.\n the decorator)\n - static-methods: Function definitions decorated as `staticmethod` (excl.\n the decorator)\n - with: `with` blocks (in their entirety)\n - try: `try` blocks (in their entirety)\n - lambda: `lambda` statements (in their entirety)\n - globals: Global, i.e. module-level variables\n - variable-identifiers: Identifiers for variables (left-hand side of\n assignments)\n - types: Types in type hints\n - identifiers: Identifiers (variable names, ...)\n\n --python-query \u0026lt;TREE-SITTER-QUERY-VALUE\u0026gt;\n Scope Python code using a custom tree-sitter query.\n \n [env: PYTHON_QUERY=]\n\n --python-query-file \u0026lt;TREE-SITTER-QUERY-FILENAME\u0026gt;\n Scope Python code using a custom tree-sitter query from file.\n \n [env: PYTHON_QUERY_FILE=]\n\n --rust \u0026lt;RUST\u0026gt;\n Scope Rust code using a prepared query.\n \n [env: RUST=]\n [aliases: rs]\n\n Possible values:\n - comments: Comments (line and block styles; excluding doc comments;\n comment chars incl.)\n - doc-comments: Doc comments (comment chars included)\n - uses: Use statements (paths only; excl. `use`/`as`/`*`)\n - strings: Strings (regular, raw, byte; includes interpolation parts in\n format strings!)\n - attribute: Attributes like `#[attr]`\n - struct: `struct` definitions\n - struct~\u0026lt;PATTERN\u0026gt;: Like struct, but only considers items whose name matches\n PATTERN.\n - priv-struct: `struct` definitions not marked `pub`\n - pub-struct: `struct` definitions marked `pub`\n - pub-crate-struct: `struct` definitions marked `pub(crate)`\n - pub-self-struct: `struct` definitions marked `pub(self)`\n - pub-super-struct: `struct` definitions marked `pub(super)`\n - enum: `enum` definitions\n - enum~\u0026lt;PATTERN\u0026gt;: Like enum, but only considers items whose name matches\n PATTERN.\n - priv-enum: `enum` definitions not marked `pub`\n - pub-enum: `enum` definitions marked `pub`\n - pub-crate-enum: `enum` definitions marked `pub(crate)`\n - pub-self-enum: `enum` definitions marked `pub(self)`\n - pub-super-enum: `enum` definitions marked `pub(super)`\n - enum-variant: Variant members of `enum` definitions\n - fn: Function definitions\n - fn~\u0026lt;PATTERN\u0026gt;: Like fn, but only considers items whose name matches\n PATTERN.\n - impl-fn: Function definitions inside `impl` blocks (associated\n functions/methods)\n - priv-fn: Function definitions not marked `pub`\n - pub-fn: Function definitions marked `pub`\n - pub-crate-fn: Function definitions marked `pub(crate)`\n - pub-self-fn: Function definitions marked `pub(self)`\n - pub-super-fn: Function definitions marked `pub(super)`\n - const-fn: Function definitions marked `const`\n - async-fn: Function definitions marked `async`\n - unsafe-fn: Function definitions marked `unsafe`\n - extern-fn: Function definitions marked `extern`\n - test-fn: Function definitions with attributes containing `test`\n (`#[test]`, `#[rstest]`, ...)\n - trait: `trait` definitions\n - trait~\u0026lt;PATTERN\u0026gt;: Like trait, but only considers items whose name matches\n PATTERN.\n - impl: `impl` blocks\n - impl-type: `impl` blocks for types (`impl SomeType {}`)\n - impl-trait: `impl` blocks for traits on types (`impl SomeTrait for\n SomeType {}`)\n - mod: `mod` blocks\n - mod~\u0026lt;PATTERN\u0026gt;: Like mod, but only considers items whose name matches\n PATTERN.\n - mod-tests: `mod tests` blocks\n - type-def: Type definitions (`struct`, `enum`, `union`)\n - identifier: Identifiers\n - type-identifier: Identifiers for types\n - closure: Closure definitions\n - unsafe: `unsafe` keyword usages (`unsafe fn`, `unsafe` blocks,\n `unsafe Trait`, `unsafe impl Trait`)\n\n --rust-query \u0026lt;TREE-SITTER-QUERY-VALUE\u0026gt;\n Scope Rust code using a custom tree-sitter query.\n \n [env: RUST_QUERY=]\n\n --rust-query-file \u0026lt;TREE-SITTER-QUERY-FILENAME\u0026gt;\n Scope Rust code using a custom tree-sitter query from file.\n \n [env: RUST_QUERY_FILE=]\n\n --typescript \u0026lt;TYPESCRIPT\u0026gt;\n Scope TypeScript code using a prepared query.\n \n [env: TYPESCRIPT=]\n [aliases: ts]\n\n Possible values:\n - comments: Comments\n - strings: Strings (literal, template)\n - imports: Imports (module specifiers)\n - function: Any `function` definitions\n - async-function: `async function` definitions\n - sync-function: Non-`async function` definitions\n - method: Method definitions\n - constructor: `constructor` method definitions\n - class: `class` definitions\n - enum: `enum` definitions\n - interface: `interface` definitions\n - try-catch: `try`/`catch`/`finally` blocks\n - var-decl: Variable declarations (`let`, `const`, `var`)\n - let: `let` variable declarations\n - const: `const` variable declarations\n - var: `var` variable declarations\n - type-params: Type (generic) parameters\n - type-alias: Type alias declarations\n - namespace: `namespace` blocks\n - export: `export` blocks\n\n --typescript-query \u0026lt;TREE-SITTER-QUERY-VALUE\u0026gt;\n Scope TypeScript code using a custom tree-sitter query.\n \n [env: TYPESCRIPT_QUERY=]\n\n --typescript-query-file \u0026lt;TREE-SITTER-QUERY-FILENAME\u0026gt;\n Scope TypeScript code using a custom tree-sitter query from file.\n \n [env: TYPESCRIPT_QUERY_FILE=]\n\nOptions (german):\n --german-prefer-original\n When some original version and its replacement are equally legal, prefer the\n original and do not modify.\n \n For example, \u0026quot;Busse\u0026quot; (original) and \u0026quot;Buße\u0026quot; (replacement) are equally legal\n words: by default, the tool would prefer the latter.\n \n [env: GERMAN_PREFER_ORIGINAL=]\n\n --german-naive\n Always perform any possible replacement ('ae' -\u0026gt; 'ä', 'ss' -\u0026gt; 'ß', etc.),\n regardless of legality of the resulting word\n \n Useful for names, which are otherwise not modifiable as they do not occur in\n dictionaries. Called 'naive' as this does not perform legal checks.\n \n [env: GERMAN_NAIVE=]\"\u003e\u003cpre\u003e$ \u003cspan class=\"pl-s1\"\u003esrgn --help\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003eA grep-like tool which understands source code syntax and allows for manipulation in\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003eaddition to search\u003c/span\u003e\n\n\u003cspan class=\"pl-c1\"\u003eUsage: srgn [OPTIONS] [SCOPE] [REPLACEMENT]\u003c/span\u003e\n\n\u003cspan class=\"pl-c1\"\u003eArguments:\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e [SCOPE]\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e Scope to apply to, as a regular expression pattern.\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e \u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e If string literal mode is requested, will be interpreted as a literal\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e string.\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e \u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e Actions will apply their transformations within this scope only.\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e \u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e The default is the global scope, matching the entire input. Where that\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e default is meaningless or dangerous (e.g., deletion), this argument is\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e required.\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e \u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e [default: .*]\u003c/span\u003e\n\n\u003cspan class=\"pl-c1\"\u003eOptions:\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e --completions \u0026lt;SHELL\u0026gt;\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e Print shell completions for the given shell.\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e \u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e [possible values: bash, elvish, fish, powershell, zsh]\u003c/span\u003e\n\n\u003cspan class=\"pl-c1\"\u003e -h, --help\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e Print help (see a summary with '-h')\u003c/span\u003e\n\n\u003cspan class=\"pl-c1\"\u003e -V, --version\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e Print version\u003c/span\u003e\n\n\u003cspan class=\"pl-c1\"\u003eComposable Actions:\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e -u, --upper\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e Uppercase anything in scope.\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e \u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e [env: UPPER=]\u003c/span\u003e\n\n\u003cspan class=\"pl-c1\"\u003e -l, --lower\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e Lowercase anything in scope.\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e \u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e [env: LOWER=]\u003c/span\u003e\n\n\u003cspan class=\"pl-c1\"\u003e -t, --titlecase\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e Titlecase anything in scope.\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e \u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e [env: TITLECASE=]\u003c/span\u003e\n\n\u003cspan class=\"pl-c1\"\u003e -n, --normalize\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e Normalize (Normalization Form D) anything in scope, and throw away marks.\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e \u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e [env: NORMALIZE=]\u003c/span\u003e\n\n\u003cspan class=\"pl-c1\"\u003e -g, --german\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e Perform substitutions on German words, such as 'Abenteuergruesse' to\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e 'Abenteuergrüße', for anything in scope.\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e \u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e ASCII spellings for Umlauts (ae, oe, ue) and Eszett (ss) are replaced by\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e their respective native Unicode (ä, ö, ü, ß).\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e \u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e Arbitrary compound words are supported.\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e \u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e Words legally containing alternative spellings are not modified.\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e \u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e Words require correct spelling to be detected.\u003c/span\u003e\n\n\u003cspan class=\"pl-c1\"\u003e -S, --symbols\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e Perform substitutions on symbols, such as '!=' to '≠', '-\u0026gt;' to '→', on\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e anything in scope.\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e \u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e Helps translate 'ASCII art' into native Unicode representations.\u003c/span\u003e\n\n\u003cspan class=\"pl-c1\"\u003e [REPLACEMENT]\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e Replace anything in scope with this value.\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e \u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e Variables are supported: if a regex pattern was used for scoping and\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e captured content in named or numbered capture groups, access these in the\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e replacement value using `$1` etc. for numbered, `$NAME` etc. for named\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e capture groups.\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e \u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e This action is specially treated as a positional argument for ergonomics and\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e compatibility with `tr`.\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e \u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e If given, will run before any other action.\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e \u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e [env: REPLACE=]\u003c/span\u003e\n\n\u003cspan class=\"pl-c1\"\u003eStandalone Actions (only usable alone):\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e -d, --delete\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e Delete anything in scope.\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e \u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e Cannot be used with any other action: there is no point in deleting and\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e performing any other processing. Sibling actions would either receive empty\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e input or have their work wiped.\u003c/span\u003e\n\n\u003cspan class=\"pl-c1\"\u003e -s, --squeeze\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e Squeeze consecutive occurrences of scope into one.\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e \u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e [env: SQUEEZE=]\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e [aliases: squeeze-repeats]\u003c/span\u003e\n\n\u003cspan class=\"pl-c1\"\u003eOptions (global):\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e -G, --glob \u0026lt;GLOB\u0026gt;\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e Glob of files to work on (instead of reading stdin).\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e \u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e If actions are applied, they overwrite files in-place.\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e \u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e For supported glob syntax, see:\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e \u0026lt;https://docs.rs/glob/0.3.1/glob/struct.Pattern.html\u0026gt;\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e \u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e Names of processed files are written to stdout.\u003c/span\u003e\n\n\u003cspan class=\"pl-c1\"\u003e --fail-no-files\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e Fail if working on files (e.g. globbing is requested) but none are found.\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e \u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e Processing no files is not an error condition in itself, but might be an\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e unexpected outcome in some contexts. This flag makes the condition explicit.\u003c/span\u003e\n\n\u003cspan class=\"pl-c1\"\u003e --dry-run\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e Do not destructively overwrite files, instead print rich diff only.\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e \u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e The diff details the names of files which would be modified, alongside all\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e changes inside those files which would be performed outside of dry running.\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e It is similar to git diff with word diffing enabled.\u003c/span\u003e\n\n\u003cspan class=\"pl-c1\"\u003e -i, --invert\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e Undo the effects of passed actions, where applicable.\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e \u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e Requires a 1:1 mapping between replacements and original, which is currently\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e available only for:\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e \u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - symbols: '≠' \u0026lt;-\u0026gt; '!=' etc.\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e \u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e Other actions:\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e \u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - german: inverting e.g. 'Ä' is ambiguous (can be 'Ae' or 'AE')\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e \u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - upper, lower, deletion, squeeze: inversion is impossible as information is\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e lost\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e \u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e These may still be passed, but will be ignored for inversion and applied\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e normally.\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e \u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e [env: INVERT=]\u003c/span\u003e\n\n\u003cspan class=\"pl-c1\"\u003e -L, --literal-string\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e Do not interpret the scope as a regex. Instead, interpret it as a literal\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e string. Will require a scope to be passed.\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e \u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e [env: LITERAL_STRING=]\u003c/span\u003e\n\n\u003cspan class=\"pl-c1\"\u003e --fail-any\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e If anything at all is found to be in scope, fail.\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e \u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e The default is to continue processing normally.\u003c/span\u003e\n\n\u003cspan class=\"pl-c1\"\u003e --fail-none\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e If nothing is found to be in scope, fail.\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e \u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e The default is to return the input unchanged (without failure).\u003c/span\u003e\n\n\u003cspan class=\"pl-c1\"\u003e -j, --join-language-scopes\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e Join (logical 'OR') multiple language scopes, instead of intersecting them.\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e \u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e The default when multiple language scopes are given is to intersect their\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e scopes, left to right. For example, `--go func --go strings` will first\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e scope down to `func` bodies, then look for strings only within those. This\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e flag instead joins (in the set logic sense) all scopes. The example would\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e then scope any `func` bodies, and any strings, anywhere. Language scopers\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e can then also be given in any order.\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e \u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e No effect if only a single language scope is given. Also does not affect\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e non-language scopers (regex pattern etc.), which always intersect.\u003c/span\u003e\n\n\u003cspan class=\"pl-c1\"\u003e -H, --hidden\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e Do not ignore hidden files and directories.\u003c/span\u003e\n\n\u003cspan class=\"pl-c1\"\u003e --gitignored\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e Do not ignore `.gitignore`d files and directories.\u003c/span\u003e\n\n\u003cspan class=\"pl-c1\"\u003e --sorted\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e Process files in lexicographically sorted order, by file path.\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e \u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e In search mode, this emits results in sorted order. Otherwise, it processes\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e files in sorted order.\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e \u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e Sorted processing disables parallel processing.\u003c/span\u003e\n\n\u003cspan class=\"pl-c1\"\u003e --threads \u0026lt;THREADS\u0026gt;\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e Number of threads to run processing on, when working with files.\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e \u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e If not specified, will default to available parallelism. Set to 1 for\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e sequential, deterministic (but not sorted) output.\u003c/span\u003e\n\n\u003cspan class=\"pl-c1\"\u003e -v, --verbose...\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e Increase log verbosity level.\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e \u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e The base log level to use is read from the `RUST_LOG` environment variable\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e (if unspecified, defaults to 'error'), and increased according to the number\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e of times this flag is given, maxing out at 'trace' verbosity.\u003c/span\u003e\n\n\u003cspan class=\"pl-c1\"\u003eLanguage scopes:\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e --c \u0026lt;C\u0026gt;\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e Scope C code using a prepared query.\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e \u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e [env: C=]\u003c/span\u003e\n\n\u003cspan class=\"pl-c1\"\u003e Possible values:\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - comments: Comments (single- and multi-line)\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - strings: Strings\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - includes: Includes\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - type-def: Type definitions\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - enum: `enum` definitions\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - struct: `struct` type definitions\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - variable: Variable definitions\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - function: All functions usages (declarations and calls)\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - function-def: Function definitions\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - function-decl: Function declaration\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - switch: `switch` blocks\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - if: `if` blocks\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - for: `for` blocks\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - while: `while` blocks\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - do: `do` blocks\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - union: `union` blocks\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - identifier: Identifier\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - declaration: Declaration\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - call-expression: Call expression\u003c/span\u003e\n\n\u003cspan class=\"pl-c1\"\u003e --c-query \u0026lt;TREE-SITTER-QUERY-VALUE\u0026gt;\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e Scope C code using a custom tree-sitter query.\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e \u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e [env: C_QUERY=]\u003c/span\u003e\n\n\u003cspan class=\"pl-c1\"\u003e --c-query-file \u0026lt;TREE-SITTER-QUERY-FILENAME\u0026gt;\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e Scope C code using a custom tree-sitter query from file.\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e \u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e [env: C_QUERY_FILE=]\u003c/span\u003e\n\n\u003cspan class=\"pl-c1\"\u003e --csharp \u0026lt;CSHARP\u0026gt;\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e Scope C# code using a prepared query.\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e \u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e [env: CSHARP=]\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e [aliases: cs]\u003c/span\u003e\n\n\u003cspan class=\"pl-c1\"\u003e Possible values:\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - comments: Comments (including XML, inline, doc comments)\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - strings: Strings (incl. verbatim, interpolated; incl. quotes,\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e except for interpolated)\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - usings: `using` directives (including periods)\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - struct: `struct` definitions (in their entirety)\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - enum: `enum` definitions (in their entirety)\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - interface: `interface` definitions (in their entirety)\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - class: `class` definitions (in their entirety)\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - method: Method definitions (in their entirety)\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - variable-declaration: Variable declarations (in their entirety)\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - property: Property definitions (in their entirety)\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - constructor: Constructor definitions (in their entirety)\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - destructor: Destructor definitions (in their entirety)\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - field: Field definitions on types (in their entirety)\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - attribute: Attribute names\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - identifier: Identifier names\u003c/span\u003e\n\n\u003cspan class=\"pl-c1\"\u003e --csharp-query \u0026lt;TREE-SITTER-QUERY-VALUE\u0026gt;\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e Scope C# code using a custom tree-sitter query.\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e \u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e [env: CSHARP_QUERY=]\u003c/span\u003e\n\n\u003cspan class=\"pl-c1\"\u003e --csharp-query-file \u0026lt;TREE-SITTER-QUERY-FILENAME\u0026gt;\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e Scope C# code using a custom tree-sitter query from file.\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e \u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e [env: CSHARP_QUERY_FILE=]\u003c/span\u003e\n\n\u003cspan class=\"pl-c1\"\u003e --go \u0026lt;GO\u0026gt;\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e Scope Go code using a prepared query.\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e \u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e [env: GO=]\u003c/span\u003e\n\n\u003cspan class=\"pl-c1\"\u003e Possible values:\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - comments: Comments (single- and multi-line)\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - strings: Strings (interpreted and raw; excluding struct tags)\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - imports: Imports\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - expression: Expressions (all of them!)\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - type-def: Type definitions\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - type-alias: Type alias assignments\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - struct: `struct` type definitions\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - struct~\u0026lt;PATTERN\u0026gt;: Like struct, but only considers items whose name matches\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e PATTERN.\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - interface: `interface` type definitions\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - interface~\u0026lt;PATTERN\u0026gt;: Like interface, but only considers items whose name\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e matches PATTERN.\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - const: `const` specifications\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - var: `var` specifications\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - func: `func` definitions\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - func~\u0026lt;PATTERN\u0026gt;: Like func, but only considers items whose name matches\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e PATTERN.\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - method: Method `func` definitions (`func (recv Recv) SomeFunc()`)\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - free-func: Free `func` definitions (`func SomeFunc()`)\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - init-func: `func init()` definitions\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - type-params: Type parameters (generics)\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - defer: `defer` blocks\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - select: `select` blocks\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - go: `go` blocks\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - switch: `switch` blocks\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - labeled: Labeled statements\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - goto: `goto` statements\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - struct-tags: Struct tags\u003c/span\u003e\n\n\u003cspan class=\"pl-c1\"\u003e --go-query \u0026lt;TREE-SITTER-QUERY-VALUE\u0026gt;\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e Scope Go code using a custom tree-sitter query.\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e \u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e [env: GO_QUERY=]\u003c/span\u003e\n\n\u003cspan class=\"pl-c1\"\u003e --go-query-file \u0026lt;TREE-SITTER-QUERY-FILENAME\u0026gt;\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e Scope Go code using a custom tree-sitter query from file.\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e \u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e [env: GO_QUERY_FILE=]\u003c/span\u003e\n\n\u003cspan class=\"pl-c1\"\u003e --hcl \u0026lt;HCL\u0026gt;\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e Scope HashiCorp Configuration Language code using a prepared query.\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e \u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e [env: HCL=]\u003c/span\u003e\n\n\u003cspan class=\"pl-c1\"\u003e Possible values:\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - variable: `variable` blocks (in their entirety)\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - resource: `resource` blocks (in their entirety)\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - data: `data` blocks (in their entirety)\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - output: `output` blocks (in their entirety)\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - provider: `provider` blocks (in their entirety)\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - terraform: `terraform` blocks (in their entirety)\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - locals: `locals` blocks (in their entirety)\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - module: `module` blocks (in their entirety)\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - variables: Variable declarations and usages\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - resource-names: `resource` name declarations and usages\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - resource-types: `resource` type declarations and usages\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - data-names: `data` name declarations and usages\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - data-sources: `data` source declarations and usages\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - comments: Comments\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - strings: Literal strings\u003c/span\u003e\n\n\u003cspan class=\"pl-c1\"\u003e --hcl-query \u0026lt;TREE-SITTER-QUERY-VALUE\u0026gt;\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e Scope HashiCorp Configuration Language code using a custom tree-sitter query.\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e \u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e [env: HCL_QUERY=]\u003c/span\u003e\n\n\u003cspan class=\"pl-c1\"\u003e --hcl-query-file \u0026lt;TREE-SITTER-QUERY-FILENAME\u0026gt;\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e Scope HashiCorp Configuration Language code using a custom tree-sitter query\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e from file.\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e \u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e [env: HCL_QUERY_FILE=]\u003c/span\u003e\n\n\u003cspan class=\"pl-c1\"\u003e --python \u0026lt;PYTHON\u0026gt;\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e Scope Python code using a prepared query.\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e \u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e [env: PYTHON=]\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e [aliases: py]\u003c/span\u003e\n\n\u003cspan class=\"pl-c1\"\u003e Possible values:\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - comments: Comments\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - strings: Strings (raw, byte, f-strings; interpolation not\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e included)\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - imports: Module names in imports (incl. periods; excl.\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e `import`/`from`/`as`/`*`)\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - doc-strings: Docstrings (not including multi-line strings)\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - function-names: Function names, at the definition site\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - function-calls: Function calls\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - class: Class definitions (in their entirety)\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - def: Function definitions (*all* `def` block in their\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e entirety)\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - async-def: Async function definitions (*all* `async def` block in\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e their entirety)\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - methods: Function definitions inside `class` bodies\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - class-methods: Function definitions decorated as `classmethod` (excl.\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e the decorator)\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - static-methods: Function definitions decorated as `staticmethod` (excl.\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e the decorator)\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - with: `with` blocks (in their entirety)\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - try: `try` blocks (in their entirety)\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - lambda: `lambda` statements (in their entirety)\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - globals: Global, i.e. module-level variables\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - variable-identifiers: Identifiers for variables (left-hand side of\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e assignments)\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - types: Types in type hints\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - identifiers: Identifiers (variable names, ...)\u003c/span\u003e\n\n\u003cspan class=\"pl-c1\"\u003e --python-query \u0026lt;TREE-SITTER-QUERY-VALUE\u0026gt;\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e Scope Python code using a custom tree-sitter query.\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e \u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e [env: PYTHON_QUERY=]\u003c/span\u003e\n\n\u003cspan class=\"pl-c1\"\u003e --python-query-file \u0026lt;TREE-SITTER-QUERY-FILENAME\u0026gt;\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e Scope Python code using a custom tree-sitter query from file.\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e \u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e [env: PYTHON_QUERY_FILE=]\u003c/span\u003e\n\n\u003cspan class=\"pl-c1\"\u003e --rust \u0026lt;RUST\u0026gt;\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e Scope Rust code using a prepared query.\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e \u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e [env: RUST=]\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e [aliases: rs]\u003c/span\u003e\n\n\u003cspan class=\"pl-c1\"\u003e Possible values:\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - comments: Comments (line and block styles; excluding doc comments;\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e comment chars incl.)\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - doc-comments: Doc comments (comment chars included)\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - uses: Use statements (paths only; excl. `use`/`as`/`*`)\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - strings: Strings (regular, raw, byte; includes interpolation parts in\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e format strings!)\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - attribute: Attributes like `#[attr]`\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - struct: `struct` definitions\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - struct~\u0026lt;PATTERN\u0026gt;: Like struct, but only considers items whose name matches\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e PATTERN.\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - priv-struct: `struct` definitions not marked `pub`\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - pub-struct: `struct` definitions marked `pub`\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - pub-crate-struct: `struct` definitions marked `pub(crate)`\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - pub-self-struct: `struct` definitions marked `pub(self)`\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - pub-super-struct: `struct` definitions marked `pub(super)`\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - enum: `enum` definitions\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - enum~\u0026lt;PATTERN\u0026gt;: Like enum, but only considers items whose name matches\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e PATTERN.\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - priv-enum: `enum` definitions not marked `pub`\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - pub-enum: `enum` definitions marked `pub`\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - pub-crate-enum: `enum` definitions marked `pub(crate)`\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - pub-self-enum: `enum` definitions marked `pub(self)`\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - pub-super-enum: `enum` definitions marked `pub(super)`\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - enum-variant: Variant members of `enum` definitions\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - fn: Function definitions\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - fn~\u0026lt;PATTERN\u0026gt;: Like fn, but only considers items whose name matches\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e PATTERN.\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - impl-fn: Function definitions inside `impl` blocks (associated\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e functions/methods)\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - priv-fn: Function definitions not marked `pub`\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - pub-fn: Function definitions marked `pub`\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - pub-crate-fn: Function definitions marked `pub(crate)`\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - pub-self-fn: Function definitions marked `pub(self)`\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - pub-super-fn: Function definitions marked `pub(super)`\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - const-fn: Function definitions marked `const`\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - async-fn: Function definitions marked `async`\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - unsafe-fn: Function definitions marked `unsafe`\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - extern-fn: Function definitions marked `extern`\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - test-fn: Function definitions with attributes containing `test`\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e (`#[test]`, `#[rstest]`, ...)\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - trait: `trait` definitions\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - trait~\u0026lt;PATTERN\u0026gt;: Like trait, but only considers items whose name matches\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e PATTERN.\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - impl: `impl` blocks\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - impl-type: `impl` blocks for types (`impl SomeType {}`)\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - impl-trait: `impl` blocks for traits on types (`impl SomeTrait for\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e SomeType {}`)\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - mod: `mod` blocks\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - mod~\u0026lt;PATTERN\u0026gt;: Like mod, but only considers items whose name matches\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e PATTERN.\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - mod-tests: `mod tests` blocks\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - type-def: Type definitions (`struct`, `enum`, `union`)\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - identifier: Identifiers\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - type-identifier: Identifiers for types\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - closure: Closure definitions\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - unsafe: `unsafe` keyword usages (`unsafe fn`, `unsafe` blocks,\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e `unsafe Trait`, `unsafe impl Trait`)\u003c/span\u003e\n\n\u003cspan class=\"pl-c1\"\u003e --rust-query \u0026lt;TREE-SITTER-QUERY-VALUE\u0026gt;\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e Scope Rust code using a custom tree-sitter query.\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e \u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e [env: RUST_QUERY=]\u003c/span\u003e\n\n\u003cspan class=\"pl-c1\"\u003e --rust-query-file \u0026lt;TREE-SITTER-QUERY-FILENAME\u0026gt;\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e Scope Rust code using a custom tree-sitter query from file.\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e \u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e [env: RUST_QUERY_FILE=]\u003c/span\u003e\n\n\u003cspan class=\"pl-c1\"\u003e --typescript \u0026lt;TYPESCRIPT\u0026gt;\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e Scope TypeScript code using a prepared query.\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e \u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e [env: TYPESCRIPT=]\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e [aliases: ts]\u003c/span\u003e\n\n\u003cspan class=\"pl-c1\"\u003e Possible values:\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - comments: Comments\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - strings: Strings (literal, template)\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - imports: Imports (module specifiers)\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - function: Any `function` definitions\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - async-function: `async function` definitions\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - sync-function: Non-`async function` definitions\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - method: Method definitions\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - constructor: `constructor` method definitions\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - class: `class` definitions\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - enum: `enum` definitions\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - interface: `interface` definitions\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - try-catch: `try`/`catch`/`finally` blocks\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - var-decl: Variable declarations (`let`, `const`, `var`)\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - let: `let` variable declarations\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - const: `const` variable declarations\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - var: `var` variable declarations\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - type-params: Type (generic) parameters\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - type-alias: Type alias declarations\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - namespace: `namespace` blocks\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e - export: `export` blocks\u003c/span\u003e\n\n\u003cspan class=\"pl-c1\"\u003e --typescript-query \u0026lt;TREE-SITTER-QUERY-VALUE\u0026gt;\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e Scope TypeScript code using a custom tree-sitter query.\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e \u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e [env: TYPESCRIPT_QUERY=]\u003c/span\u003e\n\n\u003cspan class=\"pl-c1\"\u003e --typescript-query-file \u0026lt;TREE-SITTER-QUERY-FILENAME\u0026gt;\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e Scope TypeScript code using a custom tree-sitter query from file.\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e \u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e [env: TYPESCRIPT_QUERY_FILE=]\u003c/span\u003e\n\n\u003cspan class=\"pl-c1\"\u003eOptions (german):\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e --german-prefer-original\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e When some original version and its replacement are equally legal, prefer the\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e original and do not modify.\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e \u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e For example, \"Busse\" (original) and \"Buße\" (replacement) are equally legal\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e words: by default, the tool would prefer the latter.\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e \u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e [env: GERMAN_PREFER_ORIGINAL=]\u003c/span\u003e\n\n\u003cspan class=\"pl-c1\"\u003e --german-naive\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e Always perform any possible replacement ('ae' -\u0026gt; 'ä', 'ss' -\u0026gt; 'ß', etc.),\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e regardless of legality of the resulting word\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e \u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e Useful for names, which are otherwise not modifiable as they do not occur in\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e dictionaries. Called 'naive' as this does not perform legal checks.\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e \u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e [env: GERMAN_NAIVE=]\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch2 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eRust library\u003c/h2\u003e\u003ca id=\"user-content-rust-library\" class=\"anchor\" aria-label=\"Permalink: Rust library\" href=\"#rust-library\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eWhile this tool is CLI-first, it is library-very-close-second, and library usage is\ntreated as a first-class citizen just the same. See the \u003ca href=\"https://docs.rs/srgn\" rel=\"nofollow\"\u003elibrary\ndocumentation\u003c/a\u003e for more, library-specific details.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eNote that the binary takes precedence though, which with the crate currently being both\na library \u003cem\u003eand\u003c/em\u003e binary, \u003ca href=\"https://blog.axo.dev/2024/03/its-a-lib-and-a-bin\" rel=\"nofollow\"\u003ecreates\nproblems\u003c/a\u003e. This might be fixed in the\nfuture.\u003c/p\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch3 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eStatus and stats\u003c/h3\u003e\u003ca id=\"user-content-status-and-stats\" class=\"anchor\" aria-label=\"Permalink: Status and stats\" href=\"#status-and-stats\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003e\u003ca href=\"https://docs.rs/srgn/\" rel=\"nofollow\"\u003e\u003cimg src=\"https://camo.githubusercontent.com/82ae17e05b6d73edef4d3d1462c6734dfb66b2104d61139a950edf88f9510b03/68747470733a2f2f696d672e736869656c64732e696f2f646f637372732f7372676e\" alt=\"docs.rs\" data-canonical-src=\"https://img.shields.io/docsrs/srgn\" style=\"max-width: 100%;\"\u003e\u003c/a\u003e\n\u003ca href=\"https://codecov.io/gh/alexpovel/srgn\" rel=\"nofollow\"\u003e\u003cimg src=\"https://camo.githubusercontent.com/5c9a134be0890a4ad67c67d3ec80d965ff58f5328bbcf2f3e50561112ae2f27d/68747470733a2f2f636f6465636f762e696f2f67682f616c6578706f76656c2f7372676e2f67726170682f62616467652e7376673f746f6b656e3d495055374c3942574d56\" alt=\"codecov\" data-canonical-src=\"https://codecov.io/gh/alexpovel/srgn/graph/badge.svg?token=IPU7L9BWMV\" style=\"max-width: 100%;\"\u003e\u003c/a\u003e\n\u003ca href=\"https://crates.io/crates/srgn\" rel=\"nofollow\"\u003e\u003cimg src=\"https://camo.githubusercontent.com/cc6f373ec8f83735e1d9116bc2d3179b13b76259405157d8aafe8c9f3a9fa457/68747470733a2f2f696d672e736869656c64732e696f2f6372617465732f762f7372676e2e737667\" alt=\"crates\" data-canonical-src=\"https://img.shields.io/crates/v/srgn.svg\" style=\"max-width: 100%;\"\u003e\u003c/a\u003e\n\u003ca href=\"https://deps.rs/repo/github/alexpovel/srgn\" rel=\"nofollow\"\u003e\u003cimg src=\"https://camo.githubusercontent.com/a06b51a6180041556d36903e2e4ef60bd1fb7aa4357311a916c12a8f2fc15f86/68747470733a2f2f646570732e72732f7265706f2f6769746875622f616c6578706f76656c2f7372676e2f7374617475732e737667\" alt=\"dependency status\" data-canonical-src=\"https://deps.rs/repo/github/alexpovel/srgn/status.svg\" style=\"max-width: 100%;\"\u003e\u003c/a\u003e\n\u003ca href=\"https://github.com/XAMPPRocky/tokei#badges\"\u003e\u003cimg src=\"https://camo.githubusercontent.com/63bf428750c234de971626cb4b5938c5934f6976662346984a77f4ab22b35814/68747470733a2f2f746f6b65692e72732f62312f6769746875622f616c6578706f76656c2f7372676e3f63617465676f72793d636f6465\" alt=\"Lines of Code\" data-canonical-src=\"https://tokei.rs/b1/github/alexpovel/srgn?category=code\" style=\"max-width: 100%;\"\u003e\u003c/a\u003e\n\u003ca href=\"https://hitsofcode.com/github/alexpovel/srgn/view?branch=main\" rel=\"nofollow\"\u003e\u003cimg src=\"https://camo.githubusercontent.com/328277ebb0d9055fb7361fe7e97193d102b1031319ceba2fdb1c43d98fcb7f11/68747470733a2f2f686974736f66636f64652e636f6d2f6769746875622f616c6578706f76656c2f7372676e3f6272616e63683d6d61696e\" alt=\"Hits-of-Code\" data-canonical-src=\"https://hitsofcode.com/github/alexpovel/srgn?branch=main\" style=\"max-width: 100%;\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eNote: these apply to the entire repository, including the \u003ca href=\"/alexpovel/srgn/blob/main/src/main.rs\"\u003ebinary\u003c/a\u003e.\u003c/p\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch4 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eCode coverage icicle graph\u003c/h4\u003e\u003ca id=\"user-content-code-coverage-icicle-graph\" class=\"anchor\" aria-label=\"Permalink: Code coverage icicle graph\" href=\"#code-coverage-icicle-graph\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eThe code is currently structured as (color indicates coverage):\u003c/p\u003e\n\u003cp dir=\"auto\"\u003e\u003ca href=\"https://codecov.io/gh/alexpovel/srgn/graphs/icicle.svg?token=IPU7L9BWMV\" rel=\"nofollow\"\u003e\u003cimg src=\"https://camo.githubusercontent.com/9841fefee31f9dc4a69440ae16a14054a073d9f019ae4351cc8acb653999b6d6/68747470733a2f2f636f6465636f762e696f2f67682f616c6578706f76656c2f7372676e2f6772617068732f696369636c652e7376673f746f6b656e3d495055374c3942574d56\" alt=\"Code coverage icile graph\" data-canonical-src=\"https://codecov.io/gh/alexpovel/srgn/graphs/icicle.svg?token=IPU7L9BWMV\" style=\"max-width: 100%;\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eHover over the rectangles for file names.\u003c/p\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch2 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eContributing\u003c/h2\u003e\u003ca id=\"user-content-contributing\" class=\"anchor\" aria-label=\"Permalink: Contributing\" href=\"#contributing\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eTo see how to build, refer to \u003ca href=\"#cargo-compile-from-source\"\u003ecompiling from source\u003c/a\u003e.\nOtherwise, refer to the \u003ca href=\"/alexpovel/srgn/blob/main/CONTRIBUTING.md\"\u003eguidelines\u003c/a\u003e.\u003c/p\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch2 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eSimilar tools\u003c/h2\u003e\u003ca id=\"user-content-similar-tools\" class=\"anchor\" aria-label=\"Permalink: Similar tools\" href=\"#similar-tools\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eAn unordered list of similar tools you might be interested in.\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/getgrit/gritql\"\u003eGritQL\u003c/a\u003e (very similar)\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/ast-grep/ast-grep\"\u003e\u003ccode\u003east-grep\u003c/code\u003e\u003c/a\u003e (very similar)\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://semgrep.dev/\" rel=\"nofollow\"\u003eSemgrep\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/eliben/pss\"\u003e\u003ccode\u003epss\u003c/code\u003e\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/facebookincubator/fastmod\"\u003e\u003ccode\u003efastmod\u003c/code\u003e\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/banga/prefactor\"\u003e\u003ccode\u003eprefactor\u003c/code\u003e\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/paul-gauthier/grep-ast\"\u003e\u003ccode\u003egrep-ast\u003c/code\u003e\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/dalance/amber\"\u003e\u003ccode\u003eamber\u003c/code\u003e\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/chmln/sd\"\u003e\u003ccode\u003esd\u003c/code\u003e\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/BurntSushi/ripgrep\"\u003e\u003ccode\u003eripgrep\u003c/code\u003e\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/orf/ripgrep-structured\"\u003e\u003ccode\u003eripgrep-structured\u003c/code\u003e\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/tree-sitter/tree-sitter/blob/master/cli/README.md\"\u003etree-sitter CLI\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://crates.io/crates/tree-sitter-grep\" rel=\"nofollow\"\u003e\u003ccode\u003etree-sitter-grep\u003c/code\u003e\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/tomnomnom/gron\"\u003e\u003ccode\u003egron\u003c/code\u003e\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://go-ruleguard.github.io/\" rel=\"nofollow\"\u003eRuleguard\u003c/a\u003e (quite different, but useful for custom\nlinting)\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://rust-for-linux.com/coccinelle-for-rust\" rel=\"nofollow\"\u003eCoccinelle for Rust\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch2 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eComparison with \u003ccode\u003etr\u003c/code\u003e\u003c/h2\u003e\u003ca id=\"user-content-comparison-with-tr\" class=\"anchor\" aria-label=\"Permalink: Comparison with tr\" href=\"#comparison-with-tr\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003e\u003ccode\u003esrgn\u003c/code\u003e is inspired by \u003ccode\u003etr\u003c/code\u003e, and in its simplest form behaves similarly, but not\nidentically. In theory, \u003ccode\u003etr\u003c/code\u003e is quite flexible. In practice, it is commonly used mainly\nacross a couple specific tasks. Next to its two positional arguments ('arrays of\ncharacters'), one finds four flags:\u003c/p\u003e\n\u003col dir=\"auto\"\u003e\n\u003cli\u003e\u003ccode\u003e-c\u003c/code\u003e, \u003ccode\u003e-C\u003c/code\u003e, \u003ccode\u003e--complement\u003c/code\u003e: complement the first array\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003e-d\u003c/code\u003e, \u003ccode\u003e--delete\u003c/code\u003e: delete characters in the first first array\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003e-s\u003c/code\u003e, \u003ccode\u003e--squeeze-repeats\u003c/code\u003e: squeeze repeats of characters in the first array\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003e-t\u003c/code\u003e, \u003ccode\u003e--truncate-set1\u003c/code\u003e: truncate the first array to the length of the second\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp dir=\"auto\"\u003eIn \u003ccode\u003esrgn\u003c/code\u003e, these are implemented as follows:\u003c/p\u003e\n\u003col dir=\"auto\"\u003e\n\u003cli\u003eis not available directly as an option; instead, negation of regular expression\nclasses can be used (e.g., \u003ccode\u003e[^a-z]\u003c/code\u003e), to much more potent, flexible and well-known\neffect\u003c/li\u003e\n\u003cli\u003eavailable (via regex)\u003c/li\u003e\n\u003cli\u003eavailable (via regex)\u003c/li\u003e\n\u003cli\u003enot available: it's inapplicable to regular expressions, not commonly used and, if\nused, often misused\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp dir=\"auto\"\u003eTo show how uses of \u003ccode\u003etr\u003c/code\u003e found in the wild can translate to \u003ccode\u003esrgn\u003c/code\u003e, consider the\nfollowing section.\u003c/p\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch3 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eUse cases and equivalences\u003c/h3\u003e\u003ca id=\"user-content-use-cases-and-equivalences\" class=\"anchor\" aria-label=\"Permalink: Use cases and equivalences\" href=\"#use-cases-and-equivalences\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eThe following sections are the approximate categories much of \u003ccode\u003etr\u003c/code\u003e usage falls into.\nThey were found using \u003ca href=\"https://cs.github.com\"\u003eGitHub's code search\u003c/a\u003e. The corresponding\nqueries are given. Results are from the first page of results at the time. The code\nsamples are links to their respective sources.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eAs the stdin isn't known (usually dynamic), some representative samples are used and the\ntool is exercised on those.\u003c/p\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch4 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eIdentifier Safety\u003c/h4\u003e\u003ca id=\"user-content-identifier-safety\" class=\"anchor\" aria-label=\"Permalink: Identifier Safety\" href=\"#identifier-safety\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eMaking inputs safe for use as identifiers, for example as variable names.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003e\u003ca href=\"https://github.com/search?type=code\u0026amp;q=%22tr+-c%22\"\u003eQuery\u003c/a\u003e\u003c/p\u003e\n\u003col dir=\"auto\"\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003e\u003ca href=\"https://github.com/grafana/grafana/blob/9328fda8ea8384e8cfcf1c78d1fe95d92bbad786/docs/make-docs#L234\"\u003e\u003ccode\u003etr -C '[:alnum:]_\\n' '_'\u003c/code\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eTranslates to:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-text-shell-session notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"$ echo 'some-variable? 🤔' | srgn '[^[:alnum:]_\\n]' '_'\nsome_variable___\"\u003e\u003cpre\u003e$ \u003cspan class=\"pl-s1\"\u003e\u003cspan class=\"pl-c1\"\u003eecho\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003esome-variable? 🤔\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-k\"\u003e|\u003c/span\u003e srgn \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e[^[:alnum:]_\\n]\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e_\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003esome_variable___\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eSimilar examples are:\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/elastic/go-elasticsearch/blob/594de0c207ef5c4804615ebedd043a789ef3ce75/.buildkite/functions/imports.sh#L38\"\u003e\u003ccode\u003etr -C \"[:alnum:]\" '-'\u003c/code\u003e\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/Homebrew/brew/blob/b2cf50bbe10ab996a1e3365545fadabf36df777a/Library/Homebrew/cmd/update.sh#L104\"\u003e\u003ccode\u003etr -C \"A-Za-z0-9\" \"_\"\u003c/code\u003e\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/xamarin/xamarin-macios/blob/c14f9ff7c7693ab060c4b84c78075ff975ea7c64/Make.config#L69\"\u003e\u003ccode\u003etr -c '[a-zA-Z0-9-]' '-'\u003c/code\u003e\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/openzfsonwindows/openzfs/blob/61f4ce826122f19a0a0c734efb4c2469b2aa367b/autogen.sh#L22\"\u003e\u003ccode\u003etr -C 'a-zA-Z0-9@_' '_'\u003c/code\u003e\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003e\u003ca href=\"https://github.com/freebsd/freebsd-src/blob/9dc0c983b0931f359c2ff10d47ad835ef74e929a/libexec/rc/rc.d/jail#L413\"\u003e\u003ccode\u003etr -c '[:alnum:]' _\u003c/code\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eTranslates to:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-text-shell-session notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"$ echo 'some variablê' | srgn '[^[:alnum:]]' '_'\nsome__variabl_\"\u003e\u003cpre\u003e$ \u003cspan class=\"pl-s1\"\u003e\u003cspan class=\"pl-c1\"\u003eecho\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003esome variablê\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-k\"\u003e|\u003c/span\u003e srgn \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e[^[:alnum:]]\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e_\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003esome__variabl_\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003e\u003ca href=\"https://github.com/weaviate/weaviate/blob/169381df70852ef687528ebf81e27869b3017403/ci/push_docker.sh#L26\"\u003e\u003ccode\u003etr -c -s '[:alnum:]' '-'\u003c/code\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eTranslates to:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-text-shell-session notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"$ echo '🙂 hellö???' | srgn -s '[^[:alnum:]]' '-'\n-hell-\"\u003e\u003cpre\u003e$ \u003cspan class=\"pl-s1\"\u003e\u003cspan class=\"pl-c1\"\u003eecho\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e🙂 hellö???\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-k\"\u003e|\u003c/span\u003e srgn -s \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e[^[:alnum:]]\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e-\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e-hell-\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch4 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eLiteral-to-literal translation\u003c/h4\u003e\u003ca id=\"user-content-literal-to-literal-translation\" class=\"anchor\" aria-label=\"Permalink: Literal-to-literal translation\" href=\"#literal-to-literal-translation\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eTranslates a \u003cem\u003esingle\u003c/em\u003e, literal character to another, for example to clean newlines.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003e\u003ca href=\"https://github.com/search?q=%22%7C+tr++%22+%28path%3A*.sh+OR+path%3A*.yml+OR+path%3A*.yaml%29\u0026amp;type=code\u0026amp;ref=advsearch\"\u003eQuery\u003c/a\u003e\u003c/p\u003e\n\u003col dir=\"auto\"\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003e\u003ca href=\"https://github.com/facebook/react-native/blob/d31d16b19cecb893a388fcb141602e8abad4aa76/packages/react-native/sdks/hermes-engine/utils/build-hermes-xcode.sh#L32\"\u003e\u003ccode\u003etr \" \" \";\"\u003c/code\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eTranslates to:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-text-shell-session notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"$ echo 'x86_64 arm64 i386' | srgn ' ' ';'\nx86_64;arm64;i386\"\u003e\u003cpre\u003e$ \u003cspan class=\"pl-s1\"\u003e\u003cspan class=\"pl-c1\"\u003eecho\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003ex86_64 arm64 i386\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-k\"\u003e|\u003c/span\u003e srgn \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e \u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e;\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003ex86_64;arm64;i386\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eSimilar examples are:\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/eyedol/tools/blob/e940fe4484b486aa8d42a76d9305a9227bea7552/backup.sh#L11\"\u003e\u003ccode\u003etr ' ' '-'\u003c/code\u003e\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/rerun/rerun/blob/aa5ad6360780ddbbb11835654e8f49b3827f15cd/modules/stubbs/lib/functions.sh#L147\"\u003e\u003ccode\u003etr '-' '_'\u003c/code\u003e\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003e\u003ca href=\"https://github.com/SDA-SE/cluster-image-scanner/blob/a769be53eae423f57a7f34c429cfa3a2770a859e/images/scan/syft/build.sh#L16\"\u003e\u003ccode\u003etr '.' \"\\n\"\u003c/code\u003e\u003c/a\u003e:\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eTranslates to:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-text-shell-session notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"$ echo '3.12.1' | srgn --literal-string '.' '\\n' # Escape sequence works\n3\n12\n1\n$ echo '3.12.1' | srgn '\\.' '\\n' # Escape regex otherwise\n3\n12\n1\"\u003e\u003cpre\u003e$ \u003cspan class=\"pl-s1\"\u003e\u003cspan class=\"pl-c1\"\u003eecho\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e3.12.1\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-k\"\u003e|\u003c/span\u003e srgn --literal-string \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e.\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\\n\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-c\"\u003e\u003cspan class=\"pl-c\"\u003e#\u003c/span\u003e Escape sequence works\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e3\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e12\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e1\u003c/span\u003e\n$ \u003cspan class=\"pl-s1\"\u003e\u003cspan class=\"pl-c1\"\u003eecho\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e3.12.1\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-k\"\u003e|\u003c/span\u003e srgn \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\\.\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\\n\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-c\"\u003e\u003cspan class=\"pl-c\"\u003e#\u003c/span\u003e Escape regex otherwise\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e3\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e12\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e1\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003e\u003ca href=\"https://github.com/gtoubassi/dqn-atari/blob/513b307039f4c28b5b517cd542ad625b41f0ef50/logstats.sh#L43\"\u003e\u003ccode\u003etr '\\n' ','\u003c/code\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eTranslates to:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-text-shell-session notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"$ echo -ne 'Some\\nMulti\\nLine\\nText' | srgn --literal-string '\\n' ','\nSome,Multi,Line,Text\"\u003e\u003cpre\u003e$ \u003cspan class=\"pl-s1\"\u003e\u003cspan class=\"pl-c1\"\u003eecho\u003c/span\u003e -ne \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003eSome\\nMulti\\nLine\\nText\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-k\"\u003e|\u003c/span\u003e srgn --literal-string \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\\n\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e,\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003eSome,Multi,Line,Text\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eIf escape sequences remain uninterpreted (\u003ccode\u003eecho -E\u003c/code\u003e, the default), the scope's\nescape sequence will need to be turned into a literal \u003ccode\u003e\\\u003c/code\u003e and \u003ccode\u003en\u003c/code\u003e as well, as it is\notherwise interpreted by the tool as a newline:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-text-shell-session notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"$ echo -nE 'Some\\nMulti\\nLine\\nText' | srgn --literal-string '\\\\n' ','\nSome,Multi,Line,Text\"\u003e\u003cpre\u003e$ \u003cspan class=\"pl-s1\"\u003e\u003cspan class=\"pl-c1\"\u003eecho\u003c/span\u003e -nE \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003eSome\\nMulti\\nLine\\nText\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-k\"\u003e|\u003c/span\u003e srgn --literal-string \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\\\\n\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e,\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003eSome,Multi,Line,Text\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eSimilar examples are:\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/mhassan2/splunk-n-box/blob/a721af8b8ae6103a7b274651206d4812d37db398/scripts/viz.sh#L427\"\u003e\u003ccode\u003etr '\\n' ' '\u003c/code\u003e\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/ministryofjustice/modernisation-platform-configuration-management/blob/6a1dd9f31a62d68d796ae304165eed1fcb1b822e/ansible/roles/nomis-weblogic/tasks/patch-weblogic.yml#L13\"\u003e\u003ccode\u003etr \"\\n\" \" \"\u003c/code\u003e\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch4 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eRemoving a character class\u003c/h4\u003e\u003ca id=\"user-content-removing-a-character-class\" class=\"anchor\" aria-label=\"Permalink: Removing a character class\" href=\"#removing-a-character-class\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eVery useful to remove whole categories in one fell swoop.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003e\u003ca href=\"https://github.com/search?q=%22%7C+tr++%22+%28path%3A*.sh+OR+path%3A*.yml+OR+path%3A*.yaml%29\u0026amp;type=code\u0026amp;ref=advsearch\"\u003eQuery\u003c/a\u003e\u003c/p\u003e\n\u003col dir=\"auto\"\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003e\u003ca href=\"https://github.com/CNMAT/OpenSoundControl.org/blob/fb7b3b48ba9ac64eae030e3333f9a980f4f8fd59/build-implementations.sh#L98\"\u003e\u003ccode\u003etr -d '[:punct:]'\u003c/code\u003e\u003c/a\u003e\nwhich they \u003ca href=\"https://github.com/CNMAT/OpenSoundControl.org/blob/fb7b3b48ba9ac64eae030e3333f9a980f4f8fd59/build-implementations.sh#L94\"\u003edescribe\nas\u003c/a\u003e:\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp dir=\"auto\"\u003eOmit all punctuation characters\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp dir=\"auto\"\u003etranslates to:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-text-shell-session notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"$ echo 'Lots... of... punctuation, man.' | srgn -d '[[:punct:]]'\nLots of punctuation man\"\u003e\u003cpre\u003e$ \u003cspan class=\"pl-s1\"\u003e\u003cspan class=\"pl-c1\"\u003eecho\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003eLots... of... punctuation, man.\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-k\"\u003e|\u003c/span\u003e srgn -d \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e[[:punct:]]\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003eLots of punctuation man\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp dir=\"auto\"\u003eLots of use cases also call for \u003cstrong\u003einverting\u003c/strong\u003e, then removing a character class.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003e\u003ca href=\"https://github.com/search?type=code\u0026amp;q=%22tr+-c%22\"\u003eQuery\u003c/a\u003e\u003c/p\u003e\n\u003col dir=\"auto\"\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003e\u003ca href=\"https://github.com/git/git/blob/d6c51973e4a0e889d1a426da08f52b9203fa1df2/t/lib-credential.sh#L542\"\u003e\u003ccode\u003etr -cd a-z\u003c/code\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eTranslates to:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-text-shell-session notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"$ echo 'i RLY love LOWERCASING everything!' | srgn -d '[^[:lower:]]'\niloveeverything\"\u003e\u003cpre\u003e$ \u003cspan class=\"pl-s1\"\u003e\u003cspan class=\"pl-c1\"\u003eecho\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003ei RLY love LOWERCASING everything!\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-k\"\u003e|\u003c/span\u003e srgn -d \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e[^[:lower:]]\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003eiloveeverything\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003e\u003ca href=\"https://github.com/gitlabhq/gitlabhq/blob/e74bf51e817ee50e85b1bbdc34f0443d1088fd68/doc/user/project/service_desk/configure.md?plain=1#L553\"\u003e\u003ccode\u003etr -cd 'a-zA-Z0-9'\u003c/code\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eTranslates to:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-text-shell-session notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"$ echo 'All0wed ??? 💥' | srgn -d '[^[:alnum:]]'\nAll0wed\"\u003e\u003cpre\u003e$ \u003cspan class=\"pl-s1\"\u003e\u003cspan class=\"pl-c1\"\u003eecho\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003eAll0wed ??? 💥\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-k\"\u003e|\u003c/span\u003e srgn -d \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e[^[:alnum:]]\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003eAll0wed\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003e\u003ca href=\"https://github.com/coredns/coredns/blob/b5e6291115d1e60fed561c64d70341b354e69504/Makefile.release#L94\"\u003e\u003ccode\u003etr -cd '[[:digit:]]'\u003c/code\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eTranslates to:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-text-shell-session notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"$ echo '{\u0026quot;id\u0026quot;: 34987, \u0026quot;name\u0026quot;: \u0026quot;Harold\u0026quot;}' | srgn -d '[^[:digit:]]'\n34987\"\u003e\u003cpre\u003e$ \u003cspan class=\"pl-s1\"\u003e\u003cspan class=\"pl-c1\"\u003eecho\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e{\"id\": 34987, \"name\": \"Harold\"}\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-k\"\u003e|\u003c/span\u003e srgn -d \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e[^[:digit:]]\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e34987\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch4 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eRemove literal character(s)\u003c/h4\u003e\u003ca id=\"user-content-remove-literal-characters\" class=\"anchor\" aria-label=\"Permalink: Remove literal character(s)\" href=\"#remove-literal-characters\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eIdentical to replacing them with the empty string.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003e\u003ca href=\"https://github.com/search?q=%22%7C+tr+%22\u0026amp;type=code\u0026amp;ref=advsearch\"\u003eQuery\u003c/a\u003e\u003c/p\u003e\n\u003col dir=\"auto\"\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003e\u003ca href=\"https://github.com/ohmyzsh/ohmyzsh/blob/079dbff2c4f22935a71101c511e2285327d8ab68/themes/gallois.zsh-theme#L82\"\u003e\u003ccode\u003etr -d \".\"\u003c/code\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eTranslates to:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-text-shell-session notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"$ echo '1632485561.123456' | srgn -d '\\.' # Unix timestamp\n1632485561123456\"\u003e\u003cpre\u003e$ \u003cspan class=\"pl-s1\"\u003e\u003cspan class=\"pl-c1\"\u003eecho\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e1632485561.123456\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-k\"\u003e|\u003c/span\u003e srgn -d \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\\.\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-c\"\u003e\u003cspan class=\"pl-c\"\u003e#\u003c/span\u003e Unix timestamp\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e1632485561123456\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eSimilar examples are:\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/jlevy/the-art-of-command-line/blob/6b50745d2e788add2e8f1ed29010e72659a9a074/README.md?plain=1#L22\"\u003e\u003ccode\u003etr -d '\\\u003c/code\u003e'`\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/hfg-gmuend/openmoji/blob/9782be9d240513a3d609a4bd6f1176f2d7e1b804/helpers/lib/optimize-build.sh#L77\"\u003e\u003ccode\u003etr -d ' '\u003c/code\u003e\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/PaNOSC-ViNYL/SimEx/blob/0ca295ec57864c0e468eba849d3f44f992c59634/Docker/simex_devel/simex_install.sh#L44\"\u003e\u003ccode\u003etr -d ' '\u003c/code\u003e\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003e\u003ca href=\"https://github.com/kubernetes/kubernetes/blob/37cf2638c975080232990d2fc2c24d0f40c38074/cluster/gce/util.sh#L1690\"\u003e\u003ccode\u003etr -d '\\r\\n'\u003c/code\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eTranslates to:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-text-shell-session notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"$ echo -e 'DOS-Style\\r\\n\\r\\nLines' | srgn -d '\\r\\n'\nDOS-StyleLines\"\u003e\u003cpre\u003e$ \u003cspan class=\"pl-s1\"\u003e\u003cspan class=\"pl-c1\"\u003eecho\u003c/span\u003e -e \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003eDOS-Style\\r\\n\\r\\nLines\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-k\"\u003e|\u003c/span\u003e srgn -d \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\\r\\n\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003eDOS-StyleLines\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eSimilar examples are:\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/mhassan2/splunk-n-box/blob/a721af8b8ae6103a7b274651206d4812d37db398/scripts/viz.sh#L427\"\u003e\u003ccode\u003etr -d '\\r'\u003c/code\u003e\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/Cidaas/cidaas-shopware-connect-plugin/blob/519e21a9a385b26803ec442e2a8b59918a948f77/.gitlab-ci.yml#L43\"\u003e\u003ccode\u003etr -d '\\r'\u003c/code\u003e\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch4 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eSqueeze whitespace\u003c/h4\u003e\u003ca id=\"user-content-squeeze-whitespace\" class=\"anchor\" aria-label=\"Permalink: Squeeze whitespace\" href=\"#squeeze-whitespace\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eRemove repeated whitespace, as it often occurs when slicing and dicing text.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003e\u003ca href=\"https://github.com/search?type=code\u0026amp;q=%22+tr+-s%22\"\u003eQuery\u003c/a\u003e\u003c/p\u003e\n\u003col dir=\"auto\"\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003e\u003ca href=\"https://github.com/ohmyzsh/ohmyzsh/blob/bbda81fe4b338f00bbf7c7f33e6d1b12d067dc05/plugins/alias-finder/alias-finder.plugin.zsh#L26\"\u003e\u003ccode\u003etr -s '[:space:]'\u003c/code\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eTranslates to:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-text-shell-session notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"$ echo 'Lots of space !' | srgn -s '[[:space:]]' # Single space stays\nLots of space !\"\u003e\u003cpre\u003e$ \u003cspan class=\"pl-s1\"\u003e\u003cspan class=\"pl-c1\"\u003eecho\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003eLots of space !\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-k\"\u003e|\u003c/span\u003e srgn -s \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e[[:space:]]\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-c\"\u003e\u003cspan class=\"pl-c\"\u003e#\u003c/span\u003e Single space stays\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003eLots of space !\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eSimilar examples are:\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/facebookresearch/fastText/blob/166ce2c71a497ff81cb62ec151be5b569e1f1be6/.circleci/pull_data.sh#L18\"\u003e\u003ccode\u003etr -s \" \"\u003c/code\u003e\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/Atmosphere-NX/Atmosphere/blob/4fe9a89ab8ed958a3e080d7ee11767bef9cb2d57/atmosphere.mk#L11\"\u003e\u003ccode\u003etr -s [:blank:]\u003c/code\u003e\u003c/a\u003e\n(\u003ccode\u003eblank\u003c/code\u003e is \u003ccode\u003e\\t\u003c/code\u003e and space)\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/kovidgoyal/kitty/blob/863adb3e8d8e7229610c6b0e6bc8d48db9becda5/kitty/rc/get_colors.py#L28\"\u003e\u003ccode\u003etr -s\u003c/code\u003e\u003c/a\u003e\n(no argument: this will error out; presumably space was meant)\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/google/jax/blob/bf40f75bd59501d66a0e500d255daca3f9f2895e/build/rocm/build_rocm.sh#L65\"\u003e\u003ccode\u003etr -s ' '\u003c/code\u003e\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/chromium/chromium/blob/ffed2601d91f4413ca4672a6027c2c05d49df815/docs/linux/minidump_to_core.md?plain=1#L111\"\u003e\u003ccode\u003etr -s ' '\u003c/code\u003e\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/ceph/ceph/blob/6c387554d8e104727b3e448a1def4f1991be1ff7/src/stop.sh#L188\"\u003e\u003ccode\u003etr -s '[:space:]'\u003c/code\u003e\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/PyO3/pyo3/blob/8f4a26a66ecee4cfa473ada8cb27a57c4533d04f/.netlify/build.sh#L7\"\u003e\u003ccode\u003etr -s ' '\u003c/code\u003e\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003e\u003ca href=\"https://github.com/doocs/leetcode/blob/4f89e08ed45f7d5e1047767071001073ffe4d32b/solution/0100-0199/0192.Word%20Frequency/README.md?plain=1#L54\"\u003e\u003ccode\u003etr -s ' ' '\\n'\u003c/code\u003e\u003c/a\u003e\n(squeeze, \u003cem\u003ethen replace\u003c/em\u003e)\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eTranslates to:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-text-shell-session notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"$ echo '1969-12-28 13:37:45Z' | srgn -s ' ' 'T' # ISO8601\n1969-12-28T13:37:45Z\"\u003e\u003cpre\u003e$ \u003cspan class=\"pl-s1\"\u003e\u003cspan class=\"pl-c1\"\u003eecho\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e1969-12-28 13:37:45Z\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-k\"\u003e|\u003c/span\u003e srgn -s \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e \u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003eT\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-c\"\u003e\u003cspan class=\"pl-c\"\u003e#\u003c/span\u003e ISO8601\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e1969-12-28T13:37:45Z\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003e\u003ca href=\"https://github.com/cockroachdb/cockroach/blob/985662236d7bf273b93a7b5e32def8e2d1043640/docs/generated/http/BUILD.bazel#L76\"\u003e\u003ccode\u003etr -s '[:blank:]' ':'\u003c/code\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eTranslates to:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-text-shell-session notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"$ echo -e '/usr/local/sbin \\t /usr/local/bin' | srgn -s '[[:blank:]]' ':'\n/usr/local/sbin:/usr/local/bin\"\u003e\u003cpre\u003e$ \u003cspan class=\"pl-s1\"\u003e\u003cspan class=\"pl-c1\"\u003eecho\u003c/span\u003e -e \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e/usr/local/sbin \\t /usr/local/bin\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-k\"\u003e|\u003c/span\u003e srgn -s \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e[[:blank:]]\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e:\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e/usr/local/sbin:/usr/local/bin\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch4 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eChanging character casing\u003c/h4\u003e\u003ca id=\"user-content-changing-character-casing\" class=\"anchor\" aria-label=\"Permalink: Changing character casing\" href=\"#changing-character-casing\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eA straightforward use case. Upper- and lowercase are often used.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003e\u003ca href=\"https://github.com/search?q=%22%7C+tr++%22+%28path%3A*.sh+OR+path%3A*.yml+OR+path%3A*.yaml%29\u0026amp;type=code\u0026amp;ref=advsearch\"\u003eQuery\u003c/a\u003e\u003c/p\u003e\n\u003col dir=\"auto\"\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003e\u003ca href=\"https://github.com/golang/go/blob/a742ae493ff59a71131706500ce53f85477897f0/src/encoding/xml/xml.go#L1874\"\u003e\u003ccode\u003etr A-Z a-z\u003c/code\u003e\u003c/a\u003e\n(lowercasing)\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eTranslates to:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-text-shell-session notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"$ echo 'WHY ARE WE YELLING?' | srgn --lower\nwhy are we yelling?\"\u003e\u003cpre\u003e$ \u003cspan class=\"pl-s1\"\u003e\u003cspan class=\"pl-c1\"\u003eecho\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003eWHY ARE WE YELLING?\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-k\"\u003e|\u003c/span\u003e srgn --lower\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003ewhy are we yelling?\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eNotice the default scope. It can be refined to lowercase only long words, for\nexample:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-text-shell-session notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"$ echo 'WHY ARE WE YELLING?' | srgn --lower '\\b\\w{,3}\\b'\nwhy are we YELLING?\"\u003e\u003cpre\u003e$ \u003cspan class=\"pl-s1\"\u003e\u003cspan class=\"pl-c1\"\u003eecho\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003eWHY ARE WE YELLING?\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-k\"\u003e|\u003c/span\u003e srgn --lower \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\\b\\w{,3}\\b\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003ewhy are we YELLING?\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eSimilar examples are:\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/nwchemgit/nwchem/blob/aad4ecd5657055b085b57115314e4d56271ad749/travis/guess_simd.sh#L13\"\u003e\u003ccode\u003etr 'A-Z' 'a-z'\u003c/code\u003e\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/XIMDEX/xcms/blob/4dd3c055de5cb0eebed28f1e9da87ed731a44a99/bin/lib/util.sh#L47\"\u003e\u003ccode\u003etr '[A-Z]' '[a-z]'\u003c/code\u003e\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/varunjampani/video_prop_networks/blob/4f4a39842bd9112932abe40bad746c174a242bf6/lib/davis/configure.sh#L30\"\u003e\u003ccode\u003etr '[A-Z]' '[a-z]'\u003c/code\u003e\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/PaNOSC-ViNYL/SimEx/blob/0ca295ec57864c0e468eba849d3f44f992c59634/Docker/simex_devel/simex_install.sh#L44\"\u003e\u003ccode\u003etr '[:upper:]' '[:lower:]'\u003c/code\u003e\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/tst-labs/esocial/blob/b678f59bba883a63e91be79d7f2853a57156cf7b/src/esocial-esquemas/generate-java-from-xsd.sh#L11\"\u003e\u003ccode\u003etr \"[:upper:]\" \"[:lower:]\"\u003c/code\u003e\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003e\u003ca href=\"https://github.com/henrikpersson/potatis/blob/63feb9de28781e4e9c62bd091bd335b87b474cb1/nes-android/install.sh#L10\"\u003e\u003ccode\u003etr '[a-z]' '[A-Z]'\u003c/code\u003e\u003c/a\u003e\n(uppercasing)\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eTranslates to:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-text-shell-session notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"$ echo 'why are we not yelling?' | srgn --upper\nWHY ARE WE NOT YELLING?\"\u003e\u003cpre\u003e$ \u003cspan class=\"pl-s1\"\u003e\u003cspan class=\"pl-c1\"\u003eecho\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003ewhy are we not yelling?\u003cspan class=\"pl-pds\"\u003e'\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-k\"\u003e|\u003c/span\u003e srgn --upper\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003eWHY ARE WE NOT YELLING?\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eSimilar examples are:\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/basho/riak-zabbix/blob/423e21c31821a345bf59ec4b2baba06d532a7f30/build_templates.sh#L40\"\u003e\u003ccode\u003etr '[a-z]' '[A-Z]'\u003c/code\u003e\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/Fivium/Oracle-Backup-and-Sync/blob/036aace4a8eb45ab7e6e226ddceb08f35c46b9f3/dbsync/scripts/dbsync.sh#L122\"\u003e\u003ccode\u003etr \"[:lower:]\" \"[:upper:]\"\u003c/code\u003e\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/jorgeazevedo/xenomai-lab/blob/a2ce85a86f37fd9762905026ce4a1542684c714b/data/.xenomailab/blocks/template/rename.sh#L5\"\u003e\u003ccode\u003etr \"[:lower:]\" \"[:upper:]\"\u003c/code\u003e\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch2 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eLicense\u003c/h2\u003e\u003ca id=\"user-content-license\" class=\"anchor\" aria-label=\"Permalink: License\" href=\"#license\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eThis project is licensed under either of\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003eApache License, Version 2.0, (\u003ca href=\"/alexpovel/srgn/blob/main/LICENSE-APACHE\"\u003eLICENSE-APACHE\u003c/a\u003e or\n\u003ca href=\"http://www.apache.org/licenses/LICENSE-2.0\" rel=\"nofollow\"\u003ehttp://www.apache.org/licenses/LICENSE-2.0\u003c/a\u003e)\u003c/li\u003e\n\u003cli\u003eMIT license (\u003ca href=\"/alexpovel/srgn/blob/main/LICENSE-MIT\"\u003eLICENSE-MIT\u003c/a\u003e or \u003ca href=\"http://opensource.org/licenses/MIT\" rel=\"nofollow\"\u003ehttp://opensource.org/licenses/MIT\u003c/a\u003e)\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp dir=\"auto\"\u003eat your option.\u003c/p\u003e\n\u003csection data-footnotes=\"\" class=\"footnotes\"\u003e\u003ch2 id=\"footnote-label\" class=\"sr-only\" dir=\"auto\"\u003eFootnotes\u003c/h2\u003e\n\u003col dir=\"auto\"\u003e\n\u003cli id=\"user-content-fn-3-b30ce13ed678ccbd6287a3f5e19f11b5\"\u003e\n\u003cp dir=\"auto\"\u003eWith zero actions and no language scoping provided, \u003ccode\u003esrgn\u003c/code\u003e becomes 'useless', and\nother tools such as ripgrep are much more suitable. That's why an error is emitted\nand input is returned unchanged. \u003ca href=\"#user-content-fnref-3-b30ce13ed678ccbd6287a3f5e19f11b5\" data-footnote-backref=\"\" aria-label=\"Back to reference 1\" class=\"data-footnote-backref\"\u003e↩\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli id=\"user-content-fn-1-b30ce13ed678ccbd6287a3f5e19f11b5\"\u003e\n\u003cp dir=\"auto\"\u003eCurrently, reversibility is not possible for any other action. For example,\nlowercasing is not the inverse of uppercasing. Information is lost, so it cannot be\nundone. Structure (imagine mixed case) was lost. Something something entropy... \u003ca href=\"#user-content-fnref-1-b30ce13ed678ccbd6287a3f5e19f11b5\" data-footnote-backref=\"\" aria-label=\"Back to reference 2\" class=\"data-footnote-backref\"\u003e↩\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli id=\"user-content-fn-2-b30ce13ed678ccbd6287a3f5e19f11b5\"\u003e\n\u003cp dir=\"auto\"\u003eWhy is such a bizzare, unrelated feature included? As usual, historical reasons.\nThe original, core version of \u003ccode\u003esrgn\u003c/code\u003e was merely a Rust rewrite of \u003ca href=\"https://github.com/alexpovel/betterletter\"\u003ea previous,\nexisting tool\u003c/a\u003e, which was \u003cem\u003eonly\u003c/em\u003e\nconcerned with the \u003cem\u003eGerman\u003c/em\u003e feature. \u003ccode\u003esrgn\u003c/code\u003e then grew from there. \u003ca href=\"#user-content-fnref-2-b30ce13ed678ccbd6287a3f5e19f11b5\" data-footnote-backref=\"\" aria-label=\"Back to reference 3\" class=\"data-footnote-backref\"\u003e↩\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli id=\"user-content-fn-4-b30ce13ed678ccbd6287a3f5e19f11b5\"\u003e\n\u003cp dir=\"auto\"\u003eCombined with \u003ccode\u003e--fail-any\u003c/code\u003e, the invocation could be used to fail if any \u003ccode\u003eunsafe\u003c/code\u003e\ncode is found, like a low-budget linter. In reality, for this case, just use\n\u003ca href=\"https://doc.rust-lang.org/nomicon/safe-unsafe-meaning.html\"\u003e\u003ccode\u003e#![forbid(unsafe_code)]\u003c/code\u003e\u003c/a\u003e\nthough. \u003ca href=\"#user-content-fnref-4-b30ce13ed678ccbd6287a3f5e19f11b5\" data-footnote-backref=\"\" aria-label=\"Back to reference 4\" class=\"data-footnote-backref\"\u003e↩\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\u003c/section\u003e\n\u003c/article\u003e","loaded":true,"timedOut":false,"errorMessage":null,"headerInfo":{"toc":[{"level":1,"text":"srgn - a code surgeon","anchor":"srgn---a-code-surgeon","htmlText":"srgn - a code surgeon"},{"level":2,"text":"Quick walkthrough","anchor":"quick-walkthrough","htmlText":"Quick walkthrough"},{"level":3,"text":"Multiple scopes","anchor":"multiple-scopes","htmlText":"Multiple scopes"},{"level":4,"text":"Multiple language scopes","anchor":"multiple-language-scopes","htmlText":"Multiple language scopes"},{"level":4,"text":"Working recursively","anchor":"working-recursively","htmlText":"Working recursively"},{"level":3,"text":"Combining actions and scopes","anchor":"combining-actions-and-scopes","htmlText":"Combining actions and scopes"},{"level":2,"text":"Installation","anchor":"installation","htmlText":"Installation"},{"level":3,"text":"Prebuilt binaries","anchor":"prebuilt-binaries","htmlText":"Prebuilt binaries"},{"level":3,"text":"cargo-binstall","anchor":"cargo-binstall","htmlText":"cargo-binstall"},{"level":3,"text":"Homebrew","anchor":"homebrew","htmlText":"Homebrew"},{"level":3,"text":"Nix","anchor":"nix","htmlText":"Nix"},{"level":3,"text":"Arch Linux","anchor":"arch-linux","htmlText":"Arch Linux"},{"level":3,"text":"MacPorts","anchor":"macports","htmlText":"MacPorts"},{"level":3,"text":"CI (GitHub Actions)","anchor":"ci-github-actions","htmlText":"CI (GitHub Actions)"},{"level":3,"text":"Cargo (compile from source)","anchor":"cargo-compile-from-source","htmlText":"Cargo (compile from source)"},{"level":3,"text":"Cargo (as a Rust library)","anchor":"cargo-as-a-rust-library","htmlText":"Cargo (as a Rust library)"},{"level":3,"text":"Shell completions","anchor":"shell-completions","htmlText":"Shell completions"},{"level":2,"text":"Walkthrough","anchor":"walkthrough","htmlText":"Walkthrough"},{"level":3,"text":"Actions","anchor":"actions","htmlText":"Actions"},{"level":4,"text":"Replacement","anchor":"replacement","htmlText":"Replacement"},{"level":5,"text":"Variables","anchor":"variables","htmlText":"Variables"},{"level":4,"text":"Beyond replacement","anchor":"beyond-replacement","htmlText":"Beyond replacement"},{"level":4,"text":"Deletion","anchor":"deletion","htmlText":"Deletion"},{"level":4,"text":"Squeezing","anchor":"squeezing","htmlText":"Squeezing"},{"level":4,"text":"Character casing","anchor":"character-casing","htmlText":"Character casing"},{"level":4,"text":"Normalization","anchor":"normalization","htmlText":"Normalization"},{"level":4,"text":"Symbols","anchor":"symbols","htmlText":"Symbols"},{"level":4,"text":"German","anchor":"german","htmlText":"German"},{"level":3,"text":"Combining Actions","anchor":"combining-actions","htmlText":"Combining Actions"},{"level":3,"text":"Scopes","anchor":"scopes","htmlText":"Scopes"},{"level":4,"text":"Language grammar-aware scopes","anchor":"language-grammar-aware-scopes","htmlText":"Language grammar-aware scopes"},{"level":5,"text":"Prepared queries","anchor":"prepared-queries","htmlText":"Prepared queries"},{"level":6,"text":"Finding all structs related to testing (Go)","anchor":"finding-all-structs-related-to-testing-go","htmlText":"Finding all structs related to testing (Go)"},{"level":6,"text":"Finding all unsafe code (Rust)","anchor":"finding-all-unsafe-code-rust","htmlText":"Finding all unsafe code (Rust)"},{"level":6,"text":"Replacing allow with expect for lints (Rust)","anchor":"replacing-allow-with-expect-for-lints-rust","htmlText":"Replacing allow with expect for lints (Rust)"},{"level":6,"text":"Mass import (module) renaming (Python, Rust)","anchor":"mass-import-module-renaming-python-rust","htmlText":"Mass import (module) renaming (Python, Rust)"},{"level":6,"text":"Assigning TODOs (TypeScript)","anchor":"assigning-todos-typescript","htmlText":"Assigning TODOs (TypeScript)"},{"level":6,"text":"Converting print calls to proper logging (Python)","anchor":"converting-print-calls-to-proper-logging-python","htmlText":"Converting print calls to proper logging (Python)"},{"level":6,"text":"Remove all comments (C#)","anchor":"remove-all-comments-c","htmlText":"Remove all comments (C#)"},{"level":6,"text":"Upgrade VM size (Terraform)","anchor":"upgrade-vm-size-terraform","htmlText":"Upgrade VM size (Terraform)"},{"level":6,"text":"Rename function (C)","anchor":"rename-function-c","htmlText":"Rename function (C)"},{"level":5,"text":"Custom queries","anchor":"custom-queries","htmlText":"Custom queries"},{"level":5,"text":"Custom queries from file","anchor":"custom-queries-from-file","htmlText":"Custom queries from file"},{"level":6,"text":"Ignoring parts of matches","anchor":"ignoring-parts-of-matches","htmlText":"Ignoring parts of matches"},{"level":6,"text":"Further reading","anchor":"further-reading","htmlText":"Further reading"},{"level":4,"text":"Run against multiple files","anchor":"run-against-multiple-files","htmlText":"Run against multiple files"},{"level":4,"text":"Explicit failure for (mis)matches","anchor":"explicit-failure-for-mismatches","htmlText":"Explicit failure for (mis)matches"},{"level":4,"text":"Literal scope","anchor":"literal-scope","htmlText":"Literal scope"},{"level":3,"text":"Help output","anchor":"help-output","htmlText":"Help output"},{"level":2,"text":"Rust library","anchor":"rust-library","htmlText":"Rust library"},{"level":3,"text":"Status and stats","anchor":"status-and-stats","htmlText":"Status and stats"},{"level":4,"text":"Code coverage icicle graph","anchor":"code-coverage-icicle-graph","htmlText":"Code coverage icicle graph"},{"level":2,"text":"Contributing","anchor":"contributing","htmlText":"Contributing"},{"level":2,"text":"Similar tools","anchor":"similar-tools","htmlText":"Similar tools"},{"level":2,"text":"Comparison with tr","anchor":"comparison-with-tr","htmlText":"Comparison with tr"},{"level":3,"text":"Use cases and equivalences","anchor":"use-cases-and-equivalences","htmlText":"Use cases and equivalences"},{"level":4,"text":"Identifier Safety","anchor":"identifier-safety","htmlText":"Identifier Safety"},{"level":4,"text":"Literal-to-literal translation","anchor":"literal-to-literal-translation","htmlText":"Literal-to-literal translation"},{"level":4,"text":"Removing a character class","anchor":"removing-a-character-class","htmlText":"Removing a character class"},{"level":4,"text":"Remove literal character(s)","anchor":"remove-literal-characters","htmlText":"Remove literal character(s)"},{"level":4,"text":"Squeeze whitespace","anchor":"squeeze-whitespace","htmlText":"Squeeze whitespace"},{"level":4,"text":"Changing character casing","anchor":"changing-character-casing","htmlText":"Changing character casing"},{"level":2,"text":"License","anchor":"license","htmlText":"License"}],"siteNavLoginPath":"/login?return_to=https%3A%2F%2Fgithub.com%2Falexpovel%2Fsrgn"}},{"displayName":"LICENSE-APACHE","repoName":"srgn","refName":"main","path":"LICENSE-APACHE","preferredFileType":"license","tabName":"Apache-2.0","richText":null,"loaded":false,"timedOut":false,"errorMessage":null,"headerInfo":{"toc":null,"siteNavLoginPath":"/login?return_to=https%3A%2F%2Fgithub.com%2Falexpovel%2Fsrgn"}},{"displayName":"LICENSE-MIT","repoName":"srgn","refName":"main","path":"LICENSE-MIT","preferredFileType":"license","tabName":"MIT","richText":null,"loaded":false,"timedOut":false,"errorMessage":null,"headerInfo":{"toc":null,"siteNavLoginPath":"/login?return_to=https%3A%2F%2Fgithub.com%2Falexpovel%2Fsrgn"}}],"overviewFilesProcessingTime":0}},"appPayload":{"helpUrl":"https://docs.github.com","findFileWorkerPath":"/assets-cdn/worker/find-file-worker-7d7eb7c71814.js","findInFileWorkerPath":"/assets-cdn/worker/find-in-file-worker-96e76d5fdb2c.js","githubDevUrl":null,"enabled_features":{"copilot_workspace":null,"code_nav_ui_events":false,"overview_shared_code_dropdown_button":false,"react_blob_overlay":false,"accessible_code_button":true,"github_models_repo_integration":false}}}}</script> <div data-target="react-partial.reactRoot"><style data-styled="true" data-styled-version="5.3.11">.iVEunk{margin-top:16px;margin-bottom:16px;}/*!sc*/ .jzuOtQ{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;-webkit-box-pack:justify;-webkit-justify-content:space-between;-ms-flex-pack:justify;justify-content:space-between;}/*!sc*/ .bGojzy{margin-bottom:0;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;row-gap:16px;}/*!sc*/ .iNSVHo{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-pack:justify;-webkit-justify-content:space-between;-ms-flex-pack:justify;justify-content:space-between;-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1;padding-bottom:16px;padding-top:8px;}/*!sc*/ .bVgnfw{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:row;-ms-flex-direction:row;flex-direction:row;gap:8px;}/*!sc*/ @media screen and (max-width:320px){.bVgnfw{-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1;}}/*!sc*/ .CEgMp{position:relative;}/*!sc*/ @media screen and (max-width:380px){.CEgMp .ref-selector-button-text-container{max-width:80px;}}/*!sc*/ @media screen and (max-width:320px){.CEgMp{-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1;}.CEgMp .overview-ref-selector{width:100%;}.CEgMp .overview-ref-selector > span{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-pack:start;-webkit-justify-content:flex-start;-ms-flex-pack:start;justify-content:flex-start;}.CEgMp .overview-ref-selector > span > span[data-component="text"]{-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1;}}/*!sc*/ .gMOVLe[data-size="medium"]{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;min-width:0;}/*!sc*/ .gMOVLe[data-size="medium"] svg{color:var(--fgColor-muted,var(--color-fg-muted,#656d76));}/*!sc*/ .gMOVLe[data-size="medium"] > span{width:inherit;}/*!sc*/ .gUkoLg{-webkit-box-pack:center;-webkit-justify-content:center;-ms-flex-pack:center;justify-content:center;}/*!sc*/ .bZBlpz{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;width:100%;}/*!sc*/ .lhTYNA{margin-right:4px;color:var(--fgColor-muted,var(--color-fg-muted,#656d76));}/*!sc*/ .ffLUq{font-size:14px;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}/*!sc*/ .bmcJak{min-width:0;}/*!sc*/ .fLXEGX{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;}/*!sc*/ @media screen and (max-width:1079px){.fLXEGX{display:none;}}/*!sc*/ .lmSMZJ[data-size="medium"]{color:var(--fgColor-muted,var(--color-fg-muted,#656d76));padding-left:4px;padding-right:4px;}/*!sc*/ .lmSMZJ[data-size="medium"] span[data-component="leadingVisual"]{margin-right:4px !important;}/*!sc*/ .dqfxud{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;}/*!sc*/ @media screen and (min-width:1080px){.dqfxud{display:none;}}/*!sc*/ @media screen and (max-width:543px){.dqfxud{display:none;}}/*!sc*/ .fGwBZA[data-size="medium"][data-no-visuals]{color:var(--fgColor-muted,var(--color-fg-muted,#656d76));}/*!sc*/ .jxTzTd{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;padding-left:8px;gap:8px;}/*!sc*/ .gqqBXN{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;gap:8px;}/*!sc*/ @media screen and (max-width:543px){.gqqBXN{display:none;}}/*!sc*/ .dzXgxt{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;}/*!sc*/ @media screen and (max-width:1011px){.dzXgxt{display:none;}}/*!sc*/ .iWFGlI{margin-left:8px;margin-right:8px;margin:0;}/*!sc*/ .vcvyP{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;min-width:160px;}/*!sc*/ .YUPas{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;}/*!sc*/ @media screen and (min-width:1012px){.YUPas{display:none;}}/*!sc*/ .izFOf{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;}/*!sc*/ @media screen and (min-width:544px){.izFOf{display:none;}}/*!sc*/ .vIPPs{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;gap:16px;}/*!sc*/ .fdROMU{width:100%;border-collapse:separate;border-spacing:0;border:1px solid;border-color:var(--borderColor-default,var(--color-border-default,#d0d7de));border-radius:6px;table-layout:fixed;overflow:unset;}/*!sc*/ .jGKpsv{height:0px;line-height:0px;}/*!sc*/ .jGKpsv tr{height:0px;font-size:0px;}/*!sc*/ .jdgHnn{padding:16px;color:var(--fgColor-muted,var(--color-fg-muted,#656d76));font-size:12px;text-align:left;height:40px;}/*!sc*/ .jdgHnn th{padding-left:16px;background-color:var(--bgColor-muted,var(--color-canvas-subtle,#f6f8fa));}/*!sc*/ .bQivRW{width:100%;border-top-left-radius:6px;}/*!sc*/ @media screen and (min-width:544px){.bQivRW{display:none;}}/*!sc*/ .ldkMIO{width:40%;border-top-left-radius:6px;}/*!sc*/ @media screen and (max-width:543px){.ldkMIO{display:none;}}/*!sc*/ .jMbWeI{text-align:right;padding-right:16px;width:136px;border-top-right-radius:6px;}/*!sc*/ .gpqjiB{color:var(--fgColor-muted,var(--color-fg-muted,#656d76));font-size:12px;height:40px;}/*!sc*/ .dzCJzi{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:row;-ms-flex-direction:row;flex-direction:row;-webkit-flex-wrap:wrap;-ms-flex-wrap:wrap;flex-wrap:wrap;-webkit-box-pack:justify;-webkit-justify-content:space-between;-ms-flex-pack:justify;justify-content:space-between;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;gap:8px;min-width:273px;padding:8px;}/*!sc*/ @media screen and (min-width:544px){.dzCJzi{-webkit-flex-wrap:nowrap;-ms-flex-wrap:nowrap;flex-wrap:nowrap;}}/*!sc*/ .eNCcrz{text-align:center;vertical-align:center;height:40px;border-top:1px solid;border-color:var(--borderColor-default,var(--color-border-default,#d0d7de));}/*!sc*/ .bHTcCe{border-top:1px solid var(--borderColor-default,var(--color-border-default));cursor:pointer;}/*!sc*/ .csrIcr{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1;gap:16px;}/*!sc*/ .bUQNHB{border:1px solid;border-color:var(--borderColor-default,var(--color-border-default,#d0d7de));border-radius:6px;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1;}/*!sc*/ @media screen and (max-width:543px){.bUQNHB{margin-left:-16px;margin-right:-16px;max-width:calc(100% + 32px);}}/*!sc*/ @media screen and (min-width:544px){.bUQNHB{max-width:100%;}}/*!sc*/ .jPdcfu{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;border-bottom:1px solid;border-bottom-color:var(--borderColor-default,var(--color-border-default,#d0d7de));-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;padding-right:8px;position:-webkit-sticky;position:sticky;top:0;background-color:var(--bgColor-default,var(--color-canvas-default,#ffffff));z-index:1;border-top-left-radius:6px;border-top-right-radius:6px;}/*!sc*/ .iphEWz{-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1;border-bottom:none;max-width:100%;padding-left:8px;padding-right:8px;}/*!sc*/ .hUCRAk{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;}/*!sc*/ .cwoBXV[data-size="medium"]{color:var(--fgColor-muted,var(--color-fg-subtle,#6e7781));padding-left:8px;padding-right:8px;}/*!sc*/ .QkQOb{padding:32px;overflow:auto;}/*!sc*/ data-styled.g1[id="Box-sc-g0xbh4-0"]{content:"iVEunk,jzuOtQ,bGojzy,iNSVHo,bVgnfw,CEgMp,gMOVLe,gUkoLg,bZBlpz,lhTYNA,ffLUq,bmcJak,fLXEGX,lmSMZJ,dqfxud,fGwBZA,jxTzTd,gqqBXN,dzXgxt,iWFGlI,vcvyP,YUPas,izFOf,vIPPs,fdROMU,jGKpsv,jdgHnn,bQivRW,ldkMIO,jMbWeI,gpqjiB,dzCJzi,eNCcrz,bHTcCe,csrIcr,bUQNHB,jPdcfu,iphEWz,hUCRAk,cwoBXV,QkQOb,"}/*!sc*/ .brGdpi{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;-webkit-clip:rect(0,0,0,0);clip:rect(0,0,0,0);white-space:nowrap;border-width:0;}/*!sc*/ data-styled.g5[id="_VisuallyHidden__VisuallyHidden-sc-11jhm7a-0"]{content:"brGdpi,"}/*!sc*/ .hWlpPn{position:relative;display:inline-block;}/*!sc*/ .hWlpPn::after{position:absolute;z-index:1000000;display:none;padding:0.5em 0.75em;font:normal normal 11px/1.5 -apple-system,BlinkMacSystemFont,"Segoe UI","Noto Sans",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji";-webkit-font-smoothing:subpixel-antialiased;color:var(--tooltip-fgColor,var(--fgColor-onEmphasis,var(--color-fg-on-emphasis,#ffffff)));text-align:center;-webkit-text-decoration:none;text-decoration:none;text-shadow:none;text-transform:none;-webkit-letter-spacing:normal;-moz-letter-spacing:normal;-ms-letter-spacing:normal;letter-spacing:normal;word-wrap:break-word;white-space:pre;pointer-events:none;content:attr(aria-label);background:var(--tooltip-bgColor,var(--bgColor-emphasis,var(--color-neutral-emphasis-plus,#24292f)));border-radius:6px;opacity:0;}/*!sc*/ @-webkit-keyframes tooltip-appear{from{opacity:0;}to{opacity:1;}}/*!sc*/ @keyframes tooltip-appear{from{opacity:0;}to{opacity:1;}}/*!sc*/ .hWlpPn:hover::after,.hWlpPn:active::after,.hWlpPn:focus::after,.hWlpPn:focus-within::after{display:inline-block;-webkit-text-decoration:none;text-decoration:none;-webkit-animation-name:tooltip-appear;animation-name:tooltip-appear;-webkit-animation-duration:0.1s;animation-duration:0.1s;-webkit-animation-fill-mode:forwards;animation-fill-mode:forwards;-webkit-animation-timing-function:ease-in;animation-timing-function:ease-in;-webkit-animation-delay:0s;animation-delay:0s;}/*!sc*/ .hWlpPn.tooltipped-no-delay:hover::after,.hWlpPn.tooltipped-no-delay:active::after,.hWlpPn.tooltipped-no-delay:focus::after,.hWlpPn.tooltipped-no-delay:focus-within::after{-webkit-animation-delay:0s;animation-delay:0s;}/*!sc*/ .hWlpPn.tooltipped-multiline:hover::after,.hWlpPn.tooltipped-multiline:active::after,.hWlpPn.tooltipped-multiline:focus::after,.hWlpPn.tooltipped-multiline:focus-within::after{display:table-cell;}/*!sc*/ .hWlpPn.tooltipped-s::after,.hWlpPn.tooltipped-se::after,.hWlpPn.tooltipped-sw::after{top:100%;right:50%;margin-top:6px;}/*!sc*/ .hWlpPn.tooltipped-se::after{right:auto;left:50%;margin-left:-16px;}/*!sc*/ .hWlpPn.tooltipped-sw::after{margin-right:-16px;}/*!sc*/ .hWlpPn.tooltipped-n::after,.hWlpPn.tooltipped-ne::after,.hWlpPn.tooltipped-nw::after{right:50%;bottom:100%;margin-bottom:6px;}/*!sc*/ .hWlpPn.tooltipped-ne::after{right:auto;left:50%;margin-left:-16px;}/*!sc*/ .hWlpPn.tooltipped-nw::after{margin-right:-16px;}/*!sc*/ .hWlpPn.tooltipped-s::after,.hWlpPn.tooltipped-n::after{-webkit-transform:translateX(50%);-ms-transform:translateX(50%);transform:translateX(50%);}/*!sc*/ .hWlpPn.tooltipped-w::after{right:100%;bottom:50%;margin-right:6px;-webkit-transform:translateY(50%);-ms-transform:translateY(50%);transform:translateY(50%);}/*!sc*/ .hWlpPn.tooltipped-e::after{bottom:50%;left:100%;margin-left:6px;-webkit-transform:translateY(50%);-ms-transform:translateY(50%);transform:translateY(50%);}/*!sc*/ .hWlpPn.tooltipped-multiline::after{width:-webkit-max-content;width:-moz-max-content;width:max-content;max-width:250px;word-wrap:break-word;white-space:pre-line;border-collapse:separate;}/*!sc*/ .hWlpPn.tooltipped-multiline.tooltipped-s::after,.hWlpPn.tooltipped-multiline.tooltipped-n::after{right:auto;left:50%;-webkit-transform:translateX(-50%);-ms-transform:translateX(-50%);transform:translateX(-50%);}/*!sc*/ .hWlpPn.tooltipped-multiline.tooltipped-w::after,.hWlpPn.tooltipped-multiline.tooltipped-e::after{right:100%;}/*!sc*/ .hWlpPn.tooltipped-align-right-2::after{right:0;margin-right:0;}/*!sc*/ .hWlpPn.tooltipped-align-left-2::after{left:0;margin-left:0;}/*!sc*/ data-styled.g16[id="Tooltip__TooltipBase-sc-17tf59c-0"]{content:"hWlpPn,"}/*!sc*/ .liVpTx{display:inline-block;overflow:hidden;text-overflow:ellipsis;vertical-align:top;white-space:nowrap;max-width:125px;}/*!sc*/ data-styled.g18[id="Truncate__StyledTruncate-sc-23o1d2-0"]{content:"liVpTx,"}/*!sc*/ </style> <!-- --> <!-- --> <div class="Box-sc-g0xbh4-0 iVEunk"><div class="Box-sc-g0xbh4-0 jzuOtQ"><div class="Box-sc-g0xbh4-0 bGojzy"></div></div><div class="Box-sc-g0xbh4-0 iNSVHo"><div class="Box-sc-g0xbh4-0 bVgnfw"><div class="Box-sc-g0xbh4-0 CEgMp"><button type="button" aria-haspopup="true" aria-expanded="false" tabindex="0" aria-label="main branch" data-testid="anchor-button" class="Box-sc-g0xbh4-0 gMOVLe prc-Button-ButtonBase-c50BI overview-ref-selector width-full" data-loading="false" data-size="medium" data-variant="default" aria-describedby="branch-picker-repos-header-ref-selector-loading-announcement" id="branch-picker-repos-header-ref-selector"><span data-component="buttonContent" class="Box-sc-g0xbh4-0 gUkoLg prc-Button-ButtonContent-HKbr-"><span data-component="text" class="prc-Button-Label-pTQ3x"><div class="Box-sc-g0xbh4-0 bZBlpz"><div class="Box-sc-g0xbh4-0 lhTYNA"><svg aria-hidden="true" focusable="false" class="octicon octicon-git-branch" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M9.5 3.25a2.25 2.25 0 1 1 3 2.122V6A2.5 2.5 0 0 1 10 8.5H6a1 1 0 0 0-1 1v1.128a2.251 2.251 0 1 1-1.5 0V5.372a2.25 2.25 0 1 1 1.5 0v1.836A2.493 2.493 0 0 1 6 7h4a1 1 0 0 0 1-1v-.628A2.25 2.25 0 0 1 9.5 3.25Zm-6 0a.75.75 0 1 0 1.5 0 .75.75 0 0 0-1.5 0Zm8.25-.75a.75.75 0 1 0 0 1.5.75.75 0 0 0 0-1.5ZM4.25 12a.75.75 0 1 0 0 1.5.75.75 0 0 0 0-1.5Z"></path></svg></div><div class="Box-sc-g0xbh4-0 ffLUq ref-selector-button-text-container"><span class="Box-sc-g0xbh4-0 bmcJak prc-Text-Text-0ima0"> <!-- -->main</span></div></div></span><span data-component="trailingVisual" class="prc-Button-Visual-2epfX prc-Button-VisualWrap-Db-eB"><svg aria-hidden="true" focusable="false" class="octicon octicon-triangle-down" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="m4.427 7.427 3.396 3.396a.25.25 0 0 0 .354 0l3.396-3.396A.25.25 0 0 0 11.396 7H4.604a.25.25 0 0 0-.177.427Z"></path></svg></span></span></button><button hidden="" data-hotkey-scope="read-only-cursor-text-area"></button></div><div class="Box-sc-g0xbh4-0 fLXEGX"><a style="--button-color:fg.muted" type="button" href="/alexpovel/srgn/branches" class="Box-sc-g0xbh4-0 lmSMZJ prc-Button-ButtonBase-c50BI" data-loading="false" data-size="medium" data-variant="invisible" aria-describedby=":Rclab:-loading-announcement"><span data-component="buttonContent" class="Box-sc-g0xbh4-0 gUkoLg prc-Button-ButtonContent-HKbr-"><span data-component="leadingVisual" class="prc-Button-Visual-2epfX prc-Button-VisualWrap-Db-eB"><svg aria-hidden="true" focusable="false" class="octicon octicon-git-branch" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M9.5 3.25a2.25 2.25 0 1 1 3 2.122V6A2.5 2.5 0 0 1 10 8.5H6a1 1 0 0 0-1 1v1.128a2.251 2.251 0 1 1-1.5 0V5.372a2.25 2.25 0 1 1 1.5 0v1.836A2.493 2.493 0 0 1 6 7h4a1 1 0 0 0 1-1v-.628A2.25 2.25 0 0 1 9.5 3.25Zm-6 0a.75.75 0 1 0 1.5 0 .75.75 0 0 0-1.5 0Zm8.25-.75a.75.75 0 1 0 0 1.5.75.75 0 0 0 0-1.5ZM4.25 12a.75.75 0 1 0 0 1.5.75.75 0 0 0 0-1.5Z"></path></svg></span><span data-component="text" class="prc-Button-Label-pTQ3x">Branches</span></span></a><a style="--button-color:fg.muted" type="button" href="/alexpovel/srgn/tags" class="Box-sc-g0xbh4-0 lmSMZJ prc-Button-ButtonBase-c50BI" data-loading="false" data-size="medium" data-variant="invisible" aria-describedby=":Rklab:-loading-announcement"><span data-component="buttonContent" class="Box-sc-g0xbh4-0 gUkoLg prc-Button-ButtonContent-HKbr-"><span data-component="leadingVisual" class="prc-Button-Visual-2epfX prc-Button-VisualWrap-Db-eB"><svg aria-hidden="true" focusable="false" class="octicon octicon-tag" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M1 7.775V2.75C1 1.784 1.784 1 2.75 1h5.025c.464 0 .91.184 1.238.513l6.25 6.25a1.75 1.75 0 0 1 0 2.474l-5.026 5.026a1.75 1.75 0 0 1-2.474 0l-6.25-6.25A1.752 1.752 0 0 1 1 7.775Zm1.5 0c0 .066.026.13.073.177l6.25 6.25a.25.25 0 0 0 .354 0l5.025-5.025a.25.25 0 0 0 0-.354l-6.25-6.25a.25.25 0 0 0-.177-.073H2.75a.25.25 0 0 0-.25.25ZM6 5a1 1 0 1 1 0 2 1 1 0 0 1 0-2Z"></path></svg></span><span data-component="text" class="prc-Button-Label-pTQ3x">Tags</span></span></a></div><div class="Box-sc-g0xbh4-0 dqfxud"><a style="--button-color:fg.muted" type="button" aria-label="Go to Branches page" href="/alexpovel/srgn/branches" class="Box-sc-g0xbh4-0 fGwBZA prc-Button-ButtonBase-c50BI" data-loading="false" data-no-visuals="true" data-size="medium" data-variant="invisible" aria-describedby=":Relab:-loading-announcement"><svg aria-hidden="true" focusable="false" class="octicon octicon-git-branch" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M9.5 3.25a2.25 2.25 0 1 1 3 2.122V6A2.5 2.5 0 0 1 10 8.5H6a1 1 0 0 0-1 1v1.128a2.251 2.251 0 1 1-1.5 0V5.372a2.25 2.25 0 1 1 1.5 0v1.836A2.493 2.493 0 0 1 6 7h4a1 1 0 0 0 1-1v-.628A2.25 2.25 0 0 1 9.5 3.25Zm-6 0a.75.75 0 1 0 1.5 0 .75.75 0 0 0-1.5 0Zm8.25-.75a.75.75 0 1 0 0 1.5.75.75 0 0 0 0-1.5ZM4.25 12a.75.75 0 1 0 0 1.5.75.75 0 0 0 0-1.5Z"></path></svg></a><a style="--button-color:fg.muted" type="button" aria-label="Go to Tags page" href="/alexpovel/srgn/tags" class="Box-sc-g0xbh4-0 fGwBZA prc-Button-ButtonBase-c50BI" data-loading="false" data-no-visuals="true" data-size="medium" data-variant="invisible" aria-describedby=":Rmlab:-loading-announcement"><svg aria-hidden="true" focusable="false" class="octicon octicon-tag" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M1 7.775V2.75C1 1.784 1.784 1 2.75 1h5.025c.464 0 .91.184 1.238.513l6.25 6.25a1.75 1.75 0 0 1 0 2.474l-5.026 5.026a1.75 1.75 0 0 1-2.474 0l-6.25-6.25A1.752 1.752 0 0 1 1 7.775Zm1.5 0c0 .066.026.13.073.177l6.25 6.25a.25.25 0 0 0 .354 0l5.025-5.025a.25.25 0 0 0 0-.354l-6.25-6.25a.25.25 0 0 0-.177-.073H2.75a.25.25 0 0 0-.25.25ZM6 5a1 1 0 1 1 0 2 1 1 0 0 1 0-2Z"></path></svg></a></div></div><div class="Box-sc-g0xbh4-0 jxTzTd"><div class="Box-sc-g0xbh4-0 gqqBXN"><div class="Box-sc-g0xbh4-0 dzXgxt"><!--$--><div class="Box-sc-g0xbh4-0 iWFGlI"><span class="Box-sc-g0xbh4-0 vcvyP TextInput-wrapper prc-components-TextInputWrapper-i1ofR prc-components-TextInputBaseWrapper-ueK9q" data-leading-visual="true" data-trailing-visual="true" aria-busy="false"><span class="TextInput-icon" id=":R2j5ab:" aria-hidden="true"><svg aria-hidden="true" focusable="false" class="octicon octicon-search" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M10.68 11.74a6 6 0 0 1-7.922-8.982 6 6 0 0 1 8.982 7.922l3.04 3.04a.749.749 0 0 1-.326 1.275.749.749 0 0 1-.734-.215ZM11.5 7a4.499 4.499 0 1 0-8.997 0A4.499 4.499 0 0 0 11.5 7Z"></path></svg></span><input type="text" aria-label="Go to file" role="combobox" aria-controls="file-results-list" aria-expanded="false" aria-haspopup="dialog" autoCorrect="off" spellcheck="false" placeholder="Go to file" aria-describedby=":R2j5ab: :R2j5abH1:" data-component="input" class="prc-components-Input-Ic-y8" value=""/><span class="TextInput-icon" id=":R2j5abH1:" aria-hidden="true"></span></span></div><!--/$--></div><div class="Box-sc-g0xbh4-0 YUPas"><button type="button" class="prc-Button-ButtonBase-c50BI" data-loading="false" data-no-visuals="true" data-size="medium" data-variant="default" aria-describedby=":Rr5ab:-loading-announcement"><span data-component="buttonContent" data-align="center" class="prc-Button-ButtonContent-HKbr-"><span data-component="text" class="prc-Button-Label-pTQ3x">Go to file</span></span></button></div><div class="react-directory-add-file-icon"></div><div class="react-directory-remove-file-icon"></div></div><button type="button" aria-haspopup="true" aria-expanded="false" tabindex="0" class="prc-Button-ButtonBase-c50BI" data-loading="false" data-size="medium" data-variant="primary" aria-describedby=":R55ab:-loading-announcement" id=":R55ab:"><span data-component="buttonContent" data-align="center" class="prc-Button-ButtonContent-HKbr-"><span data-component="leadingVisual" class="prc-Button-Visual-2epfX prc-Button-VisualWrap-Db-eB"><svg aria-hidden="true" focusable="false" class="octicon octicon-code hide-sm" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="m11.28 3.22 4.25 4.25a.75.75 0 0 1 0 1.06l-4.25 4.25a.749.749 0 0 1-1.275-.326.749.749 0 0 1 .215-.734L13.94 8l-3.72-3.72a.749.749 0 0 1 .326-1.275.749.749 0 0 1 .734.215Zm-6.56 0a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042L2.06 8l3.72 3.72a.749.749 0 0 1-.326 1.275.749.749 0 0 1-.734-.215L.47 8.53a.75.75 0 0 1 0-1.06Z"></path></svg></span><span data-component="text" class="prc-Button-Label-pTQ3x">Code</span><span data-component="trailingVisual" class="prc-Button-Visual-2epfX prc-Button-VisualWrap-Db-eB"><svg aria-hidden="true" focusable="false" class="octicon octicon-triangle-down" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="m4.427 7.427 3.396 3.396a.25.25 0 0 0 .354 0l3.396-3.396A.25.25 0 0 0 11.396 7H4.604a.25.25 0 0 0-.177.427Z"></path></svg></span></span></button><div class="Box-sc-g0xbh4-0 izFOf"><button data-component="IconButton" type="button" aria-label="Open more actions menu" aria-haspopup="true" aria-expanded="false" tabindex="0" class="prc-Button-ButtonBase-c50BI prc-Button-IconButton-szpyj" data-loading="false" data-no-visuals="true" data-size="medium" data-variant="default" aria-describedby=":R75ab:-loading-announcement" id=":R75ab:"><svg aria-hidden="true" focusable="false" class="octicon octicon-kebab-horizontal" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M8 9a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3ZM1.5 9a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3Zm13 0a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3Z"></path></svg></button></div></div></div><div class="Box-sc-g0xbh4-0 vIPPs"><div data-hpc="true"><button hidden="" data-testid="focus-next-element-button" data-hotkey="j"></button><button hidden="" data-testid="focus-previous-element-button" data-hotkey="k"></button><h2 class="sr-only ScreenReaderHeading-module__userSelectNone--vW4Cq prc-Heading-Heading-6CmGO" data-testid="screen-reader-heading" id="folders-and-files">Folders and files</h2><table aria-labelledby="folders-and-files" class="Box-sc-g0xbh4-0 fdROMU"><thead class="Box-sc-g0xbh4-0 jGKpsv"><tr class="Box-sc-g0xbh4-0 jdgHnn"><th colSpan="2" class="Box-sc-g0xbh4-0 bQivRW"><span class="text-bold">Name</span></th><th colSpan="1" class="Box-sc-g0xbh4-0 ldkMIO"><span class="text-bold">Name</span></th><th class="hide-sm"><div title="Last commit message" class="Truncate__StyledTruncate-sc-23o1d2-0 liVpTx width-fit"><span class="text-bold">Last commit message</span></div></th><th colSpan="1" class="Box-sc-g0xbh4-0 jMbWeI"><div title="Last commit date" class="Truncate__StyledTruncate-sc-23o1d2-0 liVpTx width-fit"><span class="text-bold">Last commit date</span></div></th></tr></thead><tbody><tr class="Box-sc-g0xbh4-0 gpqjiB"><td colSpan="3" class="bgColor-muted p-1 rounded-top-2"><div class="Box-sc-g0xbh4-0 dzCJzi"><h2 class="sr-only ScreenReaderHeading-module__userSelectNone--vW4Cq prc-Heading-Heading-6CmGO" data-testid="screen-reader-heading">Latest commit</h2><div style="width:120px" class="Skeleton Skeleton--text" data-testid="loading"> </div><div class="d-flex flex-shrink-0 gap-2"><div data-testid="latest-commit-details" class="d-none d-sm-flex flex-items-center"></div><div class="d-flex gap-2"><h2 class="sr-only ScreenReaderHeading-module__userSelectNone--vW4Cq prc-Heading-Heading-6CmGO" data-testid="screen-reader-heading">History</h2><a href="/alexpovel/srgn/commits/main/" class="prc-Button-ButtonBase-c50BI d-none d-lg-flex LinkButton-module__code-view-link-button--xvCGA flex-items-center fgColor-default" data-loading="false" data-size="small" data-variant="invisible" aria-describedby=":Raqj8pab:-loading-announcement"><span data-component="buttonContent" data-align="center" class="prc-Button-ButtonContent-HKbr-"><span data-component="leadingVisual" class="prc-Button-Visual-2epfX prc-Button-VisualWrap-Db-eB"><svg aria-hidden="true" focusable="false" class="octicon octicon-history" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="m.427 1.927 1.215 1.215a8.002 8.002 0 1 1-1.6 5.685.75.75 0 1 1 1.493-.154 6.5 6.5 0 1 0 1.18-4.458l1.358 1.358A.25.25 0 0 1 3.896 6H.25A.25.25 0 0 1 0 5.75V2.104a.25.25 0 0 1 .427-.177ZM7.75 4a.75.75 0 0 1 .75.75v2.992l2.028.812a.75.75 0 0 1-.557 1.392l-2.5-1A.751.751 0 0 1 7 8.25v-3.5A.75.75 0 0 1 7.75 4Z"></path></svg></span><span data-component="text" class="prc-Button-Label-pTQ3x"><span class="fgColor-default">690 Commits</span></span></span></a><div class="d-sm-none"></div><div class="d-flex d-lg-none"><span role="tooltip" aria-label="690 Commits" id="history-icon-button-tooltip" class="Tooltip__TooltipBase-sc-17tf59c-0 hWlpPn tooltipped-n"><a href="/alexpovel/srgn/commits/main/" class="prc-Button-ButtonBase-c50BI LinkButton-module__code-view-link-button--xvCGA flex-items-center fgColor-default" data-loading="false" data-size="small" data-variant="invisible" aria-describedby=":R1iqj8pab:-loading-announcement history-icon-button-tooltip"><span data-component="buttonContent" data-align="center" class="prc-Button-ButtonContent-HKbr-"><span data-component="leadingVisual" class="prc-Button-Visual-2epfX prc-Button-VisualWrap-Db-eB"><svg aria-hidden="true" focusable="false" class="octicon octicon-history" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="m.427 1.927 1.215 1.215a8.002 8.002 0 1 1-1.6 5.685.75.75 0 1 1 1.493-.154 6.5 6.5 0 1 0 1.18-4.458l1.358 1.358A.25.25 0 0 1 3.896 6H.25A.25.25 0 0 1 0 5.75V2.104a.25.25 0 0 1 .427-.177ZM7.75 4a.75.75 0 0 1 .75.75v2.992l2.028.812a.75.75 0 0 1-.557 1.392l-2.5-1A.751.751 0 0 1 7 8.25v-3.5A.75.75 0 0 1 7.75 4Z"></path></svg></span></span></a></span></div></div></div></div></td></tr><tr class="react-directory-row undefined" id="folder-row-0"><td class="react-directory-row-name-cell-small-screen" colSpan="2"><div class="react-directory-filename-column"><svg aria-hidden="true" focusable="false" class="octicon octicon-file-directory-fill icon-directory" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M1.75 1A1.75 1.75 0 0 0 0 2.75v10.5C0 14.216.784 15 1.75 15h12.5A1.75 1.75 0 0 0 16 13.25v-8.5A1.75 1.75 0 0 0 14.25 3H7.5a.25.25 0 0 1-.2-.1l-.9-1.2C6.07 1.26 5.55 1 5 1H1.75Z"></path></svg><div class="overflow-hidden"><div class="react-directory-filename-cell"><div class="react-directory-truncate"><a title=".github" aria-label=".github, (Directory)" class="Link--primary" href="/alexpovel/srgn/tree/main/.github">.github</a></div></div></div></div></td><td class="react-directory-row-name-cell-large-screen" colSpan="1"><div class="react-directory-filename-column"><svg aria-hidden="true" focusable="false" class="octicon octicon-file-directory-fill icon-directory" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M1.75 1A1.75 1.75 0 0 0 0 2.75v10.5C0 14.216.784 15 1.75 15h12.5A1.75 1.75 0 0 0 16 13.25v-8.5A1.75 1.75 0 0 0 14.25 3H7.5a.25.25 0 0 1-.2-.1l-.9-1.2C6.07 1.26 5.55 1 5 1H1.75Z"></path></svg><div class="overflow-hidden"><div class="react-directory-filename-cell"><div class="react-directory-truncate"><a title=".github" aria-label=".github, (Directory)" class="Link--primary" href="/alexpovel/srgn/tree/main/.github">.github</a></div></div></div></div></td><td class="react-directory-row-commit-cell"><div class="Skeleton Skeleton--text"> </div></td><td><div class="Skeleton Skeleton--text"> </div></td></tr><tr class="react-directory-row undefined" id="folder-row-1"><td class="react-directory-row-name-cell-small-screen" colSpan="2"><div class="react-directory-filename-column"><svg aria-hidden="true" focusable="false" class="octicon octicon-file-directory-fill icon-directory" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M1.75 1A1.75 1.75 0 0 0 0 2.75v10.5C0 14.216.784 15 1.75 15h12.5A1.75 1.75 0 0 0 16 13.25v-8.5A1.75 1.75 0 0 0 14.25 3H7.5a.25.25 0 0 1-.2-.1l-.9-1.2C6.07 1.26 5.55 1 5 1H1.75Z"></path></svg><div class="overflow-hidden"><div class="react-directory-filename-cell"><div class="react-directory-truncate"><a title=".vscode" aria-label=".vscode, (Directory)" class="Link--primary" href="/alexpovel/srgn/tree/main/.vscode">.vscode</a></div></div></div></div></td><td class="react-directory-row-name-cell-large-screen" colSpan="1"><div class="react-directory-filename-column"><svg aria-hidden="true" focusable="false" class="octicon octicon-file-directory-fill icon-directory" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M1.75 1A1.75 1.75 0 0 0 0 2.75v10.5C0 14.216.784 15 1.75 15h12.5A1.75 1.75 0 0 0 16 13.25v-8.5A1.75 1.75 0 0 0 14.25 3H7.5a.25.25 0 0 1-.2-.1l-.9-1.2C6.07 1.26 5.55 1 5 1H1.75Z"></path></svg><div class="overflow-hidden"><div class="react-directory-filename-cell"><div class="react-directory-truncate"><a title=".vscode" aria-label=".vscode, (Directory)" class="Link--primary" href="/alexpovel/srgn/tree/main/.vscode">.vscode</a></div></div></div></div></td><td class="react-directory-row-commit-cell"><div class="Skeleton Skeleton--text"> </div></td><td><div class="Skeleton Skeleton--text"> </div></td></tr><tr class="react-directory-row undefined" id="folder-row-2"><td class="react-directory-row-name-cell-small-screen" colSpan="2"><div class="react-directory-filename-column"><svg aria-hidden="true" focusable="false" class="octicon octicon-file-directory-fill icon-directory" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M1.75 1A1.75 1.75 0 0 0 0 2.75v10.5C0 14.216.784 15 1.75 15h12.5A1.75 1.75 0 0 0 16 13.25v-8.5A1.75 1.75 0 0 0 14.25 3H7.5a.25.25 0 0 1-.2-.1l-.9-1.2C6.07 1.26 5.55 1 5 1H1.75Z"></path></svg><div class="overflow-hidden"><div class="react-directory-filename-cell"><div class="react-directory-truncate"><a title="benches" aria-label="benches, (Directory)" class="Link--primary" href="/alexpovel/srgn/tree/main/benches">benches</a></div></div></div></div></td><td class="react-directory-row-name-cell-large-screen" colSpan="1"><div class="react-directory-filename-column"><svg aria-hidden="true" focusable="false" class="octicon octicon-file-directory-fill icon-directory" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M1.75 1A1.75 1.75 0 0 0 0 2.75v10.5C0 14.216.784 15 1.75 15h12.5A1.75 1.75 0 0 0 16 13.25v-8.5A1.75 1.75 0 0 0 14.25 3H7.5a.25.25 0 0 1-.2-.1l-.9-1.2C6.07 1.26 5.55 1 5 1H1.75Z"></path></svg><div class="overflow-hidden"><div class="react-directory-filename-cell"><div class="react-directory-truncate"><a title="benches" aria-label="benches, (Directory)" class="Link--primary" href="/alexpovel/srgn/tree/main/benches">benches</a></div></div></div></div></td><td class="react-directory-row-commit-cell"><div class="Skeleton Skeleton--text"> </div></td><td><div class="Skeleton Skeleton--text"> </div></td></tr><tr class="react-directory-row undefined" id="folder-row-3"><td class="react-directory-row-name-cell-small-screen" colSpan="2"><div class="react-directory-filename-column"><svg aria-hidden="true" focusable="false" class="octicon octicon-file-directory-fill icon-directory" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M1.75 1A1.75 1.75 0 0 0 0 2.75v10.5C0 14.216.784 15 1.75 15h12.5A1.75 1.75 0 0 0 16 13.25v-8.5A1.75 1.75 0 0 0 14.25 3H7.5a.25.25 0 0 1-.2-.1l-.9-1.2C6.07 1.26 5.55 1 5 1H1.75Z"></path></svg><div class="overflow-hidden"><div class="react-directory-filename-cell"><div class="react-directory-truncate"><a title="This path skips through empty directories" aria-label="data/word-lists, (Directory)" class="Link--primary" href="/alexpovel/srgn/tree/main/data/word-lists"><span class="react-directory-default-color" data-testid="path-name-segment">data/</span><span class="" data-testid="path-name-segment">word-lists</span></a></div></div></div></div></td><td class="react-directory-row-name-cell-large-screen" colSpan="1"><div class="react-directory-filename-column"><svg aria-hidden="true" focusable="false" class="octicon octicon-file-directory-fill icon-directory" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M1.75 1A1.75 1.75 0 0 0 0 2.75v10.5C0 14.216.784 15 1.75 15h12.5A1.75 1.75 0 0 0 16 13.25v-8.5A1.75 1.75 0 0 0 14.25 3H7.5a.25.25 0 0 1-.2-.1l-.9-1.2C6.07 1.26 5.55 1 5 1H1.75Z"></path></svg><div class="overflow-hidden"><div class="react-directory-filename-cell"><div class="react-directory-truncate"><a title="This path skips through empty directories" aria-label="data/word-lists, (Directory)" class="Link--primary" href="/alexpovel/srgn/tree/main/data/word-lists"><span class="react-directory-default-color" data-testid="path-name-segment">data/</span><span class="" data-testid="path-name-segment">word-lists</span></a></div></div></div></div></td><td class="react-directory-row-commit-cell"><div class="Skeleton Skeleton--text"> </div></td><td><div class="Skeleton Skeleton--text"> </div></td></tr><tr class="react-directory-row undefined" id="folder-row-4"><td class="react-directory-row-name-cell-small-screen" colSpan="2"><div class="react-directory-filename-column"><svg aria-hidden="true" focusable="false" class="octicon octicon-file-directory-fill icon-directory" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M1.75 1A1.75 1.75 0 0 0 0 2.75v10.5C0 14.216.784 15 1.75 15h12.5A1.75 1.75 0 0 0 16 13.25v-8.5A1.75 1.75 0 0 0 14.25 3H7.5a.25.25 0 0 1-.2-.1l-.9-1.2C6.07 1.26 5.55 1 5 1H1.75Z"></path></svg><div class="overflow-hidden"><div class="react-directory-filename-cell"><div class="react-directory-truncate"><a title="docs" aria-label="docs, (Directory)" class="Link--primary" href="/alexpovel/srgn/tree/main/docs">docs</a></div></div></div></div></td><td class="react-directory-row-name-cell-large-screen" colSpan="1"><div class="react-directory-filename-column"><svg aria-hidden="true" focusable="false" class="octicon octicon-file-directory-fill icon-directory" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M1.75 1A1.75 1.75 0 0 0 0 2.75v10.5C0 14.216.784 15 1.75 15h12.5A1.75 1.75 0 0 0 16 13.25v-8.5A1.75 1.75 0 0 0 14.25 3H7.5a.25.25 0 0 1-.2-.1l-.9-1.2C6.07 1.26 5.55 1 5 1H1.75Z"></path></svg><div class="overflow-hidden"><div class="react-directory-filename-cell"><div class="react-directory-truncate"><a title="docs" aria-label="docs, (Directory)" class="Link--primary" href="/alexpovel/srgn/tree/main/docs">docs</a></div></div></div></div></td><td class="react-directory-row-commit-cell"><div class="Skeleton Skeleton--text"> </div></td><td><div class="Skeleton Skeleton--text"> </div></td></tr><tr class="react-directory-row undefined" id="folder-row-5"><td class="react-directory-row-name-cell-small-screen" colSpan="2"><div class="react-directory-filename-column"><svg aria-hidden="true" focusable="false" class="octicon octicon-file-directory-fill icon-directory" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M1.75 1A1.75 1.75 0 0 0 0 2.75v10.5C0 14.216.784 15 1.75 15h12.5A1.75 1.75 0 0 0 16 13.25v-8.5A1.75 1.75 0 0 0 14.25 3H7.5a.25.25 0 0 1-.2-.1l-.9-1.2C6.07 1.26 5.55 1 5 1H1.75Z"></path></svg><div class="overflow-hidden"><div class="react-directory-filename-cell"><div class="react-directory-truncate"><a title="src" aria-label="src, (Directory)" class="Link--primary" href="/alexpovel/srgn/tree/main/src">src</a></div></div></div></div></td><td class="react-directory-row-name-cell-large-screen" colSpan="1"><div class="react-directory-filename-column"><svg aria-hidden="true" focusable="false" class="octicon octicon-file-directory-fill icon-directory" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M1.75 1A1.75 1.75 0 0 0 0 2.75v10.5C0 14.216.784 15 1.75 15h12.5A1.75 1.75 0 0 0 16 13.25v-8.5A1.75 1.75 0 0 0 14.25 3H7.5a.25.25 0 0 1-.2-.1l-.9-1.2C6.07 1.26 5.55 1 5 1H1.75Z"></path></svg><div class="overflow-hidden"><div class="react-directory-filename-cell"><div class="react-directory-truncate"><a title="src" aria-label="src, (Directory)" class="Link--primary" href="/alexpovel/srgn/tree/main/src">src</a></div></div></div></div></td><td class="react-directory-row-commit-cell"><div class="Skeleton Skeleton--text"> </div></td><td><div class="Skeleton Skeleton--text"> </div></td></tr><tr class="react-directory-row undefined" id="folder-row-6"><td class="react-directory-row-name-cell-small-screen" colSpan="2"><div class="react-directory-filename-column"><svg aria-hidden="true" focusable="false" class="octicon octicon-file-directory-fill icon-directory" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M1.75 1A1.75 1.75 0 0 0 0 2.75v10.5C0 14.216.784 15 1.75 15h12.5A1.75 1.75 0 0 0 16 13.25v-8.5A1.75 1.75 0 0 0 14.25 3H7.5a.25.25 0 0 1-.2-.1l-.9-1.2C6.07 1.26 5.55 1 5 1H1.75Z"></path></svg><div class="overflow-hidden"><div class="react-directory-filename-cell"><div class="react-directory-truncate"><a title="tests" aria-label="tests, (Directory)" class="Link--primary" href="/alexpovel/srgn/tree/main/tests">tests</a></div></div></div></div></td><td class="react-directory-row-name-cell-large-screen" colSpan="1"><div class="react-directory-filename-column"><svg aria-hidden="true" focusable="false" class="octicon octicon-file-directory-fill icon-directory" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M1.75 1A1.75 1.75 0 0 0 0 2.75v10.5C0 14.216.784 15 1.75 15h12.5A1.75 1.75 0 0 0 16 13.25v-8.5A1.75 1.75 0 0 0 14.25 3H7.5a.25.25 0 0 1-.2-.1l-.9-1.2C6.07 1.26 5.55 1 5 1H1.75Z"></path></svg><div class="overflow-hidden"><div class="react-directory-filename-cell"><div class="react-directory-truncate"><a title="tests" aria-label="tests, (Directory)" class="Link--primary" href="/alexpovel/srgn/tree/main/tests">tests</a></div></div></div></div></td><td class="react-directory-row-commit-cell"><div class="Skeleton Skeleton--text"> </div></td><td><div class="Skeleton Skeleton--text"> </div></td></tr><tr class="react-directory-row undefined" id="folder-row-7"><td class="react-directory-row-name-cell-small-screen" colSpan="2"><div class="react-directory-filename-column"><svg aria-hidden="true" focusable="false" class="octicon octicon-file color-fg-muted" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M2 1.75C2 .784 2.784 0 3.75 0h6.586c.464 0 .909.184 1.237.513l2.914 2.914c.329.328.513.773.513 1.237v9.586A1.75 1.75 0 0 1 13.25 16h-9.5A1.75 1.75 0 0 1 2 14.25Zm1.75-.25a.25.25 0 0 0-.25.25v12.5c0 .138.112.25.25.25h9.5a.25.25 0 0 0 .25-.25V6h-2.75A1.75 1.75 0 0 1 9 4.25V1.5Zm6.75.062V4.25c0 .138.112.25.25.25h2.688l-.011-.013-2.914-2.914-.013-.011Z"></path></svg><div class="overflow-hidden"><div class="react-directory-filename-cell"><div class="react-directory-truncate"><a title=".gitattributes" aria-label=".gitattributes, (File)" class="Link--primary" href="/alexpovel/srgn/blob/main/.gitattributes">.gitattributes</a></div></div></div></div></td><td class="react-directory-row-name-cell-large-screen" colSpan="1"><div class="react-directory-filename-column"><svg aria-hidden="true" focusable="false" class="octicon octicon-file color-fg-muted" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M2 1.75C2 .784 2.784 0 3.75 0h6.586c.464 0 .909.184 1.237.513l2.914 2.914c.329.328.513.773.513 1.237v9.586A1.75 1.75 0 0 1 13.25 16h-9.5A1.75 1.75 0 0 1 2 14.25Zm1.75-.25a.25.25 0 0 0-.25.25v12.5c0 .138.112.25.25.25h9.5a.25.25 0 0 0 .25-.25V6h-2.75A1.75 1.75 0 0 1 9 4.25V1.5Zm6.75.062V4.25c0 .138.112.25.25.25h2.688l-.011-.013-2.914-2.914-.013-.011Z"></path></svg><div class="overflow-hidden"><div class="react-directory-filename-cell"><div class="react-directory-truncate"><a title=".gitattributes" aria-label=".gitattributes, (File)" class="Link--primary" href="/alexpovel/srgn/blob/main/.gitattributes">.gitattributes</a></div></div></div></div></td><td class="react-directory-row-commit-cell"><div class="Skeleton Skeleton--text"> </div></td><td><div class="Skeleton Skeleton--text"> </div></td></tr><tr class="react-directory-row undefined" id="folder-row-8"><td class="react-directory-row-name-cell-small-screen" colSpan="2"><div class="react-directory-filename-column"><svg aria-hidden="true" focusable="false" class="octicon octicon-file color-fg-muted" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M2 1.75C2 .784 2.784 0 3.75 0h6.586c.464 0 .909.184 1.237.513l2.914 2.914c.329.328.513.773.513 1.237v9.586A1.75 1.75 0 0 1 13.25 16h-9.5A1.75 1.75 0 0 1 2 14.25Zm1.75-.25a.25.25 0 0 0-.25.25v12.5c0 .138.112.25.25.25h9.5a.25.25 0 0 0 .25-.25V6h-2.75A1.75 1.75 0 0 1 9 4.25V1.5Zm6.75.062V4.25c0 .138.112.25.25.25h2.688l-.011-.013-2.914-2.914-.013-.011Z"></path></svg><div class="overflow-hidden"><div class="react-directory-filename-cell"><div class="react-directory-truncate"><a title=".gitignore" aria-label=".gitignore, (File)" class="Link--primary" href="/alexpovel/srgn/blob/main/.gitignore">.gitignore</a></div></div></div></div></td><td class="react-directory-row-name-cell-large-screen" colSpan="1"><div class="react-directory-filename-column"><svg aria-hidden="true" focusable="false" class="octicon octicon-file color-fg-muted" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M2 1.75C2 .784 2.784 0 3.75 0h6.586c.464 0 .909.184 1.237.513l2.914 2.914c.329.328.513.773.513 1.237v9.586A1.75 1.75 0 0 1 13.25 16h-9.5A1.75 1.75 0 0 1 2 14.25Zm1.75-.25a.25.25 0 0 0-.25.25v12.5c0 .138.112.25.25.25h9.5a.25.25 0 0 0 .25-.25V6h-2.75A1.75 1.75 0 0 1 9 4.25V1.5Zm6.75.062V4.25c0 .138.112.25.25.25h2.688l-.011-.013-2.914-2.914-.013-.011Z"></path></svg><div class="overflow-hidden"><div class="react-directory-filename-cell"><div class="react-directory-truncate"><a title=".gitignore" aria-label=".gitignore, (File)" class="Link--primary" href="/alexpovel/srgn/blob/main/.gitignore">.gitignore</a></div></div></div></div></td><td class="react-directory-row-commit-cell"><div class="Skeleton Skeleton--text"> </div></td><td><div class="Skeleton Skeleton--text"> </div></td></tr><tr class="react-directory-row undefined" id="folder-row-9"><td class="react-directory-row-name-cell-small-screen" colSpan="2"><div class="react-directory-filename-column"><svg aria-hidden="true" focusable="false" class="octicon octicon-file color-fg-muted" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M2 1.75C2 .784 2.784 0 3.75 0h6.586c.464 0 .909.184 1.237.513l2.914 2.914c.329.328.513.773.513 1.237v9.586A1.75 1.75 0 0 1 13.25 16h-9.5A1.75 1.75 0 0 1 2 14.25Zm1.75-.25a.25.25 0 0 0-.25.25v12.5c0 .138.112.25.25.25h9.5a.25.25 0 0 0 .25-.25V6h-2.75A1.75 1.75 0 0 1 9 4.25V1.5Zm6.75.062V4.25c0 .138.112.25.25.25h2.688l-.011-.013-2.914-2.914-.013-.011Z"></path></svg><div class="overflow-hidden"><div class="react-directory-filename-cell"><div class="react-directory-truncate"><a title=".gitmodules" aria-label=".gitmodules, (File)" class="Link--primary" href="/alexpovel/srgn/blob/main/.gitmodules">.gitmodules</a></div></div></div></div></td><td class="react-directory-row-name-cell-large-screen" colSpan="1"><div class="react-directory-filename-column"><svg aria-hidden="true" focusable="false" class="octicon octicon-file color-fg-muted" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M2 1.75C2 .784 2.784 0 3.75 0h6.586c.464 0 .909.184 1.237.513l2.914 2.914c.329.328.513.773.513 1.237v9.586A1.75 1.75 0 0 1 13.25 16h-9.5A1.75 1.75 0 0 1 2 14.25Zm1.75-.25a.25.25 0 0 0-.25.25v12.5c0 .138.112.25.25.25h9.5a.25.25 0 0 0 .25-.25V6h-2.75A1.75 1.75 0 0 1 9 4.25V1.5Zm6.75.062V4.25c0 .138.112.25.25.25h2.688l-.011-.013-2.914-2.914-.013-.011Z"></path></svg><div class="overflow-hidden"><div class="react-directory-filename-cell"><div class="react-directory-truncate"><a title=".gitmodules" aria-label=".gitmodules, (File)" class="Link--primary" href="/alexpovel/srgn/blob/main/.gitmodules">.gitmodules</a></div></div></div></div></td><td class="react-directory-row-commit-cell"><div class="Skeleton Skeleton--text"> </div></td><td><div class="Skeleton Skeleton--text"> </div></td></tr><tr class="react-directory-row truncate-for-mobile" id="folder-row-10"><td class="react-directory-row-name-cell-small-screen" colSpan="2"><div class="react-directory-filename-column"><svg aria-hidden="true" focusable="false" class="octicon octicon-file color-fg-muted" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M2 1.75C2 .784 2.784 0 3.75 0h6.586c.464 0 .909.184 1.237.513l2.914 2.914c.329.328.513.773.513 1.237v9.586A1.75 1.75 0 0 1 13.25 16h-9.5A1.75 1.75 0 0 1 2 14.25Zm1.75-.25a.25.25 0 0 0-.25.25v12.5c0 .138.112.25.25.25h9.5a.25.25 0 0 0 .25-.25V6h-2.75A1.75 1.75 0 0 1 9 4.25V1.5Zm6.75.062V4.25c0 .138.112.25.25.25h2.688l-.011-.013-2.914-2.914-.013-.011Z"></path></svg><div class="overflow-hidden"><div class="react-directory-filename-cell"><div class="react-directory-truncate"><a title=".markdownlint.yaml" aria-label=".markdownlint.yaml, (File)" class="Link--primary" href="/alexpovel/srgn/blob/main/.markdownlint.yaml">.markdownlint.yaml</a></div></div></div></div></td><td class="react-directory-row-name-cell-large-screen" colSpan="1"><div class="react-directory-filename-column"><svg aria-hidden="true" focusable="false" class="octicon octicon-file color-fg-muted" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M2 1.75C2 .784 2.784 0 3.75 0h6.586c.464 0 .909.184 1.237.513l2.914 2.914c.329.328.513.773.513 1.237v9.586A1.75 1.75 0 0 1 13.25 16h-9.5A1.75 1.75 0 0 1 2 14.25Zm1.75-.25a.25.25 0 0 0-.25.25v12.5c0 .138.112.25.25.25h9.5a.25.25 0 0 0 .25-.25V6h-2.75A1.75 1.75 0 0 1 9 4.25V1.5Zm6.75.062V4.25c0 .138.112.25.25.25h2.688l-.011-.013-2.914-2.914-.013-.011Z"></path></svg><div class="overflow-hidden"><div class="react-directory-filename-cell"><div class="react-directory-truncate"><a title=".markdownlint.yaml" aria-label=".markdownlint.yaml, (File)" class="Link--primary" href="/alexpovel/srgn/blob/main/.markdownlint.yaml">.markdownlint.yaml</a></div></div></div></div></td><td class="react-directory-row-commit-cell"><div class="Skeleton Skeleton--text"> </div></td><td><div class="Skeleton Skeleton--text"> </div></td></tr><tr class="react-directory-row truncate-for-mobile" id="folder-row-11"><td class="react-directory-row-name-cell-small-screen" colSpan="2"><div class="react-directory-filename-column"><svg aria-hidden="true" focusable="false" class="octicon octicon-file color-fg-muted" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M2 1.75C2 .784 2.784 0 3.75 0h6.586c.464 0 .909.184 1.237.513l2.914 2.914c.329.328.513.773.513 1.237v9.586A1.75 1.75 0 0 1 13.25 16h-9.5A1.75 1.75 0 0 1 2 14.25Zm1.75-.25a.25.25 0 0 0-.25.25v12.5c0 .138.112.25.25.25h9.5a.25.25 0 0 0 .25-.25V6h-2.75A1.75 1.75 0 0 1 9 4.25V1.5Zm6.75.062V4.25c0 .138.112.25.25.25h2.688l-.011-.013-2.914-2.914-.013-.011Z"></path></svg><div class="overflow-hidden"><div class="react-directory-filename-cell"><div class="react-directory-truncate"><a title=".markdownlintignore" aria-label=".markdownlintignore, (File)" class="Link--primary" href="/alexpovel/srgn/blob/main/.markdownlintignore">.markdownlintignore</a></div></div></div></div></td><td class="react-directory-row-name-cell-large-screen" colSpan="1"><div class="react-directory-filename-column"><svg aria-hidden="true" focusable="false" class="octicon octicon-file color-fg-muted" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M2 1.75C2 .784 2.784 0 3.75 0h6.586c.464 0 .909.184 1.237.513l2.914 2.914c.329.328.513.773.513 1.237v9.586A1.75 1.75 0 0 1 13.25 16h-9.5A1.75 1.75 0 0 1 2 14.25Zm1.75-.25a.25.25 0 0 0-.25.25v12.5c0 .138.112.25.25.25h9.5a.25.25 0 0 0 .25-.25V6h-2.75A1.75 1.75 0 0 1 9 4.25V1.5Zm6.75.062V4.25c0 .138.112.25.25.25h2.688l-.011-.013-2.914-2.914-.013-.011Z"></path></svg><div class="overflow-hidden"><div class="react-directory-filename-cell"><div class="react-directory-truncate"><a title=".markdownlintignore" aria-label=".markdownlintignore, (File)" class="Link--primary" href="/alexpovel/srgn/blob/main/.markdownlintignore">.markdownlintignore</a></div></div></div></div></td><td class="react-directory-row-commit-cell"><div class="Skeleton Skeleton--text"> </div></td><td><div class="Skeleton Skeleton--text"> </div></td></tr><tr class="react-directory-row truncate-for-mobile" id="folder-row-12"><td class="react-directory-row-name-cell-small-screen" colSpan="2"><div class="react-directory-filename-column"><svg aria-hidden="true" focusable="false" class="octicon octicon-file color-fg-muted" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M2 1.75C2 .784 2.784 0 3.75 0h6.586c.464 0 .909.184 1.237.513l2.914 2.914c.329.328.513.773.513 1.237v9.586A1.75 1.75 0 0 1 13.25 16h-9.5A1.75 1.75 0 0 1 2 14.25Zm1.75-.25a.25.25 0 0 0-.25.25v12.5c0 .138.112.25.25.25h9.5a.25.25 0 0 0 .25-.25V6h-2.75A1.75 1.75 0 0 1 9 4.25V1.5Zm6.75.062V4.25c0 .138.112.25.25.25h2.688l-.011-.013-2.914-2.914-.013-.011Z"></path></svg><div class="overflow-hidden"><div class="react-directory-filename-cell"><div class="react-directory-truncate"><a title=".pre-commit-config.yaml" aria-label=".pre-commit-config.yaml, (File)" class="Link--primary" href="/alexpovel/srgn/blob/main/.pre-commit-config.yaml">.pre-commit-config.yaml</a></div></div></div></div></td><td class="react-directory-row-name-cell-large-screen" colSpan="1"><div class="react-directory-filename-column"><svg aria-hidden="true" focusable="false" class="octicon octicon-file color-fg-muted" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M2 1.75C2 .784 2.784 0 3.75 0h6.586c.464 0 .909.184 1.237.513l2.914 2.914c.329.328.513.773.513 1.237v9.586A1.75 1.75 0 0 1 13.25 16h-9.5A1.75 1.75 0 0 1 2 14.25Zm1.75-.25a.25.25 0 0 0-.25.25v12.5c0 .138.112.25.25.25h9.5a.25.25 0 0 0 .25-.25V6h-2.75A1.75 1.75 0 0 1 9 4.25V1.5Zm6.75.062V4.25c0 .138.112.25.25.25h2.688l-.011-.013-2.914-2.914-.013-.011Z"></path></svg><div class="overflow-hidden"><div class="react-directory-filename-cell"><div class="react-directory-truncate"><a title=".pre-commit-config.yaml" aria-label=".pre-commit-config.yaml, (File)" class="Link--primary" href="/alexpovel/srgn/blob/main/.pre-commit-config.yaml">.pre-commit-config.yaml</a></div></div></div></div></td><td class="react-directory-row-commit-cell"><div class="Skeleton Skeleton--text"> </div></td><td><div class="Skeleton Skeleton--text"> </div></td></tr><tr class="react-directory-row truncate-for-mobile" id="folder-row-13"><td class="react-directory-row-name-cell-small-screen" colSpan="2"><div class="react-directory-filename-column"><svg aria-hidden="true" focusable="false" class="octicon octicon-file color-fg-muted" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M2 1.75C2 .784 2.784 0 3.75 0h6.586c.464 0 .909.184 1.237.513l2.914 2.914c.329.328.513.773.513 1.237v9.586A1.75 1.75 0 0 1 13.25 16h-9.5A1.75 1.75 0 0 1 2 14.25Zm1.75-.25a.25.25 0 0 0-.25.25v12.5c0 .138.112.25.25.25h9.5a.25.25 0 0 0 .25-.25V6h-2.75A1.75 1.75 0 0 1 9 4.25V1.5Zm6.75.062V4.25c0 .138.112.25.25.25h2.688l-.011-.013-2.914-2.914-.013-.011Z"></path></svg><div class="overflow-hidden"><div class="react-directory-filename-cell"><div class="react-directory-truncate"><a title=".release-please-manifest.json" aria-label=".release-please-manifest.json, (File)" class="Link--primary" href="/alexpovel/srgn/blob/main/.release-please-manifest.json">.release-please-manifest.json</a></div></div></div></div></td><td class="react-directory-row-name-cell-large-screen" colSpan="1"><div class="react-directory-filename-column"><svg aria-hidden="true" focusable="false" class="octicon octicon-file color-fg-muted" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M2 1.75C2 .784 2.784 0 3.75 0h6.586c.464 0 .909.184 1.237.513l2.914 2.914c.329.328.513.773.513 1.237v9.586A1.75 1.75 0 0 1 13.25 16h-9.5A1.75 1.75 0 0 1 2 14.25Zm1.75-.25a.25.25 0 0 0-.25.25v12.5c0 .138.112.25.25.25h9.5a.25.25 0 0 0 .25-.25V6h-2.75A1.75 1.75 0 0 1 9 4.25V1.5Zm6.75.062V4.25c0 .138.112.25.25.25h2.688l-.011-.013-2.914-2.914-.013-.011Z"></path></svg><div class="overflow-hidden"><div class="react-directory-filename-cell"><div class="react-directory-truncate"><a title=".release-please-manifest.json" aria-label=".release-please-manifest.json, (File)" class="Link--primary" href="/alexpovel/srgn/blob/main/.release-please-manifest.json">.release-please-manifest.json</a></div></div></div></div></td><td class="react-directory-row-commit-cell"><div class="Skeleton Skeleton--text"> </div></td><td><div class="Skeleton Skeleton--text"> </div></td></tr><tr class="react-directory-row truncate-for-mobile" id="folder-row-14"><td class="react-directory-row-name-cell-small-screen" colSpan="2"><div class="react-directory-filename-column"><svg aria-hidden="true" focusable="false" class="octicon octicon-file color-fg-muted" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M2 1.75C2 .784 2.784 0 3.75 0h6.586c.464 0 .909.184 1.237.513l2.914 2.914c.329.328.513.773.513 1.237v9.586A1.75 1.75 0 0 1 13.25 16h-9.5A1.75 1.75 0 0 1 2 14.25Zm1.75-.25a.25.25 0 0 0-.25.25v12.5c0 .138.112.25.25.25h9.5a.25.25 0 0 0 .25-.25V6h-2.75A1.75 1.75 0 0 1 9 4.25V1.5Zm6.75.062V4.25c0 .138.112.25.25.25h2.688l-.011-.013-2.914-2.914-.013-.011Z"></path></svg><div class="overflow-hidden"><div class="react-directory-filename-cell"><div class="react-directory-truncate"><a title="CHANGELOG.md" aria-label="CHANGELOG.md, (File)" class="Link--primary" href="/alexpovel/srgn/blob/main/CHANGELOG.md">CHANGELOG.md</a></div></div></div></div></td><td class="react-directory-row-name-cell-large-screen" colSpan="1"><div class="react-directory-filename-column"><svg aria-hidden="true" focusable="false" class="octicon octicon-file color-fg-muted" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M2 1.75C2 .784 2.784 0 3.75 0h6.586c.464 0 .909.184 1.237.513l2.914 2.914c.329.328.513.773.513 1.237v9.586A1.75 1.75 0 0 1 13.25 16h-9.5A1.75 1.75 0 0 1 2 14.25Zm1.75-.25a.25.25 0 0 0-.25.25v12.5c0 .138.112.25.25.25h9.5a.25.25 0 0 0 .25-.25V6h-2.75A1.75 1.75 0 0 1 9 4.25V1.5Zm6.75.062V4.25c0 .138.112.25.25.25h2.688l-.011-.013-2.914-2.914-.013-.011Z"></path></svg><div class="overflow-hidden"><div class="react-directory-filename-cell"><div class="react-directory-truncate"><a title="CHANGELOG.md" aria-label="CHANGELOG.md, (File)" class="Link--primary" href="/alexpovel/srgn/blob/main/CHANGELOG.md">CHANGELOG.md</a></div></div></div></div></td><td class="react-directory-row-commit-cell"><div class="Skeleton Skeleton--text"> </div></td><td><div class="Skeleton Skeleton--text"> </div></td></tr><tr class="react-directory-row truncate-for-mobile" id="folder-row-15"><td class="react-directory-row-name-cell-small-screen" colSpan="2"><div class="react-directory-filename-column"><svg aria-hidden="true" focusable="false" class="octicon octicon-file color-fg-muted" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M2 1.75C2 .784 2.784 0 3.75 0h6.586c.464 0 .909.184 1.237.513l2.914 2.914c.329.328.513.773.513 1.237v9.586A1.75 1.75 0 0 1 13.25 16h-9.5A1.75 1.75 0 0 1 2 14.25Zm1.75-.25a.25.25 0 0 0-.25.25v12.5c0 .138.112.25.25.25h9.5a.25.25 0 0 0 .25-.25V6h-2.75A1.75 1.75 0 0 1 9 4.25V1.5Zm6.75.062V4.25c0 .138.112.25.25.25h2.688l-.011-.013-2.914-2.914-.013-.011Z"></path></svg><div class="overflow-hidden"><div class="react-directory-filename-cell"><div class="react-directory-truncate"><a title="CONTRIBUTING.md" aria-label="CONTRIBUTING.md, (File)" class="Link--primary" href="/alexpovel/srgn/blob/main/CONTRIBUTING.md">CONTRIBUTING.md</a></div></div></div></div></td><td class="react-directory-row-name-cell-large-screen" colSpan="1"><div class="react-directory-filename-column"><svg aria-hidden="true" focusable="false" class="octicon octicon-file color-fg-muted" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M2 1.75C2 .784 2.784 0 3.75 0h6.586c.464 0 .909.184 1.237.513l2.914 2.914c.329.328.513.773.513 1.237v9.586A1.75 1.75 0 0 1 13.25 16h-9.5A1.75 1.75 0 0 1 2 14.25Zm1.75-.25a.25.25 0 0 0-.25.25v12.5c0 .138.112.25.25.25h9.5a.25.25 0 0 0 .25-.25V6h-2.75A1.75 1.75 0 0 1 9 4.25V1.5Zm6.75.062V4.25c0 .138.112.25.25.25h2.688l-.011-.013-2.914-2.914-.013-.011Z"></path></svg><div class="overflow-hidden"><div class="react-directory-filename-cell"><div class="react-directory-truncate"><a title="CONTRIBUTING.md" aria-label="CONTRIBUTING.md, (File)" class="Link--primary" href="/alexpovel/srgn/blob/main/CONTRIBUTING.md">CONTRIBUTING.md</a></div></div></div></div></td><td class="react-directory-row-commit-cell"><div class="Skeleton Skeleton--text"> </div></td><td><div class="Skeleton Skeleton--text"> </div></td></tr><tr class="react-directory-row truncate-for-mobile" id="folder-row-16"><td class="react-directory-row-name-cell-small-screen" colSpan="2"><div class="react-directory-filename-column"><svg aria-hidden="true" focusable="false" class="octicon octicon-file color-fg-muted" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M2 1.75C2 .784 2.784 0 3.75 0h6.586c.464 0 .909.184 1.237.513l2.914 2.914c.329.328.513.773.513 1.237v9.586A1.75 1.75 0 0 1 13.25 16h-9.5A1.75 1.75 0 0 1 2 14.25Zm1.75-.25a.25.25 0 0 0-.25.25v12.5c0 .138.112.25.25.25h9.5a.25.25 0 0 0 .25-.25V6h-2.75A1.75 1.75 0 0 1 9 4.25V1.5Zm6.75.062V4.25c0 .138.112.25.25.25h2.688l-.011-.013-2.914-2.914-.013-.011Z"></path></svg><div class="overflow-hidden"><div class="react-directory-filename-cell"><div class="react-directory-truncate"><a title="Cargo.lock" aria-label="Cargo.lock, (File)" class="Link--primary" href="/alexpovel/srgn/blob/main/Cargo.lock">Cargo.lock</a></div></div></div></div></td><td class="react-directory-row-name-cell-large-screen" colSpan="1"><div class="react-directory-filename-column"><svg aria-hidden="true" focusable="false" class="octicon octicon-file color-fg-muted" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M2 1.75C2 .784 2.784 0 3.75 0h6.586c.464 0 .909.184 1.237.513l2.914 2.914c.329.328.513.773.513 1.237v9.586A1.75 1.75 0 0 1 13.25 16h-9.5A1.75 1.75 0 0 1 2 14.25Zm1.75-.25a.25.25 0 0 0-.25.25v12.5c0 .138.112.25.25.25h9.5a.25.25 0 0 0 .25-.25V6h-2.75A1.75 1.75 0 0 1 9 4.25V1.5Zm6.75.062V4.25c0 .138.112.25.25.25h2.688l-.011-.013-2.914-2.914-.013-.011Z"></path></svg><div class="overflow-hidden"><div class="react-directory-filename-cell"><div class="react-directory-truncate"><a title="Cargo.lock" aria-label="Cargo.lock, (File)" class="Link--primary" href="/alexpovel/srgn/blob/main/Cargo.lock">Cargo.lock</a></div></div></div></div></td><td class="react-directory-row-commit-cell"><div class="Skeleton Skeleton--text"> </div></td><td><div class="Skeleton Skeleton--text"> </div></td></tr><tr class="react-directory-row truncate-for-mobile" id="folder-row-17"><td class="react-directory-row-name-cell-small-screen" colSpan="2"><div class="react-directory-filename-column"><svg aria-hidden="true" focusable="false" class="octicon octicon-file color-fg-muted" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M2 1.75C2 .784 2.784 0 3.75 0h6.586c.464 0 .909.184 1.237.513l2.914 2.914c.329.328.513.773.513 1.237v9.586A1.75 1.75 0 0 1 13.25 16h-9.5A1.75 1.75 0 0 1 2 14.25Zm1.75-.25a.25.25 0 0 0-.25.25v12.5c0 .138.112.25.25.25h9.5a.25.25 0 0 0 .25-.25V6h-2.75A1.75 1.75 0 0 1 9 4.25V1.5Zm6.75.062V4.25c0 .138.112.25.25.25h2.688l-.011-.013-2.914-2.914-.013-.011Z"></path></svg><div class="overflow-hidden"><div class="react-directory-filename-cell"><div class="react-directory-truncate"><a title="Cargo.toml" aria-label="Cargo.toml, (File)" class="Link--primary" href="/alexpovel/srgn/blob/main/Cargo.toml">Cargo.toml</a></div></div></div></div></td><td class="react-directory-row-name-cell-large-screen" colSpan="1"><div class="react-directory-filename-column"><svg aria-hidden="true" focusable="false" class="octicon octicon-file color-fg-muted" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M2 1.75C2 .784 2.784 0 3.75 0h6.586c.464 0 .909.184 1.237.513l2.914 2.914c.329.328.513.773.513 1.237v9.586A1.75 1.75 0 0 1 13.25 16h-9.5A1.75 1.75 0 0 1 2 14.25Zm1.75-.25a.25.25 0 0 0-.25.25v12.5c0 .138.112.25.25.25h9.5a.25.25 0 0 0 .25-.25V6h-2.75A1.75 1.75 0 0 1 9 4.25V1.5Zm6.75.062V4.25c0 .138.112.25.25.25h2.688l-.011-.013-2.914-2.914-.013-.011Z"></path></svg><div class="overflow-hidden"><div class="react-directory-filename-cell"><div class="react-directory-truncate"><a title="Cargo.toml" aria-label="Cargo.toml, (File)" class="Link--primary" href="/alexpovel/srgn/blob/main/Cargo.toml">Cargo.toml</a></div></div></div></div></td><td class="react-directory-row-commit-cell"><div class="Skeleton Skeleton--text"> </div></td><td><div class="Skeleton Skeleton--text"> </div></td></tr><tr class="react-directory-row truncate-for-mobile" id="folder-row-18"><td class="react-directory-row-name-cell-small-screen" colSpan="2"><div class="react-directory-filename-column"><svg aria-hidden="true" focusable="false" class="octicon octicon-file color-fg-muted" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M2 1.75C2 .784 2.784 0 3.75 0h6.586c.464 0 .909.184 1.237.513l2.914 2.914c.329.328.513.773.513 1.237v9.586A1.75 1.75 0 0 1 13.25 16h-9.5A1.75 1.75 0 0 1 2 14.25Zm1.75-.25a.25.25 0 0 0-.25.25v12.5c0 .138.112.25.25.25h9.5a.25.25 0 0 0 .25-.25V6h-2.75A1.75 1.75 0 0 1 9 4.25V1.5Zm6.75.062V4.25c0 .138.112.25.25.25h2.688l-.011-.013-2.914-2.914-.013-.011Z"></path></svg><div class="overflow-hidden"><div class="react-directory-filename-cell"><div class="react-directory-truncate"><a title="LICENSE-APACHE" aria-label="LICENSE-APACHE, (File)" class="Link--primary" href="/alexpovel/srgn/blob/main/LICENSE-APACHE">LICENSE-APACHE</a></div></div></div></div></td><td class="react-directory-row-name-cell-large-screen" colSpan="1"><div class="react-directory-filename-column"><svg aria-hidden="true" focusable="false" class="octicon octicon-file color-fg-muted" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M2 1.75C2 .784 2.784 0 3.75 0h6.586c.464 0 .909.184 1.237.513l2.914 2.914c.329.328.513.773.513 1.237v9.586A1.75 1.75 0 0 1 13.25 16h-9.5A1.75 1.75 0 0 1 2 14.25Zm1.75-.25a.25.25 0 0 0-.25.25v12.5c0 .138.112.25.25.25h9.5a.25.25 0 0 0 .25-.25V6h-2.75A1.75 1.75 0 0 1 9 4.25V1.5Zm6.75.062V4.25c0 .138.112.25.25.25h2.688l-.011-.013-2.914-2.914-.013-.011Z"></path></svg><div class="overflow-hidden"><div class="react-directory-filename-cell"><div class="react-directory-truncate"><a title="LICENSE-APACHE" aria-label="LICENSE-APACHE, (File)" class="Link--primary" href="/alexpovel/srgn/blob/main/LICENSE-APACHE">LICENSE-APACHE</a></div></div></div></div></td><td class="react-directory-row-commit-cell"><div class="Skeleton Skeleton--text"> </div></td><td><div class="Skeleton Skeleton--text"> </div></td></tr><tr class="react-directory-row truncate-for-mobile" id="folder-row-19"><td class="react-directory-row-name-cell-small-screen" colSpan="2"><div class="react-directory-filename-column"><svg aria-hidden="true" focusable="false" class="octicon octicon-file color-fg-muted" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M2 1.75C2 .784 2.784 0 3.75 0h6.586c.464 0 .909.184 1.237.513l2.914 2.914c.329.328.513.773.513 1.237v9.586A1.75 1.75 0 0 1 13.25 16h-9.5A1.75 1.75 0 0 1 2 14.25Zm1.75-.25a.25.25 0 0 0-.25.25v12.5c0 .138.112.25.25.25h9.5a.25.25 0 0 0 .25-.25V6h-2.75A1.75 1.75 0 0 1 9 4.25V1.5Zm6.75.062V4.25c0 .138.112.25.25.25h2.688l-.011-.013-2.914-2.914-.013-.011Z"></path></svg><div class="overflow-hidden"><div class="react-directory-filename-cell"><div class="react-directory-truncate"><a title="LICENSE-MIT" aria-label="LICENSE-MIT, (File)" class="Link--primary" href="/alexpovel/srgn/blob/main/LICENSE-MIT">LICENSE-MIT</a></div></div></div></div></td><td class="react-directory-row-name-cell-large-screen" colSpan="1"><div class="react-directory-filename-column"><svg aria-hidden="true" focusable="false" class="octicon octicon-file color-fg-muted" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M2 1.75C2 .784 2.784 0 3.75 0h6.586c.464 0 .909.184 1.237.513l2.914 2.914c.329.328.513.773.513 1.237v9.586A1.75 1.75 0 0 1 13.25 16h-9.5A1.75 1.75 0 0 1 2 14.25Zm1.75-.25a.25.25 0 0 0-.25.25v12.5c0 .138.112.25.25.25h9.5a.25.25 0 0 0 .25-.25V6h-2.75A1.75 1.75 0 0 1 9 4.25V1.5Zm6.75.062V4.25c0 .138.112.25.25.25h2.688l-.011-.013-2.914-2.914-.013-.011Z"></path></svg><div class="overflow-hidden"><div class="react-directory-filename-cell"><div class="react-directory-truncate"><a title="LICENSE-MIT" aria-label="LICENSE-MIT, (File)" class="Link--primary" href="/alexpovel/srgn/blob/main/LICENSE-MIT">LICENSE-MIT</a></div></div></div></div></td><td class="react-directory-row-commit-cell"><div class="Skeleton Skeleton--text"> </div></td><td><div class="Skeleton Skeleton--text"> </div></td></tr><tr class="react-directory-row truncate-for-mobile" id="folder-row-20"><td class="react-directory-row-name-cell-small-screen" colSpan="2"><div class="react-directory-filename-column"><svg aria-hidden="true" focusable="false" class="octicon octicon-file color-fg-muted" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M2 1.75C2 .784 2.784 0 3.75 0h6.586c.464 0 .909.184 1.237.513l2.914 2.914c.329.328.513.773.513 1.237v9.586A1.75 1.75 0 0 1 13.25 16h-9.5A1.75 1.75 0 0 1 2 14.25Zm1.75-.25a.25.25 0 0 0-.25.25v12.5c0 .138.112.25.25.25h9.5a.25.25 0 0 0 .25-.25V6h-2.75A1.75 1.75 0 0 1 9 4.25V1.5Zm6.75.062V4.25c0 .138.112.25.25.25h2.688l-.011-.013-2.914-2.914-.013-.011Z"></path></svg><div class="overflow-hidden"><div class="react-directory-filename-cell"><div class="react-directory-truncate"><a title="NOTICE" aria-label="NOTICE, (File)" class="Link--primary" href="/alexpovel/srgn/blob/main/NOTICE">NOTICE</a></div></div></div></div></td><td class="react-directory-row-name-cell-large-screen" colSpan="1"><div class="react-directory-filename-column"><svg aria-hidden="true" focusable="false" class="octicon octicon-file color-fg-muted" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M2 1.75C2 .784 2.784 0 3.75 0h6.586c.464 0 .909.184 1.237.513l2.914 2.914c.329.328.513.773.513 1.237v9.586A1.75 1.75 0 0 1 13.25 16h-9.5A1.75 1.75 0 0 1 2 14.25Zm1.75-.25a.25.25 0 0 0-.25.25v12.5c0 .138.112.25.25.25h9.5a.25.25 0 0 0 .25-.25V6h-2.75A1.75 1.75 0 0 1 9 4.25V1.5Zm6.75.062V4.25c0 .138.112.25.25.25h2.688l-.011-.013-2.914-2.914-.013-.011Z"></path></svg><div class="overflow-hidden"><div class="react-directory-filename-cell"><div class="react-directory-truncate"><a title="NOTICE" aria-label="NOTICE, (File)" class="Link--primary" href="/alexpovel/srgn/blob/main/NOTICE">NOTICE</a></div></div></div></div></td><td class="react-directory-row-commit-cell"><div class="Skeleton Skeleton--text"> </div></td><td><div class="Skeleton Skeleton--text"> </div></td></tr><tr class="react-directory-row truncate-for-mobile" id="folder-row-21"><td class="react-directory-row-name-cell-small-screen" colSpan="2"><div class="react-directory-filename-column"><svg aria-hidden="true" focusable="false" class="octicon octicon-file color-fg-muted" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M2 1.75C2 .784 2.784 0 3.75 0h6.586c.464 0 .909.184 1.237.513l2.914 2.914c.329.328.513.773.513 1.237v9.586A1.75 1.75 0 0 1 13.25 16h-9.5A1.75 1.75 0 0 1 2 14.25Zm1.75-.25a.25.25 0 0 0-.25.25v12.5c0 .138.112.25.25.25h9.5a.25.25 0 0 0 .25-.25V6h-2.75A1.75 1.75 0 0 1 9 4.25V1.5Zm6.75.062V4.25c0 .138.112.25.25.25h2.688l-.011-.013-2.914-2.914-.013-.011Z"></path></svg><div class="overflow-hidden"><div class="react-directory-filename-cell"><div class="react-directory-truncate"><a title="README.md" aria-label="README.md, (File)" class="Link--primary" href="/alexpovel/srgn/blob/main/README.md">README.md</a></div></div></div></div></td><td class="react-directory-row-name-cell-large-screen" colSpan="1"><div class="react-directory-filename-column"><svg aria-hidden="true" focusable="false" class="octicon octicon-file color-fg-muted" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M2 1.75C2 .784 2.784 0 3.75 0h6.586c.464 0 .909.184 1.237.513l2.914 2.914c.329.328.513.773.513 1.237v9.586A1.75 1.75 0 0 1 13.25 16h-9.5A1.75 1.75 0 0 1 2 14.25Zm1.75-.25a.25.25 0 0 0-.25.25v12.5c0 .138.112.25.25.25h9.5a.25.25 0 0 0 .25-.25V6h-2.75A1.75 1.75 0 0 1 9 4.25V1.5Zm6.75.062V4.25c0 .138.112.25.25.25h2.688l-.011-.013-2.914-2.914-.013-.011Z"></path></svg><div class="overflow-hidden"><div class="react-directory-filename-cell"><div class="react-directory-truncate"><a title="README.md" aria-label="README.md, (File)" class="Link--primary" href="/alexpovel/srgn/blob/main/README.md">README.md</a></div></div></div></div></td><td class="react-directory-row-commit-cell"><div class="Skeleton Skeleton--text"> </div></td><td><div class="Skeleton Skeleton--text"> </div></td></tr><tr class="react-directory-row truncate-for-mobile" id="folder-row-22"><td class="react-directory-row-name-cell-small-screen" colSpan="2"><div class="react-directory-filename-column"><svg aria-hidden="true" focusable="false" class="octicon octicon-file color-fg-muted" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M2 1.75C2 .784 2.784 0 3.75 0h6.586c.464 0 .909.184 1.237.513l2.914 2.914c.329.328.513.773.513 1.237v9.586A1.75 1.75 0 0 1 13.25 16h-9.5A1.75 1.75 0 0 1 2 14.25Zm1.75-.25a.25.25 0 0 0-.25.25v12.5c0 .138.112.25.25.25h9.5a.25.25 0 0 0 .25-.25V6h-2.75A1.75 1.75 0 0 1 9 4.25V1.5Zm6.75.062V4.25c0 .138.112.25.25.25h2.688l-.011-.013-2.914-2.914-.013-.011Z"></path></svg><div class="overflow-hidden"><div class="react-directory-filename-cell"><div class="react-directory-truncate"><a title="build.rs" aria-label="build.rs, (File)" class="Link--primary" href="/alexpovel/srgn/blob/main/build.rs">build.rs</a></div></div></div></div></td><td class="react-directory-row-name-cell-large-screen" colSpan="1"><div class="react-directory-filename-column"><svg aria-hidden="true" focusable="false" class="octicon octicon-file color-fg-muted" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M2 1.75C2 .784 2.784 0 3.75 0h6.586c.464 0 .909.184 1.237.513l2.914 2.914c.329.328.513.773.513 1.237v9.586A1.75 1.75 0 0 1 13.25 16h-9.5A1.75 1.75 0 0 1 2 14.25Zm1.75-.25a.25.25 0 0 0-.25.25v12.5c0 .138.112.25.25.25h9.5a.25.25 0 0 0 .25-.25V6h-2.75A1.75 1.75 0 0 1 9 4.25V1.5Zm6.75.062V4.25c0 .138.112.25.25.25h2.688l-.011-.013-2.914-2.914-.013-.011Z"></path></svg><div class="overflow-hidden"><div class="react-directory-filename-cell"><div class="react-directory-truncate"><a title="build.rs" aria-label="build.rs, (File)" class="Link--primary" href="/alexpovel/srgn/blob/main/build.rs">build.rs</a></div></div></div></div></td><td class="react-directory-row-commit-cell"><div class="Skeleton Skeleton--text"> </div></td><td><div class="Skeleton Skeleton--text"> </div></td></tr><tr class="react-directory-row truncate-for-mobile" id="folder-row-23"><td class="react-directory-row-name-cell-small-screen" colSpan="2"><div class="react-directory-filename-column"><svg aria-hidden="true" focusable="false" class="octicon octicon-file color-fg-muted" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M2 1.75C2 .784 2.784 0 3.75 0h6.586c.464 0 .909.184 1.237.513l2.914 2.914c.329.328.513.773.513 1.237v9.586A1.75 1.75 0 0 1 13.25 16h-9.5A1.75 1.75 0 0 1 2 14.25Zm1.75-.25a.25.25 0 0 0-.25.25v12.5c0 .138.112.25.25.25h9.5a.25.25 0 0 0 .25-.25V6h-2.75A1.75 1.75 0 0 1 9 4.25V1.5Zm6.75.062V4.25c0 .138.112.25.25.25h2.688l-.011-.013-2.914-2.914-.013-.011Z"></path></svg><div class="overflow-hidden"><div class="react-directory-filename-cell"><div class="react-directory-truncate"><a title="codecov.yml" aria-label="codecov.yml, (File)" class="Link--primary" href="/alexpovel/srgn/blob/main/codecov.yml">codecov.yml</a></div></div></div></div></td><td class="react-directory-row-name-cell-large-screen" colSpan="1"><div class="react-directory-filename-column"><svg aria-hidden="true" focusable="false" class="octicon octicon-file color-fg-muted" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M2 1.75C2 .784 2.784 0 3.75 0h6.586c.464 0 .909.184 1.237.513l2.914 2.914c.329.328.513.773.513 1.237v9.586A1.75 1.75 0 0 1 13.25 16h-9.5A1.75 1.75 0 0 1 2 14.25Zm1.75-.25a.25.25 0 0 0-.25.25v12.5c0 .138.112.25.25.25h9.5a.25.25 0 0 0 .25-.25V6h-2.75A1.75 1.75 0 0 1 9 4.25V1.5Zm6.75.062V4.25c0 .138.112.25.25.25h2.688l-.011-.013-2.914-2.914-.013-.011Z"></path></svg><div class="overflow-hidden"><div class="react-directory-filename-cell"><div class="react-directory-truncate"><a title="codecov.yml" aria-label="codecov.yml, (File)" class="Link--primary" href="/alexpovel/srgn/blob/main/codecov.yml">codecov.yml</a></div></div></div></div></td><td class="react-directory-row-commit-cell"><div class="Skeleton Skeleton--text"> </div></td><td><div class="Skeleton Skeleton--text"> </div></td></tr><tr class="react-directory-row truncate-for-mobile" id="folder-row-24"><td class="react-directory-row-name-cell-small-screen" colSpan="2"><div class="react-directory-filename-column"><svg aria-hidden="true" focusable="false" class="octicon octicon-file color-fg-muted" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M2 1.75C2 .784 2.784 0 3.75 0h6.586c.464 0 .909.184 1.237.513l2.914 2.914c.329.328.513.773.513 1.237v9.586A1.75 1.75 0 0 1 13.25 16h-9.5A1.75 1.75 0 0 1 2 14.25Zm1.75-.25a.25.25 0 0 0-.25.25v12.5c0 .138.112.25.25.25h9.5a.25.25 0 0 0 .25-.25V6h-2.75A1.75 1.75 0 0 1 9 4.25V1.5Zm6.75.062V4.25c0 .138.112.25.25.25h2.688l-.011-.013-2.914-2.914-.013-.011Z"></path></svg><div class="overflow-hidden"><div class="react-directory-filename-cell"><div class="react-directory-truncate"><a title="release-please-config.json" aria-label="release-please-config.json, (File)" class="Link--primary" href="/alexpovel/srgn/blob/main/release-please-config.json">release-please-config.json</a></div></div></div></div></td><td class="react-directory-row-name-cell-large-screen" colSpan="1"><div class="react-directory-filename-column"><svg aria-hidden="true" focusable="false" class="octicon octicon-file color-fg-muted" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M2 1.75C2 .784 2.784 0 3.75 0h6.586c.464 0 .909.184 1.237.513l2.914 2.914c.329.328.513.773.513 1.237v9.586A1.75 1.75 0 0 1 13.25 16h-9.5A1.75 1.75 0 0 1 2 14.25Zm1.75-.25a.25.25 0 0 0-.25.25v12.5c0 .138.112.25.25.25h9.5a.25.25 0 0 0 .25-.25V6h-2.75A1.75 1.75 0 0 1 9 4.25V1.5Zm6.75.062V4.25c0 .138.112.25.25.25h2.688l-.011-.013-2.914-2.914-.013-.011Z"></path></svg><div class="overflow-hidden"><div class="react-directory-filename-cell"><div class="react-directory-truncate"><a title="release-please-config.json" aria-label="release-please-config.json, (File)" class="Link--primary" href="/alexpovel/srgn/blob/main/release-please-config.json">release-please-config.json</a></div></div></div></div></td><td class="react-directory-row-commit-cell"><div class="Skeleton Skeleton--text"> </div></td><td><div class="Skeleton Skeleton--text"> </div></td></tr><tr class="react-directory-row truncate-for-mobile" id="folder-row-25"><td class="react-directory-row-name-cell-small-screen" colSpan="2"><div class="react-directory-filename-column"><svg aria-hidden="true" focusable="false" class="octicon octicon-file color-fg-muted" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M2 1.75C2 .784 2.784 0 3.75 0h6.586c.464 0 .909.184 1.237.513l2.914 2.914c.329.328.513.773.513 1.237v9.586A1.75 1.75 0 0 1 13.25 16h-9.5A1.75 1.75 0 0 1 2 14.25Zm1.75-.25a.25.25 0 0 0-.25.25v12.5c0 .138.112.25.25.25h9.5a.25.25 0 0 0 .25-.25V6h-2.75A1.75 1.75 0 0 1 9 4.25V1.5Zm6.75.062V4.25c0 .138.112.25.25.25h2.688l-.011-.013-2.914-2.914-.013-.011Z"></path></svg><div class="overflow-hidden"><div class="react-directory-filename-cell"><div class="react-directory-truncate"><a title="rustfmt.toml" aria-label="rustfmt.toml, (File)" class="Link--primary" href="/alexpovel/srgn/blob/main/rustfmt.toml">rustfmt.toml</a></div></div></div></div></td><td class="react-directory-row-name-cell-large-screen" colSpan="1"><div class="react-directory-filename-column"><svg aria-hidden="true" focusable="false" class="octicon octicon-file color-fg-muted" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M2 1.75C2 .784 2.784 0 3.75 0h6.586c.464 0 .909.184 1.237.513l2.914 2.914c.329.328.513.773.513 1.237v9.586A1.75 1.75 0 0 1 13.25 16h-9.5A1.75 1.75 0 0 1 2 14.25Zm1.75-.25a.25.25 0 0 0-.25.25v12.5c0 .138.112.25.25.25h9.5a.25.25 0 0 0 .25-.25V6h-2.75A1.75 1.75 0 0 1 9 4.25V1.5Zm6.75.062V4.25c0 .138.112.25.25.25h2.688l-.011-.013-2.914-2.914-.013-.011Z"></path></svg><div class="overflow-hidden"><div class="react-directory-filename-cell"><div class="react-directory-truncate"><a title="rustfmt.toml" aria-label="rustfmt.toml, (File)" class="Link--primary" href="/alexpovel/srgn/blob/main/rustfmt.toml">rustfmt.toml</a></div></div></div></div></td><td class="react-directory-row-commit-cell"><div class="Skeleton Skeleton--text"> </div></td><td><div class="Skeleton Skeleton--text"> </div></td></tr><tr class="react-directory-row truncate-for-mobile" id="folder-row-26"><td class="react-directory-row-name-cell-small-screen" colSpan="2"><div class="react-directory-filename-column"><svg aria-hidden="true" focusable="false" class="octicon octicon-file color-fg-muted" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M2 1.75C2 .784 2.784 0 3.75 0h6.586c.464 0 .909.184 1.237.513l2.914 2.914c.329.328.513.773.513 1.237v9.586A1.75 1.75 0 0 1 13.25 16h-9.5A1.75 1.75 0 0 1 2 14.25Zm1.75-.25a.25.25 0 0 0-.25.25v12.5c0 .138.112.25.25.25h9.5a.25.25 0 0 0 .25-.25V6h-2.75A1.75 1.75 0 0 1 9 4.25V1.5Zm6.75.062V4.25c0 .138.112.25.25.25h2.688l-.011-.013-2.914-2.914-.013-.011Z"></path></svg><div class="overflow-hidden"><div class="react-directory-filename-cell"><div class="react-directory-truncate"><a title="tarpaulin.toml" aria-label="tarpaulin.toml, (File)" class="Link--primary" href="/alexpovel/srgn/blob/main/tarpaulin.toml">tarpaulin.toml</a></div></div></div></div></td><td class="react-directory-row-name-cell-large-screen" colSpan="1"><div class="react-directory-filename-column"><svg aria-hidden="true" focusable="false" class="octicon octicon-file color-fg-muted" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M2 1.75C2 .784 2.784 0 3.75 0h6.586c.464 0 .909.184 1.237.513l2.914 2.914c.329.328.513.773.513 1.237v9.586A1.75 1.75 0 0 1 13.25 16h-9.5A1.75 1.75 0 0 1 2 14.25Zm1.75-.25a.25.25 0 0 0-.25.25v12.5c0 .138.112.25.25.25h9.5a.25.25 0 0 0 .25-.25V6h-2.75A1.75 1.75 0 0 1 9 4.25V1.5Zm6.75.062V4.25c0 .138.112.25.25.25h2.688l-.011-.013-2.914-2.914-.013-.011Z"></path></svg><div class="overflow-hidden"><div class="react-directory-filename-cell"><div class="react-directory-truncate"><a title="tarpaulin.toml" aria-label="tarpaulin.toml, (File)" class="Link--primary" href="/alexpovel/srgn/blob/main/tarpaulin.toml">tarpaulin.toml</a></div></div></div></div></td><td class="react-directory-row-commit-cell"><div class="Skeleton Skeleton--text"> </div></td><td><div class="Skeleton Skeleton--text"> </div></td></tr><tr class="Box-sc-g0xbh4-0 eNCcrz show-for-mobile" data-testid="view-all-files-row"><td colSpan="3" class="Box-sc-g0xbh4-0 bHTcCe"><div><button class="prc-Link-Link-85e08">View all files</button></div></td></tr></tbody></table></div><div class="Box-sc-g0xbh4-0 csrIcr"><div class="Box-sc-g0xbh4-0 bUQNHB"><div itemscope="" itemType="https://schema.org/abstract" class="Box-sc-g0xbh4-0 jPdcfu"><h2 class="_VisuallyHidden__VisuallyHidden-sc-11jhm7a-0 brGdpi">Repository files navigation</h2><nav class="Box-sc-g0xbh4-0 iphEWz prc-components-UnderlineWrapper-oOh5J" aria-label="Repository files"><ul class="prc-components-UnderlineItemList-b23Hf" role="list"><li class="Box-sc-g0xbh4-0 hUCRAk"><a class="prc-components-UnderlineItem-lJsg-" href="#" aria-current="page"><span data-component="icon"><svg aria-hidden="true" focusable="false" class="octicon octicon-book" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M0 1.75A.75.75 0 0 1 .75 1h4.253c1.227 0 2.317.59 3 1.501A3.743 3.743 0 0 1 11.006 1h4.245a.75.75 0 0 1 .75.75v10.5a.75.75 0 0 1-.75.75h-4.507a2.25 2.25 0 0 0-1.591.659l-.622.621a.75.75 0 0 1-1.06 0l-.622-.621A2.25 2.25 0 0 0 5.258 13H.75a.75.75 0 0 1-.75-.75Zm7.251 10.324.004-5.073-.002-2.253A2.25 2.25 0 0 0 5.003 2.5H1.5v9h3.757a3.75 3.75 0 0 1 1.994.574ZM8.755 4.75l-.004 7.322a3.752 3.752 0 0 1 1.992-.572H14.5v-9h-3.495a2.25 2.25 0 0 0-2.25 2.25Z"></path></svg></span><span data-component="text" data-content="README">README</span></a></li><li class="Box-sc-g0xbh4-0 hUCRAk"><a class="prc-components-UnderlineItem-lJsg-" href="#"><span data-component="icon"><svg aria-hidden="true" focusable="false" class="octicon octicon-law" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M8.75.75V2h.985c.304 0 .603.08.867.231l1.29.736c.038.022.08.033.124.033h2.234a.75.75 0 0 1 0 1.5h-.427l2.111 4.692a.75.75 0 0 1-.154.838l-.53-.53.529.531-.001.002-.002.002-.006.006-.006.005-.01.01-.045.04c-.21.176-.441.327-.686.45C14.556 10.78 13.88 11 13 11a4.498 4.498 0 0 1-2.023-.454 3.544 3.544 0 0 1-.686-.45l-.045-.04-.016-.015-.006-.006-.004-.004v-.001a.75.75 0 0 1-.154-.838L12.178 4.5h-.162c-.305 0-.604-.079-.868-.231l-1.29-.736a.245.245 0 0 0-.124-.033H8.75V13h2.5a.75.75 0 0 1 0 1.5h-6.5a.75.75 0 0 1 0-1.5h2.5V3.5h-.984a.245.245 0 0 0-.124.033l-1.289.737c-.265.15-.564.23-.869.23h-.162l2.112 4.692a.75.75 0 0 1-.154.838l-.53-.53.529.531-.001.002-.002.002-.006.006-.016.015-.045.04c-.21.176-.441.327-.686.45C4.556 10.78 3.88 11 3 11a4.498 4.498 0 0 1-2.023-.454 3.544 3.544 0 0 1-.686-.45l-.045-.04-.016-.015-.006-.006-.004-.004v-.001a.75.75 0 0 1-.154-.838L2.178 4.5H1.75a.75.75 0 0 1 0-1.5h2.234a.249.249 0 0 0 .125-.033l1.288-.737c.265-.15.564-.23.869-.23h.984V.75a.75.75 0 0 1 1.5 0Zm2.945 8.477c.285.135.718.273 1.305.273s1.02-.138 1.305-.273L13 6.327Zm-10 0c.285.135.718.273 1.305.273s1.02-.138 1.305-.273L3 6.327Z"></path></svg></span><span data-component="text" data-content="Apache-2.0 license">Apache-2.0 license</span></a></li><li class="Box-sc-g0xbh4-0 hUCRAk"><a class="prc-components-UnderlineItem-lJsg-" href="#"><span data-component="icon"><svg aria-hidden="true" focusable="false" class="octicon octicon-law" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M8.75.75V2h.985c.304 0 .603.08.867.231l1.29.736c.038.022.08.033.124.033h2.234a.75.75 0 0 1 0 1.5h-.427l2.111 4.692a.75.75 0 0 1-.154.838l-.53-.53.529.531-.001.002-.002.002-.006.006-.006.005-.01.01-.045.04c-.21.176-.441.327-.686.45C14.556 10.78 13.88 11 13 11a4.498 4.498 0 0 1-2.023-.454 3.544 3.544 0 0 1-.686-.45l-.045-.04-.016-.015-.006-.006-.004-.004v-.001a.75.75 0 0 1-.154-.838L12.178 4.5h-.162c-.305 0-.604-.079-.868-.231l-1.29-.736a.245.245 0 0 0-.124-.033H8.75V13h2.5a.75.75 0 0 1 0 1.5h-6.5a.75.75 0 0 1 0-1.5h2.5V3.5h-.984a.245.245 0 0 0-.124.033l-1.289.737c-.265.15-.564.23-.869.23h-.162l2.112 4.692a.75.75 0 0 1-.154.838l-.53-.53.529.531-.001.002-.002.002-.006.006-.016.015-.045.04c-.21.176-.441.327-.686.45C4.556 10.78 3.88 11 3 11a4.498 4.498 0 0 1-2.023-.454 3.544 3.544 0 0 1-.686-.45l-.045-.04-.016-.015-.006-.006-.004-.004v-.001a.75.75 0 0 1-.154-.838L2.178 4.5H1.75a.75.75 0 0 1 0-1.5h2.234a.249.249 0 0 0 .125-.033l1.288-.737c.265-.15.564-.23.869-.23h.984V.75a.75.75 0 0 1 1.5 0Zm2.945 8.477c.285.135.718.273 1.305.273s1.02-.138 1.305-.273L13 6.327Zm-10 0c.285.135.718.273 1.305.273s1.02-.138 1.305-.273L3 6.327Z"></path></svg></span><span data-component="text" data-content="MIT license">MIT license</span></a></li></ul></nav><button style="--button-color:fg.subtle" type="button" aria-label="Outline" aria-haspopup="true" aria-expanded="false" tabindex="0" class="Box-sc-g0xbh4-0 cwoBXV prc-Button-ButtonBase-c50BI" data-loading="false" data-size="medium" data-variant="invisible" aria-describedby=":Rr9ab:-loading-announcement" id=":Rr9ab:"><svg aria-hidden="true" focusable="false" class="octicon octicon-list-unordered" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M5.75 2.5h8.5a.75.75 0 0 1 0 1.5h-8.5a.75.75 0 0 1 0-1.5Zm0 5h8.5a.75.75 0 0 1 0 1.5h-8.5a.75.75 0 0 1 0-1.5Zm0 5h8.5a.75.75 0 0 1 0 1.5h-8.5a.75.75 0 0 1 0-1.5ZM2 14a1 1 0 1 1 0-2 1 1 0 0 1 0 2Zm1-6a1 1 0 1 1-2 0 1 1 0 0 1 2 0ZM2 4a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z"></path></svg></button></div><div class="Box-sc-g0xbh4-0 QkQOb js-snippet-clipboard-copy-unpositioned undefined" data-hpc="true"><article class="markdown-body entry-content container-lg" itemprop="text"><div class="markdown-heading" dir="auto"><h1 tabindex="-1" class="heading-element" dir="auto">srgn - a code surgeon</h1><a id="user-content-srgn---a-code-surgeon" class="anchor" aria-label="Permalink: srgn - a code surgeon" href="#srgn---a-code-surgeon"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">A <code>grep</code>-like tool which understands source code syntax and allows for manipulation in addition to search.</p> <p dir="auto">Like <code>grep</code>, regular expressions are a core primitive. Unlike <code>grep</code>, additional capabilities allow for <strong>higher precision</strong>, with <strong>options for manipulation</strong>. This allows <code>srgn</code> to operate along dimensions regular expressions and IDE tooling (<em>Rename all</em>, <em>Find all references</em>, ...) alone cannot, complementing them.</p> <p dir="auto"><code>srgn</code> is organized around <em>actions</em> to take (if any), acting only within precise, optionally <strong>language grammar-aware</strong> <em>scopes</em>. In terms of existing tools, think of it as a mix of <a href="https://www.gnu.org/software/coreutils/manual/html_node/tr-invocation.html#tr-invocation" rel="nofollow"><code>tr</code></a>, <a href="https://www.gnu.org/software/sed/" rel="nofollow"><code>sed</code></a>, <a href="https://github.com/BurntSushi/ripgrep">ripgrep</a> and <a href="https://tree-sitter.github.io/tree-sitter/" rel="nofollow"><code>tree-sitter</code></a>, with a design goal of <em>simplicity</em>: if you know regex and the basics of the language you are working with, you are good to go.</p> <blockquote> <p dir="auto">The answer to "What if <code>grep</code>, <code>tr</code>, <code>sed</code> and <code>tree-sitter</code> got really drunk one night and had a baby?"</p> <p dir="auto">-- <a href="https://realpython.com/podcasts/rpp/225/#t=2286" rel="nofollow">Real Python Podcast</a></p> </blockquote> <div class="markdown-heading" dir="auto"><h2 tabindex="-1" class="heading-element" dir="auto">Quick walkthrough</h2><a id="user-content-quick-walkthrough" class="anchor" aria-label="Permalink: Quick walkthrough" href="#quick-walkthrough"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <div class="markdown-alert markdown-alert-tip" dir="auto"><p class="markdown-alert-title" dir="auto"><svg class="octicon octicon-light-bulb mr-2" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="M8 1.5c-2.363 0-4 1.69-4 3.75 0 .984.424 1.625.984 2.304l.214.253c.223.264.47.556.673.848.284.411.537.896.621 1.49a.75.75 0 0 1-1.484.211c-.04-.282-.163-.547-.37-.847a8.456 8.456 0 0 0-.542-.68c-.084-.1-.173-.205-.268-.32C3.201 7.75 2.5 6.766 2.5 5.25 2.5 2.31 4.863 0 8 0s5.5 2.31 5.5 5.25c0 1.516-.701 2.5-1.328 3.259-.095.115-.184.22-.268.319-.207.245-.383.453-.541.681-.208.3-.33.565-.37.847a.751.751 0 0 1-1.485-.212c.084-.593.337-1.078.621-1.489.203-.292.45-.584.673-.848.075-.088.147-.173.213-.253.561-.679.985-1.32.985-2.304 0-2.06-1.637-3.75-4-3.75ZM5.75 12h4.5a.75.75 0 0 1 0 1.5h-4.5a.75.75 0 0 1 0-1.5ZM6 15.25a.75.75 0 0 1 .75-.75h2.5a.75.75 0 0 1 0 1.5h-2.5a.75.75 0 0 1-.75-.75Z"></path></svg>Tip</p> <p dir="auto">All code snippets displayed here are <a href="/alexpovel/srgn/blob/main/tests/readme.rs">verified as part of unit tests</a> using the actual <code>srgn</code> binary. What is showcased here is guaranteed to work.</p> </div> <p dir="auto">The most simple <code>srgn</code> usage works <a href="#comparison-with-tr">similar to <code>tr</code></a>:</p> <div class="highlight highlight-source-shell notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="$ echo 'Hello World!' | srgn '[wW]orld' 'there' # replacement Hello there!"><pre>$ <span class="pl-c1">echo</span> <span class="pl-s"><span class="pl-pds">'</span>Hello World!<span class="pl-pds">'</span></span> <span class="pl-k">|</span> srgn <span class="pl-s"><span class="pl-pds">'</span>[wW]orld<span class="pl-pds">'</span></span> <span class="pl-s"><span class="pl-pds">'</span>there<span class="pl-pds">'</span></span> <span class="pl-c"><span class="pl-c">#</span> replacement</span> Hello there<span class="pl-k">!</span></pre></div> <p dir="auto">Matches for the regular expression pattern <code>'[wW]orld'</code> (the <em>scope</em>) are replaced (the <em>action</em>) by the second positional argument. Zero or more actions can be specified:</p> <div class="highlight highlight-source-shell notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="$ echo 'Hello World!' | srgn '[wW]orld' # zero actions: input returned unchanged Hello World! $ echo 'Hello World!' | srgn --upper '[wW]orld' 'you' # two actions: replacement, afterwards uppercasing Hello YOU!"><pre>$ <span class="pl-c1">echo</span> <span class="pl-s"><span class="pl-pds">'</span>Hello World!<span class="pl-pds">'</span></span> <span class="pl-k">|</span> srgn <span class="pl-s"><span class="pl-pds">'</span>[wW]orld<span class="pl-pds">'</span></span> <span class="pl-c"><span class="pl-c">#</span> zero actions: input returned unchanged</span> Hello World<span class="pl-k">!</span> $ <span class="pl-c1">echo</span> <span class="pl-s"><span class="pl-pds">'</span>Hello World!<span class="pl-pds">'</span></span> <span class="pl-k">|</span> srgn --upper <span class="pl-s"><span class="pl-pds">'</span>[wW]orld<span class="pl-pds">'</span></span> <span class="pl-s"><span class="pl-pds">'</span>you<span class="pl-pds">'</span></span> <span class="pl-c"><span class="pl-c">#</span> two actions: replacement, afterwards uppercasing</span> Hello YOU<span class="pl-k">!</span></pre></div> <p dir="auto">Replacement is always performed first and specified positionally. Any <a href="#actions">other actions</a> are applied after and given as command line flags.</p> <div class="markdown-heading" dir="auto"><h3 tabindex="-1" class="heading-element" dir="auto">Multiple scopes</h3><a id="user-content-multiple-scopes" class="anchor" aria-label="Permalink: Multiple scopes" href="#multiple-scopes"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">Similarly, more than one scope can be specified: in addition to the regex pattern, a <a href="https://tree-sitter.github.io/tree-sitter/" rel="nofollow"><strong>language grammar-aware</strong></a> scope can be given, which scopes to <strong>syntactical elements of source code</strong> (think, for example, "all bodies of <code>class</code> definitions in Python"). If both are given, the regular expression pattern is then <strong>only applied <em>within</em> that first, language scope</strong>. This enables search and manipulation at precision not normally possible using plain regular expressions, and serving a dimension different from tools such as <em>Rename all</em> in IDEs.</p> <p dir="auto">For example, consider this (pointless) Python source file:</p> <div class="highlight highlight-source-python notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="&quot;&quot;&quot;Module for watching birds and their age.&quot;&quot;&quot; from dataclasses import dataclass @dataclass class Bird: &quot;&quot;&quot;A bird!&quot;&quot;&quot; name: str age: int def celebrate_birthday(self): print(&quot;🎉&quot;) self.age += 1 @classmethod def from_egg(egg): &quot;&quot;&quot;Create a bird from an egg.&quot;&quot;&quot; pass # No bird here yet! def register_bird(bird: Bird, db: Db) -&gt; None: assert bird.age &gt;= 0 with db.tx() as tx: tx.insert(bird)"><pre><span class="pl-s">"""Module for watching birds and their age."""</span> <span class="pl-k">from</span> <span class="pl-s1">dataclasses</span> <span class="pl-k">import</span> <span class="pl-s1">dataclass</span> <span class="pl-en">@<span class="pl-s1">dataclass</span></span> <span class="pl-k">class</span> <span class="pl-v">Bird</span>: <span class="pl-s">"""A bird!"""</span> <span class="pl-s1">name</span>: <span class="pl-smi">str</span> <span class="pl-s1">age</span>: <span class="pl-smi">int</span> <span class="pl-k">def</span> <span class="pl-en">celebrate_birthday</span>(<span class="pl-s1">self</span>): <span class="pl-en">print</span>(<span class="pl-s">"🎉"</span>) <span class="pl-s1">self</span>.<span class="pl-c1">age</span> <span class="pl-c1">+=</span> <span class="pl-c1">1</span> <span class="pl-en">@<span class="pl-s1">classmethod</span></span> <span class="pl-k">def</span> <span class="pl-en">from_egg</span>(<span class="pl-s1">egg</span>): <span class="pl-s">"""Create a bird from an egg."""</span> <span class="pl-k">pass</span> <span class="pl-c"># No bird here yet!</span> <span class="pl-k">def</span> <span class="pl-en">register_bird</span>(<span class="pl-s1">bird</span>: <span class="pl-smi">Bird</span>, <span class="pl-s1">db</span>: <span class="pl-smi">Db</span>) <span class="pl-c1">-&gt;</span> <span class="pl-c1">None</span>: <span class="pl-k">assert</span> <span class="pl-s1">bird</span>.<span class="pl-c1">age</span> <span class="pl-c1">&gt;=</span> <span class="pl-c1">0</span> <span class="pl-k">with</span> <span class="pl-s1">db</span>.<span class="pl-c1">tx</span>() <span class="pl-k">as</span> <span class="pl-s1">tx</span>: <span class="pl-s1">tx</span>.<span class="pl-c1">insert</span>(<span class="pl-s1">bird</span>)</pre></div> <p dir="auto">which can be searched using:</p> <div class="highlight highlight-text-shell-session notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="$ cat birds.py | srgn --python 'class' 'age' 11: age: int 15: self.age += 1"><pre>$ <span class="pl-s1">cat birds.py <span class="pl-k">|</span> srgn --python <span class="pl-s"><span class="pl-pds">'</span>class<span class="pl-pds">'</span></span> <span class="pl-s"><span class="pl-pds">'</span>age<span class="pl-pds">'</span></span></span> <span class="pl-c1">11: age: int</span> <span class="pl-c1">15: self.age += 1</span></pre></div> <p dir="auto">The string <code>age</code> was sought and found <em>only</em> within Python <code>class</code> definitions (and not, for example, in function bodies such as <code>register_bird</code>, where <code>age</code> also occurs and would be nigh impossible to exclude from consideration in vanilla <code>grep</code>). By default, this 'search mode' also prints line numbers. <strong>Search mode is entered if no actions are specified</strong>, and a language such as <code>--python</code> is given<sup><a href="#user-content-fn-3-b30ce13ed678ccbd6287a3f5e19f11b5" id="user-content-fnref-3-b30ce13ed678ccbd6287a3f5e19f11b5" data-footnote-ref="" aria-describedby="footnote-label">1</a></sup>—think of it like '<a href="https://github.com/BurntSushi/ripgrep">ripgrep</a> but with syntactical language elements'.</p> <p dir="auto">Searching can also be performed <a href="https://docs.rs/regex/1.10.5/regex/index.html#grouping-and-flags" rel="nofollow">across lines</a>, for example to find methods (aka <em><code>def</code> within <code>class</code></em>) lacking docstrings:</p> <div class="highlight highlight-text-shell-session notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="$ cat birds.py | srgn --python 'class' 'def .+:\n\s+[^&quot;\s]{3}' # do not try this pattern at home 13: def celebrate_birthday(self): 14: print(&quot;🎉&quot;)"><pre>$ <span class="pl-s1">cat birds.py <span class="pl-k">|</span> srgn --python <span class="pl-s"><span class="pl-pds">'</span>class<span class="pl-pds">'</span></span> <span class="pl-s"><span class="pl-pds">'</span>def .+:\n\s+[^"\s]{3}<span class="pl-pds">'</span></span> <span class="pl-c"><span class="pl-c">#</span> do not try this pattern at home</span></span> <span class="pl-c1">13: def celebrate_birthday(self):</span> <span class="pl-c1">14: print("🎉")</span></pre></div> <p dir="auto">Note how this does not surface either <code>from_egg</code> (has a docstring) or <code>register_bird</code> (not a method, <em><code>def</code> outside <code>class</code></em>).</p> <div class="markdown-heading" dir="auto"><h4 tabindex="-1" class="heading-element" dir="auto">Multiple language scopes</h4><a id="user-content-multiple-language-scopes" class="anchor" aria-label="Permalink: Multiple language scopes" href="#multiple-language-scopes"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">Language scopes themselves can be specified multiple times as well. For example, in the Rust snippet</p> <div class="highlight highlight-source-rust notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="pub enum Genre { Rock(Subgenre), Jazz, } const MOST_POPULAR_SUBGENRE: Subgenre = Subgenre::Something; pub struct Musician { name: String, genres: Vec&lt;Subgenre&gt;, }"><pre><span class="pl-k">pub</span> <span class="pl-k">enum</span> <span class="pl-smi">Genre</span> <span class="pl-kos">{</span> <span class="pl-v">Rock</span><span class="pl-kos">(</span><span class="pl-smi">Subgenre</span><span class="pl-kos">)</span><span class="pl-kos">,</span> <span class="pl-v">Jazz</span><span class="pl-kos">,</span> <span class="pl-kos">}</span> <span class="pl-k">const</span> <span class="pl-v">MOST_POPULAR_SUBGENRE</span><span class="pl-kos">:</span> <span class="pl-smi">Subgenre</span> = <span class="pl-smi">Subgenre</span><span class="pl-kos">::</span><span class="pl-v">Something</span><span class="pl-kos">;</span> <span class="pl-k">pub</span> <span class="pl-k">struct</span> <span class="pl-smi">Musician</span> <span class="pl-kos">{</span> <span class="pl-c1">name</span><span class="pl-kos">:</span> <span class="pl-smi">String</span><span class="pl-kos">,</span> <span class="pl-c1">genres</span><span class="pl-kos">:</span> <span class="pl-smi">Vec</span><span class="pl-kos">&lt;</span><span class="pl-smi">Subgenre</span><span class="pl-kos">&gt;</span><span class="pl-kos">,</span> <span class="pl-kos">}</span></pre></div> <p dir="auto">multiple items can be surgically drilled down into as</p> <div class="highlight highlight-text-shell-session notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="$ cat music.rs | srgn --rust 'pub-enum' --rust 'type-identifier' 'Subgenre' # AND'ed together 2: Rock(Subgenre),"><pre>$ <span class="pl-s1">cat music.rs <span class="pl-k">|</span> srgn --rust <span class="pl-s"><span class="pl-pds">'</span>pub-enum<span class="pl-pds">'</span></span> --rust <span class="pl-s"><span class="pl-pds">'</span>type-identifier<span class="pl-pds">'</span></span> <span class="pl-s"><span class="pl-pds">'</span>Subgenre<span class="pl-pds">'</span></span> <span class="pl-c"><span class="pl-c">#</span> AND'ed together</span></span> <span class="pl-c1">2: Rock(Subgenre),</span></pre></div> <p dir="auto">where only lines matching <em>all</em> criteria are returned, acting like a logical <em>and</em> between all conditions. Note that conditions are evaluated left-to-right, precluding some combinations from making sense: for example, searching for a Python <code>class</code> body <em>inside</em> of Python <code>doc-strings</code> usually returns nothing. The inverse works as expected however:</p> <div class="highlight highlight-text-shell-session notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="$ cat birds.py | srgn --py 'class' --py 'doc-strings' 8: &quot;&quot;&quot;A bird!&quot;&quot;&quot; 19: &quot;&quot;&quot;Create a bird from an egg.&quot;&quot;&quot;"><pre>$ <span class="pl-s1">cat birds.py <span class="pl-k">|</span> srgn --py <span class="pl-s"><span class="pl-pds">'</span>class<span class="pl-pds">'</span></span> --py <span class="pl-s"><span class="pl-pds">'</span>doc-strings<span class="pl-pds">'</span></span> </span> <span class="pl-c1">8: """A bird!"""</span> <span class="pl-c1">19: """Create a bird from an egg."""</span></pre></div> <p dir="auto">No docstrings outside <code>class</code> bodies are surfaced!</p> <p dir="auto">The <a href="#help-output"><code>-j</code> flag</a> changes this behavior: from intersecting left-to-right, to running all queries independently and joining their results, allowing you to search multiple ways at once:</p> <div class="highlight highlight-text-shell-session notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="$ cat birds.py | srgn -j --python 'comments' --python 'doc-strings' 'bird[^s]' 8: &quot;&quot;&quot;A bird!&quot;&quot;&quot; 19: &quot;&quot;&quot;Create a bird from an egg.&quot;&quot;&quot; 20: pass # No bird here yet!"><pre>$ <span class="pl-s1">cat birds.py <span class="pl-k">|</span> srgn -j --python <span class="pl-s"><span class="pl-pds">'</span>comments<span class="pl-pds">'</span></span> --python <span class="pl-s"><span class="pl-pds">'</span>doc-strings<span class="pl-pds">'</span></span> <span class="pl-s"><span class="pl-pds">'</span>bird[^s]<span class="pl-pds">'</span></span></span> <span class="pl-c1">8: """A bird!"""</span> <span class="pl-c1">19: """Create a bird from an egg."""</span> <span class="pl-c1">20: pass # No bird here yet!</span></pre></div> <p dir="auto">The pattern <code>bird[^s]</code> was found inside of comments <em>or</em> docstrings likewise, not just "docstrings <em>within</em> comments".</p> <div class="markdown-heading" dir="auto"><h4 tabindex="-1" class="heading-element" dir="auto">Working recursively</h4><a id="user-content-working-recursively" class="anchor" aria-label="Permalink: Working recursively" href="#working-recursively"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">If standard input is not given, <code>srgn</code> knows how to find relevant source files automatically, for example in this repository:</p> <div class="highlight highlight-text-shell-session notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="$ srgn --python 'class' 'age' docs/samples/birds 11: age: int 15: self.age += 1 docs/samples/birds.py 9: age: int 13: self.age += 1"><pre>$ <span class="pl-s1">srgn --python <span class="pl-s"><span class="pl-pds">'</span>class<span class="pl-pds">'</span></span> <span class="pl-s"><span class="pl-pds">'</span>age<span class="pl-pds">'</span></span></span> <span class="pl-c1">docs/samples/birds</span> <span class="pl-c1">11: age: int</span> <span class="pl-c1">15: self.age += 1</span> <span class="pl-c1">docs/samples/birds.py</span> <span class="pl-c1">9: age: int</span> <span class="pl-c1">13: self.age += 1</span></pre></div> <p dir="auto">It recursively walks its current directory, finding files based on <a href="/alexpovel/srgn/blob/main/docs/samples/birds.py">file extensions</a> and <a href="/alexpovel/srgn/blob/main/docs/samples/birds">shebang lines</a>, processing at very high speed. For example, <code>srgn --go strings '\d+'</code> finds and prints all ~140,000 runs of digits in literal Go strings inside the <a href="https://github.com/kubernetes/kubernetes/tree/5639f8f848720329f4a9d53555a228891550cb79">Kubernetes codebase</a> of ~3,000,000 lines of Go code within 3 seconds on 12 cores of M3. For more on working with many files, see <a href="#run-against-multiple-files">below</a>.</p> <div class="markdown-heading" dir="auto"><h3 tabindex="-1" class="heading-element" dir="auto">Combining actions and scopes</h3><a id="user-content-combining-actions-and-scopes" class="anchor" aria-label="Permalink: Combining actions and scopes" href="#combining-actions-and-scopes"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">Scopes and actions can be combined almost arbitrarily (though many combinations are not going to be use- or even meaningful). For example, consider this Python snippet (for examples using other supported languages see <a href="#prepared-queries">below</a>):</p> <div class="highlight highlight-source-python notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="&quot;&quot;&quot;GNU module.&quot;&quot;&quot; def GNU_says_moo(): &quot;&quot;&quot;The GNU function -&gt; say moo -&gt; ✅&quot;&quot;&quot; GNU = &quot;&quot;&quot; GNU &quot;&quot;&quot; # the GNU... print(GNU + &quot; says moo&quot;) # ...says moo"><pre><span class="pl-s">"""GNU module."""</span> <span class="pl-k">def</span> <span class="pl-en">GNU_says_moo</span>(): <span class="pl-s">"""The GNU function -&gt; say moo -&gt; ✅"""</span> <span class="pl-c1">GNU</span> <span class="pl-c1">=</span> <span class="pl-s">"""</span> <span class="pl-s"> GNU</span> <span class="pl-s"> """</span> <span class="pl-c"># the GNU...</span> <span class="pl-en">print</span>(<span class="pl-c1">GNU</span> <span class="pl-c1">+</span> <span class="pl-s">" says moo"</span>) <span class="pl-c"># ...says moo</span></pre></div> <p dir="auto">against which the following command is run:</p> <div class="highlight highlight-source-shell notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="cat gnu.py | srgn --titlecase --python 'doc-strings' '(?&lt;!The )GNU ([a-z]+)' '$1: GNU 🐂 is not Unix'"><pre>cat gnu.py <span class="pl-k">|</span> srgn --titlecase --python <span class="pl-s"><span class="pl-pds">'</span>doc-strings<span class="pl-pds">'</span></span> <span class="pl-s"><span class="pl-pds">'</span>(?&lt;!The )GNU ([a-z]+)<span class="pl-pds">'</span></span> <span class="pl-s"><span class="pl-pds">'</span>$1: GNU 🐂 is not Unix<span class="pl-pds">'</span></span></pre></div> <p dir="auto">The anatomy of that invocation is:</p> <ul dir="auto"> <li> <p dir="auto"><code>--titlecase</code> (an <a href="#character-casing">action</a>) will Titlecase Everything Found In Scope</p> </li> <li> <p dir="auto"><code>--python 'doc-strings'</code> (a <a href="#language-grammar-aware-scopes">scope</a>) will scope to (i.e., only take into consideration) docstrings according to the Python language grammar</p> </li> <li> <p dir="auto"><code>'(?&lt;!The )GNU ([a-z]+)'</code> (a <a href="#scopes">scope</a>) sees only what was already scoped by the previous option, and will narrow it down further. It can never extend the previous scope. The regular expression scope is applied after any language scope(s).</p> <p dir="auto"><code>(?&lt;!)</code> is <a href="https://docs.rs/fancy-regex/latest/fancy_regex/#syntax" rel="nofollow">negative lookbehind</a> syntax, demonstrating how this advanced feature is available. Strings of <code>GNU</code> prefixed by <code>The </code> will not be considered.</p> </li> <li> <p dir="auto"><code>'$1: GNU 🐂 is not Unix'</code> (an <a href="#replacement">action</a>) will <em>replace</em> each matched occurrence (i.e., each input section found to be in scope) with this string. Matched occurrences are patterns of <code>'(?&lt;!The )GNU ([a-z]+)'</code> <em>only within</em> Python docstrings. Notably, this replacement string demonstrates:</p> <ul dir="auto"> <li>dynamic <a href="#variables">variable binding and substitution</a> using <code>$1</code>, which carries the contents captured by the first capturing regex group. That's <code>([a-z]+)</code>, as <code>(?&lt;!The )</code> is not capturing.</li> <li>full Unicode support (🐂).</li> </ul> </li> </ul> <p dir="auto">The command makes use of multiple scopes (language and regex pattern) and multiple actions (replacement and titlecasing). The result then reads</p> <div class="highlight highlight-source-python notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="&quot;&quot;&quot;Module: GNU 🐂 Is Not Unix.&quot;&quot;&quot; def GNU_says_moo(): &quot;&quot;&quot;The GNU function -&gt; say moo -&gt; ✅&quot;&quot;&quot; GNU = &quot;&quot;&quot; GNU &quot;&quot;&quot; # the GNU... print(GNU + &quot; says moo&quot;) # ...says moo"><pre><span class="pl-s">"""Module: GNU 🐂 Is Not Unix."""</span> <span class="pl-k">def</span> <span class="pl-en">GNU_says_moo</span>(): <span class="pl-s">"""The GNU function -&gt; say moo -&gt; ✅"""</span> <span class="pl-c1">GNU</span> <span class="pl-c1">=</span> <span class="pl-s">"""</span> <span class="pl-s"> GNU</span> <span class="pl-s"> """</span> <span class="pl-c"># the GNU...</span> <span class="pl-en">print</span>(<span class="pl-c1">GNU</span> <span class="pl-c1">+</span> <span class="pl-s">" says moo"</span>) <span class="pl-c"># ...says moo</span></pre></div> <p dir="auto">where the changes are limited to:</p> <div class="highlight highlight-source-diff notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="- &quot;&quot;&quot;GNU module.&quot;&quot;&quot; + &quot;&quot;&quot;Module: GNU 🐂 Is Not Unix.&quot;&quot;&quot; def GNU_says_moo(): &quot;&quot;&quot;The GNU -&gt; say moo -&gt; ✅&quot;&quot;&quot;"><pre><span class="pl-md"><span class="pl-md">-</span> """GNU module."""</span> <span class="pl-mi1"><span class="pl-mi1">+</span> """Module: GNU 🐂 Is Not Unix."""</span> def GNU_says_moo(): """The GNU -&gt; say moo -&gt; ✅"""</pre></div> <div class="markdown-alert markdown-alert-warning" dir="auto"><p class="markdown-alert-title" dir="auto"><svg class="octicon octicon-alert mr-2" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z"></path></svg>Warning</p> <p dir="auto">While <code>srgn</code> is in beta (<a href="https://semver.org/" rel="nofollow">major version</a> 0), make sure to only (recursively) process files you can safely <a href="https://git-scm.com/docs/git-restore" rel="nofollow">restore</a>.</p> <p dir="auto">Search mode does not overwrite files, so is always safe.</p> </div> <p dir="auto">See <a href="#help-output">below</a> for the full help output of the tool.</p> <div class="markdown-alert markdown-alert-note" dir="auto"><p class="markdown-alert-title" dir="auto"><svg class="octicon octicon-info mr-2" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z"></path></svg>Note</p> <p dir="auto">Supported languages are</p> <ul dir="auto"> <li>C</li> <li>C#</li> <li>Go</li> <li>HCL (Terraform)</li> <li>Python</li> <li>Rust</li> <li>TypeScript</li> </ul> </div> <div class="markdown-heading" dir="auto"><h2 tabindex="-1" class="heading-element" dir="auto">Installation</h2><a id="user-content-installation" class="anchor" aria-label="Permalink: Installation" href="#installation"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <div class="markdown-heading" dir="auto"><h3 tabindex="-1" class="heading-element" dir="auto">Prebuilt binaries</h3><a id="user-content-prebuilt-binaries" class="anchor" aria-label="Permalink: Prebuilt binaries" href="#prebuilt-binaries"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">Download a prebuilt binary from the <a href="https://github.com/alexpovel/srgn/releases/latest">releases</a>.</p> <div class="markdown-heading" dir="auto"><h3 tabindex="-1" class="heading-element" dir="auto">cargo-binstall</h3><a id="user-content-cargo-binstall" class="anchor" aria-label="Permalink: cargo-binstall" href="#cargo-binstall"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">This crate provides its binaries in a format <a href="https://github.com/cargo-bins/cargo-binstall/blob/9cfc0cd5f97300925ae60f67712b74970a380aca/SUPPORT.md#support-for-cargo-binstall">compatible</a> with <a href="https://github.com/cargo-bins/cargo-binstall"><code>cargo-binstall</code></a>:</p> <ol dir="auto"> <li>Install the <a href="https://www.rust-lang.org/tools/install" rel="nofollow">Rust toolchain</a></li> <li>Run <code>cargo install cargo-binstall</code> (might take a while)</li> <li>Run <code>cargo binstall srgn</code> (couple seconds, as it downloads <a href="#prebuilt-binaries">prebuilt binaries</a> from GitHub)</li> </ol> <p dir="auto">These steps are guaranteed to work™, as they are <a href="/alexpovel/srgn/blob/main/.github/workflows/main.yml">tested in CI</a>. They also work if no prebuilt binaries are available for your platform, as the tool will fall back to <a href="#cargo-compile-from-source">compiling from source</a>.</p> <div class="markdown-heading" dir="auto"><h3 tabindex="-1" class="heading-element" dir="auto">Homebrew</h3><a id="user-content-homebrew" class="anchor" aria-label="Permalink: Homebrew" href="#homebrew"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">A <a href="https://formulae.brew.sh/formula/srgn" rel="nofollow">formula</a> is available via:</p> <div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="brew install srgn"><pre lang="text" class="notranslate"><code>brew install srgn </code></pre></div> <div class="markdown-heading" dir="auto"><h3 tabindex="-1" class="heading-element" dir="auto">Nix</h3><a id="user-content-nix" class="anchor" aria-label="Permalink: Nix" href="#nix"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">Available via <a href="https://search.nixos.org/packages?channel=unstable&amp;show=srgn&amp;from=0&amp;size=50&amp;sort=relevance&amp;type=packages&amp;query=srgn" rel="nofollow">unstable</a>:</p> <div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="nix-shell -p srgn"><pre lang="text" class="notranslate"><code>nix-shell -p srgn </code></pre></div> <div class="markdown-heading" dir="auto"><h3 tabindex="-1" class="heading-element" dir="auto">Arch Linux</h3><a id="user-content-arch-linux" class="anchor" aria-label="Permalink: Arch Linux" href="#arch-linux"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">Available via the <a href="https://aur.archlinux.org/cgit/aur.git/tree/PKGBUILD?h=srgn" rel="nofollow">AUR</a>.</p> <div class="markdown-heading" dir="auto"><h3 tabindex="-1" class="heading-element" dir="auto">MacPorts</h3><a id="user-content-macports" class="anchor" aria-label="Permalink: MacPorts" href="#macports"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">A <a href="https://ports.macports.org/port/srgn/" rel="nofollow">port</a> is available:</p> <div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="sudo port install srgn"><pre lang="text" class="notranslate"><code>sudo port install srgn </code></pre></div> <div class="markdown-heading" dir="auto"><h3 tabindex="-1" class="heading-element" dir="auto">CI (GitHub Actions)</h3><a id="user-content-ci-github-actions" class="anchor" aria-label="Permalink: CI (GitHub Actions)" href="#ci-github-actions"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">All <a href="https://github.com/actions/runner-images/tree/main/images">GitHub Actions runner images</a> come with <code>cargo</code> preinstalled, and <code>cargo-binstall</code> provides a convenient <a href="https://github.com/marketplace/actions/install-cargo-binstall">GitHub Action</a>:</p> <div class="highlight highlight-source-yaml notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="jobs: srgn: name: Install srgn in CI # All three major OSes work runs-on: ubuntu-latest steps: - uses: cargo-bins/cargo-binstall@main - name: Install binary run: &gt; cargo binstall --no-confirm srgn - name: Use binary run: srgn --version"><pre><span class="pl-ent">jobs</span>: <span class="pl-ent">srgn</span>: <span class="pl-ent">name</span>: <span class="pl-s">Install srgn in CI</span> <span class="pl-c"><span class="pl-c">#</span> All three major OSes work</span> <span class="pl-ent">runs-on</span>: <span class="pl-s">ubuntu-latest</span> <span class="pl-ent">steps</span>: - <span class="pl-ent">uses</span>: <span class="pl-s">cargo-bins/cargo-binstall@main</span> - <span class="pl-ent">name</span>: <span class="pl-s">Install binary</span> <span class="pl-ent">run</span>: <span class="pl-s">&gt;</span> <span class="pl-s"> cargo binstall</span> <span class="pl-s"> --no-confirm</span> <span class="pl-s"> srgn</span> <span class="pl-s"></span> - <span class="pl-ent">name</span>: <span class="pl-s">Use binary</span> <span class="pl-ent">run</span>: <span class="pl-s">srgn --version</span></pre></div> <p dir="auto">The above concludes in just <a href="https://github.com/alexpovel/srgn/actions/runs/6605290729/job/17940329899">5 seconds total</a>, as no compilation is required. For more context, see <a href="https://github.com/cargo-bins/cargo-binstall#can-i-use-it-in-ci"><code>cargo-binstall</code>'s advise on CI</a>.</p> <div class="markdown-heading" dir="auto"><h3 tabindex="-1" class="heading-element" dir="auto">Cargo (compile from source)</h3><a id="user-content-cargo-compile-from-source" class="anchor" aria-label="Permalink: Cargo (compile from source)" href="#cargo-compile-from-source"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <ol dir="auto"> <li>Install the <a href="https://www.rust-lang.org/tools/install" rel="nofollow">Rust toolchain</a></li> <li>A C compiler is required: <ol dir="auto"> <li> <p dir="auto">On Linux, <code>gcc</code> works.</p> </li> <li> <p dir="auto">On macOS, use <code>clang</code>.</p> </li> <li> <p dir="auto">On Windows, <a href="https://visualstudio.microsoft.com/downloads/" rel="nofollow">MSVC</a> works.</p> <p dir="auto">Select "Desktop development with C++" on installation.</p> </li> </ol> </li> <li>Run <code>cargo install srgn</code></li> </ol> <div class="markdown-heading" dir="auto"><h3 tabindex="-1" class="heading-element" dir="auto">Cargo (as a Rust library)</h3><a id="user-content-cargo-as-a-rust-library" class="anchor" aria-label="Permalink: Cargo (as a Rust library)" href="#cargo-as-a-rust-library"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="cargo add srgn"><pre lang="text" class="notranslate"><code>cargo add srgn </code></pre></div> <p dir="auto">See <a href="#rust-library">here</a> for more.</p> <div class="markdown-heading" dir="auto"><h3 tabindex="-1" class="heading-element" dir="auto">Shell completions</h3><a id="user-content-shell-completions" class="anchor" aria-label="Permalink: Shell completions" href="#shell-completions"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto"><a href="https://docs.rs/clap_complete/4.5.1/clap_complete/shells/enum.Shell.html#variants" rel="nofollow">Various shells</a> are supported for shell completion scripts. For example, append <code>eval "$(srgn --completions zsh)"</code> to <code>~/.zshrc</code> for completions in ZSH. An interactive session can then look like:</p> <p dir="auto"><a href="https://asciinema.org/a/673473" rel="nofollow"><img src="/alexpovel/srgn/raw/main/docs/images/interactive-use-shell-completion.gif" alt="srgn shell completion" data-animated-image="" style="max-width: 100%;"></a></p> <div class="markdown-heading" dir="auto"><h2 tabindex="-1" class="heading-element" dir="auto">Walkthrough</h2><a id="user-content-walkthrough" class="anchor" aria-label="Permalink: Walkthrough" href="#walkthrough"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">The tool is designed around <strong>scopes</strong> and <strong>actions</strong>. Scopes narrow down the parts of the input to process. Actions then perform the processing. Generally, both scopes and actions are composable, so more than one of each may be passed. Both are optional (but taking no action is pointless); specifying no scope implies the entire input is in scope.</p> <p dir="auto">At the same time, there is <a href="#comparison-with-tr">considerable overlap</a> with plain <a href="https://www.gnu.org/software/coreutils/manual/html_node/tr-invocation.html" rel="nofollow"><code>tr</code></a>: the tool is designed to have close correspondence in the most common use cases, and only go beyond when needed.</p> <div class="markdown-heading" dir="auto"><h3 tabindex="-1" class="heading-element" dir="auto">Actions</h3><a id="user-content-actions" class="anchor" aria-label="Permalink: Actions" href="#actions"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">The simplest action is replacement. It is specially accessed (as an argument, not an option) for compatibility with <a href="https://www.gnu.org/software/coreutils/manual/html_node/tr-invocation.html" rel="nofollow"><code>tr</code></a>, and general ergonomics. All other actions are given as flags, or options should they take a value.</p> <div class="markdown-heading" dir="auto"><h4 tabindex="-1" class="heading-element" dir="auto">Replacement</h4><a id="user-content-replacement" class="anchor" aria-label="Permalink: Replacement" href="#replacement"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">For example, simple, single-character replacements work as in <a href="https://www.gnu.org/software/coreutils/manual/html_node/tr-invocation.html" rel="nofollow"><code>tr</code></a>:</p> <div class="highlight highlight-text-shell-session notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="$ echo 'Hello, World!' | srgn 'H' 'J' Jello, World!"><pre>$ <span class="pl-s1"><span class="pl-c1">echo</span> <span class="pl-s"><span class="pl-pds">'</span>Hello, World!<span class="pl-pds">'</span></span> <span class="pl-k">|</span> srgn <span class="pl-s"><span class="pl-pds">'</span>H<span class="pl-pds">'</span></span> <span class="pl-s"><span class="pl-pds">'</span>J<span class="pl-pds">'</span></span></span> <span class="pl-c1">Jello, World!</span></pre></div> <p dir="auto">The first argument is the scope (literal <code>H</code> in this case). Anything matched by it is subject to processing (replacement by <code>J</code>, the second argument, in this case). However, there is <strong>no direct concept of character classes</strong> as in <a href="https://www.gnu.org/software/coreutils/manual/html_node/tr-invocation.html" rel="nofollow"><code>tr</code></a>. Instead, by default, the scope is a regular expression pattern, so <em>its</em> <a href="https://docs.rs/regex/1.9.5/regex/index.html#character-classes" rel="nofollow">classes</a> can be used to similar effect:</p> <div class="highlight highlight-text-shell-session notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="$ echo 'Hello, World!' | srgn '[a-z]' '_' H____, W____!"><pre>$ <span class="pl-s1"><span class="pl-c1">echo</span> <span class="pl-s"><span class="pl-pds">'</span>Hello, World!<span class="pl-pds">'</span></span> <span class="pl-k">|</span> srgn <span class="pl-s"><span class="pl-pds">'</span>[a-z]<span class="pl-pds">'</span></span> <span class="pl-s"><span class="pl-pds">'</span>_<span class="pl-pds">'</span></span></span> <span class="pl-c1">H____, W____!</span></pre></div> <p dir="auto">The replacement occurs greedily across the entire match by default (note the <a href="https://docs.rs/regex/1.9.5/regex/index.html#ascii-character-classes" rel="nofollow">UTS character class</a>, reminiscent of <a href="https://github.com/coreutils/coreutils/blob/769ace51e8a1129c44ee4e7e209c3b2df2111524/src/tr.c#L322C25-L322C25"><code>tr</code>'s <code>[:alnum:]</code></a>):</p> <div class="highlight highlight-text-shell-session notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="$ echo 'ghp_oHn0As3cr3T!!' | srgn 'ghp_[[:alnum:]]+' '*' # A GitHub token *!!"><pre>$ <span class="pl-s1"><span class="pl-c1">echo</span> <span class="pl-s"><span class="pl-pds">'</span>ghp_oHn0As3cr3T!!<span class="pl-pds">'</span></span> <span class="pl-k">|</span> srgn <span class="pl-s"><span class="pl-pds">'</span>ghp_[[:alnum:]]+<span class="pl-pds">'</span></span> <span class="pl-s"><span class="pl-pds">'</span>*<span class="pl-pds">'</span></span> <span class="pl-c"><span class="pl-c">#</span> A GitHub token</span></span> <span class="pl-c1">*!!</span></pre></div> <p dir="auto">Advanced regex features are <a href="https://docs.rs/fancy-regex/0.11.0/fancy_regex/index.html#syntax" rel="nofollow">supported</a>, for example lookarounds:</p> <div class="highlight highlight-text-shell-session notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="$ echo 'ghp_oHn0As3cr3T' | srgn '(?&lt;=ghp_)[[:alnum:]]+' '*' ghp_*"><pre>$ <span class="pl-s1"><span class="pl-c1">echo</span> <span class="pl-s"><span class="pl-pds">'</span>ghp_oHn0As3cr3T<span class="pl-pds">'</span></span> <span class="pl-k">|</span> srgn <span class="pl-s"><span class="pl-pds">'</span>(?&lt;=ghp_)[[:alnum:]]+<span class="pl-pds">'</span></span> <span class="pl-s"><span class="pl-pds">'</span>*<span class="pl-pds">'</span></span></span> <span class="pl-c1">ghp_*</span></pre></div> <p dir="auto">Take care in using these safely, as advanced patterns come without certain <a href="https://docs.rs/regex/latest/regex/#untrusted-input" rel="nofollow">safety and performance guarantees</a>. If they aren't used, <a href="https://docs.rs/fancy-regex/0.11.0/fancy_regex/index.html#" rel="nofollow">performance is not impacted</a>.</p> <p dir="auto">The replacement is not limited to a single character. It can be any string, for example to fix <a href="http://regex.info/blog/2006-09-15/247" rel="nofollow">this quote</a>:</p> <div class="highlight highlight-text-shell-session notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="$ echo '&quot;Using regex, I now have no issues.&quot;' | srgn 'no issues' '2 problems' &quot;Using regex, I now have 2 problems.&quot;"><pre>$ <span class="pl-s1"><span class="pl-c1">echo</span> <span class="pl-s"><span class="pl-pds">'</span>"Using regex, I now have no issues."<span class="pl-pds">'</span></span> <span class="pl-k">|</span> srgn <span class="pl-s"><span class="pl-pds">'</span>no issues<span class="pl-pds">'</span></span> <span class="pl-s"><span class="pl-pds">'</span>2 problems<span class="pl-pds">'</span></span></span> <span class="pl-c1">"Using regex, I now have 2 problems."</span></pre></div> <p dir="auto">The tool is fully Unicode-aware, with useful support for <a href="https://github.com/rust-lang/regex/blob/061ee815ef2c44101dba7b0b124600fcb03c1912/UNICODE.md#rl12-properties">certain advanced character classes</a>:</p> <div class="highlight highlight-text-shell-session notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="$ echo 'Mood: 🙂' | srgn '🙂' '😀' Mood: 😀 $ echo 'Mood: 🤮🤒🤧🦠 :(' | srgn '\p{Emoji_Presentation}' '😷' Mood: 😷😷😷😷 :("><pre>$ <span class="pl-s1"><span class="pl-c1">echo</span> <span class="pl-s"><span class="pl-pds">'</span>Mood: 🙂<span class="pl-pds">'</span></span> <span class="pl-k">|</span> srgn <span class="pl-s"><span class="pl-pds">'</span>🙂<span class="pl-pds">'</span></span> <span class="pl-s"><span class="pl-pds">'</span>😀<span class="pl-pds">'</span></span></span> <span class="pl-c1">Mood: 😀</span> $ <span class="pl-s1"><span class="pl-c1">echo</span> <span class="pl-s"><span class="pl-pds">'</span>Mood: 🤮🤒🤧🦠 :(<span class="pl-pds">'</span></span> <span class="pl-k">|</span> srgn <span class="pl-s"><span class="pl-pds">'</span>\p{Emoji_Presentation}<span class="pl-pds">'</span></span> <span class="pl-s"><span class="pl-pds">'</span>😷<span class="pl-pds">'</span></span></span> <span class="pl-c1">Mood: 😷😷😷😷 :(</span></pre></div> <div class="markdown-heading" dir="auto"><h5 tabindex="-1" class="heading-element" dir="auto">Variables</h5><a id="user-content-variables" class="anchor" aria-label="Permalink: Variables" href="#variables"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">Replacements are aware of variables, which are made accessible for use through regex capture groups. Capture groups can be numbered, or optionally named. The zeroth capture group corresponds to the entire match.</p> <div class="highlight highlight-text-shell-session notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="$ echo 'Swap It' | srgn '(\w+) (\w+)' '$2 $1' # Regular, numbered It Swap $ echo 'Swap It' | srgn '(\w+) (\w+)' '$2 $1$1$1' # Use as many times as you'd like It SwapSwapSwap $ echo 'Call +1-206-555-0100!' | srgn 'Call (\+?\d\-\d{3}\-\d{3}\-\d{4}).+' 'The phone number in &quot;$0&quot; is: $1.' # Variable `0` is the entire match The phone number in &quot;Call +1-206-555-0100!&quot; is: +1-206-555-0100."><pre>$ <span class="pl-s1"><span class="pl-c1">echo</span> <span class="pl-s"><span class="pl-pds">'</span>Swap It<span class="pl-pds">'</span></span> <span class="pl-k">|</span> srgn <span class="pl-s"><span class="pl-pds">'</span>(\w+) (\w+)<span class="pl-pds">'</span></span> <span class="pl-s"><span class="pl-pds">'</span>$2 $1<span class="pl-pds">'</span></span> <span class="pl-c"><span class="pl-c">#</span> Regular, numbered</span></span> <span class="pl-c1">It Swap</span> $ <span class="pl-s1"><span class="pl-c1">echo</span> <span class="pl-s"><span class="pl-pds">'</span>Swap It<span class="pl-pds">'</span></span> <span class="pl-k">|</span> srgn <span class="pl-s"><span class="pl-pds">'</span>(\w+) (\w+)<span class="pl-pds">'</span></span> <span class="pl-s"><span class="pl-pds">'</span>$2 $1$1$1<span class="pl-pds">'</span></span> <span class="pl-c"><span class="pl-c">#</span> Use as many times as you'd like</span></span> <span class="pl-c1">It SwapSwapSwap</span> $ <span class="pl-s1"><span class="pl-c1">echo</span> <span class="pl-s"><span class="pl-pds">'</span>Call +1-206-555-0100!<span class="pl-pds">'</span></span> <span class="pl-k">|</span> srgn <span class="pl-s"><span class="pl-pds">'</span>Call (\+?\d\-\d{3}\-\d{3}\-\d{4}).+<span class="pl-pds">'</span></span> <span class="pl-s"><span class="pl-pds">'</span>The phone number in "$0" is: $1.<span class="pl-pds">'</span></span> <span class="pl-c"><span class="pl-c">#</span> Variable `0` is the entire match</span></span> <span class="pl-c1">The phone number in "Call +1-206-555-0100!" is: +1-206-555-0100.</span></pre></div> <p dir="auto">A more advanced use case is, for example, code refactoring using named capture groups (perhaps you can come up with a more useful one...):</p> <div class="highlight highlight-text-shell-session notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="$ echo 'let x = 3;' | srgn 'let (?&lt;var&gt;[a-z]+) = (?&lt;expr&gt;.+);' 'const $var$var = $expr + $expr;' const xx = 3 + 3;"><pre>$ <span class="pl-s1"><span class="pl-c1">echo</span> <span class="pl-s"><span class="pl-pds">'</span>let x = 3;<span class="pl-pds">'</span></span> <span class="pl-k">|</span> srgn <span class="pl-s"><span class="pl-pds">'</span>let (?&lt;var&gt;[a-z]+) = (?&lt;expr&gt;.+);<span class="pl-pds">'</span></span> <span class="pl-s"><span class="pl-pds">'</span>const $var$var = $expr + $expr;<span class="pl-pds">'</span></span></span> <span class="pl-c1">const xx = 3 + 3;</span></pre></div> <p dir="auto">As in bash, use curly braces to disambiguate variables from immediately adjacent content:</p> <div class="highlight highlight-text-shell-session notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="$ echo '12' | srgn '(\d)(\d)' '$2${1}1' 211 $ echo '12' | srgn '(\d)(\d)' '$2$11' # will fail (`11` is unknown) $ echo '12' | srgn '(\d)(\d)' '$2${11' # will fail (brace was not closed)"><pre>$ <span class="pl-s1"><span class="pl-c1">echo</span> <span class="pl-s"><span class="pl-pds">'</span>12<span class="pl-pds">'</span></span> <span class="pl-k">|</span> srgn <span class="pl-s"><span class="pl-pds">'</span>(\d)(\d)<span class="pl-pds">'</span></span> <span class="pl-s"><span class="pl-pds">'</span>$2${1}1<span class="pl-pds">'</span></span></span> <span class="pl-c1">211</span> $ <span class="pl-s1"><span class="pl-c1">echo</span> <span class="pl-s"><span class="pl-pds">'</span>12<span class="pl-pds">'</span></span> <span class="pl-k">|</span> srgn <span class="pl-s"><span class="pl-pds">'</span>(\d)(\d)<span class="pl-pds">'</span></span> <span class="pl-s"><span class="pl-pds">'</span>$2$11<span class="pl-pds">'</span></span> <span class="pl-c"><span class="pl-c">#</span> will fail (`11` is unknown)</span></span> $ <span class="pl-s1"><span class="pl-c1">echo</span> <span class="pl-s"><span class="pl-pds">'</span>12<span class="pl-pds">'</span></span> <span class="pl-k">|</span> srgn <span class="pl-s"><span class="pl-pds">'</span>(\d)(\d)<span class="pl-pds">'</span></span> <span class="pl-s"><span class="pl-pds">'</span>$2${11<span class="pl-pds">'</span></span> <span class="pl-c"><span class="pl-c">#</span> will fail (brace was not closed)</span></span></pre></div> <div class="markdown-heading" dir="auto"><h4 tabindex="-1" class="heading-element" dir="auto">Beyond replacement</h4><a id="user-content-beyond-replacement" class="anchor" aria-label="Permalink: Beyond replacement" href="#beyond-replacement"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">Seeing how the replacement is merely a static string, its usefulness is limited. This is where <a href="https://maizure.org/projects/decoded-gnu-coreutils/tr.html" rel="nofollow"><code>tr</code>'s secret sauce</a> ordinarily comes into play: using its character classes, which are valid in the second position as well, neatly translating from members of the first to the second. Here, those classes are instead regexes, and only valid in first position (the scope). A regular expression being a state machine, it is impossible to match onto a 'list of characters', which in <code>tr</code> is the second (optional) argument. That concept is out the window, and its flexibility lost.</p> <p dir="auto">Instead, the offered actions, all of them <strong>fixed</strong>, are used. A peek at <a href="#use-cases-and-equivalences">the most common use cases for <code>tr</code></a> reveals that the provided set of actions covers virtually all of them! Feel free to file an issue if your use case is not covered.</p> <p dir="auto">Onto the next action.</p> <div class="markdown-heading" dir="auto"><h4 tabindex="-1" class="heading-element" dir="auto">Deletion</h4><a id="user-content-deletion" class="anchor" aria-label="Permalink: Deletion" href="#deletion"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">Removes whatever is found from the input. Same flag name as in <code>tr</code>.</p> <div class="highlight highlight-text-shell-session notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="$ echo 'Hello, World!' | srgn -d '(H|W|!)' ello, orld"><pre>$ <span class="pl-s1"><span class="pl-c1">echo</span> <span class="pl-s"><span class="pl-pds">'</span>Hello, World!<span class="pl-pds">'</span></span> <span class="pl-k">|</span> srgn -d <span class="pl-s"><span class="pl-pds">'</span>(H|W|!)<span class="pl-pds">'</span></span></span> <span class="pl-c1">ello, orld</span></pre></div> <div class="markdown-alert markdown-alert-note" dir="auto"><p class="markdown-alert-title" dir="auto"><svg class="octicon octicon-info mr-2" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z"></path></svg>Note</p><p dir="auto">As the default scope is to match the entire input, it is an error to specify deletion without a scope.</p> </div> <div class="markdown-heading" dir="auto"><h4 tabindex="-1" class="heading-element" dir="auto">Squeezing</h4><a id="user-content-squeezing" class="anchor" aria-label="Permalink: Squeezing" href="#squeezing"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">Squeezes repeats of characters matching the scope into single occurrences. Same flag name as in <code>tr</code>.</p> <div class="highlight highlight-text-shell-session notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="$ echo 'Helloooo Woooorld!!!' | srgn -s '(o|!)' Hello World!"><pre>$ <span class="pl-s1"><span class="pl-c1">echo</span> <span class="pl-s"><span class="pl-pds">'</span>Helloooo Woooorld!!!<span class="pl-pds">'</span></span> <span class="pl-k">|</span> srgn -s <span class="pl-s"><span class="pl-pds">'</span>(o|!)<span class="pl-pds">'</span></span></span> <span class="pl-c1">Hello World!</span></pre></div> <p dir="auto">If a character class is passed, all members of that class are squeezed into whatever class member was encountered first:</p> <div class="highlight highlight-text-shell-session notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="$ echo 'The number is: 3490834' | srgn -s '\d' The number is: 3"><pre>$ <span class="pl-s1"><span class="pl-c1">echo</span> <span class="pl-s"><span class="pl-pds">'</span>The number is: 3490834<span class="pl-pds">'</span></span> <span class="pl-k">|</span> srgn -s <span class="pl-s"><span class="pl-pds">'</span>\d<span class="pl-pds">'</span></span></span> <span class="pl-c1">The number is: 3</span></pre></div> <p dir="auto">Greediness in matching is not modified, so take care:</p> <div class="highlight highlight-text-shell-session notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="$ echo 'Winter is coming... 🌞🌞🌞' | srgn -s '🌞+' Winter is coming... 🌞🌞🌞"><pre>$ <span class="pl-s1"><span class="pl-c1">echo</span> <span class="pl-s"><span class="pl-pds">'</span>Winter is coming... 🌞🌞🌞<span class="pl-pds">'</span></span> <span class="pl-k">|</span> srgn -s <span class="pl-s"><span class="pl-pds">'</span>🌞+<span class="pl-pds">'</span></span></span> <span class="pl-c1">Winter is coming... 🌞🌞🌞</span></pre></div> <div class="markdown-alert markdown-alert-note" dir="auto"><p class="markdown-alert-title" dir="auto"><svg class="octicon octicon-info mr-2" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z"></path></svg>Note</p><p dir="auto">The pattern matched the <em>entire</em> run of suns, so there's nothing to squeeze. Summer prevails.</p> </div> <p dir="auto">Invert greediness if the use case calls for it:</p> <div class="highlight highlight-text-shell-session notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="$ echo 'Winter is coming... 🌞🌞🌞' | srgn -s '🌞+?' '☃️' Winter is coming... ☃️"><pre>$ <span class="pl-s1"><span class="pl-c1">echo</span> <span class="pl-s"><span class="pl-pds">'</span>Winter is coming... 🌞🌞🌞<span class="pl-pds">'</span></span> <span class="pl-k">|</span> srgn -s <span class="pl-s"><span class="pl-pds">'</span>🌞+?<span class="pl-pds">'</span></span> <span class="pl-s"><span class="pl-pds">'</span>☃️<span class="pl-pds">'</span></span></span> <span class="pl-c1">Winter is coming... ☃️</span></pre></div> <div class="markdown-alert markdown-alert-note" dir="auto"><p class="markdown-alert-title" dir="auto"><svg class="octicon octicon-info mr-2" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z"></path></svg>Note</p><p dir="auto">Again, as with <a href="#deletion">deletion</a>, specifying squeezing without an <em>explicit</em> scope is an error. Otherwise, the entire input is squeezed.</p> </div> <div class="markdown-heading" dir="auto"><h4 tabindex="-1" class="heading-element" dir="auto">Character casing</h4><a id="user-content-character-casing" class="anchor" aria-label="Permalink: Character casing" href="#character-casing"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">A good chunk of <code>tr</code> usage <a href="#changing-character-casing">falls into this category</a>. It's very straightforward.</p> <div class="highlight highlight-text-shell-session notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="$ echo 'Hello, World!' | srgn --lower hello, world! $ echo 'Hello, World!' | srgn --upper HELLO, WORLD! $ echo 'hello, world!' | srgn --titlecase Hello, World!"><pre>$ <span class="pl-s1"><span class="pl-c1">echo</span> <span class="pl-s"><span class="pl-pds">'</span>Hello, World!<span class="pl-pds">'</span></span> <span class="pl-k">|</span> srgn --lower</span> <span class="pl-c1">hello, world!</span> $ <span class="pl-s1"><span class="pl-c1">echo</span> <span class="pl-s"><span class="pl-pds">'</span>Hello, World!<span class="pl-pds">'</span></span> <span class="pl-k">|</span> srgn --upper</span> <span class="pl-c1">HELLO, WORLD!</span> $ <span class="pl-s1"><span class="pl-c1">echo</span> <span class="pl-s"><span class="pl-pds">'</span>hello, world!<span class="pl-pds">'</span></span> <span class="pl-k">|</span> srgn --titlecase</span> <span class="pl-c1">Hello, World!</span></pre></div> <div class="markdown-heading" dir="auto"><h4 tabindex="-1" class="heading-element" dir="auto">Normalization</h4><a id="user-content-normalization" class="anchor" aria-label="Permalink: Normalization" href="#normalization"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">Decomposes input according to <a href="https://en.wikipedia.org/wiki/Unicode_equivalence#Normal_forms" rel="nofollow">Normalization Form D</a>, and then discards code points of the <a href="https://en.wikipedia.org/wiki/Unicode_character_property#General_Category" rel="nofollow">Mark category</a> (see <a href="https://www.compart.com/en/unicode/category/Mn" rel="nofollow">examples</a>). That roughly means: take fancy character, rip off dangly bits, throw those away.</p> <div class="highlight highlight-text-shell-session notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="$ echo 'Naïve jalapeño ärgert mgła' | srgn -d '\P{ASCII}' # Naive approach Nave jalapeo rgert mga $ echo 'Naïve jalapeño ärgert mgła' | srgn --normalize # Normalize is smarter Naive jalapeno argert mgła"><pre>$ <span class="pl-s1"><span class="pl-c1">echo</span> <span class="pl-s"><span class="pl-pds">'</span>Naïve jalapeño ärgert mgła<span class="pl-pds">'</span></span> <span class="pl-k">|</span> srgn -d <span class="pl-s"><span class="pl-pds">'</span>\P{ASCII}<span class="pl-pds">'</span></span> <span class="pl-c"><span class="pl-c">#</span> Naive approach</span></span> <span class="pl-c1">Nave jalapeo rgert mga</span> $ <span class="pl-s1"><span class="pl-c1">echo</span> <span class="pl-s"><span class="pl-pds">'</span>Naïve jalapeño ärgert mgła<span class="pl-pds">'</span></span> <span class="pl-k">|</span> srgn --normalize <span class="pl-c"><span class="pl-c">#</span> Normalize is smarter</span></span> <span class="pl-c1">Naive jalapeno argert mgła</span></pre></div> <p dir="auto">Notice how <code>mgła</code> is out of scope for NFD, as it is "atomic" and thus not decomposable (at least that's what ChatGPT whispers in my ear).</p> <div class="markdown-heading" dir="auto"><h4 tabindex="-1" class="heading-element" dir="auto">Symbols</h4><a id="user-content-symbols" class="anchor" aria-label="Permalink: Symbols" href="#symbols"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">This action replaces multi-character, ASCII symbols with appropriate single-code point, native Unicode counterparts.</p> <div class="highlight highlight-text-shell-session notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="$ echo '(A --&gt; B) != C --- obviously' | srgn --symbols (A ⟶ B) ≠ C — obviously"><pre>$ <span class="pl-s1"><span class="pl-c1">echo</span> <span class="pl-s"><span class="pl-pds">'</span>(A --&gt; B) != C --- obviously<span class="pl-pds">'</span></span> <span class="pl-k">|</span> srgn --symbols</span> <span class="pl-c1">(A ⟶ B) ≠ C — obviously</span></pre></div> <p dir="auto">Alternatively, if you're only interested in math, make use of scoping:</p> <div class="highlight highlight-text-shell-session notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="$ echo 'A &lt;= B --- More is--obviously--possible' | srgn --symbols '&lt;=' A ≤ B --- More is--obviously--possible"><pre>$ <span class="pl-s1"><span class="pl-c1">echo</span> <span class="pl-s"><span class="pl-pds">'</span>A &lt;= B --- More is--obviously--possible<span class="pl-pds">'</span></span> <span class="pl-k">|</span> srgn --symbols <span class="pl-s"><span class="pl-pds">'</span>&lt;=<span class="pl-pds">'</span></span></span> <span class="pl-c1">A ≤ B --- More is--obviously--possible</span></pre></div> <p dir="auto">As there is a <a href="https://en.wikipedia.org/wiki/Bijection" rel="nofollow">1:1 correspondence</a> between an ASCII symbol and its replacement, the effect is reversible<sup><a href="#user-content-fn-1-b30ce13ed678ccbd6287a3f5e19f11b5" id="user-content-fnref-1-b30ce13ed678ccbd6287a3f5e19f11b5" data-footnote-ref="" aria-describedby="footnote-label">2</a></sup>:</p> <div class="highlight highlight-text-shell-session notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="$ echo 'A ⇒ B' | srgn --symbols --invert A =&gt; B"><pre>$ <span class="pl-s1"><span class="pl-c1">echo</span> <span class="pl-s"><span class="pl-pds">'</span>A ⇒ B<span class="pl-pds">'</span></span> <span class="pl-k">|</span> srgn --symbols --invert</span> <span class="pl-c1">A =&gt; B</span></pre></div> <p dir="auto">There is only a limited set of symbols supported as of right now, but more can be added.</p> <div class="markdown-heading" dir="auto"><h4 tabindex="-1" class="heading-element" dir="auto">German</h4><a id="user-content-german" class="anchor" aria-label="Permalink: German" href="#german"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">This action replaces alternative spellings of German special characters (ae, oe, ue, ss) with their native versions (ä, ö, ü, ß)<sup><a href="#user-content-fn-2-b30ce13ed678ccbd6287a3f5e19f11b5" id="user-content-fnref-2-b30ce13ed678ccbd6287a3f5e19f11b5" data-footnote-ref="" aria-describedby="footnote-label">3</a></sup>.</p> <div class="highlight highlight-text-shell-session notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="$ echo 'Gruess Gott, Neueroeffnungen, Poeten und Abenteuergruetze!' | srgn --german Grüß Gott, Neueröffnungen, Poeten und Abenteuergrütze!"><pre>$ <span class="pl-s1"><span class="pl-c1">echo</span> <span class="pl-s"><span class="pl-pds">'</span>Gruess Gott, Neueroeffnungen, Poeten und Abenteuergruetze!<span class="pl-pds">'</span></span> <span class="pl-k">|</span> srgn --german</span> <span class="pl-c1">Grüß Gott, Neueröffnungen, Poeten und Abenteuergrütze!</span></pre></div> <p dir="auto">This action is based on a <a href="/alexpovel/srgn/blob/main/data/word-lists/de.txt">word list</a> (compile without <code>german</code> feature if this bloats your binary too much). Note the following features about the above example:</p> <ul dir="auto"> <li>empty scope and replacement: the entire input will be processed, and no replacement is performed</li> <li><code>Poeten</code> remained as-is, instead of being naively and mistakenly converted to <code>Pöten</code></li> <li>as a (compound) word, <code>Abenteuergrütze</code> is not going to be found in <a href="https://www.duden.de/suchen/dudenonline/Abenteuergr%C3%BCtze" rel="nofollow">any reasonable word list</a>, but was handled properly nonetheless</li> <li>while part of a compound word, <code>Abenteuer</code> remained as-is as well, instead of being incorrectly converted to <code>Abenteür</code></li> <li>lastly, <code>Neueroeffnungen</code> sneakily forms a <code>ue</code> element neither constituent word (<code>neu</code>, <code>Eröffnungen</code>) possesses, but is still processed correctly (despite the mismatched casings as well)</li> </ul> <p dir="auto">On request, replacements may be forced, as is potentially useful for names:</p> <div class="highlight highlight-text-shell-session notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="$ echo 'Frau Loetter steht ueber der Mauer.' | srgn --german-naive '(?&lt;=Frau )\w+' Frau Lötter steht ueber der Mauer."><pre>$ <span class="pl-s1"><span class="pl-c1">echo</span> <span class="pl-s"><span class="pl-pds">'</span>Frau Loetter steht ueber der Mauer.<span class="pl-pds">'</span></span> <span class="pl-k">|</span> srgn --german-naive <span class="pl-s"><span class="pl-pds">'</span>(?&lt;=Frau )\w+<span class="pl-pds">'</span></span></span> <span class="pl-c1">Frau Lötter steht ueber der Mauer.</span></pre></div> <p dir="auto">Through positive lookahead, nothing but the salutation was scoped and therefore changed. <code>Mauer</code> correctly remained as-is, but <code>ueber</code> was not processed. A second pass fixes this:</p> <div class="highlight highlight-text-shell-session notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="$ echo 'Frau Loetter steht ueber der Mauer.' | srgn --german-naive '(?&lt;=Frau )\w+' | srgn --german Frau Lötter steht über der Mauer."><pre>$ <span class="pl-s1"><span class="pl-c1">echo</span> <span class="pl-s"><span class="pl-pds">'</span>Frau Loetter steht ueber der Mauer.<span class="pl-pds">'</span></span> <span class="pl-k">|</span> srgn --german-naive <span class="pl-s"><span class="pl-pds">'</span>(?&lt;=Frau )\w+<span class="pl-pds">'</span></span> <span class="pl-k">|</span> srgn --german</span> <span class="pl-c1">Frau Lötter steht über der Mauer.</span></pre></div> <div class="markdown-alert markdown-alert-note" dir="auto"><p class="markdown-alert-title" dir="auto"><svg class="octicon octicon-info mr-2" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z"></path></svg>Note</p> <p dir="auto">Options and flags pertaining to some "parent" are prefixed with their parent's name, and will <em>imply</em> their parent when given, such that the latter does not need to be passed explicitly. That's why <code>--german-naive</code> is named as it is, and <code>--german</code> needn't be passed.</p> <p dir="auto">This behavior might change once <code>clap</code> supports <a href="https://github.com/clap-rs/clap/issues/2222" data-hovercard-type="issue" data-hovercard-url="/clap-rs/clap/issues/2222/hovercard">subcommand chaining</a>.</p> </div> <p dir="auto">Some branches are undecidable for this modest tool, as it operates without language context. For example, both <code>Busse</code> (busses) and <code>Buße</code> (penance) are legal words. By default, replacements are greedily performed if legal (that's the <a href="https://en.wikipedia.org/wiki/Principle_of_least_astonishment" rel="nofollow">whole point</a> of <code>srgn</code>, after all), but there's a flag for toggling this behavior:</p> <div class="highlight highlight-text-shell-session notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="$ echo 'Busse und Geluebte 🙏' | srgn --german Buße und Gelübte 🙏 $ echo 'Busse 🚌 und Fussgaenger 🚶‍♀️' | srgn --german-prefer-original Busse 🚌 und Fußgänger 🚶‍♀️"><pre>$ <span class="pl-s1"><span class="pl-c1">echo</span> <span class="pl-s"><span class="pl-pds">'</span>Busse und Geluebte 🙏<span class="pl-pds">'</span></span> <span class="pl-k">|</span> srgn --german</span> <span class="pl-c1">Buße und Gelübte 🙏</span> $ <span class="pl-s1"><span class="pl-c1">echo</span> <span class="pl-s"><span class="pl-pds">'</span>Busse 🚌 und Fussgaenger 🚶‍♀️<span class="pl-pds">'</span></span> <span class="pl-k">|</span> srgn --german-prefer-original</span> <span class="pl-c1">Busse 🚌 und Fußgänger 🚶‍♀️</span></pre></div> <div class="markdown-heading" dir="auto"><h3 tabindex="-1" class="heading-element" dir="auto">Combining Actions</h3><a id="user-content-combining-actions" class="anchor" aria-label="Permalink: Combining Actions" href="#combining-actions"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">Most actions are composable, unless doing so were nonsensical (like for <a href="#deletion">deletion</a>). Their order of application is fixed, so the <em>order</em> of the flags given has no influence (piping multiple runs is an alternative, if needed). Replacements always occur first. Generally, the CLI is designed to prevent misuse and <a href="https://en.wikipedia.org/wiki/Principle_of_least_astonishment" rel="nofollow">surprises</a>: it prefers crashing to doing something unexpected (which is subjective, of course). Note that lots of combinations <em>are</em> technically possible, but might yield nonsensical results.</p> <p dir="auto">Combining actions might look like:</p> <div class="highlight highlight-text-shell-session notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="$ echo 'Koeffizienten != Bruecken...' | srgn -Sgu KOEFFIZIENTEN ≠ BRÜCKEN..."><pre>$ <span class="pl-s1"><span class="pl-c1">echo</span> <span class="pl-s"><span class="pl-pds">'</span>Koeffizienten != Bruecken...<span class="pl-pds">'</span></span> <span class="pl-k">|</span> srgn -Sgu</span> <span class="pl-c1">KOEFFIZIENTEN ≠ BRÜCKEN...</span></pre></div> <p dir="auto">A more narrow scope can be specified, and will apply to <em>all</em> actions equally:</p> <div class="highlight highlight-text-shell-session notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="$ echo 'Koeffizienten != Bruecken...' | srgn -Sgu '\b\w{1,8}\b' Koeffizienten != BRÜCKEN..."><pre>$ <span class="pl-s1"><span class="pl-c1">echo</span> <span class="pl-s"><span class="pl-pds">'</span>Koeffizienten != Bruecken...<span class="pl-pds">'</span></span> <span class="pl-k">|</span> srgn -Sgu <span class="pl-s"><span class="pl-pds">'</span>\b\w{1,8}\b<span class="pl-pds">'</span></span></span> <span class="pl-c1">Koeffizienten != BRÜCKEN...</span></pre></div> <p dir="auto">The <a href="https://www.regular-expressions.info/wordboundaries.html" rel="nofollow">word boundaries</a> are required as otherwise <code>Koeffizienten</code> is matched as <code>Koeffizi</code> and <code>enten</code>. Note how the trailing periods cannot be, for example, squeezed. The required scope of <code>\.</code> would interfere with the given one. Regular piping solves this:</p> <div class="highlight highlight-text-shell-session notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="$ echo 'Koeffizienten != Bruecken...' | srgn -Sgu '\b\w{1,8}\b' | srgn -s '\.' Koeffizienten != BRÜCKEN."><pre>$ <span class="pl-s1"><span class="pl-c1">echo</span> <span class="pl-s"><span class="pl-pds">'</span>Koeffizienten != Bruecken...<span class="pl-pds">'</span></span> <span class="pl-k">|</span> srgn -Sgu <span class="pl-s"><span class="pl-pds">'</span>\b\w{1,8}\b<span class="pl-pds">'</span></span> <span class="pl-k">|</span> srgn -s <span class="pl-s"><span class="pl-pds">'</span>\.<span class="pl-pds">'</span></span></span> <span class="pl-c1">Koeffizienten != BRÜCKEN.</span></pre></div> <p dir="auto">Note: regex escaping (<code>\.</code>) can be circumvent using <a href="#literal-scope">literal scoping</a>. The specially treated replacement action is also composable:</p> <div class="highlight highlight-text-shell-session notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="$ echo 'Mooood: 🤮🤒🤧🦠!!!' | srgn -s '\p{Emoji}' '😷' Mooood: 😷!!!"><pre>$ <span class="pl-s1"><span class="pl-c1">echo</span> <span class="pl-s"><span class="pl-pds">'</span>Mooood: 🤮🤒🤧🦠!!!<span class="pl-pds">'</span></span> <span class="pl-k">|</span> srgn -s <span class="pl-s"><span class="pl-pds">'</span>\p{Emoji}<span class="pl-pds">'</span></span> <span class="pl-s"><span class="pl-pds">'</span>😷<span class="pl-pds">'</span></span></span> <span class="pl-c1">Mooood: 😷!!!</span></pre></div> <p dir="auto">Emojis are first all replaced, then squeezed. Notice how nothing else is squeezed.</p> <div class="markdown-heading" dir="auto"><h3 tabindex="-1" class="heading-element" dir="auto">Scopes</h3><a id="user-content-scopes" class="anchor" aria-label="Permalink: Scopes" href="#scopes"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">Scopes are the second driving concept to <code>srgn</code>. In the default case, the main scope is a regular expression. The <a href="#actions">actions</a> section showcased this use case in some detail, so it's not repeated here. It is given as a first positional argument.</p> <div class="markdown-heading" dir="auto"><h4 tabindex="-1" class="heading-element" dir="auto">Language grammar-aware scopes</h4><a id="user-content-language-grammar-aware-scopes" class="anchor" aria-label="Permalink: Language grammar-aware scopes" href="#language-grammar-aware-scopes"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto"><code>srgn</code> extends this through prepared, language grammar-aware scopes, made possible through the excellent <a href="https://tree-sitter.github.io/tree-sitter/" rel="nofollow"><code>tree-sitter</code></a> library. It offers a <a href="https://tree-sitter.github.io/tree-sitter/using-parsers#query-syntax" rel="nofollow">queries</a> feature, which works much like pattern matching against a <a href="https://en.wikipedia.org/wiki/Parse_tree" rel="nofollow">tree data structure</a>.</p> <p dir="auto"><code>srgn</code> comes bundled with a handful of the most useful of these queries. Through its discoverable API (either <a href="#rust-library">as a library</a> or via CLI, <code>srgn --help</code>), one can learn of the supported languages and available, prepared queries. Each supported language comes with an escape hatch, allowing you to run your own, custom ad-hoc queries. The hatch comes in the form of <code>--lang-query &lt;S EXPRESSION&gt;</code>, where <code>lang</code> is a language such as <code>python</code>. See <a href="#custom-queries">below</a> for more on this advanced topic.</p> <div class="markdown-alert markdown-alert-note" dir="auto"><p class="markdown-alert-title" dir="auto"><svg class="octicon octicon-info mr-2" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z"></path></svg>Note</p> <p dir="auto">Language scopes are applied <em>first</em>, so whatever regex aka main scope you pass, it operates on each matched language construct individually.</p> </div> <div class="markdown-heading" dir="auto"><h5 tabindex="-1" class="heading-element" dir="auto">Prepared queries</h5><a id="user-content-prepared-queries" class="anchor" aria-label="Permalink: Prepared queries" href="#prepared-queries"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">This section shows examples for some of the <strong>prepared queries</strong>.</p> <p dir="auto">Most prepared queries are static, e.g. they always scope "all comments", for example. Various language elements are naturally <em>named</em> however: functions, classes, structs, modules and more are usually not anonymous, but carry names. Some prepared queries therefore have <em>dynamic</em> variants, where an optional regular expression pattern can additionally be supplied. The pattern then applies to the name of the item, and will only scope those items whose name matches the pattern. This allows for an extra degree of freedom for querying. Examples follow.</p> <div class="markdown-heading" dir="auto"><h6 tabindex="-1" class="heading-element" dir="auto">Finding all structs related to testing (Go)</h6><a id="user-content-finding-all-structs-related-to-testing-go" class="anchor" aria-label="Permalink: Finding all structs related to testing (Go)" href="#finding-all-structs-related-to-testing-go"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">An input like</p> <div class="highlight highlight-source-go notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="type PublicTestInput struct { Name string Value int } type privateTestInput struct { name string value int } type ActualDomainType struct { Name string Value int }"><pre><span class="pl-k">type</span> <span class="pl-smi">PublicTestInput</span> <span class="pl-k">struct</span> { <span class="pl-c1">Name</span> <span class="pl-smi">string</span> <span class="pl-c1">Value</span> <span class="pl-smi">int</span> } <span class="pl-k">type</span> <span class="pl-smi">privateTestInput</span> <span class="pl-k">struct</span> { <span class="pl-c1">name</span> <span class="pl-smi">string</span> <span class="pl-c1">value</span> <span class="pl-smi">int</span> } <span class="pl-k">type</span> <span class="pl-smi">ActualDomainType</span> <span class="pl-k">struct</span> { <span class="pl-c1">Name</span> <span class="pl-smi">string</span> <span class="pl-c1">Value</span> <span class="pl-smi">int</span> }</pre></div> <p dir="auto">can be searched as</p> <div class="highlight highlight-text-shell-session notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="$ cat testing.go | srgn --go 'struct~[tT]est' 1:type PublicTestInput struct { 2: Name string 3: Value int 4:} 6:type privateTestInput struct { 7: name string 8: value int 9:}"><pre>$ <span class="pl-s1">cat testing.go <span class="pl-k">|</span> srgn --go <span class="pl-s"><span class="pl-pds">'</span>struct~[tT]est<span class="pl-pds">'</span></span></span> <span class="pl-c1">1:type PublicTestInput struct {</span> <span class="pl-c1">2: Name string</span> <span class="pl-c1">3: Value int</span> <span class="pl-c1">4:}</span> <span class="pl-c1">6:type privateTestInput struct {</span> <span class="pl-c1">7: name string</span> <span class="pl-c1">8: value int</span> <span class="pl-c1">9:}</span></pre></div> <p dir="auto">surfacing only <code>struct</code>s whose name matches <code>[tT]est</code>. The <code>~</code> character serves as the separator between the language grammar/node type and pattern. This approach allows manipulation of <em>only these structs</em>, e.g.</p> <div class="highlight highlight-text-shell-session notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="$ cat testing.go | srgn --go 'struct~[tT]est' '(\s+)Name' '${1}TestName' type PublicTestInput struct { TestName string Value int } type privateTestInput struct { name string value int } type ActualDomainType struct { Name string Value int }"><pre>$ <span class="pl-s1">cat testing.go <span class="pl-k">|</span> srgn --go <span class="pl-s"><span class="pl-pds">'</span>struct~[tT]est<span class="pl-pds">'</span></span> <span class="pl-s"><span class="pl-pds">'</span>(\s+)Name<span class="pl-pds">'</span></span> <span class="pl-s"><span class="pl-pds">'</span>${1}TestName<span class="pl-pds">'</span></span></span> <span class="pl-c1">type PublicTestInput struct {</span> <span class="pl-c1"> TestName string</span> <span class="pl-c1"> Value int</span> <span class="pl-c1">}</span> <span class="pl-c1">type privateTestInput struct {</span> <span class="pl-c1"> name string</span> <span class="pl-c1"> value int</span> <span class="pl-c1">}</span> <span class="pl-c1">type ActualDomainType struct {</span> <span class="pl-c1"> Name string</span> <span class="pl-c1"> Value int</span> <span class="pl-c1">}</span></pre></div> <div class="markdown-heading" dir="auto"><h6 tabindex="-1" class="heading-element" dir="auto">Finding all <code>unsafe</code> code (Rust)</h6><a id="user-content-finding-all-unsafe-code-rust" class="anchor" aria-label="Permalink: Finding all unsafe code (Rust)" href="#finding-all-unsafe-code-rust"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">One advantage of the <a href="https://doc.rust-lang.org/book/ch19-01-unsafe-rust.html" rel="nofollow"><code>unsafe</code> keyword in Rust</a> is its "grepability". However, an <code>rg 'unsafe'</code> will of course surface <em>all</em> string matches (<code>rg '\bunsafe\b'</code> helps to an extent), not just those in of the actual Rust language keyword. <code>srgn</code> helps make this more precise. For example:</p> <div class="highlight highlight-source-rust notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="// Oh no, an unsafe module! mod scary_unsafe_operations { pub unsafe fn unsafe_array_access(arr: &amp;[i32], index: usize) -&gt; i32 { // UNSAFE: This function performs unsafe array access without bounds checking *arr.get_unchecked(index) } pub fn call_unsafe_function() { let unsafe_numbers = vec![1, 2, 3, 4, 5]; println!(&quot;About to perform an unsafe operation!&quot;); let result = unsafe { // Calling an unsafe function unsafe_array_access(&amp;unsafe_numbers, 10) }; println!(&quot;Result of unsafe operation: {}&quot;, result); } }"><pre><span class="pl-c">// Oh no, an unsafe module!</span> <span class="pl-k">mod</span> scary_unsafe_operations <span class="pl-kos">{</span> <span class="pl-k">pub</span> <span class="pl-k">unsafe</span> <span class="pl-k">fn</span> <span class="pl-en">unsafe_array_access</span><span class="pl-kos">(</span><span class="pl-s1">arr</span><span class="pl-kos">:</span> <span class="pl-c1">&amp;</span><span class="pl-kos">[</span><span class="pl-smi">i32</span><span class="pl-kos">]</span><span class="pl-kos">,</span> <span class="pl-s1">index</span><span class="pl-kos">:</span> <span class="pl-smi">usize</span><span class="pl-kos">)</span> -&gt; <span class="pl-smi">i32</span> <span class="pl-kos">{</span> <span class="pl-c">// UNSAFE: This function performs unsafe array access without bounds checking</span> <span class="pl-c1">*</span>arr<span class="pl-kos">.</span><span class="pl-en">get_unchecked</span><span class="pl-kos">(</span>index<span class="pl-kos">)</span> <span class="pl-kos">}</span> <span class="pl-k">pub</span> <span class="pl-k">fn</span> <span class="pl-en">call_unsafe_function</span><span class="pl-kos">(</span><span class="pl-kos">)</span> <span class="pl-kos">{</span> <span class="pl-k">let</span> unsafe_numbers = <span class="pl-en">vec</span><span class="pl-en">!</span><span class="pl-kos">[</span><span class="pl-c1">1</span><span class="pl-kos">,</span> <span class="pl-c1">2</span><span class="pl-kos">,</span> <span class="pl-c1">3</span><span class="pl-kos">,</span> <span class="pl-c1">4</span><span class="pl-kos">,</span> <span class="pl-c1">5</span><span class="pl-kos">]</span><span class="pl-kos">;</span> <span class="pl-en">println</span><span class="pl-en">!</span><span class="pl-kos">(</span><span class="pl-s">"About to perform an unsafe operation!"</span><span class="pl-kos">)</span><span class="pl-kos">;</span> <span class="pl-k">let</span> result = <span class="pl-k">unsafe</span> <span class="pl-kos">{</span> <span class="pl-c">// Calling an unsafe function</span> <span class="pl-en">unsafe_array_access</span><span class="pl-kos">(</span><span class="pl-c1">&amp;</span>unsafe_numbers<span class="pl-kos">,</span> <span class="pl-c1">10</span><span class="pl-kos">)</span> <span class="pl-kos">}</span><span class="pl-kos">;</span> <span class="pl-en">println</span><span class="pl-en">!</span><span class="pl-kos">(</span><span class="pl-s">"Result of unsafe operation: {}"</span><span class="pl-kos">,</span> result<span class="pl-kos">)</span><span class="pl-kos">;</span> <span class="pl-kos">}</span> <span class="pl-kos">}</span></pre></div> <p dir="auto">can be searched as</p> <div class="highlight highlight-text-shell-session notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="$ cat unsafe.rs | srgn --rs 'unsafe' # Note: no 2nd argument necessary 3: pub unsafe fn unsafe_array_access(arr: &amp;[i32], index: usize) -&gt; i32 { 4: // UNSAFE: This function performs unsafe array access without bounds checking 5: *arr.get_unchecked(index) 6: } 11: let result = unsafe { 12: // Calling an unsafe function 13: unsafe_array_access(&amp;unsafe_numbers, 10) 14: };"><pre>$ <span class="pl-s1">cat unsafe.rs <span class="pl-k">|</span> srgn --rs <span class="pl-s"><span class="pl-pds">'</span>unsafe<span class="pl-pds">'</span></span> <span class="pl-c"><span class="pl-c">#</span> Note: no 2nd argument necessary</span></span> <span class="pl-c1">3: pub unsafe fn unsafe_array_access(arr: &amp;[i32], index: usize) -&gt; i32 {</span> <span class="pl-c1">4: // UNSAFE: This function performs unsafe array access without bounds checking</span> <span class="pl-c1">5: *arr.get_unchecked(index)</span> <span class="pl-c1">6: }</span> <span class="pl-c1">11: let result = unsafe {</span> <span class="pl-c1">12: // Calling an unsafe function</span> <span class="pl-c1">13: unsafe_array_access(&amp;unsafe_numbers, 10)</span> <span class="pl-c1">14: };</span></pre></div> <p dir="auto">surfacing only truly <code>unsafe</code> items (and not comments, strings etc. merely mentioning it).<sup><a href="#user-content-fn-4-b30ce13ed678ccbd6287a3f5e19f11b5" id="user-content-fnref-4-b30ce13ed678ccbd6287a3f5e19f11b5" data-footnote-ref="" aria-describedby="footnote-label">4</a></sup></p> <div class="markdown-heading" dir="auto"><h6 tabindex="-1" class="heading-element" dir="auto">Replacing <code>allow</code> with <code>expect</code> for lints (Rust)</h6><a id="user-content-replacing-allow-with-expect-for-lints-rust" class="anchor" aria-label="Permalink: Replacing allow with expect for lints (Rust)" href="#replacing-allow-with-expect-for-lints-rust"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">Taking advantage of the stabilization of the <code>expect</code> lint level in <a href="https://blog.rust-lang.org/2024/09/05/Rust-1.81.0.html#expectlint" rel="nofollow">Rust 1.81</a>, one might want to migrate from <code>allow</code> to <code>expect</code> throughout (cf. 959a692f1d788d071d5f55376e2bb5ff3c2ae15a in this repo):</p> <div class="highlight highlight-source-rust notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="#[allow(unsafe_code)] if let Some(env_value) = env_value { unsafe { env::set_var(DEFAULT_FILTER_ENV, env_value); } }"><pre><span class="pl-c1">#<span class="pl-kos">[</span>allow<span class="pl-kos">(</span>unsafe_code<span class="pl-kos">)</span><span class="pl-kos">]</span></span> <span class="pl-k">if</span> <span class="pl-k">let</span> <span class="pl-v">Some</span><span class="pl-kos">(</span>env_value<span class="pl-kos">)</span> = env_value <span class="pl-kos">{</span> <span class="pl-k">unsafe</span> <span class="pl-kos">{</span> env<span class="pl-kos">::</span><span class="pl-en">set_var</span><span class="pl-kos">(</span><span class="pl-v">DEFAULT_FILTER_ENV</span><span class="pl-kos">,</span> env_value<span class="pl-kos">)</span><span class="pl-kos">;</span> <span class="pl-kos">}</span> <span class="pl-kos">}</span></pre></div> <p dir="auto">can be refactored using</p> <div class="highlight highlight-source-shell notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="cat allow.rs | srgn --rust 'attribute' '^allow' 'expect'"><pre>cat allow.rs <span class="pl-k">|</span> srgn --rust <span class="pl-s"><span class="pl-pds">'</span>attribute<span class="pl-pds">'</span></span> <span class="pl-s"><span class="pl-pds">'</span>^allow<span class="pl-pds">'</span></span> <span class="pl-s"><span class="pl-pds">'</span>expect<span class="pl-pds">'</span></span></pre></div> <p dir="auto">which will yield</p> <div class="highlight highlight-source-rust notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="#[expect(unsafe_code)] if let Some(env_value) = env_value { unsafe { env::set_var(DEFAULT_FILTER_ENV, env_value); } }"><pre><span class="pl-c1">#<span class="pl-kos">[</span>expect<span class="pl-kos">(</span>unsafe_code<span class="pl-kos">)</span><span class="pl-kos">]</span></span> <span class="pl-k">if</span> <span class="pl-k">let</span> <span class="pl-v">Some</span><span class="pl-kos">(</span>env_value<span class="pl-kos">)</span> = env_value <span class="pl-kos">{</span> <span class="pl-k">unsafe</span> <span class="pl-kos">{</span> env<span class="pl-kos">::</span><span class="pl-en">set_var</span><span class="pl-kos">(</span><span class="pl-v">DEFAULT_FILTER_ENV</span><span class="pl-kos">,</span> env_value<span class="pl-kos">)</span><span class="pl-kos">;</span> <span class="pl-kos">}</span> <span class="pl-kos">}</span></pre></div> <div class="markdown-heading" dir="auto"><h6 tabindex="-1" class="heading-element" dir="auto">Mass import (module) renaming (Python, Rust)</h6><a id="user-content-mass-import-module-renaming-python-rust" class="anchor" aria-label="Permalink: Mass import (module) renaming (Python, Rust)" href="#mass-import-module-renaming-python-rust"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">As part of a large refactor (say, after an acquisition), imagine all imports of a specific package needed renaming:</p> <div class="highlight highlight-source-python notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="import math from pathlib import Path import good_company.infra import good_company.aws.auth as aws_auth from good_company.util.iter import dedupe from good_company.shopping.cart import * # Ok but don't do this at home! good_company = &quot;good_company&quot; # good_company"><pre><span class="pl-k">import</span> <span class="pl-s1">math</span> <span class="pl-k">from</span> <span class="pl-s1">pathlib</span> <span class="pl-k">import</span> <span class="pl-v">Path</span> <span class="pl-k">import</span> <span class="pl-s1">good_company</span>.<span class="pl-s1">infra</span> <span class="pl-k">import</span> <span class="pl-s1">good_company</span>.<span class="pl-s1">aws</span>.<span class="pl-s1">auth</span> <span class="pl-k">as</span> <span class="pl-s1">aws_auth</span> <span class="pl-k">from</span> <span class="pl-s1">good_company</span>.<span class="pl-s1">util</span>.<span class="pl-s1">iter</span> <span class="pl-k">import</span> <span class="pl-s1">dedupe</span> <span class="pl-k">from</span> <span class="pl-s1">good_company</span>.<span class="pl-s1">shopping</span>.<span class="pl-s1">cart</span> <span class="pl-k">import</span> <span class="pl-c1">*</span> <span class="pl-c"># Ok but don't do this at home!</span> <span class="pl-s1">good_company</span> <span class="pl-c1">=</span> <span class="pl-s">"good_company"</span> <span class="pl-c"># good_company</span></pre></div> <p dir="auto">At the same time, a move to <a href="https://packaging.python.org/en/latest/discussions/src-layout-vs-flat-layout/" rel="nofollow"><code>src/</code> layout</a> is desired. Achieve this move with:</p> <div class="highlight highlight-source-shell notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="cat imports.py | srgn --python 'imports' '^good_company' 'src.better_company'"><pre>cat imports.py <span class="pl-k">|</span> srgn --python <span class="pl-s"><span class="pl-pds">'</span>imports<span class="pl-pds">'</span></span> <span class="pl-s"><span class="pl-pds">'</span>^good_company<span class="pl-pds">'</span></span> <span class="pl-s"><span class="pl-pds">'</span>src.better_company<span class="pl-pds">'</span></span></pre></div> <p dir="auto">which will yield</p> <div class="highlight highlight-source-python notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="import math from pathlib import Path import src.better_company.infra import src.better_company.aws.auth as aws_auth from src.better_company.util.iter import dedupe from src.better_company.shopping.cart import * # Ok but don't do this at home! good_company = &quot;good_company&quot; # good_company"><pre><span class="pl-k">import</span> <span class="pl-s1">math</span> <span class="pl-k">from</span> <span class="pl-s1">pathlib</span> <span class="pl-k">import</span> <span class="pl-v">Path</span> <span class="pl-k">import</span> <span class="pl-s1">src</span>.<span class="pl-s1">better_company</span>.<span class="pl-s1">infra</span> <span class="pl-k">import</span> <span class="pl-s1">src</span>.<span class="pl-s1">better_company</span>.<span class="pl-s1">aws</span>.<span class="pl-s1">auth</span> <span class="pl-k">as</span> <span class="pl-s1">aws_auth</span> <span class="pl-k">from</span> <span class="pl-s1">src</span>.<span class="pl-s1">better_company</span>.<span class="pl-s1">util</span>.<span class="pl-s1">iter</span> <span class="pl-k">import</span> <span class="pl-s1">dedupe</span> <span class="pl-k">from</span> <span class="pl-s1">src</span>.<span class="pl-s1">better_company</span>.<span class="pl-s1">shopping</span>.<span class="pl-s1">cart</span> <span class="pl-k">import</span> <span class="pl-c1">*</span> <span class="pl-c"># Ok but don't do this at home!</span> <span class="pl-s1">good_company</span> <span class="pl-c1">=</span> <span class="pl-s">"good_company"</span> <span class="pl-c"># good_company</span></pre></div> <p dir="auto">Note how the last line remains untouched by this particular operation. To run across many files, see <a href="#run-against-multiple-files">the <code>files</code> option</a>.</p> <p dir="auto">Similar import-related edits are supported for other languages as well, for example Rust:</p> <div class="highlight highlight-source-rust notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="use std::collections::HashMap; use good_company::infra; use good_company::aws::auth as aws_auth; use good_company::util::iter::dedupe; use good_company::shopping::cart::*; good_company = &quot;good_company&quot;; // good_company"><pre><span class="pl-k">use</span> std<span class="pl-kos">::</span>collections<span class="pl-kos">::</span><span class="pl-v">HashMap</span><span class="pl-kos">;</span> <span class="pl-k">use</span> good_company<span class="pl-kos">::</span>infra<span class="pl-kos">;</span> <span class="pl-k">use</span> good_company<span class="pl-kos">::</span>aws<span class="pl-kos">::</span>auth <span class="pl-k">as</span> aws_auth<span class="pl-kos">;</span> <span class="pl-k">use</span> good_company<span class="pl-kos">::</span>util<span class="pl-kos">::</span>iter<span class="pl-kos">::</span>dedupe<span class="pl-kos">;</span> <span class="pl-k">use</span> good_company<span class="pl-kos">::</span>shopping<span class="pl-kos">::</span>cart<span class="pl-kos">::</span><span class="pl-c1">*</span><span class="pl-kos">;</span> good_company = <span class="pl-s">"good_company"</span><span class="pl-kos">;</span> <span class="pl-c">// good_company</span></pre></div> <p dir="auto">which, using</p> <div class="highlight highlight-source-shell notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="cat imports.rs | srgn --rust 'uses' '^good_company' 'better_company'"><pre>cat imports.rs <span class="pl-k">|</span> srgn --rust <span class="pl-s"><span class="pl-pds">'</span>uses<span class="pl-pds">'</span></span> <span class="pl-s"><span class="pl-pds">'</span>^good_company<span class="pl-pds">'</span></span> <span class="pl-s"><span class="pl-pds">'</span>better_company<span class="pl-pds">'</span></span></pre></div> <p dir="auto">becomes</p> <div class="highlight highlight-source-rust notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="use std::collections::HashMap; use better_company::infra; use better_company::aws::auth as aws_auth; use better_company::util::iter::dedupe; use better_company::shopping::cart::*; good_company = &quot;good_company&quot;; // good_company"><pre><span class="pl-k">use</span> std<span class="pl-kos">::</span>collections<span class="pl-kos">::</span><span class="pl-v">HashMap</span><span class="pl-kos">;</span> <span class="pl-k">use</span> better_company<span class="pl-kos">::</span>infra<span class="pl-kos">;</span> <span class="pl-k">use</span> better_company<span class="pl-kos">::</span>aws<span class="pl-kos">::</span>auth <span class="pl-k">as</span> aws_auth<span class="pl-kos">;</span> <span class="pl-k">use</span> better_company<span class="pl-kos">::</span>util<span class="pl-kos">::</span>iter<span class="pl-kos">::</span>dedupe<span class="pl-kos">;</span> <span class="pl-k">use</span> better_company<span class="pl-kos">::</span>shopping<span class="pl-kos">::</span>cart<span class="pl-kos">::</span><span class="pl-c1">*</span><span class="pl-kos">;</span> good_company = <span class="pl-s">"good_company"</span><span class="pl-kos">;</span> <span class="pl-c">// good_company</span></pre></div> <div class="markdown-heading" dir="auto"><h6 tabindex="-1" class="heading-element" dir="auto">Assigning <code>TODO</code>s (TypeScript)</h6><a id="user-content-assigning-todos-typescript" class="anchor" aria-label="Permalink: Assigning TODOs (TypeScript)" href="#assigning-todos-typescript"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">Perhaps you're using a system of <code>TODO</code> notes in comments:</p> <div class="highlight highlight-source-ts notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="class TODOApp { // TODO app for writing TODO lists addTodo(todo: TODO): void { // TODO: everything, actually 🤷‍♀️ } }"><pre><span class="pl-k">class</span> <span class="pl-smi">TODOApp</span> <span class="pl-kos">{</span> <span class="pl-c">// TODO app for writing TODO lists</span> <span class="pl-en">addTodo</span><span class="pl-kos">(</span><span class="pl-s1">todo</span>: <span class="pl-smi">TODO</span><span class="pl-kos">)</span>: <span class="pl-smi"><span class="pl-k">void</span></span> <span class="pl-kos">{</span> <span class="pl-c">// TODO: everything, actually 🤷‍♀️</span> <span class="pl-kos">}</span> <span class="pl-kos">}</span></pre></div> <p dir="auto">and <em>usually</em> assign people to each note. It's possible to automate assigning yourself to every unassigned note (lucky you!) using</p> <div class="highlight highlight-source-shell notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="cat todo.ts | srgn --typescript 'comments' 'TODO(?=:)' 'TODO(@poorguy)'"><pre>cat todo.ts <span class="pl-k">|</span> srgn --typescript <span class="pl-s"><span class="pl-pds">'</span>comments<span class="pl-pds">'</span></span> <span class="pl-s"><span class="pl-pds">'</span>TODO(?=:)<span class="pl-pds">'</span></span> <span class="pl-s"><span class="pl-pds">'</span>TODO(@poorguy)<span class="pl-pds">'</span></span></pre></div> <p dir="auto">which in this case gives</p> <div class="highlight highlight-source-ts notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="class TODOApp { // TODO app for writing TODO lists addTodo(todo: TODO): void { // TODO(@poorguy): everything, actually 🤷‍♀️ } }"><pre><span class="pl-k">class</span> <span class="pl-smi">TODOApp</span> <span class="pl-kos">{</span> <span class="pl-c">// TODO app for writing TODO lists</span> <span class="pl-en">addTodo</span><span class="pl-kos">(</span><span class="pl-s1">todo</span>: <span class="pl-smi">TODO</span><span class="pl-kos">)</span>: <span class="pl-smi"><span class="pl-k">void</span></span> <span class="pl-kos">{</span> <span class="pl-c">// TODO(@poorguy): everything, actually 🤷‍♀️</span> <span class="pl-kos">}</span> <span class="pl-kos">}</span></pre></div> <p dir="auto">Notice the <a href="https://www.regular-expressions.info/lookaround.html" rel="nofollow">positive lookahead</a> of <code>(?=:)</code>, ensuring an actual <code>TODO</code> note is hit (<code>TODO:</code>). Otherwise, the other <code>TODO</code>s mentioned around the comments would be matched as well.</p> <div class="markdown-heading" dir="auto"><h6 tabindex="-1" class="heading-element" dir="auto">Converting <code>print</code> calls to proper <code>logging</code> (Python)</h6><a id="user-content-converting-print-calls-to-proper-logging-python" class="anchor" aria-label="Permalink: Converting print calls to proper logging (Python)" href="#converting-print-calls-to-proper-logging-python"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">Say there's code making liberal use of <code>print</code>:</p> <div class="highlight highlight-source-python notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="def print_money(): &quot;&quot;&quot;Let's print money 💸.&quot;&quot;&quot; amount = 32 print(&quot;Got here.&quot;) print_more = lambda s: print(f&quot;Printed {s}&quot;) print_more(23) # print the stuff print_money() print(&quot;Done.&quot;)"><pre><span class="pl-k">def</span> <span class="pl-en">print_money</span>(): <span class="pl-s">"""Let's print money 💸."""</span> <span class="pl-s1">amount</span> <span class="pl-c1">=</span> <span class="pl-c1">32</span> <span class="pl-en">print</span>(<span class="pl-s">"Got here."</span>) <span class="pl-s1">print_more</span> <span class="pl-c1">=</span> <span class="pl-k">lambda</span> <span class="pl-s1">s</span>: <span class="pl-en">print</span>(<span class="pl-s">f"Printed <span class="pl-s1"><span class="pl-kos">{</span><span class="pl-s1">s</span><span class="pl-kos">}</span></span>"</span>) <span class="pl-en">print_more</span>(<span class="pl-c1">23</span>) <span class="pl-c"># print the stuff</span> <span class="pl-en">print_money</span>() <span class="pl-en">print</span>(<span class="pl-s">"Done."</span>)</pre></div> <p dir="auto">and a move to <a href="https://docs.python.org/3/library/logging.html" rel="nofollow"><code>logging</code></a> is desired. That's fully automated by a call of</p> <div class="highlight highlight-source-shell notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="cat money.py | srgn --python 'function-calls' '^print$' 'logging.info'"><pre>cat money.py <span class="pl-k">|</span> srgn --python <span class="pl-s"><span class="pl-pds">'</span>function-calls<span class="pl-pds">'</span></span> <span class="pl-s"><span class="pl-pds">'</span>^print$<span class="pl-pds">'</span></span> <span class="pl-s"><span class="pl-pds">'</span>logging.info<span class="pl-pds">'</span></span></pre></div> <p dir="auto">yielding</p> <div class="highlight highlight-source-python notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="def print_money(): &quot;&quot;&quot;Let's print money 💸.&quot;&quot;&quot; amount = 32 logging.info(&quot;Got here.&quot;) print_more = lambda s: logging.info(f&quot;Printed {s}&quot;) print_more(23) # print the stuff print_money() logging.info(&quot;Done.&quot;)"><pre><span class="pl-k">def</span> <span class="pl-en">print_money</span>(): <span class="pl-s">"""Let's print money 💸."""</span> <span class="pl-s1">amount</span> <span class="pl-c1">=</span> <span class="pl-c1">32</span> <span class="pl-s1">logging</span>.<span class="pl-c1">info</span>(<span class="pl-s">"Got here."</span>) <span class="pl-s1">print_more</span> <span class="pl-c1">=</span> <span class="pl-k">lambda</span> <span class="pl-s1">s</span>: <span class="pl-s1">logging</span>.<span class="pl-c1">info</span>(<span class="pl-s">f"Printed <span class="pl-s1"><span class="pl-kos">{</span><span class="pl-s1">s</span><span class="pl-kos">}</span></span>"</span>) <span class="pl-en">print_more</span>(<span class="pl-c1">23</span>) <span class="pl-c"># print the stuff</span> <span class="pl-en">print_money</span>() <span class="pl-s1">logging</span>.<span class="pl-c1">info</span>(<span class="pl-s">"Done."</span>)</pre></div> <div class="markdown-alert markdown-alert-note" dir="auto"><p class="markdown-alert-title" dir="auto"><svg class="octicon octicon-info mr-2" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z"></path></svg>Note</p><p dir="auto">Note the <a href="https://www.regular-expressions.info/anchors.html" rel="nofollow">anchors</a>: <code>print_more</code> is a function call as well, but <code>^print$</code> ensures it's not matched.</p> <p dir="auto">The regular expression applies <em>after</em> grammar scoping, so operates entirely within the already-scoped context.</p> </div> <div class="markdown-heading" dir="auto"><h6 tabindex="-1" class="heading-element" dir="auto">Remove all comments (C#)</h6><a id="user-content-remove-all-comments-c" class="anchor" aria-label="Permalink: Remove all comments (C#)" href="#remove-all-comments-c"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">Overdone, comments can turn into <a href="https://refactoring.guru/smells/comments" rel="nofollow">smells</a>. If not tended to, they might very well start lying:</p> <div class="highlight highlight-source-cs notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="using System.Linq; public class UserService { private readonly AppDbContext _dbContext; /// &lt;summary&gt; /// Initializes a new instance of the &lt;see cref=&quot;FileService&quot;/&gt; class. /// &lt;/summary&gt; /// &lt;param name=&quot;dbContext&quot;&gt;The configuration for manipulating text.&lt;/param&gt; public UserService(AppDbContext dbContext) { _dbContext /* the logging context */ = dbContext; } /// &lt;summary&gt; /// Uploads a file to the server. /// &lt;/summary&gt; // Method to log users out of the system public void DoWork() { _dbContext.Database.EnsureCreated(); // Ensure the database schema is deleted _dbContext.Users.Add(new User /* the car */ { Name = &quot;Alice&quot; }); /* Begin reading file */ _dbContext.SaveChanges(); var user = _dbContext.Users.Where(/* fetch products */ u =&gt; u.Name == &quot;Alice&quot;).FirstOrDefault(); /// Delete all records before proceeding if (user /* the product */ != null) { System.Console.WriteLine($&quot;Found user with ID: {user.Id}&quot;); } } }"><pre><span class="pl-k">using</span> <span class="pl-s1">System</span><span class="pl-kos">.</span><span class="pl-s1">Linq</span><span class="pl-kos">;</span> <span class="pl-k">public</span> <span class="pl-k">class</span> <span class="pl-smi">UserService</span> <span class="pl-kos">{</span> <span class="pl-k">private</span> <span class="pl-k">readonly</span> <span class="pl-smi">AppDbContext</span> <span class="pl-s1">_dbContext</span><span class="pl-kos">;</span> <span class="pl-c">/// &lt;summary&gt;</span> <span class="pl-c">/// Initializes a new instance of the &lt;see cref="FileService"/&gt; class.</span> <span class="pl-c">/// &lt;/summary&gt;</span> <span class="pl-c">/// &lt;param name="dbContext"&gt;The configuration for manipulating text.&lt;/param&gt;</span> <span class="pl-k">public</span> <span class="pl-v">UserService</span><span class="pl-kos">(</span><span class="pl-smi">AppDbContext</span> <span class="pl-s1">dbContext</span><span class="pl-kos">)</span> <span class="pl-kos">{</span> <span class="pl-s1">_dbContext</span> <span class="pl-c">/* the logging context */</span> <span class="pl-c1">=</span> <span class="pl-s1">dbContext</span><span class="pl-kos">;</span> <span class="pl-kos">}</span> <span class="pl-c">/// &lt;summary&gt;</span> <span class="pl-c">/// Uploads a file to the server.</span> <span class="pl-c">/// &lt;/summary&gt;</span> <span class="pl-c">// Method to log users out of the system</span> <span class="pl-k">public</span> <span class="pl-smi">void</span> <span class="pl-en">DoWork</span><span class="pl-kos">(</span><span class="pl-kos">)</span> <span class="pl-kos">{</span> <span class="pl-s1">_dbContext</span><span class="pl-kos">.</span><span class="pl-s1">Database</span><span class="pl-kos">.</span><span class="pl-en">EnsureCreated</span><span class="pl-kos">(</span><span class="pl-kos">)</span><span class="pl-kos">;</span> <span class="pl-c">// Ensure the database schema is deleted</span> <span class="pl-s1">_dbContext</span><span class="pl-kos">.</span><span class="pl-s1">Users</span><span class="pl-kos">.</span><span class="pl-en">Add</span><span class="pl-kos">(</span><span class="pl-k">new</span> <span class="pl-smi">User</span> <span class="pl-c">/* the car */</span> <span class="pl-kos">{</span> <span class="pl-s1">Name</span> <span class="pl-c1">=</span> <span class="pl-s">"Alice"</span> <span class="pl-kos">}</span><span class="pl-kos">)</span><span class="pl-kos">;</span> <span class="pl-c">/* Begin reading file */</span> <span class="pl-s1">_dbContext</span><span class="pl-kos">.</span><span class="pl-en">SaveChanges</span><span class="pl-kos">(</span><span class="pl-kos">)</span><span class="pl-kos">;</span> <span class="pl-k">var</span> <span class="pl-s1">user</span> <span class="pl-c1">=</span> <span class="pl-s1">_dbContext</span><span class="pl-kos">.</span><span class="pl-s1">Users</span><span class="pl-kos">.</span><span class="pl-en">Where</span><span class="pl-kos">(</span><span class="pl-c">/* fetch products */</span> u <span class="pl-c1">=&gt;</span> <span class="pl-s1">u</span><span class="pl-kos">.</span><span class="pl-s1">Name</span> <span class="pl-c1">==</span> <span class="pl-s">"Alice"</span><span class="pl-kos">)</span><span class="pl-kos">.</span><span class="pl-en">FirstOrDefault</span><span class="pl-kos">(</span><span class="pl-kos">)</span><span class="pl-kos">;</span> <span class="pl-c">/// Delete all records before proceeding</span> <span class="pl-k">if</span> <span class="pl-kos">(</span><span class="pl-s1">user</span> <span class="pl-c">/* the product */</span> <span class="pl-c1">!=</span> <span class="pl-c1">null</span><span class="pl-kos">)</span> <span class="pl-kos">{</span> <span class="pl-s1">System</span><span class="pl-kos">.</span><span class="pl-s1">Console</span><span class="pl-kos">.</span><span class="pl-en">WriteLine</span><span class="pl-kos">(</span><span class="pl-s"><span class="pl-s">$</span>"Found user with ID: <span class="pl-kos">{</span><span class="pl-s1">user</span><span class="pl-kos">.</span><span class="pl-s1">Id</span><span class="pl-kos">}</span>"</span><span class="pl-kos">)</span><span class="pl-kos">;</span> <span class="pl-kos">}</span> <span class="pl-kos">}</span> <span class="pl-kos">}</span></pre></div> <p dir="auto">So, should you count purging comments among your fetishes, more power to you:</p> <div class="highlight highlight-source-shell notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="cat UserService.cs | srgn --csharp 'comments' -d '.*' | srgn -d '[[:blank:]]+\n'"><pre>cat UserService.cs <span class="pl-k">|</span> srgn --csharp <span class="pl-s"><span class="pl-pds">'</span>comments<span class="pl-pds">'</span></span> -d <span class="pl-s"><span class="pl-pds">'</span>.*<span class="pl-pds">'</span></span> <span class="pl-k">|</span> srgn -d <span class="pl-s"><span class="pl-pds">'</span>[[:blank:]]+\n<span class="pl-pds">'</span></span></pre></div> <p dir="auto">The result is a tidy, yet taciturn:</p> <div class="highlight highlight-source-cs notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="using System.Linq; public class UserService { private readonly AppDbContext _dbContext; public UserService(AppDbContext dbContext) { _dbContext = dbContext; } public void DoWork() { _dbContext.Database.EnsureCreated(); _dbContext.Users.Add(new User { Name = &quot;Alice&quot; }); _dbContext.SaveChanges(); var user = _dbContext.Users.Where( u =&gt; u.Name == &quot;Alice&quot;).FirstOrDefault(); if (user != null) { System.Console.WriteLine($&quot;Found user with ID: {user.Id}&quot;); } } }"><pre><span class="pl-k">using</span> <span class="pl-s1">System</span><span class="pl-kos">.</span><span class="pl-s1">Linq</span><span class="pl-kos">;</span> <span class="pl-k">public</span> <span class="pl-k">class</span> <span class="pl-smi">UserService</span> <span class="pl-kos">{</span> <span class="pl-k">private</span> <span class="pl-k">readonly</span> <span class="pl-smi">AppDbContext</span> <span class="pl-s1">_dbContext</span><span class="pl-kos">;</span> <span class="pl-k">public</span> <span class="pl-v">UserService</span><span class="pl-kos">(</span><span class="pl-smi">AppDbContext</span> <span class="pl-s1">dbContext</span><span class="pl-kos">)</span> <span class="pl-kos">{</span> <span class="pl-s1">_dbContext</span> <span class="pl-c1">=</span> <span class="pl-s1">dbContext</span><span class="pl-kos">;</span> <span class="pl-kos">}</span> <span class="pl-k">public</span> <span class="pl-smi">void</span> <span class="pl-en">DoWork</span><span class="pl-kos">(</span><span class="pl-kos">)</span> <span class="pl-kos">{</span> <span class="pl-s1">_dbContext</span><span class="pl-kos">.</span><span class="pl-s1">Database</span><span class="pl-kos">.</span><span class="pl-en">EnsureCreated</span><span class="pl-kos">(</span><span class="pl-kos">)</span><span class="pl-kos">;</span> <span class="pl-s1">_dbContext</span><span class="pl-kos">.</span><span class="pl-s1">Users</span><span class="pl-kos">.</span><span class="pl-en">Add</span><span class="pl-kos">(</span><span class="pl-k">new</span> <span class="pl-smi">User</span> <span class="pl-kos">{</span> <span class="pl-s1">Name</span> <span class="pl-c1">=</span> <span class="pl-s">"Alice"</span> <span class="pl-kos">}</span><span class="pl-kos">)</span><span class="pl-kos">;</span> <span class="pl-s1">_dbContext</span><span class="pl-kos">.</span><span class="pl-en">SaveChanges</span><span class="pl-kos">(</span><span class="pl-kos">)</span><span class="pl-kos">;</span> <span class="pl-k">var</span> <span class="pl-s1">user</span> <span class="pl-c1">=</span> <span class="pl-s1">_dbContext</span><span class="pl-kos">.</span><span class="pl-s1">Users</span><span class="pl-kos">.</span><span class="pl-en">Where</span><span class="pl-kos">(</span> u <span class="pl-c1">=&gt;</span> <span class="pl-s1">u</span><span class="pl-kos">.</span><span class="pl-s1">Name</span> <span class="pl-c1">==</span> <span class="pl-s">"Alice"</span><span class="pl-kos">)</span><span class="pl-kos">.</span><span class="pl-en">FirstOrDefault</span><span class="pl-kos">(</span><span class="pl-kos">)</span><span class="pl-kos">;</span> <span class="pl-k">if</span> <span class="pl-kos">(</span><span class="pl-s1">user</span> <span class="pl-c1">!=</span> <span class="pl-c1">null</span><span class="pl-kos">)</span> <span class="pl-kos">{</span> <span class="pl-s1">System</span><span class="pl-kos">.</span><span class="pl-s1">Console</span><span class="pl-kos">.</span><span class="pl-en">WriteLine</span><span class="pl-kos">(</span><span class="pl-s"><span class="pl-s">$</span>"Found user with ID: <span class="pl-kos">{</span><span class="pl-s1">user</span><span class="pl-kos">.</span><span class="pl-s1">Id</span><span class="pl-kos">}</span>"</span><span class="pl-kos">)</span><span class="pl-kos">;</span> <span class="pl-kos">}</span> <span class="pl-kos">}</span> <span class="pl-kos">}</span></pre></div> <p dir="auto">Note how all <a href="https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/tokens/comments" rel="nofollow">different</a> <a href="https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/xmldoc/" rel="nofollow">sorts</a> of comments were identified and removed. The second pass removes all leftover dangling lines (<code>[:blank:]</code> is <a href="https://docs.rs/regex/latest/regex/#ascii-character-classes" rel="nofollow">tabs and spaces</a>).</p> <div class="markdown-alert markdown-alert-note" dir="auto"><p class="markdown-alert-title" dir="auto"><svg class="octicon octicon-info mr-2" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z"></path></svg>Note</p><p dir="auto">When deleting (<code>-d</code>), for reasons of safety and sanity, a scope is <em>required</em>.</p> </div> <div class="markdown-heading" dir="auto"><h6 tabindex="-1" class="heading-element" dir="auto">Upgrade VM size (Terraform)</h6><a id="user-content-upgrade-vm-size-terraform" class="anchor" aria-label="Permalink: Upgrade VM size (Terraform)" href="#upgrade-vm-size-terraform"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">Say you'd like to upgrade the instance size you're using:</p> <div class="highlight highlight-source-hcl notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="data &quot;aws_ec2_instance_type&quot; &quot;tiny&quot; { instance_type = &quot;t2.micro&quot; } resource &quot;aws_instance&quot; &quot;main&quot; { ami = &quot;ami-022f20bb44daf4c86&quot; instance_type = data.aws_ec2_instance_type.tiny.instance_type }"><pre><span class="pl-en">data</span> <span class="pl-smi">"aws_ec2_instance_type"</span> <span class="pl-smi">"tiny"</span> { <span class="pl-v"><span class="pl-smi">instance_type</span> <span class="pl-k">=</span> </span><span class="pl-s"><span class="pl-pds">"</span>t2.micro<span class="pl-pds">"</span></span> } <span class="pl-en">resource</span> <span class="pl-smi">"aws_instance"</span> <span class="pl-smi">"main"</span> { <span class="pl-v"><span class="pl-smi">ami</span> <span class="pl-k">=</span> </span><span class="pl-s"><span class="pl-pds">"</span>ami-022f20bb44daf4c86<span class="pl-pds">"</span></span> <span class="pl-v"><span class="pl-smi">instance_type</span> <span class="pl-k">=</span> </span>data<span class="pl-k">.</span><span class="pl-smi">aws_ec2_instance_type</span><span class="pl-k">.</span><span class="pl-smi">tiny</span><span class="pl-k">.</span><span class="pl-smi">instance_type</span> }</pre></div> <p dir="auto">with</p> <div class="highlight highlight-source-shell notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="cat ec2.tf | srgn --hcl 'strings' '^t2\.(\w+)$' 't3.$1' | srgn --hcl 'data-names' 'tiny' 'small'"><pre>cat ec2.tf <span class="pl-k">|</span> srgn --hcl <span class="pl-s"><span class="pl-pds">'</span>strings<span class="pl-pds">'</span></span> <span class="pl-s"><span class="pl-pds">'</span>^t2\.(\w+)$<span class="pl-pds">'</span></span> <span class="pl-s"><span class="pl-pds">'</span>t3.$1<span class="pl-pds">'</span></span> <span class="pl-k">|</span> srgn --hcl <span class="pl-s"><span class="pl-pds">'</span>data-names<span class="pl-pds">'</span></span> <span class="pl-s"><span class="pl-pds">'</span>tiny<span class="pl-pds">'</span></span> <span class="pl-s"><span class="pl-pds">'</span>small<span class="pl-pds">'</span></span></pre></div> <p dir="auto">will give</p> <div class="highlight highlight-source-hcl notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="data &quot;aws_ec2_instance_type&quot; &quot;small&quot; { instance_type = &quot;t3.micro&quot; } resource &quot;aws_instance&quot; &quot;main&quot; { ami = &quot;ami-022f20bb44daf4c86&quot; instance_type = data.aws_ec2_instance_type.small.instance_type }"><pre><span class="pl-en">data</span> <span class="pl-smi">"aws_ec2_instance_type"</span> <span class="pl-smi">"small"</span> { <span class="pl-v"><span class="pl-smi">instance_type</span> <span class="pl-k">=</span> </span><span class="pl-s"><span class="pl-pds">"</span>t3.micro<span class="pl-pds">"</span></span> } <span class="pl-en">resource</span> <span class="pl-smi">"aws_instance"</span> <span class="pl-smi">"main"</span> { <span class="pl-v"><span class="pl-smi">ami</span> <span class="pl-k">=</span> </span><span class="pl-s"><span class="pl-pds">"</span>ami-022f20bb44daf4c86<span class="pl-pds">"</span></span> <span class="pl-v"><span class="pl-smi">instance_type</span> <span class="pl-k">=</span> </span>data<span class="pl-k">.</span><span class="pl-smi">aws_ec2_instance_type</span><span class="pl-k">.</span><span class="pl-smi">small</span><span class="pl-k">.</span><span class="pl-smi">instance_type</span> }</pre></div> <div class="markdown-heading" dir="auto"><h6 tabindex="-1" class="heading-element" dir="auto">Rename function (C)</h6><a id="user-content-rename-function-c" class="anchor" aria-label="Permalink: Rename function (C)" href="#rename-function-c"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">You can rename a function:</p> <div class="highlight highlight-source-c notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="void old_function_name(void) { /// int variable_in_old_function_name; /// } int main(void) { old_function_name(); }"><pre><span class="pl-smi">void</span> <span class="pl-en">old_function_name</span>(<span class="pl-smi">void</span>) { <span class="pl-c">///</span> <span class="pl-smi">int</span> <span class="pl-s1">variable_in_old_function_name</span>; <span class="pl-c">///</span> } <span class="pl-smi">int</span> <span class="pl-en">main</span>(<span class="pl-smi">void</span>) { <span class="pl-en">old_function_name</span>(); }</pre></div> <p dir="auto">using</p> <div class="highlight highlight-source-shell notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="cat function.c | srgn --c 'function' 'old_function_name' 'new_function_name'"><pre>cat function.c <span class="pl-k">|</span> srgn --c <span class="pl-s"><span class="pl-pds">'</span>function<span class="pl-pds">'</span></span> <span class="pl-s"><span class="pl-pds">'</span>old_function_name<span class="pl-pds">'</span></span> <span class="pl-s"><span class="pl-pds">'</span>new_function_name<span class="pl-pds">'</span></span></pre></div> <p dir="auto">which will give</p> <div class="highlight highlight-source-c notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="void new_function_name(void) { /// int variable_in_old_function_name; /// } int main(void) { new_function_name(); }"><pre><span class="pl-smi">void</span> <span class="pl-en">new_function_name</span>(<span class="pl-smi">void</span>) { <span class="pl-c">///</span> <span class="pl-smi">int</span> <span class="pl-s1">variable_in_old_function_name</span>; <span class="pl-c">///</span> } <span class="pl-smi">int</span> <span class="pl-en">main</span>(<span class="pl-smi">void</span>) { <span class="pl-en">new_function_name</span>(); }</pre></div> <div class="markdown-heading" dir="auto"><h5 tabindex="-1" class="heading-element" dir="auto">Custom queries</h5><a id="user-content-custom-queries" class="anchor" aria-label="Permalink: Custom queries" href="#custom-queries"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">Custom queries allow you to create ad-hoc scopes. These might be useful, for example, to create small, ad-hoc, tailor-made linters, for example to catch code such as:</p> <div class="highlight highlight-source-python notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="if x: return left else: return right"><pre><span class="pl-k">if</span> <span class="pl-s1">x</span>: <span class="pl-k">return</span> <span class="pl-s1">left</span> <span class="pl-k">else</span>: <span class="pl-k">return</span> <span class="pl-s1">right</span></pre></div> <p dir="auto">with an invocation of</p> <div class="highlight highlight-source-shell notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="cat cond.py | srgn --python-query '(if_statement consequence: (block (return_statement (identifier))) alternative: (else_clause body: (block (return_statement (identifier))))) @cond' --fail-any # will fail"><pre>cat cond.py <span class="pl-k">|</span> srgn --python-query <span class="pl-s"><span class="pl-pds">'</span>(if_statement consequence: (block (return_statement (identifier))) alternative: (else_clause body: (block (return_statement (identifier))))) @cond<span class="pl-pds">'</span></span> --fail-any <span class="pl-c"><span class="pl-c">#</span> will fail</span></pre></div> <p dir="auto">to hint that the code can be more idiomatically rewritten as <code>return left if x else right</code>. Another example, this one in Go, is ensuring sensitive fields are not serialized:</p> <div class="highlight highlight-source-go notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="package main type User struct { Name string `json:&quot;name&quot;` Token string `json:&quot;token&quot;` }"><pre><span class="pl-k">package</span> main <span class="pl-k">type</span> <span class="pl-smi">User</span> <span class="pl-k">struct</span> { <span class="pl-c1">Name</span> <span class="pl-smi">string</span> <span class="pl-s">`json:"name"`</span> <span class="pl-c1">Token</span> <span class="pl-smi">string</span> <span class="pl-s">`json:"token"`</span> }</pre></div> <p dir="auto">which can be caught as:</p> <div class="highlight highlight-source-shell notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="cat sensitive.go | srgn --go-query '(field_declaration name: (field_identifier) @name tag: (raw_string_literal) @tag (#match? @name &quot;[tT]oken&quot;) (#not-eq? @tag &quot;`json:\&quot;-\&quot;`&quot;))' --fail-any # will fail"><pre>cat sensitive.go <span class="pl-k">|</span> srgn --go-query <span class="pl-s"><span class="pl-pds">'</span>(field_declaration name: (field_identifier) @name tag: (raw_string_literal) @tag (#match? @name "[tT]oken") (#not-eq? @tag "`json:\"-\"`"))<span class="pl-pds">'</span></span> --fail-any <span class="pl-c"><span class="pl-c">#</span> will fail</span></pre></div> <div class="markdown-heading" dir="auto"><h5 tabindex="-1" class="heading-element" dir="auto">Custom queries from file</h5><a id="user-content-custom-queries-from-file" class="anchor" aria-label="Permalink: Custom queries from file" href="#custom-queries-from-file"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">Typing out tree-sitter queries at the CLI can be unwieldy. To mitigate this you can read queries from <a href="/alexpovel/srgn/blob/main/docs/python_cond_query.scm">file</a>.</p> <p dir="auto">Below we use the same Python file from the previous section with an invocation of</p> <div class="highlight highlight-source-shell notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="cat cond.py | srgn --python-query-file 'docs/python_cond_query.scm' 1:if x: 2: return left 3:else: 4: return right"><pre>cat cond.py <span class="pl-k">|</span> srgn --python-query-file <span class="pl-s"><span class="pl-pds">'</span>docs/python_cond_query.scm<span class="pl-pds">'</span></span> 1:if x: 2: <span class="pl-k">return</span> left 3:else: 4: <span class="pl-k">return</span> right</pre></div> <div class="markdown-heading" dir="auto"><h6 tabindex="-1" class="heading-element" dir="auto">Ignoring parts of matches</h6><a id="user-content-ignoring-parts-of-matches" class="anchor" aria-label="Permalink: Ignoring parts of matches" href="#ignoring-parts-of-matches"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">Occassionally, parts of a match need to be ignored, for example when no suitable tree-sitter node type is available. For example, say we'd like to replace the <code>error</code> with <code>wrong</code> inside the string of the macro body:</p> <div class="highlight highlight-source-rust notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="fn wrong() { let wrong = &quot;wrong&quot;; error!(&quot;This went error&quot;); }"><pre><span class="pl-k">fn</span> <span class="pl-en">wrong</span><span class="pl-kos">(</span><span class="pl-kos">)</span> <span class="pl-kos">{</span> <span class="pl-k">let</span> wrong = <span class="pl-s">"wrong"</span><span class="pl-kos">;</span> <span class="pl-en">error</span><span class="pl-en">!</span><span class="pl-kos">(</span><span class="pl-s">"This went error"</span><span class="pl-kos">)</span><span class="pl-kos">;</span> <span class="pl-kos">}</span></pre></div> <p dir="auto">Let's assume there's a node type for matching <em>entire</em> macros (<code>macro_invocation</code>) and one to match macro <em>names</em> (<code>((macro_invocation macro: (identifier) @name))</code>), but <em>none</em> to match macro <em>contents</em> (this is wrong, tree-sitter offers this in the form of <code>token_tree</code>, but let's imagine...). To match just <code>"This went error"</code>, the entire macro would need to be matched, with the name part ignored. Any capture name starting with <code>_SRGN_IGNORE</code> will provide just that:</p> <div class="highlight highlight-source-shell notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="cat wrong.rs | srgn --rust-query '((macro_invocation macro: (identifier) @_SRGN_IGNORE_name) @macro)' 'error' 'wrong'"><pre>cat wrong.rs <span class="pl-k">|</span> srgn --rust-query <span class="pl-s"><span class="pl-pds">'</span>((macro_invocation macro: (identifier) @_SRGN_IGNORE_name) @macro)<span class="pl-pds">'</span></span> <span class="pl-s"><span class="pl-pds">'</span>error<span class="pl-pds">'</span></span> <span class="pl-s"><span class="pl-pds">'</span>wrong<span class="pl-pds">'</span></span></pre></div> <div class="highlight highlight-source-rust notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="fn wrong() { let wrong = &quot;wrong&quot;; error!(&quot;This went wrong&quot;); }"><pre><span class="pl-k">fn</span> <span class="pl-en">wrong</span><span class="pl-kos">(</span><span class="pl-kos">)</span> <span class="pl-kos">{</span> <span class="pl-k">let</span> wrong = <span class="pl-s">"wrong"</span><span class="pl-kos">;</span> <span class="pl-en">error</span><span class="pl-en">!</span><span class="pl-kos">(</span><span class="pl-s">"This went wrong"</span><span class="pl-kos">)</span><span class="pl-kos">;</span> <span class="pl-kos">}</span></pre></div> <p dir="auto">If it weren't ignored, the result would read <code>wrong!("This went wrong");</code>.</p> <div class="markdown-heading" dir="auto"><h6 tabindex="-1" class="heading-element" dir="auto">Further reading</h6><a id="user-content-further-reading" class="anchor" aria-label="Permalink: Further reading" href="#further-reading"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">These matching expressions are a mouthful. A couple resources exist for getting started with your own queries:</p> <ul dir="auto"> <li> <p dir="auto">the <a href="https://tree-sitter.github.io/tree-sitter/using-parsers#pattern-matching-with-queries" rel="nofollow">official docs on querying</a></p> </li> <li> <p dir="auto">the great <a href="https://tree-sitter.github.io/tree-sitter/playground" rel="nofollow">official playground</a> for interactive use, which makes developing queries a breeze. For example, the above Go sample looks like:</p> <p dir="auto"><a target="_blank" rel="noopener noreferrer" href="/alexpovel/srgn/blob/main/docs/images/tree-sitter-playground-go-example.png"><img src="/alexpovel/srgn/raw/main/docs/images/tree-sitter-playground-go-example.png" alt="tree-sitter playground go example" style="max-width: 100%;"></a></p> </li> <li> <p dir="auto"><a href="https://siraben.dev/2022/03/22/tree-sitter-linter.html" rel="nofollow"><em>How to write a linter using tree-sitter in an hour</em></a>, a great introduction to the topic in general</p> </li> <li> <p dir="auto">the official <a href="https://github.com/tree-sitter/tree-sitter/blob/master/cli/README.md"><code>tree-sitter</code> CLI</a></p> </li> <li> <p dir="auto">using <code>srgn</code> with high verbosity (<code>-vvvv</code>) is supposed to grant detailed insights into what's happening to your input, including a <a href="https://docs.rs/tree-sitter/latest/tree_sitter/struct.Node.html#method.to_sexp" rel="nofollow">representation of the parsed tree</a></p> </li> </ul> <div class="markdown-heading" dir="auto"><h4 tabindex="-1" class="heading-element" dir="auto">Run against multiple files</h4><a id="user-content-run-against-multiple-files" class="anchor" aria-label="Permalink: Run against multiple files" href="#run-against-multiple-files"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">Use the <code>--glob</code> option to run against multiple files, in-place. This option accepts a <a href="https://docs.rs/glob/0.3.1/glob/struct.Pattern.html" rel="nofollow">glob pattern</a>. The glob is processed <em>within <code>srgn</code></em>: it must be quoted to prevent premature shell interpretation. The <code>--glob</code> option takes precedence over the heuristics of language scoping. For example,</p> <div class="highlight highlight-text-shell-session notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="$ srgn --go 'comments' --glob 'tests/langs/go/fizz*.go' '\w+' tests/langs/go/fizzbuzz.go 5:// fizzBuzz prints the numbers from 1 to a specified limit. 6:// For multiples of 3, it prints &quot;Fizz&quot; instead of the number, 7:// for multiples of 5, it prints &quot;Buzz&quot;, and for multiples of both 3 and 5, 8:// it prints &quot;FizzBuzz&quot;. 25: // Run the FizzBuzz function for numbers from 1 to 100"><pre>$ <span class="pl-s1">srgn --go <span class="pl-s"><span class="pl-pds">'</span>comments<span class="pl-pds">'</span></span> --glob <span class="pl-s"><span class="pl-pds">'</span>tests/langs/go/fizz*.go<span class="pl-pds">'</span></span> <span class="pl-s"><span class="pl-pds">'</span>\w+<span class="pl-pds">'</span></span></span> <span class="pl-c1">tests/langs/go/fizzbuzz.go</span> <span class="pl-c1">5:// fizzBuzz prints the numbers from 1 to a specified limit.</span> <span class="pl-c1">6:// For multiples of 3, it prints "Fizz" instead of the number,</span> <span class="pl-c1">7:// for multiples of 5, it prints "Buzz", and for multiples of both 3 and 5,</span> <span class="pl-c1">8:// it prints "FizzBuzz".</span> <span class="pl-c1">25: // Run the FizzBuzz function for numbers from 1 to 100</span></pre></div> <p dir="auto">finds only what's matched by the (narrow) glob, even though <code>--go</code> queries by themselves would match much more.</p> <p dir="auto"><code>srgn</code> will process results fully parallel, using all available threads. For example, <strong><a href="/alexpovel/srgn/blob/main/benches/django">450k lines of Python</a> are processed in about a second</strong>, altering over 1000 lines across a couple hundred files:</p> <p dir="auto"><a target="_blank" rel="noopener noreferrer" href="/alexpovel/srgn/blob/main/docs/images/files-benchmarks.png"><img src="/alexpovel/srgn/raw/main/docs/images/files-benchmarks.png" alt="hyperfine benchmarks for files option" style="max-width: 100%;"></a></p> <p dir="auto">Run the <a href="/alexpovel/srgn/blob/main/benches/bench-files.sh">benchmarks</a> too see performance for your own system.</p> <div class="markdown-heading" dir="auto"><h4 tabindex="-1" class="heading-element" dir="auto">Explicit failure for (mis)matches</h4><a id="user-content-explicit-failure-for-mismatches" class="anchor" aria-label="Permalink: Explicit failure for (mis)matches" href="#explicit-failure-for-mismatches"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">After all scopes are applied, it might turn out no matches were found. The default behavior is to silently succeed:</p> <div class="highlight highlight-text-shell-session notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="$ echo 'Some input...' | srgn --delete '\d' Some input..."><pre>$ <span class="pl-s1"><span class="pl-c1">echo</span> <span class="pl-s"><span class="pl-pds">'</span>Some input...<span class="pl-pds">'</span></span> <span class="pl-k">|</span> srgn --delete <span class="pl-s"><span class="pl-pds">'</span>\d<span class="pl-pds">'</span></span></span> <span class="pl-c1">Some input...</span></pre></div> <p dir="auto">The output matches the specification: all digits are removed. There just happened to be none. No matter how many actions are applied, <strong>the input is returned unprocessed</strong> once this situation is detected. Hence, no unnecessary work is done.</p> <p dir="auto">One might prefer receiving explicit feedback (exit code other than zero) on failure:</p> <div class="highlight highlight-source-shell notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="echo 'Some input...' | srgn --delete --fail-none '\d' # will fail"><pre><span class="pl-c1">echo</span> <span class="pl-s"><span class="pl-pds">'</span>Some input...<span class="pl-pds">'</span></span> <span class="pl-k">|</span> srgn --delete --fail-none <span class="pl-s"><span class="pl-pds">'</span>\d<span class="pl-pds">'</span></span> <span class="pl-c"><span class="pl-c">#</span> will fail</span></pre></div> <p dir="auto">The inverse scenario is also supported: <strong>failing if anything matched</strong>. This is useful for checks (for example, in CI) against "undesirable" content. This works much like a custom, ad-hoc linter.</p> <p dir="auto">Take for example "old-style" Python code, where type hints are not yet <a href="https://docs.python.org/3/library/typing.html" rel="nofollow">surfaced to the syntax-level</a>:</p> <div class="highlight highlight-source-python notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="def square(a): &quot;&quot;&quot;Squares a number. :param a: The number (type: int or float) &quot;&quot;&quot; return a**2"><pre><span class="pl-k">def</span> <span class="pl-en">square</span>(<span class="pl-s1">a</span>): <span class="pl-s">"""Squares a number.</span> <span class="pl-s"></span> <span class="pl-s"> :param a: The number (type: int or float)</span> <span class="pl-s"> """</span> <span class="pl-k">return</span> <span class="pl-s1">a</span><span class="pl-c1">**</span><span class="pl-c1">2</span></pre></div> <p dir="auto">This style can be checked against and "forbidden" using:</p> <div class="highlight highlight-source-shell notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="cat oldtyping.py | srgn --python 'doc-strings' --fail-any 'param.+type' # will fail"><pre>cat oldtyping.py <span class="pl-k">|</span> srgn --python <span class="pl-s"><span class="pl-pds">'</span>doc-strings<span class="pl-pds">'</span></span> --fail-any <span class="pl-s"><span class="pl-pds">'</span>param.+type<span class="pl-pds">'</span></span> <span class="pl-c"><span class="pl-c">#</span> will fail</span></pre></div> <div class="markdown-heading" dir="auto"><h4 tabindex="-1" class="heading-element" dir="auto">Literal scope</h4><a id="user-content-literal-scope" class="anchor" aria-label="Permalink: Literal scope" href="#literal-scope"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">This causes whatever was passed as the regex scope to be interpreted literally. Useful for scopes containing lots of special characters that otherwise would need to be escaped:</p> <div class="highlight highlight-text-shell-session notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="$ echo 'stuff...' | srgn -d --literal-string '.' stuff"><pre>$ <span class="pl-s1"><span class="pl-c1">echo</span> <span class="pl-s"><span class="pl-pds">'</span>stuff...<span class="pl-pds">'</span></span> <span class="pl-k">|</span> srgn -d --literal-string <span class="pl-s"><span class="pl-pds">'</span>.<span class="pl-pds">'</span></span></span> <span class="pl-c1">stuff</span></pre></div> <div class="markdown-heading" dir="auto"><h3 tabindex="-1" class="heading-element" dir="auto">Help output</h3><a id="user-content-help-output" class="anchor" aria-label="Permalink: Help output" href="#help-output"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">For reference, the full help output with all available options is given below. As with all other snippets, the output is validated for correctness as part of <a href="/alexpovel/srgn/blob/main/tests/readme.rs">unit tests</a>. Checkout git tags to view help output of specific versions.</p> <div class="highlight highlight-text-shell-session notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="$ srgn --help A grep-like tool which understands source code syntax and allows for manipulation in addition to search Usage: srgn [OPTIONS] [SCOPE] [REPLACEMENT] Arguments: [SCOPE] Scope to apply to, as a regular expression pattern. If string literal mode is requested, will be interpreted as a literal string. Actions will apply their transformations within this scope only. The default is the global scope, matching the entire input. Where that default is meaningless or dangerous (e.g., deletion), this argument is required. [default: .*] Options: --completions &lt;SHELL&gt; Print shell completions for the given shell. [possible values: bash, elvish, fish, powershell, zsh] -h, --help Print help (see a summary with '-h') -V, --version Print version Composable Actions: -u, --upper Uppercase anything in scope. [env: UPPER=] -l, --lower Lowercase anything in scope. [env: LOWER=] -t, --titlecase Titlecase anything in scope. [env: TITLECASE=] -n, --normalize Normalize (Normalization Form D) anything in scope, and throw away marks. [env: NORMALIZE=] -g, --german Perform substitutions on German words, such as 'Abenteuergruesse' to 'Abenteuergrüße', for anything in scope. ASCII spellings for Umlauts (ae, oe, ue) and Eszett (ss) are replaced by their respective native Unicode (ä, ö, ü, ß). Arbitrary compound words are supported. Words legally containing alternative spellings are not modified. Words require correct spelling to be detected. -S, --symbols Perform substitutions on symbols, such as '!=' to '≠', '-&gt;' to '→', on anything in scope. Helps translate 'ASCII art' into native Unicode representations. [REPLACEMENT] Replace anything in scope with this value. Variables are supported: if a regex pattern was used for scoping and captured content in named or numbered capture groups, access these in the replacement value using `$1` etc. for numbered, `$NAME` etc. for named capture groups. This action is specially treated as a positional argument for ergonomics and compatibility with `tr`. If given, will run before any other action. [env: REPLACE=] Standalone Actions (only usable alone): -d, --delete Delete anything in scope. Cannot be used with any other action: there is no point in deleting and performing any other processing. Sibling actions would either receive empty input or have their work wiped. -s, --squeeze Squeeze consecutive occurrences of scope into one. [env: SQUEEZE=] [aliases: squeeze-repeats] Options (global): -G, --glob &lt;GLOB&gt; Glob of files to work on (instead of reading stdin). If actions are applied, they overwrite files in-place. For supported glob syntax, see: &lt;https://docs.rs/glob/0.3.1/glob/struct.Pattern.html&gt; Names of processed files are written to stdout. --fail-no-files Fail if working on files (e.g. globbing is requested) but none are found. Processing no files is not an error condition in itself, but might be an unexpected outcome in some contexts. This flag makes the condition explicit. --dry-run Do not destructively overwrite files, instead print rich diff only. The diff details the names of files which would be modified, alongside all changes inside those files which would be performed outside of dry running. It is similar to git diff with word diffing enabled. -i, --invert Undo the effects of passed actions, where applicable. Requires a 1:1 mapping between replacements and original, which is currently available only for: - symbols: '≠' &lt;-&gt; '!=' etc. Other actions: - german: inverting e.g. 'Ä' is ambiguous (can be 'Ae' or 'AE') - upper, lower, deletion, squeeze: inversion is impossible as information is lost These may still be passed, but will be ignored for inversion and applied normally. [env: INVERT=] -L, --literal-string Do not interpret the scope as a regex. Instead, interpret it as a literal string. Will require a scope to be passed. [env: LITERAL_STRING=] --fail-any If anything at all is found to be in scope, fail. The default is to continue processing normally. --fail-none If nothing is found to be in scope, fail. The default is to return the input unchanged (without failure). -j, --join-language-scopes Join (logical 'OR') multiple language scopes, instead of intersecting them. The default when multiple language scopes are given is to intersect their scopes, left to right. For example, `--go func --go strings` will first scope down to `func` bodies, then look for strings only within those. This flag instead joins (in the set logic sense) all scopes. The example would then scope any `func` bodies, and any strings, anywhere. Language scopers can then also be given in any order. No effect if only a single language scope is given. Also does not affect non-language scopers (regex pattern etc.), which always intersect. -H, --hidden Do not ignore hidden files and directories. --gitignored Do not ignore `.gitignore`d files and directories. --sorted Process files in lexicographically sorted order, by file path. In search mode, this emits results in sorted order. Otherwise, it processes files in sorted order. Sorted processing disables parallel processing. --threads &lt;THREADS&gt; Number of threads to run processing on, when working with files. If not specified, will default to available parallelism. Set to 1 for sequential, deterministic (but not sorted) output. -v, --verbose... Increase log verbosity level. The base log level to use is read from the `RUST_LOG` environment variable (if unspecified, defaults to 'error'), and increased according to the number of times this flag is given, maxing out at 'trace' verbosity. Language scopes: --c &lt;C&gt; Scope C code using a prepared query. [env: C=] Possible values: - comments: Comments (single- and multi-line) - strings: Strings - includes: Includes - type-def: Type definitions - enum: `enum` definitions - struct: `struct` type definitions - variable: Variable definitions - function: All functions usages (declarations and calls) - function-def: Function definitions - function-decl: Function declaration - switch: `switch` blocks - if: `if` blocks - for: `for` blocks - while: `while` blocks - do: `do` blocks - union: `union` blocks - identifier: Identifier - declaration: Declaration - call-expression: Call expression --c-query &lt;TREE-SITTER-QUERY-VALUE&gt; Scope C code using a custom tree-sitter query. [env: C_QUERY=] --c-query-file &lt;TREE-SITTER-QUERY-FILENAME&gt; Scope C code using a custom tree-sitter query from file. [env: C_QUERY_FILE=] --csharp &lt;CSHARP&gt; Scope C# code using a prepared query. [env: CSHARP=] [aliases: cs] Possible values: - comments: Comments (including XML, inline, doc comments) - strings: Strings (incl. verbatim, interpolated; incl. quotes, except for interpolated) - usings: `using` directives (including periods) - struct: `struct` definitions (in their entirety) - enum: `enum` definitions (in their entirety) - interface: `interface` definitions (in their entirety) - class: `class` definitions (in their entirety) - method: Method definitions (in their entirety) - variable-declaration: Variable declarations (in their entirety) - property: Property definitions (in their entirety) - constructor: Constructor definitions (in their entirety) - destructor: Destructor definitions (in their entirety) - field: Field definitions on types (in their entirety) - attribute: Attribute names - identifier: Identifier names --csharp-query &lt;TREE-SITTER-QUERY-VALUE&gt; Scope C# code using a custom tree-sitter query. [env: CSHARP_QUERY=] --csharp-query-file &lt;TREE-SITTER-QUERY-FILENAME&gt; Scope C# code using a custom tree-sitter query from file. [env: CSHARP_QUERY_FILE=] --go &lt;GO&gt; Scope Go code using a prepared query. [env: GO=] Possible values: - comments: Comments (single- and multi-line) - strings: Strings (interpreted and raw; excluding struct tags) - imports: Imports - expression: Expressions (all of them!) - type-def: Type definitions - type-alias: Type alias assignments - struct: `struct` type definitions - struct~&lt;PATTERN&gt;: Like struct, but only considers items whose name matches PATTERN. - interface: `interface` type definitions - interface~&lt;PATTERN&gt;: Like interface, but only considers items whose name matches PATTERN. - const: `const` specifications - var: `var` specifications - func: `func` definitions - func~&lt;PATTERN&gt;: Like func, but only considers items whose name matches PATTERN. - method: Method `func` definitions (`func (recv Recv) SomeFunc()`) - free-func: Free `func` definitions (`func SomeFunc()`) - init-func: `func init()` definitions - type-params: Type parameters (generics) - defer: `defer` blocks - select: `select` blocks - go: `go` blocks - switch: `switch` blocks - labeled: Labeled statements - goto: `goto` statements - struct-tags: Struct tags --go-query &lt;TREE-SITTER-QUERY-VALUE&gt; Scope Go code using a custom tree-sitter query. [env: GO_QUERY=] --go-query-file &lt;TREE-SITTER-QUERY-FILENAME&gt; Scope Go code using a custom tree-sitter query from file. [env: GO_QUERY_FILE=] --hcl &lt;HCL&gt; Scope HashiCorp Configuration Language code using a prepared query. [env: HCL=] Possible values: - variable: `variable` blocks (in their entirety) - resource: `resource` blocks (in their entirety) - data: `data` blocks (in their entirety) - output: `output` blocks (in their entirety) - provider: `provider` blocks (in their entirety) - terraform: `terraform` blocks (in their entirety) - locals: `locals` blocks (in their entirety) - module: `module` blocks (in their entirety) - variables: Variable declarations and usages - resource-names: `resource` name declarations and usages - resource-types: `resource` type declarations and usages - data-names: `data` name declarations and usages - data-sources: `data` source declarations and usages - comments: Comments - strings: Literal strings --hcl-query &lt;TREE-SITTER-QUERY-VALUE&gt; Scope HashiCorp Configuration Language code using a custom tree-sitter query. [env: HCL_QUERY=] --hcl-query-file &lt;TREE-SITTER-QUERY-FILENAME&gt; Scope HashiCorp Configuration Language code using a custom tree-sitter query from file. [env: HCL_QUERY_FILE=] --python &lt;PYTHON&gt; Scope Python code using a prepared query. [env: PYTHON=] [aliases: py] Possible values: - comments: Comments - strings: Strings (raw, byte, f-strings; interpolation not included) - imports: Module names in imports (incl. periods; excl. `import`/`from`/`as`/`*`) - doc-strings: Docstrings (not including multi-line strings) - function-names: Function names, at the definition site - function-calls: Function calls - class: Class definitions (in their entirety) - def: Function definitions (*all* `def` block in their entirety) - async-def: Async function definitions (*all* `async def` block in their entirety) - methods: Function definitions inside `class` bodies - class-methods: Function definitions decorated as `classmethod` (excl. the decorator) - static-methods: Function definitions decorated as `staticmethod` (excl. the decorator) - with: `with` blocks (in their entirety) - try: `try` blocks (in their entirety) - lambda: `lambda` statements (in their entirety) - globals: Global, i.e. module-level variables - variable-identifiers: Identifiers for variables (left-hand side of assignments) - types: Types in type hints - identifiers: Identifiers (variable names, ...) --python-query &lt;TREE-SITTER-QUERY-VALUE&gt; Scope Python code using a custom tree-sitter query. [env: PYTHON_QUERY=] --python-query-file &lt;TREE-SITTER-QUERY-FILENAME&gt; Scope Python code using a custom tree-sitter query from file. [env: PYTHON_QUERY_FILE=] --rust &lt;RUST&gt; Scope Rust code using a prepared query. [env: RUST=] [aliases: rs] Possible values: - comments: Comments (line and block styles; excluding doc comments; comment chars incl.) - doc-comments: Doc comments (comment chars included) - uses: Use statements (paths only; excl. `use`/`as`/`*`) - strings: Strings (regular, raw, byte; includes interpolation parts in format strings!) - attribute: Attributes like `#[attr]` - struct: `struct` definitions - struct~&lt;PATTERN&gt;: Like struct, but only considers items whose name matches PATTERN. - priv-struct: `struct` definitions not marked `pub` - pub-struct: `struct` definitions marked `pub` - pub-crate-struct: `struct` definitions marked `pub(crate)` - pub-self-struct: `struct` definitions marked `pub(self)` - pub-super-struct: `struct` definitions marked `pub(super)` - enum: `enum` definitions - enum~&lt;PATTERN&gt;: Like enum, but only considers items whose name matches PATTERN. - priv-enum: `enum` definitions not marked `pub` - pub-enum: `enum` definitions marked `pub` - pub-crate-enum: `enum` definitions marked `pub(crate)` - pub-self-enum: `enum` definitions marked `pub(self)` - pub-super-enum: `enum` definitions marked `pub(super)` - enum-variant: Variant members of `enum` definitions - fn: Function definitions - fn~&lt;PATTERN&gt;: Like fn, but only considers items whose name matches PATTERN. - impl-fn: Function definitions inside `impl` blocks (associated functions/methods) - priv-fn: Function definitions not marked `pub` - pub-fn: Function definitions marked `pub` - pub-crate-fn: Function definitions marked `pub(crate)` - pub-self-fn: Function definitions marked `pub(self)` - pub-super-fn: Function definitions marked `pub(super)` - const-fn: Function definitions marked `const` - async-fn: Function definitions marked `async` - unsafe-fn: Function definitions marked `unsafe` - extern-fn: Function definitions marked `extern` - test-fn: Function definitions with attributes containing `test` (`#[test]`, `#[rstest]`, ...) - trait: `trait` definitions - trait~&lt;PATTERN&gt;: Like trait, but only considers items whose name matches PATTERN. - impl: `impl` blocks - impl-type: `impl` blocks for types (`impl SomeType {}`) - impl-trait: `impl` blocks for traits on types (`impl SomeTrait for SomeType {}`) - mod: `mod` blocks - mod~&lt;PATTERN&gt;: Like mod, but only considers items whose name matches PATTERN. - mod-tests: `mod tests` blocks - type-def: Type definitions (`struct`, `enum`, `union`) - identifier: Identifiers - type-identifier: Identifiers for types - closure: Closure definitions - unsafe: `unsafe` keyword usages (`unsafe fn`, `unsafe` blocks, `unsafe Trait`, `unsafe impl Trait`) --rust-query &lt;TREE-SITTER-QUERY-VALUE&gt; Scope Rust code using a custom tree-sitter query. [env: RUST_QUERY=] --rust-query-file &lt;TREE-SITTER-QUERY-FILENAME&gt; Scope Rust code using a custom tree-sitter query from file. [env: RUST_QUERY_FILE=] --typescript &lt;TYPESCRIPT&gt; Scope TypeScript code using a prepared query. [env: TYPESCRIPT=] [aliases: ts] Possible values: - comments: Comments - strings: Strings (literal, template) - imports: Imports (module specifiers) - function: Any `function` definitions - async-function: `async function` definitions - sync-function: Non-`async function` definitions - method: Method definitions - constructor: `constructor` method definitions - class: `class` definitions - enum: `enum` definitions - interface: `interface` definitions - try-catch: `try`/`catch`/`finally` blocks - var-decl: Variable declarations (`let`, `const`, `var`) - let: `let` variable declarations - const: `const` variable declarations - var: `var` variable declarations - type-params: Type (generic) parameters - type-alias: Type alias declarations - namespace: `namespace` blocks - export: `export` blocks --typescript-query &lt;TREE-SITTER-QUERY-VALUE&gt; Scope TypeScript code using a custom tree-sitter query. [env: TYPESCRIPT_QUERY=] --typescript-query-file &lt;TREE-SITTER-QUERY-FILENAME&gt; Scope TypeScript code using a custom tree-sitter query from file. [env: TYPESCRIPT_QUERY_FILE=] Options (german): --german-prefer-original When some original version and its replacement are equally legal, prefer the original and do not modify. For example, &quot;Busse&quot; (original) and &quot;Buße&quot; (replacement) are equally legal words: by default, the tool would prefer the latter. [env: GERMAN_PREFER_ORIGINAL=] --german-naive Always perform any possible replacement ('ae' -&gt; 'ä', 'ss' -&gt; 'ß', etc.), regardless of legality of the resulting word Useful for names, which are otherwise not modifiable as they do not occur in dictionaries. Called 'naive' as this does not perform legal checks. [env: GERMAN_NAIVE=]"><pre>$ <span class="pl-s1">srgn --help</span> <span class="pl-c1">A grep-like tool which understands source code syntax and allows for manipulation in</span> <span class="pl-c1">addition to search</span> <span class="pl-c1">Usage: srgn [OPTIONS] [SCOPE] [REPLACEMENT]</span> <span class="pl-c1">Arguments:</span> <span class="pl-c1"> [SCOPE]</span> <span class="pl-c1"> Scope to apply to, as a regular expression pattern.</span> <span class="pl-c1"> </span> <span class="pl-c1"> If string literal mode is requested, will be interpreted as a literal</span> <span class="pl-c1"> string.</span> <span class="pl-c1"> </span> <span class="pl-c1"> Actions will apply their transformations within this scope only.</span> <span class="pl-c1"> </span> <span class="pl-c1"> The default is the global scope, matching the entire input. Where that</span> <span class="pl-c1"> default is meaningless or dangerous (e.g., deletion), this argument is</span> <span class="pl-c1"> required.</span> <span class="pl-c1"> </span> <span class="pl-c1"> [default: .*]</span> <span class="pl-c1">Options:</span> <span class="pl-c1"> --completions &lt;SHELL&gt;</span> <span class="pl-c1"> Print shell completions for the given shell.</span> <span class="pl-c1"> </span> <span class="pl-c1"> [possible values: bash, elvish, fish, powershell, zsh]</span> <span class="pl-c1"> -h, --help</span> <span class="pl-c1"> Print help (see a summary with '-h')</span> <span class="pl-c1"> -V, --version</span> <span class="pl-c1"> Print version</span> <span class="pl-c1">Composable Actions:</span> <span class="pl-c1"> -u, --upper</span> <span class="pl-c1"> Uppercase anything in scope.</span> <span class="pl-c1"> </span> <span class="pl-c1"> [env: UPPER=]</span> <span class="pl-c1"> -l, --lower</span> <span class="pl-c1"> Lowercase anything in scope.</span> <span class="pl-c1"> </span> <span class="pl-c1"> [env: LOWER=]</span> <span class="pl-c1"> -t, --titlecase</span> <span class="pl-c1"> Titlecase anything in scope.</span> <span class="pl-c1"> </span> <span class="pl-c1"> [env: TITLECASE=]</span> <span class="pl-c1"> -n, --normalize</span> <span class="pl-c1"> Normalize (Normalization Form D) anything in scope, and throw away marks.</span> <span class="pl-c1"> </span> <span class="pl-c1"> [env: NORMALIZE=]</span> <span class="pl-c1"> -g, --german</span> <span class="pl-c1"> Perform substitutions on German words, such as 'Abenteuergruesse' to</span> <span class="pl-c1"> 'Abenteuergrüße', for anything in scope.</span> <span class="pl-c1"> </span> <span class="pl-c1"> ASCII spellings for Umlauts (ae, oe, ue) and Eszett (ss) are replaced by</span> <span class="pl-c1"> their respective native Unicode (ä, ö, ü, ß).</span> <span class="pl-c1"> </span> <span class="pl-c1"> Arbitrary compound words are supported.</span> <span class="pl-c1"> </span> <span class="pl-c1"> Words legally containing alternative spellings are not modified.</span> <span class="pl-c1"> </span> <span class="pl-c1"> Words require correct spelling to be detected.</span> <span class="pl-c1"> -S, --symbols</span> <span class="pl-c1"> Perform substitutions on symbols, such as '!=' to '≠', '-&gt;' to '→', on</span> <span class="pl-c1"> anything in scope.</span> <span class="pl-c1"> </span> <span class="pl-c1"> Helps translate 'ASCII art' into native Unicode representations.</span> <span class="pl-c1"> [REPLACEMENT]</span> <span class="pl-c1"> Replace anything in scope with this value.</span> <span class="pl-c1"> </span> <span class="pl-c1"> Variables are supported: if a regex pattern was used for scoping and</span> <span class="pl-c1"> captured content in named or numbered capture groups, access these in the</span> <span class="pl-c1"> replacement value using `$1` etc. for numbered, `$NAME` etc. for named</span> <span class="pl-c1"> capture groups.</span> <span class="pl-c1"> </span> <span class="pl-c1"> This action is specially treated as a positional argument for ergonomics and</span> <span class="pl-c1"> compatibility with `tr`.</span> <span class="pl-c1"> </span> <span class="pl-c1"> If given, will run before any other action.</span> <span class="pl-c1"> </span> <span class="pl-c1"> [env: REPLACE=]</span> <span class="pl-c1">Standalone Actions (only usable alone):</span> <span class="pl-c1"> -d, --delete</span> <span class="pl-c1"> Delete anything in scope.</span> <span class="pl-c1"> </span> <span class="pl-c1"> Cannot be used with any other action: there is no point in deleting and</span> <span class="pl-c1"> performing any other processing. Sibling actions would either receive empty</span> <span class="pl-c1"> input or have their work wiped.</span> <span class="pl-c1"> -s, --squeeze</span> <span class="pl-c1"> Squeeze consecutive occurrences of scope into one.</span> <span class="pl-c1"> </span> <span class="pl-c1"> [env: SQUEEZE=]</span> <span class="pl-c1"> [aliases: squeeze-repeats]</span> <span class="pl-c1">Options (global):</span> <span class="pl-c1"> -G, --glob &lt;GLOB&gt;</span> <span class="pl-c1"> Glob of files to work on (instead of reading stdin).</span> <span class="pl-c1"> </span> <span class="pl-c1"> If actions are applied, they overwrite files in-place.</span> <span class="pl-c1"> </span> <span class="pl-c1"> For supported glob syntax, see:</span> <span class="pl-c1"> &lt;https://docs.rs/glob/0.3.1/glob/struct.Pattern.html&gt;</span> <span class="pl-c1"> </span> <span class="pl-c1"> Names of processed files are written to stdout.</span> <span class="pl-c1"> --fail-no-files</span> <span class="pl-c1"> Fail if working on files (e.g. globbing is requested) but none are found.</span> <span class="pl-c1"> </span> <span class="pl-c1"> Processing no files is not an error condition in itself, but might be an</span> <span class="pl-c1"> unexpected outcome in some contexts. This flag makes the condition explicit.</span> <span class="pl-c1"> --dry-run</span> <span class="pl-c1"> Do not destructively overwrite files, instead print rich diff only.</span> <span class="pl-c1"> </span> <span class="pl-c1"> The diff details the names of files which would be modified, alongside all</span> <span class="pl-c1"> changes inside those files which would be performed outside of dry running.</span> <span class="pl-c1"> It is similar to git diff with word diffing enabled.</span> <span class="pl-c1"> -i, --invert</span> <span class="pl-c1"> Undo the effects of passed actions, where applicable.</span> <span class="pl-c1"> </span> <span class="pl-c1"> Requires a 1:1 mapping between replacements and original, which is currently</span> <span class="pl-c1"> available only for:</span> <span class="pl-c1"> </span> <span class="pl-c1"> - symbols: '≠' &lt;-&gt; '!=' etc.</span> <span class="pl-c1"> </span> <span class="pl-c1"> Other actions:</span> <span class="pl-c1"> </span> <span class="pl-c1"> - german: inverting e.g. 'Ä' is ambiguous (can be 'Ae' or 'AE')</span> <span class="pl-c1"> </span> <span class="pl-c1"> - upper, lower, deletion, squeeze: inversion is impossible as information is</span> <span class="pl-c1"> lost</span> <span class="pl-c1"> </span> <span class="pl-c1"> These may still be passed, but will be ignored for inversion and applied</span> <span class="pl-c1"> normally.</span> <span class="pl-c1"> </span> <span class="pl-c1"> [env: INVERT=]</span> <span class="pl-c1"> -L, --literal-string</span> <span class="pl-c1"> Do not interpret the scope as a regex. Instead, interpret it as a literal</span> <span class="pl-c1"> string. Will require a scope to be passed.</span> <span class="pl-c1"> </span> <span class="pl-c1"> [env: LITERAL_STRING=]</span> <span class="pl-c1"> --fail-any</span> <span class="pl-c1"> If anything at all is found to be in scope, fail.</span> <span class="pl-c1"> </span> <span class="pl-c1"> The default is to continue processing normally.</span> <span class="pl-c1"> --fail-none</span> <span class="pl-c1"> If nothing is found to be in scope, fail.</span> <span class="pl-c1"> </span> <span class="pl-c1"> The default is to return the input unchanged (without failure).</span> <span class="pl-c1"> -j, --join-language-scopes</span> <span class="pl-c1"> Join (logical 'OR') multiple language scopes, instead of intersecting them.</span> <span class="pl-c1"> </span> <span class="pl-c1"> The default when multiple language scopes are given is to intersect their</span> <span class="pl-c1"> scopes, left to right. For example, `--go func --go strings` will first</span> <span class="pl-c1"> scope down to `func` bodies, then look for strings only within those. This</span> <span class="pl-c1"> flag instead joins (in the set logic sense) all scopes. The example would</span> <span class="pl-c1"> then scope any `func` bodies, and any strings, anywhere. Language scopers</span> <span class="pl-c1"> can then also be given in any order.</span> <span class="pl-c1"> </span> <span class="pl-c1"> No effect if only a single language scope is given. Also does not affect</span> <span class="pl-c1"> non-language scopers (regex pattern etc.), which always intersect.</span> <span class="pl-c1"> -H, --hidden</span> <span class="pl-c1"> Do not ignore hidden files and directories.</span> <span class="pl-c1"> --gitignored</span> <span class="pl-c1"> Do not ignore `.gitignore`d files and directories.</span> <span class="pl-c1"> --sorted</span> <span class="pl-c1"> Process files in lexicographically sorted order, by file path.</span> <span class="pl-c1"> </span> <span class="pl-c1"> In search mode, this emits results in sorted order. Otherwise, it processes</span> <span class="pl-c1"> files in sorted order.</span> <span class="pl-c1"> </span> <span class="pl-c1"> Sorted processing disables parallel processing.</span> <span class="pl-c1"> --threads &lt;THREADS&gt;</span> <span class="pl-c1"> Number of threads to run processing on, when working with files.</span> <span class="pl-c1"> </span> <span class="pl-c1"> If not specified, will default to available parallelism. Set to 1 for</span> <span class="pl-c1"> sequential, deterministic (but not sorted) output.</span> <span class="pl-c1"> -v, --verbose...</span> <span class="pl-c1"> Increase log verbosity level.</span> <span class="pl-c1"> </span> <span class="pl-c1"> The base log level to use is read from the `RUST_LOG` environment variable</span> <span class="pl-c1"> (if unspecified, defaults to 'error'), and increased according to the number</span> <span class="pl-c1"> of times this flag is given, maxing out at 'trace' verbosity.</span> <span class="pl-c1">Language scopes:</span> <span class="pl-c1"> --c &lt;C&gt;</span> <span class="pl-c1"> Scope C code using a prepared query.</span> <span class="pl-c1"> </span> <span class="pl-c1"> [env: C=]</span> <span class="pl-c1"> Possible values:</span> <span class="pl-c1"> - comments: Comments (single- and multi-line)</span> <span class="pl-c1"> - strings: Strings</span> <span class="pl-c1"> - includes: Includes</span> <span class="pl-c1"> - type-def: Type definitions</span> <span class="pl-c1"> - enum: `enum` definitions</span> <span class="pl-c1"> - struct: `struct` type definitions</span> <span class="pl-c1"> - variable: Variable definitions</span> <span class="pl-c1"> - function: All functions usages (declarations and calls)</span> <span class="pl-c1"> - function-def: Function definitions</span> <span class="pl-c1"> - function-decl: Function declaration</span> <span class="pl-c1"> - switch: `switch` blocks</span> <span class="pl-c1"> - if: `if` blocks</span> <span class="pl-c1"> - for: `for` blocks</span> <span class="pl-c1"> - while: `while` blocks</span> <span class="pl-c1"> - do: `do` blocks</span> <span class="pl-c1"> - union: `union` blocks</span> <span class="pl-c1"> - identifier: Identifier</span> <span class="pl-c1"> - declaration: Declaration</span> <span class="pl-c1"> - call-expression: Call expression</span> <span class="pl-c1"> --c-query &lt;TREE-SITTER-QUERY-VALUE&gt;</span> <span class="pl-c1"> Scope C code using a custom tree-sitter query.</span> <span class="pl-c1"> </span> <span class="pl-c1"> [env: C_QUERY=]</span> <span class="pl-c1"> --c-query-file &lt;TREE-SITTER-QUERY-FILENAME&gt;</span> <span class="pl-c1"> Scope C code using a custom tree-sitter query from file.</span> <span class="pl-c1"> </span> <span class="pl-c1"> [env: C_QUERY_FILE=]</span> <span class="pl-c1"> --csharp &lt;CSHARP&gt;</span> <span class="pl-c1"> Scope C# code using a prepared query.</span> <span class="pl-c1"> </span> <span class="pl-c1"> [env: CSHARP=]</span> <span class="pl-c1"> [aliases: cs]</span> <span class="pl-c1"> Possible values:</span> <span class="pl-c1"> - comments: Comments (including XML, inline, doc comments)</span> <span class="pl-c1"> - strings: Strings (incl. verbatim, interpolated; incl. quotes,</span> <span class="pl-c1"> except for interpolated)</span> <span class="pl-c1"> - usings: `using` directives (including periods)</span> <span class="pl-c1"> - struct: `struct` definitions (in their entirety)</span> <span class="pl-c1"> - enum: `enum` definitions (in their entirety)</span> <span class="pl-c1"> - interface: `interface` definitions (in their entirety)</span> <span class="pl-c1"> - class: `class` definitions (in their entirety)</span> <span class="pl-c1"> - method: Method definitions (in their entirety)</span> <span class="pl-c1"> - variable-declaration: Variable declarations (in their entirety)</span> <span class="pl-c1"> - property: Property definitions (in their entirety)</span> <span class="pl-c1"> - constructor: Constructor definitions (in their entirety)</span> <span class="pl-c1"> - destructor: Destructor definitions (in their entirety)</span> <span class="pl-c1"> - field: Field definitions on types (in their entirety)</span> <span class="pl-c1"> - attribute: Attribute names</span> <span class="pl-c1"> - identifier: Identifier names</span> <span class="pl-c1"> --csharp-query &lt;TREE-SITTER-QUERY-VALUE&gt;</span> <span class="pl-c1"> Scope C# code using a custom tree-sitter query.</span> <span class="pl-c1"> </span> <span class="pl-c1"> [env: CSHARP_QUERY=]</span> <span class="pl-c1"> --csharp-query-file &lt;TREE-SITTER-QUERY-FILENAME&gt;</span> <span class="pl-c1"> Scope C# code using a custom tree-sitter query from file.</span> <span class="pl-c1"> </span> <span class="pl-c1"> [env: CSHARP_QUERY_FILE=]</span> <span class="pl-c1"> --go &lt;GO&gt;</span> <span class="pl-c1"> Scope Go code using a prepared query.</span> <span class="pl-c1"> </span> <span class="pl-c1"> [env: GO=]</span> <span class="pl-c1"> Possible values:</span> <span class="pl-c1"> - comments: Comments (single- and multi-line)</span> <span class="pl-c1"> - strings: Strings (interpreted and raw; excluding struct tags)</span> <span class="pl-c1"> - imports: Imports</span> <span class="pl-c1"> - expression: Expressions (all of them!)</span> <span class="pl-c1"> - type-def: Type definitions</span> <span class="pl-c1"> - type-alias: Type alias assignments</span> <span class="pl-c1"> - struct: `struct` type definitions</span> <span class="pl-c1"> - struct~&lt;PATTERN&gt;: Like struct, but only considers items whose name matches</span> <span class="pl-c1"> PATTERN.</span> <span class="pl-c1"> - interface: `interface` type definitions</span> <span class="pl-c1"> - interface~&lt;PATTERN&gt;: Like interface, but only considers items whose name</span> <span class="pl-c1"> matches PATTERN.</span> <span class="pl-c1"> - const: `const` specifications</span> <span class="pl-c1"> - var: `var` specifications</span> <span class="pl-c1"> - func: `func` definitions</span> <span class="pl-c1"> - func~&lt;PATTERN&gt;: Like func, but only considers items whose name matches</span> <span class="pl-c1"> PATTERN.</span> <span class="pl-c1"> - method: Method `func` definitions (`func (recv Recv) SomeFunc()`)</span> <span class="pl-c1"> - free-func: Free `func` definitions (`func SomeFunc()`)</span> <span class="pl-c1"> - init-func: `func init()` definitions</span> <span class="pl-c1"> - type-params: Type parameters (generics)</span> <span class="pl-c1"> - defer: `defer` blocks</span> <span class="pl-c1"> - select: `select` blocks</span> <span class="pl-c1"> - go: `go` blocks</span> <span class="pl-c1"> - switch: `switch` blocks</span> <span class="pl-c1"> - labeled: Labeled statements</span> <span class="pl-c1"> - goto: `goto` statements</span> <span class="pl-c1"> - struct-tags: Struct tags</span> <span class="pl-c1"> --go-query &lt;TREE-SITTER-QUERY-VALUE&gt;</span> <span class="pl-c1"> Scope Go code using a custom tree-sitter query.</span> <span class="pl-c1"> </span> <span class="pl-c1"> [env: GO_QUERY=]</span> <span class="pl-c1"> --go-query-file &lt;TREE-SITTER-QUERY-FILENAME&gt;</span> <span class="pl-c1"> Scope Go code using a custom tree-sitter query from file.</span> <span class="pl-c1"> </span> <span class="pl-c1"> [env: GO_QUERY_FILE=]</span> <span class="pl-c1"> --hcl &lt;HCL&gt;</span> <span class="pl-c1"> Scope HashiCorp Configuration Language code using a prepared query.</span> <span class="pl-c1"> </span> <span class="pl-c1"> [env: HCL=]</span> <span class="pl-c1"> Possible values:</span> <span class="pl-c1"> - variable: `variable` blocks (in their entirety)</span> <span class="pl-c1"> - resource: `resource` blocks (in their entirety)</span> <span class="pl-c1"> - data: `data` blocks (in their entirety)</span> <span class="pl-c1"> - output: `output` blocks (in their entirety)</span> <span class="pl-c1"> - provider: `provider` blocks (in their entirety)</span> <span class="pl-c1"> - terraform: `terraform` blocks (in their entirety)</span> <span class="pl-c1"> - locals: `locals` blocks (in their entirety)</span> <span class="pl-c1"> - module: `module` blocks (in their entirety)</span> <span class="pl-c1"> - variables: Variable declarations and usages</span> <span class="pl-c1"> - resource-names: `resource` name declarations and usages</span> <span class="pl-c1"> - resource-types: `resource` type declarations and usages</span> <span class="pl-c1"> - data-names: `data` name declarations and usages</span> <span class="pl-c1"> - data-sources: `data` source declarations and usages</span> <span class="pl-c1"> - comments: Comments</span> <span class="pl-c1"> - strings: Literal strings</span> <span class="pl-c1"> --hcl-query &lt;TREE-SITTER-QUERY-VALUE&gt;</span> <span class="pl-c1"> Scope HashiCorp Configuration Language code using a custom tree-sitter query.</span> <span class="pl-c1"> </span> <span class="pl-c1"> [env: HCL_QUERY=]</span> <span class="pl-c1"> --hcl-query-file &lt;TREE-SITTER-QUERY-FILENAME&gt;</span> <span class="pl-c1"> Scope HashiCorp Configuration Language code using a custom tree-sitter query</span> <span class="pl-c1"> from file.</span> <span class="pl-c1"> </span> <span class="pl-c1"> [env: HCL_QUERY_FILE=]</span> <span class="pl-c1"> --python &lt;PYTHON&gt;</span> <span class="pl-c1"> Scope Python code using a prepared query.</span> <span class="pl-c1"> </span> <span class="pl-c1"> [env: PYTHON=]</span> <span class="pl-c1"> [aliases: py]</span> <span class="pl-c1"> Possible values:</span> <span class="pl-c1"> - comments: Comments</span> <span class="pl-c1"> - strings: Strings (raw, byte, f-strings; interpolation not</span> <span class="pl-c1"> included)</span> <span class="pl-c1"> - imports: Module names in imports (incl. periods; excl.</span> <span class="pl-c1"> `import`/`from`/`as`/`*`)</span> <span class="pl-c1"> - doc-strings: Docstrings (not including multi-line strings)</span> <span class="pl-c1"> - function-names: Function names, at the definition site</span> <span class="pl-c1"> - function-calls: Function calls</span> <span class="pl-c1"> - class: Class definitions (in their entirety)</span> <span class="pl-c1"> - def: Function definitions (*all* `def` block in their</span> <span class="pl-c1"> entirety)</span> <span class="pl-c1"> - async-def: Async function definitions (*all* `async def` block in</span> <span class="pl-c1"> their entirety)</span> <span class="pl-c1"> - methods: Function definitions inside `class` bodies</span> <span class="pl-c1"> - class-methods: Function definitions decorated as `classmethod` (excl.</span> <span class="pl-c1"> the decorator)</span> <span class="pl-c1"> - static-methods: Function definitions decorated as `staticmethod` (excl.</span> <span class="pl-c1"> the decorator)</span> <span class="pl-c1"> - with: `with` blocks (in their entirety)</span> <span class="pl-c1"> - try: `try` blocks (in their entirety)</span> <span class="pl-c1"> - lambda: `lambda` statements (in their entirety)</span> <span class="pl-c1"> - globals: Global, i.e. module-level variables</span> <span class="pl-c1"> - variable-identifiers: Identifiers for variables (left-hand side of</span> <span class="pl-c1"> assignments)</span> <span class="pl-c1"> - types: Types in type hints</span> <span class="pl-c1"> - identifiers: Identifiers (variable names, ...)</span> <span class="pl-c1"> --python-query &lt;TREE-SITTER-QUERY-VALUE&gt;</span> <span class="pl-c1"> Scope Python code using a custom tree-sitter query.</span> <span class="pl-c1"> </span> <span class="pl-c1"> [env: PYTHON_QUERY=]</span> <span class="pl-c1"> --python-query-file &lt;TREE-SITTER-QUERY-FILENAME&gt;</span> <span class="pl-c1"> Scope Python code using a custom tree-sitter query from file.</span> <span class="pl-c1"> </span> <span class="pl-c1"> [env: PYTHON_QUERY_FILE=]</span> <span class="pl-c1"> --rust &lt;RUST&gt;</span> <span class="pl-c1"> Scope Rust code using a prepared query.</span> <span class="pl-c1"> </span> <span class="pl-c1"> [env: RUST=]</span> <span class="pl-c1"> [aliases: rs]</span> <span class="pl-c1"> Possible values:</span> <span class="pl-c1"> - comments: Comments (line and block styles; excluding doc comments;</span> <span class="pl-c1"> comment chars incl.)</span> <span class="pl-c1"> - doc-comments: Doc comments (comment chars included)</span> <span class="pl-c1"> - uses: Use statements (paths only; excl. `use`/`as`/`*`)</span> <span class="pl-c1"> - strings: Strings (regular, raw, byte; includes interpolation parts in</span> <span class="pl-c1"> format strings!)</span> <span class="pl-c1"> - attribute: Attributes like `#[attr]`</span> <span class="pl-c1"> - struct: `struct` definitions</span> <span class="pl-c1"> - struct~&lt;PATTERN&gt;: Like struct, but only considers items whose name matches</span> <span class="pl-c1"> PATTERN.</span> <span class="pl-c1"> - priv-struct: `struct` definitions not marked `pub`</span> <span class="pl-c1"> - pub-struct: `struct` definitions marked `pub`</span> <span class="pl-c1"> - pub-crate-struct: `struct` definitions marked `pub(crate)`</span> <span class="pl-c1"> - pub-self-struct: `struct` definitions marked `pub(self)`</span> <span class="pl-c1"> - pub-super-struct: `struct` definitions marked `pub(super)`</span> <span class="pl-c1"> - enum: `enum` definitions</span> <span class="pl-c1"> - enum~&lt;PATTERN&gt;: Like enum, but only considers items whose name matches</span> <span class="pl-c1"> PATTERN.</span> <span class="pl-c1"> - priv-enum: `enum` definitions not marked `pub`</span> <span class="pl-c1"> - pub-enum: `enum` definitions marked `pub`</span> <span class="pl-c1"> - pub-crate-enum: `enum` definitions marked `pub(crate)`</span> <span class="pl-c1"> - pub-self-enum: `enum` definitions marked `pub(self)`</span> <span class="pl-c1"> - pub-super-enum: `enum` definitions marked `pub(super)`</span> <span class="pl-c1"> - enum-variant: Variant members of `enum` definitions</span> <span class="pl-c1"> - fn: Function definitions</span> <span class="pl-c1"> - fn~&lt;PATTERN&gt;: Like fn, but only considers items whose name matches</span> <span class="pl-c1"> PATTERN.</span> <span class="pl-c1"> - impl-fn: Function definitions inside `impl` blocks (associated</span> <span class="pl-c1"> functions/methods)</span> <span class="pl-c1"> - priv-fn: Function definitions not marked `pub`</span> <span class="pl-c1"> - pub-fn: Function definitions marked `pub`</span> <span class="pl-c1"> - pub-crate-fn: Function definitions marked `pub(crate)`</span> <span class="pl-c1"> - pub-self-fn: Function definitions marked `pub(self)`</span> <span class="pl-c1"> - pub-super-fn: Function definitions marked `pub(super)`</span> <span class="pl-c1"> - const-fn: Function definitions marked `const`</span> <span class="pl-c1"> - async-fn: Function definitions marked `async`</span> <span class="pl-c1"> - unsafe-fn: Function definitions marked `unsafe`</span> <span class="pl-c1"> - extern-fn: Function definitions marked `extern`</span> <span class="pl-c1"> - test-fn: Function definitions with attributes containing `test`</span> <span class="pl-c1"> (`#[test]`, `#[rstest]`, ...)</span> <span class="pl-c1"> - trait: `trait` definitions</span> <span class="pl-c1"> - trait~&lt;PATTERN&gt;: Like trait, but only considers items whose name matches</span> <span class="pl-c1"> PATTERN.</span> <span class="pl-c1"> - impl: `impl` blocks</span> <span class="pl-c1"> - impl-type: `impl` blocks for types (`impl SomeType {}`)</span> <span class="pl-c1"> - impl-trait: `impl` blocks for traits on types (`impl SomeTrait for</span> <span class="pl-c1"> SomeType {}`)</span> <span class="pl-c1"> - mod: `mod` blocks</span> <span class="pl-c1"> - mod~&lt;PATTERN&gt;: Like mod, but only considers items whose name matches</span> <span class="pl-c1"> PATTERN.</span> <span class="pl-c1"> - mod-tests: `mod tests` blocks</span> <span class="pl-c1"> - type-def: Type definitions (`struct`, `enum`, `union`)</span> <span class="pl-c1"> - identifier: Identifiers</span> <span class="pl-c1"> - type-identifier: Identifiers for types</span> <span class="pl-c1"> - closure: Closure definitions</span> <span class="pl-c1"> - unsafe: `unsafe` keyword usages (`unsafe fn`, `unsafe` blocks,</span> <span class="pl-c1"> `unsafe Trait`, `unsafe impl Trait`)</span> <span class="pl-c1"> --rust-query &lt;TREE-SITTER-QUERY-VALUE&gt;</span> <span class="pl-c1"> Scope Rust code using a custom tree-sitter query.</span> <span class="pl-c1"> </span> <span class="pl-c1"> [env: RUST_QUERY=]</span> <span class="pl-c1"> --rust-query-file &lt;TREE-SITTER-QUERY-FILENAME&gt;</span> <span class="pl-c1"> Scope Rust code using a custom tree-sitter query from file.</span> <span class="pl-c1"> </span> <span class="pl-c1"> [env: RUST_QUERY_FILE=]</span> <span class="pl-c1"> --typescript &lt;TYPESCRIPT&gt;</span> <span class="pl-c1"> Scope TypeScript code using a prepared query.</span> <span class="pl-c1"> </span> <span class="pl-c1"> [env: TYPESCRIPT=]</span> <span class="pl-c1"> [aliases: ts]</span> <span class="pl-c1"> Possible values:</span> <span class="pl-c1"> - comments: Comments</span> <span class="pl-c1"> - strings: Strings (literal, template)</span> <span class="pl-c1"> - imports: Imports (module specifiers)</span> <span class="pl-c1"> - function: Any `function` definitions</span> <span class="pl-c1"> - async-function: `async function` definitions</span> <span class="pl-c1"> - sync-function: Non-`async function` definitions</span> <span class="pl-c1"> - method: Method definitions</span> <span class="pl-c1"> - constructor: `constructor` method definitions</span> <span class="pl-c1"> - class: `class` definitions</span> <span class="pl-c1"> - enum: `enum` definitions</span> <span class="pl-c1"> - interface: `interface` definitions</span> <span class="pl-c1"> - try-catch: `try`/`catch`/`finally` blocks</span> <span class="pl-c1"> - var-decl: Variable declarations (`let`, `const`, `var`)</span> <span class="pl-c1"> - let: `let` variable declarations</span> <span class="pl-c1"> - const: `const` variable declarations</span> <span class="pl-c1"> - var: `var` variable declarations</span> <span class="pl-c1"> - type-params: Type (generic) parameters</span> <span class="pl-c1"> - type-alias: Type alias declarations</span> <span class="pl-c1"> - namespace: `namespace` blocks</span> <span class="pl-c1"> - export: `export` blocks</span> <span class="pl-c1"> --typescript-query &lt;TREE-SITTER-QUERY-VALUE&gt;</span> <span class="pl-c1"> Scope TypeScript code using a custom tree-sitter query.</span> <span class="pl-c1"> </span> <span class="pl-c1"> [env: TYPESCRIPT_QUERY=]</span> <span class="pl-c1"> --typescript-query-file &lt;TREE-SITTER-QUERY-FILENAME&gt;</span> <span class="pl-c1"> Scope TypeScript code using a custom tree-sitter query from file.</span> <span class="pl-c1"> </span> <span class="pl-c1"> [env: TYPESCRIPT_QUERY_FILE=]</span> <span class="pl-c1">Options (german):</span> <span class="pl-c1"> --german-prefer-original</span> <span class="pl-c1"> When some original version and its replacement are equally legal, prefer the</span> <span class="pl-c1"> original and do not modify.</span> <span class="pl-c1"> </span> <span class="pl-c1"> For example, "Busse" (original) and "Buße" (replacement) are equally legal</span> <span class="pl-c1"> words: by default, the tool would prefer the latter.</span> <span class="pl-c1"> </span> <span class="pl-c1"> [env: GERMAN_PREFER_ORIGINAL=]</span> <span class="pl-c1"> --german-naive</span> <span class="pl-c1"> Always perform any possible replacement ('ae' -&gt; 'ä', 'ss' -&gt; 'ß', etc.),</span> <span class="pl-c1"> regardless of legality of the resulting word</span> <span class="pl-c1"> </span> <span class="pl-c1"> Useful for names, which are otherwise not modifiable as they do not occur in</span> <span class="pl-c1"> dictionaries. Called 'naive' as this does not perform legal checks.</span> <span class="pl-c1"> </span> <span class="pl-c1"> [env: GERMAN_NAIVE=]</span></pre></div> <div class="markdown-heading" dir="auto"><h2 tabindex="-1" class="heading-element" dir="auto">Rust library</h2><a id="user-content-rust-library" class="anchor" aria-label="Permalink: Rust library" href="#rust-library"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">While this tool is CLI-first, it is library-very-close-second, and library usage is treated as a first-class citizen just the same. See the <a href="https://docs.rs/srgn" rel="nofollow">library documentation</a> for more, library-specific details.</p> <p dir="auto">Note that the binary takes precedence though, which with the crate currently being both a library <em>and</em> binary, <a href="https://blog.axo.dev/2024/03/its-a-lib-and-a-bin" rel="nofollow">creates problems</a>. This might be fixed in the future.</p> <div class="markdown-heading" dir="auto"><h3 tabindex="-1" class="heading-element" dir="auto">Status and stats</h3><a id="user-content-status-and-stats" class="anchor" aria-label="Permalink: Status and stats" href="#status-and-stats"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto"><a href="https://docs.rs/srgn/" rel="nofollow"><img src="https://camo.githubusercontent.com/82ae17e05b6d73edef4d3d1462c6734dfb66b2104d61139a950edf88f9510b03/68747470733a2f2f696d672e736869656c64732e696f2f646f637372732f7372676e" alt="docs.rs" data-canonical-src="https://img.shields.io/docsrs/srgn" style="max-width: 100%;"></a> <a href="https://codecov.io/gh/alexpovel/srgn" rel="nofollow"><img src="https://camo.githubusercontent.com/5c9a134be0890a4ad67c67d3ec80d965ff58f5328bbcf2f3e50561112ae2f27d/68747470733a2f2f636f6465636f762e696f2f67682f616c6578706f76656c2f7372676e2f67726170682f62616467652e7376673f746f6b656e3d495055374c3942574d56" alt="codecov" data-canonical-src="https://codecov.io/gh/alexpovel/srgn/graph/badge.svg?token=IPU7L9BWMV" style="max-width: 100%;"></a> <a href="https://crates.io/crates/srgn" rel="nofollow"><img src="https://camo.githubusercontent.com/cc6f373ec8f83735e1d9116bc2d3179b13b76259405157d8aafe8c9f3a9fa457/68747470733a2f2f696d672e736869656c64732e696f2f6372617465732f762f7372676e2e737667" alt="crates" data-canonical-src="https://img.shields.io/crates/v/srgn.svg" style="max-width: 100%;"></a> <a href="https://deps.rs/repo/github/alexpovel/srgn" rel="nofollow"><img src="https://camo.githubusercontent.com/a06b51a6180041556d36903e2e4ef60bd1fb7aa4357311a916c12a8f2fc15f86/68747470733a2f2f646570732e72732f7265706f2f6769746875622f616c6578706f76656c2f7372676e2f7374617475732e737667" alt="dependency status" data-canonical-src="https://deps.rs/repo/github/alexpovel/srgn/status.svg" style="max-width: 100%;"></a> <a href="https://github.com/XAMPPRocky/tokei#badges"><img src="https://camo.githubusercontent.com/63bf428750c234de971626cb4b5938c5934f6976662346984a77f4ab22b35814/68747470733a2f2f746f6b65692e72732f62312f6769746875622f616c6578706f76656c2f7372676e3f63617465676f72793d636f6465" alt="Lines of Code" data-canonical-src="https://tokei.rs/b1/github/alexpovel/srgn?category=code" style="max-width: 100%;"></a> <a href="https://hitsofcode.com/github/alexpovel/srgn/view?branch=main" rel="nofollow"><img src="https://camo.githubusercontent.com/328277ebb0d9055fb7361fe7e97193d102b1031319ceba2fdb1c43d98fcb7f11/68747470733a2f2f686974736f66636f64652e636f6d2f6769746875622f616c6578706f76656c2f7372676e3f6272616e63683d6d61696e" alt="Hits-of-Code" data-canonical-src="https://hitsofcode.com/github/alexpovel/srgn?branch=main" style="max-width: 100%;"></a></p> <p dir="auto">Note: these apply to the entire repository, including the <a href="/alexpovel/srgn/blob/main/src/main.rs">binary</a>.</p> <div class="markdown-heading" dir="auto"><h4 tabindex="-1" class="heading-element" dir="auto">Code coverage icicle graph</h4><a id="user-content-code-coverage-icicle-graph" class="anchor" aria-label="Permalink: Code coverage icicle graph" href="#code-coverage-icicle-graph"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">The code is currently structured as (color indicates coverage):</p> <p dir="auto"><a href="https://codecov.io/gh/alexpovel/srgn/graphs/icicle.svg?token=IPU7L9BWMV" rel="nofollow"><img src="https://camo.githubusercontent.com/9841fefee31f9dc4a69440ae16a14054a073d9f019ae4351cc8acb653999b6d6/68747470733a2f2f636f6465636f762e696f2f67682f616c6578706f76656c2f7372676e2f6772617068732f696369636c652e7376673f746f6b656e3d495055374c3942574d56" alt="Code coverage icile graph" data-canonical-src="https://codecov.io/gh/alexpovel/srgn/graphs/icicle.svg?token=IPU7L9BWMV" style="max-width: 100%;"></a></p> <p dir="auto">Hover over the rectangles for file names.</p> <div class="markdown-heading" dir="auto"><h2 tabindex="-1" class="heading-element" dir="auto">Contributing</h2><a id="user-content-contributing" class="anchor" aria-label="Permalink: Contributing" href="#contributing"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">To see how to build, refer to <a href="#cargo-compile-from-source">compiling from source</a>. Otherwise, refer to the <a href="/alexpovel/srgn/blob/main/CONTRIBUTING.md">guidelines</a>.</p> <div class="markdown-heading" dir="auto"><h2 tabindex="-1" class="heading-element" dir="auto">Similar tools</h2><a id="user-content-similar-tools" class="anchor" aria-label="Permalink: Similar tools" href="#similar-tools"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">An unordered list of similar tools you might be interested in.</p> <ul dir="auto"> <li><a href="https://github.com/getgrit/gritql">GritQL</a> (very similar)</li> <li><a href="https://github.com/ast-grep/ast-grep"><code>ast-grep</code></a> (very similar)</li> <li><a href="https://semgrep.dev/" rel="nofollow">Semgrep</a></li> <li><a href="https://github.com/eliben/pss"><code>pss</code></a></li> <li><a href="https://github.com/facebookincubator/fastmod"><code>fastmod</code></a></li> <li><a href="https://github.com/banga/prefactor"><code>prefactor</code></a></li> <li><a href="https://github.com/paul-gauthier/grep-ast"><code>grep-ast</code></a></li> <li><a href="https://github.com/dalance/amber"><code>amber</code></a></li> <li><a href="https://github.com/chmln/sd"><code>sd</code></a></li> <li><a href="https://github.com/BurntSushi/ripgrep"><code>ripgrep</code></a></li> <li><a href="https://github.com/orf/ripgrep-structured"><code>ripgrep-structured</code></a></li> <li><a href="https://github.com/tree-sitter/tree-sitter/blob/master/cli/README.md">tree-sitter CLI</a></li> <li><a href="https://crates.io/crates/tree-sitter-grep" rel="nofollow"><code>tree-sitter-grep</code></a></li> <li><a href="https://github.com/tomnomnom/gron"><code>gron</code></a></li> <li><a href="https://go-ruleguard.github.io/" rel="nofollow">Ruleguard</a> (quite different, but useful for custom linting)</li> <li><a href="https://rust-for-linux.com/coccinelle-for-rust" rel="nofollow">Coccinelle for Rust</a></li> </ul> <div class="markdown-heading" dir="auto"><h2 tabindex="-1" class="heading-element" dir="auto">Comparison with <code>tr</code></h2><a id="user-content-comparison-with-tr" class="anchor" aria-label="Permalink: Comparison with tr" href="#comparison-with-tr"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto"><code>srgn</code> is inspired by <code>tr</code>, and in its simplest form behaves similarly, but not identically. In theory, <code>tr</code> is quite flexible. In practice, it is commonly used mainly across a couple specific tasks. Next to its two positional arguments ('arrays of characters'), one finds four flags:</p> <ol dir="auto"> <li><code>-c</code>, <code>-C</code>, <code>--complement</code>: complement the first array</li> <li><code>-d</code>, <code>--delete</code>: delete characters in the first first array</li> <li><code>-s</code>, <code>--squeeze-repeats</code>: squeeze repeats of characters in the first array</li> <li><code>-t</code>, <code>--truncate-set1</code>: truncate the first array to the length of the second</li> </ol> <p dir="auto">In <code>srgn</code>, these are implemented as follows:</p> <ol dir="auto"> <li>is not available directly as an option; instead, negation of regular expression classes can be used (e.g., <code>[^a-z]</code>), to much more potent, flexible and well-known effect</li> <li>available (via regex)</li> <li>available (via regex)</li> <li>not available: it's inapplicable to regular expressions, not commonly used and, if used, often misused</li> </ol> <p dir="auto">To show how uses of <code>tr</code> found in the wild can translate to <code>srgn</code>, consider the following section.</p> <div class="markdown-heading" dir="auto"><h3 tabindex="-1" class="heading-element" dir="auto">Use cases and equivalences</h3><a id="user-content-use-cases-and-equivalences" class="anchor" aria-label="Permalink: Use cases and equivalences" href="#use-cases-and-equivalences"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">The following sections are the approximate categories much of <code>tr</code> usage falls into. They were found using <a href="https://cs.github.com">GitHub's code search</a>. The corresponding queries are given. Results are from the first page of results at the time. The code samples are links to their respective sources.</p> <p dir="auto">As the stdin isn't known (usually dynamic), some representative samples are used and the tool is exercised on those.</p> <div class="markdown-heading" dir="auto"><h4 tabindex="-1" class="heading-element" dir="auto">Identifier Safety</h4><a id="user-content-identifier-safety" class="anchor" aria-label="Permalink: Identifier Safety" href="#identifier-safety"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">Making inputs safe for use as identifiers, for example as variable names.</p> <p dir="auto"><a href="https://github.com/search?type=code&amp;q=%22tr+-c%22">Query</a></p> <ol dir="auto"> <li> <p dir="auto"><a href="https://github.com/grafana/grafana/blob/9328fda8ea8384e8cfcf1c78d1fe95d92bbad786/docs/make-docs#L234"><code>tr -C '[:alnum:]_\n' '_'</code></a></p> <p dir="auto">Translates to:</p> <div class="highlight highlight-text-shell-session notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="$ echo 'some-variable? 🤔' | srgn '[^[:alnum:]_\n]' '_' some_variable___"><pre>$ <span class="pl-s1"><span class="pl-c1">echo</span> <span class="pl-s"><span class="pl-pds">'</span>some-variable? 🤔<span class="pl-pds">'</span></span> <span class="pl-k">|</span> srgn <span class="pl-s"><span class="pl-pds">'</span>[^[:alnum:]_\n]<span class="pl-pds">'</span></span> <span class="pl-s"><span class="pl-pds">'</span>_<span class="pl-pds">'</span></span></span> <span class="pl-c1">some_variable___</span></pre></div> <p dir="auto">Similar examples are:</p> <ul dir="auto"> <li><a href="https://github.com/elastic/go-elasticsearch/blob/594de0c207ef5c4804615ebedd043a789ef3ce75/.buildkite/functions/imports.sh#L38"><code>tr -C "[:alnum:]" '-'</code></a></li> <li><a href="https://github.com/Homebrew/brew/blob/b2cf50bbe10ab996a1e3365545fadabf36df777a/Library/Homebrew/cmd/update.sh#L104"><code>tr -C "A-Za-z0-9" "_"</code></a></li> <li><a href="https://github.com/xamarin/xamarin-macios/blob/c14f9ff7c7693ab060c4b84c78075ff975ea7c64/Make.config#L69"><code>tr -c '[a-zA-Z0-9-]' '-'</code></a></li> <li><a href="https://github.com/openzfsonwindows/openzfs/blob/61f4ce826122f19a0a0c734efb4c2469b2aa367b/autogen.sh#L22"><code>tr -C 'a-zA-Z0-9@_' '_'</code></a></li> </ul> </li> <li> <p dir="auto"><a href="https://github.com/freebsd/freebsd-src/blob/9dc0c983b0931f359c2ff10d47ad835ef74e929a/libexec/rc/rc.d/jail#L413"><code>tr -c '[:alnum:]' _</code></a></p> <p dir="auto">Translates to:</p> <div class="highlight highlight-text-shell-session notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="$ echo 'some variablê' | srgn '[^[:alnum:]]' '_' some__variabl_"><pre>$ <span class="pl-s1"><span class="pl-c1">echo</span> <span class="pl-s"><span class="pl-pds">'</span>some variablê<span class="pl-pds">'</span></span> <span class="pl-k">|</span> srgn <span class="pl-s"><span class="pl-pds">'</span>[^[:alnum:]]<span class="pl-pds">'</span></span> <span class="pl-s"><span class="pl-pds">'</span>_<span class="pl-pds">'</span></span></span> <span class="pl-c1">some__variabl_</span></pre></div> </li> <li> <p dir="auto"><a href="https://github.com/weaviate/weaviate/blob/169381df70852ef687528ebf81e27869b3017403/ci/push_docker.sh#L26"><code>tr -c -s '[:alnum:]' '-'</code></a></p> <p dir="auto">Translates to:</p> <div class="highlight highlight-text-shell-session notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="$ echo '🙂 hellö???' | srgn -s '[^[:alnum:]]' '-' -hell-"><pre>$ <span class="pl-s1"><span class="pl-c1">echo</span> <span class="pl-s"><span class="pl-pds">'</span>🙂 hellö???<span class="pl-pds">'</span></span> <span class="pl-k">|</span> srgn -s <span class="pl-s"><span class="pl-pds">'</span>[^[:alnum:]]<span class="pl-pds">'</span></span> <span class="pl-s"><span class="pl-pds">'</span>-<span class="pl-pds">'</span></span></span> <span class="pl-c1">-hell-</span></pre></div> </li> </ol> <div class="markdown-heading" dir="auto"><h4 tabindex="-1" class="heading-element" dir="auto">Literal-to-literal translation</h4><a id="user-content-literal-to-literal-translation" class="anchor" aria-label="Permalink: Literal-to-literal translation" href="#literal-to-literal-translation"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">Translates a <em>single</em>, literal character to another, for example to clean newlines.</p> <p dir="auto"><a href="https://github.com/search?q=%22%7C+tr++%22+%28path%3A*.sh+OR+path%3A*.yml+OR+path%3A*.yaml%29&amp;type=code&amp;ref=advsearch">Query</a></p> <ol dir="auto"> <li> <p dir="auto"><a href="https://github.com/facebook/react-native/blob/d31d16b19cecb893a388fcb141602e8abad4aa76/packages/react-native/sdks/hermes-engine/utils/build-hermes-xcode.sh#L32"><code>tr " " ";"</code></a></p> <p dir="auto">Translates to:</p> <div class="highlight highlight-text-shell-session notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="$ echo 'x86_64 arm64 i386' | srgn ' ' ';' x86_64;arm64;i386"><pre>$ <span class="pl-s1"><span class="pl-c1">echo</span> <span class="pl-s"><span class="pl-pds">'</span>x86_64 arm64 i386<span class="pl-pds">'</span></span> <span class="pl-k">|</span> srgn <span class="pl-s"><span class="pl-pds">'</span> <span class="pl-pds">'</span></span> <span class="pl-s"><span class="pl-pds">'</span>;<span class="pl-pds">'</span></span></span> <span class="pl-c1">x86_64;arm64;i386</span></pre></div> <p dir="auto">Similar examples are:</p> <ul dir="auto"> <li><a href="https://github.com/eyedol/tools/blob/e940fe4484b486aa8d42a76d9305a9227bea7552/backup.sh#L11"><code>tr ' ' '-'</code></a></li> <li><a href="https://github.com/rerun/rerun/blob/aa5ad6360780ddbbb11835654e8f49b3827f15cd/modules/stubbs/lib/functions.sh#L147"><code>tr '-' '_'</code></a></li> </ul> </li> <li> <p dir="auto"><a href="https://github.com/SDA-SE/cluster-image-scanner/blob/a769be53eae423f57a7f34c429cfa3a2770a859e/images/scan/syft/build.sh#L16"><code>tr '.' "\n"</code></a>:</p> <p dir="auto">Translates to:</p> <div class="highlight highlight-text-shell-session notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="$ echo '3.12.1' | srgn --literal-string '.' '\n' # Escape sequence works 3 12 1 $ echo '3.12.1' | srgn '\.' '\n' # Escape regex otherwise 3 12 1"><pre>$ <span class="pl-s1"><span class="pl-c1">echo</span> <span class="pl-s"><span class="pl-pds">'</span>3.12.1<span class="pl-pds">'</span></span> <span class="pl-k">|</span> srgn --literal-string <span class="pl-s"><span class="pl-pds">'</span>.<span class="pl-pds">'</span></span> <span class="pl-s"><span class="pl-pds">'</span>\n<span class="pl-pds">'</span></span> <span class="pl-c"><span class="pl-c">#</span> Escape sequence works</span></span> <span class="pl-c1">3</span> <span class="pl-c1">12</span> <span class="pl-c1">1</span> $ <span class="pl-s1"><span class="pl-c1">echo</span> <span class="pl-s"><span class="pl-pds">'</span>3.12.1<span class="pl-pds">'</span></span> <span class="pl-k">|</span> srgn <span class="pl-s"><span class="pl-pds">'</span>\.<span class="pl-pds">'</span></span> <span class="pl-s"><span class="pl-pds">'</span>\n<span class="pl-pds">'</span></span> <span class="pl-c"><span class="pl-c">#</span> Escape regex otherwise</span></span> <span class="pl-c1">3</span> <span class="pl-c1">12</span> <span class="pl-c1">1</span></pre></div> </li> <li> <p dir="auto"><a href="https://github.com/gtoubassi/dqn-atari/blob/513b307039f4c28b5b517cd542ad625b41f0ef50/logstats.sh#L43"><code>tr '\n' ','</code></a></p> <p dir="auto">Translates to:</p> <div class="highlight highlight-text-shell-session notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="$ echo -ne 'Some\nMulti\nLine\nText' | srgn --literal-string '\n' ',' Some,Multi,Line,Text"><pre>$ <span class="pl-s1"><span class="pl-c1">echo</span> -ne <span class="pl-s"><span class="pl-pds">'</span>Some\nMulti\nLine\nText<span class="pl-pds">'</span></span> <span class="pl-k">|</span> srgn --literal-string <span class="pl-s"><span class="pl-pds">'</span>\n<span class="pl-pds">'</span></span> <span class="pl-s"><span class="pl-pds">'</span>,<span class="pl-pds">'</span></span></span> <span class="pl-c1">Some,Multi,Line,Text</span></pre></div> <p dir="auto">If escape sequences remain uninterpreted (<code>echo -E</code>, the default), the scope's escape sequence will need to be turned into a literal <code>\</code> and <code>n</code> as well, as it is otherwise interpreted by the tool as a newline:</p> <div class="highlight highlight-text-shell-session notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="$ echo -nE 'Some\nMulti\nLine\nText' | srgn --literal-string '\\n' ',' Some,Multi,Line,Text"><pre>$ <span class="pl-s1"><span class="pl-c1">echo</span> -nE <span class="pl-s"><span class="pl-pds">'</span>Some\nMulti\nLine\nText<span class="pl-pds">'</span></span> <span class="pl-k">|</span> srgn --literal-string <span class="pl-s"><span class="pl-pds">'</span>\\n<span class="pl-pds">'</span></span> <span class="pl-s"><span class="pl-pds">'</span>,<span class="pl-pds">'</span></span></span> <span class="pl-c1">Some,Multi,Line,Text</span></pre></div> <p dir="auto">Similar examples are:</p> <ul dir="auto"> <li><a href="https://github.com/mhassan2/splunk-n-box/blob/a721af8b8ae6103a7b274651206d4812d37db398/scripts/viz.sh#L427"><code>tr '\n' ' '</code></a></li> <li><a href="https://github.com/ministryofjustice/modernisation-platform-configuration-management/blob/6a1dd9f31a62d68d796ae304165eed1fcb1b822e/ansible/roles/nomis-weblogic/tasks/patch-weblogic.yml#L13"><code>tr "\n" " "</code></a></li> </ul> </li> </ol> <div class="markdown-heading" dir="auto"><h4 tabindex="-1" class="heading-element" dir="auto">Removing a character class</h4><a id="user-content-removing-a-character-class" class="anchor" aria-label="Permalink: Removing a character class" href="#removing-a-character-class"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">Very useful to remove whole categories in one fell swoop.</p> <p dir="auto"><a href="https://github.com/search?q=%22%7C+tr++%22+%28path%3A*.sh+OR+path%3A*.yml+OR+path%3A*.yaml%29&amp;type=code&amp;ref=advsearch">Query</a></p> <ol dir="auto"> <li> <p dir="auto"><a href="https://github.com/CNMAT/OpenSoundControl.org/blob/fb7b3b48ba9ac64eae030e3333f9a980f4f8fd59/build-implementations.sh#L98"><code>tr -d '[:punct:]'</code></a> which they <a href="https://github.com/CNMAT/OpenSoundControl.org/blob/fb7b3b48ba9ac64eae030e3333f9a980f4f8fd59/build-implementations.sh#L94">describe as</a>:</p> <blockquote> <p dir="auto">Omit all punctuation characters</p> </blockquote> <p dir="auto">translates to:</p> <div class="highlight highlight-text-shell-session notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="$ echo 'Lots... of... punctuation, man.' | srgn -d '[[:punct:]]' Lots of punctuation man"><pre>$ <span class="pl-s1"><span class="pl-c1">echo</span> <span class="pl-s"><span class="pl-pds">'</span>Lots... of... punctuation, man.<span class="pl-pds">'</span></span> <span class="pl-k">|</span> srgn -d <span class="pl-s"><span class="pl-pds">'</span>[[:punct:]]<span class="pl-pds">'</span></span></span> <span class="pl-c1">Lots of punctuation man</span></pre></div> </li> </ol> <p dir="auto">Lots of use cases also call for <strong>inverting</strong>, then removing a character class.</p> <p dir="auto"><a href="https://github.com/search?type=code&amp;q=%22tr+-c%22">Query</a></p> <ol dir="auto"> <li> <p dir="auto"><a href="https://github.com/git/git/blob/d6c51973e4a0e889d1a426da08f52b9203fa1df2/t/lib-credential.sh#L542"><code>tr -cd a-z</code></a></p> <p dir="auto">Translates to:</p> <div class="highlight highlight-text-shell-session notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="$ echo 'i RLY love LOWERCASING everything!' | srgn -d '[^[:lower:]]' iloveeverything"><pre>$ <span class="pl-s1"><span class="pl-c1">echo</span> <span class="pl-s"><span class="pl-pds">'</span>i RLY love LOWERCASING everything!<span class="pl-pds">'</span></span> <span class="pl-k">|</span> srgn -d <span class="pl-s"><span class="pl-pds">'</span>[^[:lower:]]<span class="pl-pds">'</span></span></span> <span class="pl-c1">iloveeverything</span></pre></div> </li> <li> <p dir="auto"><a href="https://github.com/gitlabhq/gitlabhq/blob/e74bf51e817ee50e85b1bbdc34f0443d1088fd68/doc/user/project/service_desk/configure.md?plain=1#L553"><code>tr -cd 'a-zA-Z0-9'</code></a></p> <p dir="auto">Translates to:</p> <div class="highlight highlight-text-shell-session notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="$ echo 'All0wed ??? 💥' | srgn -d '[^[:alnum:]]' All0wed"><pre>$ <span class="pl-s1"><span class="pl-c1">echo</span> <span class="pl-s"><span class="pl-pds">'</span>All0wed ??? 💥<span class="pl-pds">'</span></span> <span class="pl-k">|</span> srgn -d <span class="pl-s"><span class="pl-pds">'</span>[^[:alnum:]]<span class="pl-pds">'</span></span></span> <span class="pl-c1">All0wed</span></pre></div> </li> <li> <p dir="auto"><a href="https://github.com/coredns/coredns/blob/b5e6291115d1e60fed561c64d70341b354e69504/Makefile.release#L94"><code>tr -cd '[[:digit:]]'</code></a></p> <p dir="auto">Translates to:</p> <div class="highlight highlight-text-shell-session notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="$ echo '{&quot;id&quot;: 34987, &quot;name&quot;: &quot;Harold&quot;}' | srgn -d '[^[:digit:]]' 34987"><pre>$ <span class="pl-s1"><span class="pl-c1">echo</span> <span class="pl-s"><span class="pl-pds">'</span>{"id": 34987, "name": "Harold"}<span class="pl-pds">'</span></span> <span class="pl-k">|</span> srgn -d <span class="pl-s"><span class="pl-pds">'</span>[^[:digit:]]<span class="pl-pds">'</span></span></span> <span class="pl-c1">34987</span></pre></div> </li> </ol> <div class="markdown-heading" dir="auto"><h4 tabindex="-1" class="heading-element" dir="auto">Remove literal character(s)</h4><a id="user-content-remove-literal-characters" class="anchor" aria-label="Permalink: Remove literal character(s)" href="#remove-literal-characters"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">Identical to replacing them with the empty string.</p> <p dir="auto"><a href="https://github.com/search?q=%22%7C+tr+%22&amp;type=code&amp;ref=advsearch">Query</a></p> <ol dir="auto"> <li> <p dir="auto"><a href="https://github.com/ohmyzsh/ohmyzsh/blob/079dbff2c4f22935a71101c511e2285327d8ab68/themes/gallois.zsh-theme#L82"><code>tr -d "."</code></a></p> <p dir="auto">Translates to:</p> <div class="highlight highlight-text-shell-session notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="$ echo '1632485561.123456' | srgn -d '\.' # Unix timestamp 1632485561123456"><pre>$ <span class="pl-s1"><span class="pl-c1">echo</span> <span class="pl-s"><span class="pl-pds">'</span>1632485561.123456<span class="pl-pds">'</span></span> <span class="pl-k">|</span> srgn -d <span class="pl-s"><span class="pl-pds">'</span>\.<span class="pl-pds">'</span></span> <span class="pl-c"><span class="pl-c">#</span> Unix timestamp</span></span> <span class="pl-c1">1632485561123456</span></pre></div> <p dir="auto">Similar examples are:</p> <ul dir="auto"> <li><a href="https://github.com/jlevy/the-art-of-command-line/blob/6b50745d2e788add2e8f1ed29010e72659a9a074/README.md?plain=1#L22"><code>tr -d '\</code>'`</a></li> <li><a href="https://github.com/hfg-gmuend/openmoji/blob/9782be9d240513a3d609a4bd6f1176f2d7e1b804/helpers/lib/optimize-build.sh#L77"><code>tr -d ' '</code></a></li> <li><a href="https://github.com/PaNOSC-ViNYL/SimEx/blob/0ca295ec57864c0e468eba849d3f44f992c59634/Docker/simex_devel/simex_install.sh#L44"><code>tr -d ' '</code></a></li> </ul> </li> <li> <p dir="auto"><a href="https://github.com/kubernetes/kubernetes/blob/37cf2638c975080232990d2fc2c24d0f40c38074/cluster/gce/util.sh#L1690"><code>tr -d '\r\n'</code></a></p> <p dir="auto">Translates to:</p> <div class="highlight highlight-text-shell-session notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="$ echo -e 'DOS-Style\r\n\r\nLines' | srgn -d '\r\n' DOS-StyleLines"><pre>$ <span class="pl-s1"><span class="pl-c1">echo</span> -e <span class="pl-s"><span class="pl-pds">'</span>DOS-Style\r\n\r\nLines<span class="pl-pds">'</span></span> <span class="pl-k">|</span> srgn -d <span class="pl-s"><span class="pl-pds">'</span>\r\n<span class="pl-pds">'</span></span></span> <span class="pl-c1">DOS-StyleLines</span></pre></div> <p dir="auto">Similar examples are:</p> <ul dir="auto"> <li><a href="https://github.com/mhassan2/splunk-n-box/blob/a721af8b8ae6103a7b274651206d4812d37db398/scripts/viz.sh#L427"><code>tr -d '\r'</code></a></li> <li><a href="https://github.com/Cidaas/cidaas-shopware-connect-plugin/blob/519e21a9a385b26803ec442e2a8b59918a948f77/.gitlab-ci.yml#L43"><code>tr -d '\r'</code></a></li> </ul> </li> </ol> <div class="markdown-heading" dir="auto"><h4 tabindex="-1" class="heading-element" dir="auto">Squeeze whitespace</h4><a id="user-content-squeeze-whitespace" class="anchor" aria-label="Permalink: Squeeze whitespace" href="#squeeze-whitespace"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">Remove repeated whitespace, as it often occurs when slicing and dicing text.</p> <p dir="auto"><a href="https://github.com/search?type=code&amp;q=%22+tr+-s%22">Query</a></p> <ol dir="auto"> <li> <p dir="auto"><a href="https://github.com/ohmyzsh/ohmyzsh/blob/bbda81fe4b338f00bbf7c7f33e6d1b12d067dc05/plugins/alias-finder/alias-finder.plugin.zsh#L26"><code>tr -s '[:space:]'</code></a></p> <p dir="auto">Translates to:</p> <div class="highlight highlight-text-shell-session notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="$ echo 'Lots of space !' | srgn -s '[[:space:]]' # Single space stays Lots of space !"><pre>$ <span class="pl-s1"><span class="pl-c1">echo</span> <span class="pl-s"><span class="pl-pds">'</span>Lots of space !<span class="pl-pds">'</span></span> <span class="pl-k">|</span> srgn -s <span class="pl-s"><span class="pl-pds">'</span>[[:space:]]<span class="pl-pds">'</span></span> <span class="pl-c"><span class="pl-c">#</span> Single space stays</span></span> <span class="pl-c1">Lots of space !</span></pre></div> <p dir="auto">Similar examples are:</p> <ul dir="auto"> <li><a href="https://github.com/facebookresearch/fastText/blob/166ce2c71a497ff81cb62ec151be5b569e1f1be6/.circleci/pull_data.sh#L18"><code>tr -s " "</code></a></li> <li><a href="https://github.com/Atmosphere-NX/Atmosphere/blob/4fe9a89ab8ed958a3e080d7ee11767bef9cb2d57/atmosphere.mk#L11"><code>tr -s [:blank:]</code></a> (<code>blank</code> is <code>\t</code> and space)</li> <li><a href="https://github.com/kovidgoyal/kitty/blob/863adb3e8d8e7229610c6b0e6bc8d48db9becda5/kitty/rc/get_colors.py#L28"><code>tr -s</code></a> (no argument: this will error out; presumably space was meant)</li> <li><a href="https://github.com/google/jax/blob/bf40f75bd59501d66a0e500d255daca3f9f2895e/build/rocm/build_rocm.sh#L65"><code>tr -s ' '</code></a></li> <li><a href="https://github.com/chromium/chromium/blob/ffed2601d91f4413ca4672a6027c2c05d49df815/docs/linux/minidump_to_core.md?plain=1#L111"><code>tr -s ' '</code></a></li> <li><a href="https://github.com/ceph/ceph/blob/6c387554d8e104727b3e448a1def4f1991be1ff7/src/stop.sh#L188"><code>tr -s '[:space:]'</code></a></li> <li><a href="https://github.com/PyO3/pyo3/blob/8f4a26a66ecee4cfa473ada8cb27a57c4533d04f/.netlify/build.sh#L7"><code>tr -s ' '</code></a></li> </ul> </li> <li> <p dir="auto"><a href="https://github.com/doocs/leetcode/blob/4f89e08ed45f7d5e1047767071001073ffe4d32b/solution/0100-0199/0192.Word%20Frequency/README.md?plain=1#L54"><code>tr -s ' ' '\n'</code></a> (squeeze, <em>then replace</em>)</p> <p dir="auto">Translates to:</p> <div class="highlight highlight-text-shell-session notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="$ echo '1969-12-28 13:37:45Z' | srgn -s ' ' 'T' # ISO8601 1969-12-28T13:37:45Z"><pre>$ <span class="pl-s1"><span class="pl-c1">echo</span> <span class="pl-s"><span class="pl-pds">'</span>1969-12-28 13:37:45Z<span class="pl-pds">'</span></span> <span class="pl-k">|</span> srgn -s <span class="pl-s"><span class="pl-pds">'</span> <span class="pl-pds">'</span></span> <span class="pl-s"><span class="pl-pds">'</span>T<span class="pl-pds">'</span></span> <span class="pl-c"><span class="pl-c">#</span> ISO8601</span></span> <span class="pl-c1">1969-12-28T13:37:45Z</span></pre></div> </li> <li> <p dir="auto"><a href="https://github.com/cockroachdb/cockroach/blob/985662236d7bf273b93a7b5e32def8e2d1043640/docs/generated/http/BUILD.bazel#L76"><code>tr -s '[:blank:]' ':'</code></a></p> <p dir="auto">Translates to:</p> <div class="highlight highlight-text-shell-session notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="$ echo -e '/usr/local/sbin \t /usr/local/bin' | srgn -s '[[:blank:]]' ':' /usr/local/sbin:/usr/local/bin"><pre>$ <span class="pl-s1"><span class="pl-c1">echo</span> -e <span class="pl-s"><span class="pl-pds">'</span>/usr/local/sbin \t /usr/local/bin<span class="pl-pds">'</span></span> <span class="pl-k">|</span> srgn -s <span class="pl-s"><span class="pl-pds">'</span>[[:blank:]]<span class="pl-pds">'</span></span> <span class="pl-s"><span class="pl-pds">'</span>:<span class="pl-pds">'</span></span></span> <span class="pl-c1">/usr/local/sbin:/usr/local/bin</span></pre></div> </li> </ol> <div class="markdown-heading" dir="auto"><h4 tabindex="-1" class="heading-element" dir="auto">Changing character casing</h4><a id="user-content-changing-character-casing" class="anchor" aria-label="Permalink: Changing character casing" href="#changing-character-casing"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">A straightforward use case. Upper- and lowercase are often used.</p> <p dir="auto"><a href="https://github.com/search?q=%22%7C+tr++%22+%28path%3A*.sh+OR+path%3A*.yml+OR+path%3A*.yaml%29&amp;type=code&amp;ref=advsearch">Query</a></p> <ol dir="auto"> <li> <p dir="auto"><a href="https://github.com/golang/go/blob/a742ae493ff59a71131706500ce53f85477897f0/src/encoding/xml/xml.go#L1874"><code>tr A-Z a-z</code></a> (lowercasing)</p> <p dir="auto">Translates to:</p> <div class="highlight highlight-text-shell-session notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="$ echo 'WHY ARE WE YELLING?' | srgn --lower why are we yelling?"><pre>$ <span class="pl-s1"><span class="pl-c1">echo</span> <span class="pl-s"><span class="pl-pds">'</span>WHY ARE WE YELLING?<span class="pl-pds">'</span></span> <span class="pl-k">|</span> srgn --lower</span> <span class="pl-c1">why are we yelling?</span></pre></div> <p dir="auto">Notice the default scope. It can be refined to lowercase only long words, for example:</p> <div class="highlight highlight-text-shell-session notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="$ echo 'WHY ARE WE YELLING?' | srgn --lower '\b\w{,3}\b' why are we YELLING?"><pre>$ <span class="pl-s1"><span class="pl-c1">echo</span> <span class="pl-s"><span class="pl-pds">'</span>WHY ARE WE YELLING?<span class="pl-pds">'</span></span> <span class="pl-k">|</span> srgn --lower <span class="pl-s"><span class="pl-pds">'</span>\b\w{,3}\b<span class="pl-pds">'</span></span></span> <span class="pl-c1">why are we YELLING?</span></pre></div> <p dir="auto">Similar examples are:</p> <ul dir="auto"> <li><a href="https://github.com/nwchemgit/nwchem/blob/aad4ecd5657055b085b57115314e4d56271ad749/travis/guess_simd.sh#L13"><code>tr 'A-Z' 'a-z'</code></a></li> <li><a href="https://github.com/XIMDEX/xcms/blob/4dd3c055de5cb0eebed28f1e9da87ed731a44a99/bin/lib/util.sh#L47"><code>tr '[A-Z]' '[a-z]'</code></a></li> <li><a href="https://github.com/varunjampani/video_prop_networks/blob/4f4a39842bd9112932abe40bad746c174a242bf6/lib/davis/configure.sh#L30"><code>tr '[A-Z]' '[a-z]'</code></a></li> <li><a href="https://github.com/PaNOSC-ViNYL/SimEx/blob/0ca295ec57864c0e468eba849d3f44f992c59634/Docker/simex_devel/simex_install.sh#L44"><code>tr '[:upper:]' '[:lower:]'</code></a></li> <li><a href="https://github.com/tst-labs/esocial/blob/b678f59bba883a63e91be79d7f2853a57156cf7b/src/esocial-esquemas/generate-java-from-xsd.sh#L11"><code>tr "[:upper:]" "[:lower:]"</code></a></li> </ul> </li> <li> <p dir="auto"><a href="https://github.com/henrikpersson/potatis/blob/63feb9de28781e4e9c62bd091bd335b87b474cb1/nes-android/install.sh#L10"><code>tr '[a-z]' '[A-Z]'</code></a> (uppercasing)</p> <p dir="auto">Translates to:</p> <div class="highlight highlight-text-shell-session notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="$ echo 'why are we not yelling?' | srgn --upper WHY ARE WE NOT YELLING?"><pre>$ <span class="pl-s1"><span class="pl-c1">echo</span> <span class="pl-s"><span class="pl-pds">'</span>why are we not yelling?<span class="pl-pds">'</span></span> <span class="pl-k">|</span> srgn --upper</span> <span class="pl-c1">WHY ARE WE NOT YELLING?</span></pre></div> <p dir="auto">Similar examples are:</p> <ul dir="auto"> <li><a href="https://github.com/basho/riak-zabbix/blob/423e21c31821a345bf59ec4b2baba06d532a7f30/build_templates.sh#L40"><code>tr '[a-z]' '[A-Z]'</code></a></li> <li><a href="https://github.com/Fivium/Oracle-Backup-and-Sync/blob/036aace4a8eb45ab7e6e226ddceb08f35c46b9f3/dbsync/scripts/dbsync.sh#L122"><code>tr "[:lower:]" "[:upper:]"</code></a></li> <li><a href="https://github.com/jorgeazevedo/xenomai-lab/blob/a2ce85a86f37fd9762905026ce4a1542684c714b/data/.xenomailab/blocks/template/rename.sh#L5"><code>tr "[:lower:]" "[:upper:]"</code></a></li> </ul> </li> </ol> <div class="markdown-heading" dir="auto"><h2 tabindex="-1" class="heading-element" dir="auto">License</h2><a id="user-content-license" class="anchor" aria-label="Permalink: License" href="#license"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">This project is licensed under either of</p> <ul dir="auto"> <li>Apache License, Version 2.0, (<a href="/alexpovel/srgn/blob/main/LICENSE-APACHE">LICENSE-APACHE</a> or <a href="http://www.apache.org/licenses/LICENSE-2.0" rel="nofollow">http://www.apache.org/licenses/LICENSE-2.0</a>)</li> <li>MIT license (<a href="/alexpovel/srgn/blob/main/LICENSE-MIT">LICENSE-MIT</a> or <a href="http://opensource.org/licenses/MIT" rel="nofollow">http://opensource.org/licenses/MIT</a>)</li> </ul> <p dir="auto">at your option.</p> <section data-footnotes="" class="footnotes"><h2 id="footnote-label" class="sr-only" dir="auto">Footnotes</h2> <ol dir="auto"> <li id="user-content-fn-3-b30ce13ed678ccbd6287a3f5e19f11b5"> <p dir="auto">With zero actions and no language scoping provided, <code>srgn</code> becomes 'useless', and other tools such as ripgrep are much more suitable. That's why an error is emitted and input is returned unchanged. <a href="#user-content-fnref-3-b30ce13ed678ccbd6287a3f5e19f11b5" data-footnote-backref="" aria-label="Back to reference 1" class="data-footnote-backref">↩</a></p> </li> <li id="user-content-fn-1-b30ce13ed678ccbd6287a3f5e19f11b5"> <p dir="auto">Currently, reversibility is not possible for any other action. For example, lowercasing is not the inverse of uppercasing. Information is lost, so it cannot be undone. Structure (imagine mixed case) was lost. Something something entropy... <a href="#user-content-fnref-1-b30ce13ed678ccbd6287a3f5e19f11b5" data-footnote-backref="" aria-label="Back to reference 2" class="data-footnote-backref">↩</a></p> </li> <li id="user-content-fn-2-b30ce13ed678ccbd6287a3f5e19f11b5"> <p dir="auto">Why is such a bizzare, unrelated feature included? As usual, historical reasons. The original, core version of <code>srgn</code> was merely a Rust rewrite of <a href="https://github.com/alexpovel/betterletter">a previous, existing tool</a>, which was <em>only</em> concerned with the <em>German</em> feature. <code>srgn</code> then grew from there. <a href="#user-content-fnref-2-b30ce13ed678ccbd6287a3f5e19f11b5" data-footnote-backref="" aria-label="Back to reference 3" class="data-footnote-backref">↩</a></p> </li> <li id="user-content-fn-4-b30ce13ed678ccbd6287a3f5e19f11b5"> <p dir="auto">Combined with <code>--fail-any</code>, the invocation could be used to fail if any <code>unsafe</code> code is found, like a low-budget linter. In reality, for this case, just use <a href="https://doc.rust-lang.org/nomicon/safe-unsafe-meaning.html"><code>#![forbid(unsafe_code)]</code></a> though. <a href="#user-content-fnref-4-b30ce13ed678ccbd6287a3f5e19f11b5" data-footnote-backref="" aria-label="Back to reference 4" class="data-footnote-backref">↩</a></p> </li> </ol> </section> </article></div></div></div></div></div> <!-- --> <!-- --> <script type="application/json" id="__PRIMER_DATA_:R0:__">{"resolvedServerColorMode":"day"}</script></div> </react-partial> <input type="hidden" data-csrf="true" value="kgkWnF1vYMPtIxGOh0N1dEJ+g+MjUMmE+c6nYaYQxyJ2kLJFCQmFv83NPiSX1rWzqPkvsfcz9NIWuqKtyIiA2A==" /> </div> <div data-view-component="true" class="Layout-sidebar"> <div class="BorderGrid about-margin" data-pjax> <div class="BorderGrid-row"> <div class="BorderGrid-cell"> <div class="hide-sm hide-md"> <h2 class="mb-3 h4">About</h2> <p class="f4 my-3"> A grep-like tool which understands source code syntax and allows for manipulation in addition to search </p> <div class="my-3 d-flex flex-items-center"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-link flex-shrink-0 mr-2"> <path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path> </svg> <span class="flex-auto min-width-0 css-truncate css-truncate-target width-fit"> <a title="https://crates.io/crates/srgn/" role="link" target="_blank" rel="noopener noreferrer nofollow" class="text-bold" href="https://crates.io/crates/srgn/">crates.io/crates/srgn/</a> </span> </div> <h3 class="sr-only">Topics</h3> <div class="my-3"> <div class="f6"> <a href="/topics/python" title="Topic: python" data-view-component="true" class="topic-tag topic-tag-link"> python </a> <a href="/topics/c" title="Topic: c" data-view-component="true" class="topic-tag topic-tag-link"> c </a> <a href="/topics/go" title="Topic: go" data-view-component="true" class="topic-tag topic-tag-link"> go </a> <a href="/topics/rust" title="Topic: rust" data-view-component="true" class="topic-tag topic-tag-link"> rust </a> <a href="/topics/cli" title="Topic: cli" data-view-component="true" class="topic-tag topic-tag-link"> cli </a> <a href="/topics/tree-sitter" title="Topic: tree-sitter" data-view-component="true" class="topic-tag topic-tag-link"> tree-sitter </a> <a href="/topics/typescript" title="Topic: typescript" data-view-component="true" class="topic-tag topic-tag-link"> typescript </a> <a href="/topics/csharp" title="Topic: csharp" data-view-component="true" class="topic-tag topic-tag-link"> csharp </a> <a href="/topics/regex" title="Topic: regex" data-view-component="true" class="topic-tag topic-tag-link"> regex </a> <a href="/topics/clang" title="Topic: clang" data-view-component="true" class="topic-tag topic-tag-link"> clang </a> <a href="/topics/rust-lang" title="Topic: rust-lang" data-view-component="true" class="topic-tag topic-tag-link"> rust-lang </a> <a href="/topics/hcl" title="Topic: hcl" data-view-component="true" class="topic-tag topic-tag-link"> hcl </a> <a href="/topics/tr" title="Topic: tr" data-view-component="true" class="topic-tag topic-tag-link"> tr </a> <a href="/topics/sed" title="Topic: sed" data-view-component="true" class="topic-tag topic-tag-link"> sed </a> <a href="/topics/grep" title="Topic: grep" data-view-component="true" class="topic-tag topic-tag-link"> grep </a> <a href="/topics/hacktoberfest" title="Topic: hacktoberfest" data-view-component="true" class="topic-tag topic-tag-link"> hacktoberfest </a> <a href="/topics/abstract-syntax-tree" title="Topic: abstract-syntax-tree" data-view-component="true" class="topic-tag topic-tag-link"> abstract-syntax-tree </a> </div> </div> <h3 class="sr-only">Resources</h3> <div class="mt-2"> <a class="Link--muted" data-analytics-event="{&quot;category&quot;:&quot;Repository Overview&quot;,&quot;action&quot;:&quot;click&quot;,&quot;label&quot;:&quot;location:sidebar;file:readme&quot;}" href="#readme-ov-file"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-book mr-2"> <path d="M0 1.75A.75.75 0 0 1 .75 1h4.253c1.227 0 2.317.59 3 1.501A3.743 3.743 0 0 1 11.006 1h4.245a.75.75 0 0 1 .75.75v10.5a.75.75 0 0 1-.75.75h-4.507a2.25 2.25 0 0 0-1.591.659l-.622.621a.75.75 0 0 1-1.06 0l-.622-.621A2.25 2.25 0 0 0 5.258 13H.75a.75.75 0 0 1-.75-.75Zm7.251 10.324.004-5.073-.002-2.253A2.25 2.25 0 0 0 5.003 2.5H1.5v9h3.757a3.75 3.75 0 0 1 1.994.574ZM8.755 4.75l-.004 7.322a3.752 3.752 0 0 1 1.992-.572H14.5v-9h-3.495a2.25 2.25 0 0 0-2.25 2.25Z"></path> </svg> Readme </a> </div> <h3 class="sr-only">License</h3> <details class="details-reset details-overlay details-overlay-dark lh-default color-fg-default d-inline mt-2"> <summary class="Link--muted" > <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-law mr-2"> <path d="M8.75.75V2h.985c.304 0 .603.08.867.231l1.29.736c.038.022.08.033.124.033h2.234a.75.75 0 0 1 0 1.5h-.427l2.111 4.692a.75.75 0 0 1-.154.838l-.53-.53.529.531-.001.002-.002.002-.006.006-.006.005-.01.01-.045.04c-.21.176-.441.327-.686.45C14.556 10.78 13.88 11 13 11a4.498 4.498 0 0 1-2.023-.454 3.544 3.544 0 0 1-.686-.45l-.045-.04-.016-.015-.006-.006-.004-.004v-.001a.75.75 0 0 1-.154-.838L12.178 4.5h-.162c-.305 0-.604-.079-.868-.231l-1.29-.736a.245.245 0 0 0-.124-.033H8.75V13h2.5a.75.75 0 0 1 0 1.5h-6.5a.75.75 0 0 1 0-1.5h2.5V3.5h-.984a.245.245 0 0 0-.124.033l-1.289.737c-.265.15-.564.23-.869.23h-.162l2.112 4.692a.75.75 0 0 1-.154.838l-.53-.53.529.531-.001.002-.002.002-.006.006-.016.015-.045.04c-.21.176-.441.327-.686.45C4.556 10.78 3.88 11 3 11a4.498 4.498 0 0 1-2.023-.454 3.544 3.544 0 0 1-.686-.45l-.045-.04-.016-.015-.006-.006-.004-.004v-.001a.75.75 0 0 1-.154-.838L2.178 4.5H1.75a.75.75 0 0 1 0-1.5h2.234a.249.249 0 0 0 .125-.033l1.288-.737c.265-.15.564-.23.869-.23h.984V.75a.75.75 0 0 1 1.5 0Zm2.945 8.477c.285.135.718.273 1.305.273s1.02-.138 1.305-.273L13 6.327Zm-10 0c.285.135.718.273 1.305.273s1.02-.138 1.305-.273L3 6.327Z"></path> </svg> Apache-2.0, MIT licenses found </summary> <details-dialog class="Box Box--overlay d-flex flex-column anim-fade-in fast" aria-label="Licenses found"> <div class="Box-header"> <button type="button" class="Box-btn-octicon btn-octicon float-right" data-action="toggle" data-close-dialog aria-label="Close licenses dialog"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-x"> <path d="M3.72 3.72a.75.75 0 0 1 1.06 0L8 6.94l3.22-3.22a.749.749 0 0 1 1.275.326.749.749 0 0 1-.215.734L9.06 8l3.22 3.22a.749.749 0 0 1-.326 1.275.749.749 0 0 1-.734-.215L8 9.06l-3.22 3.22a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042L6.94 8 3.72 4.78a.75.75 0 0 1 0-1.06Z"></path> </svg> </button> <h3 class="Box-title">Licenses found</h3> </div> <a class="Link--primary no-underline" aria-label="Apache-2.0 license" href="/alexpovel/srgn/blob/main/./LICENSE-APACHE"> <div class="Box-row Box-row--hover-gray border-top rounded-0"> <div class="text-bold">Apache-2.0</div> <span class="f6 color-fg-muted">LICENSE-APACHE</span> </div> </a> <a class="Link--primary no-underline" aria-label="MIT license" href="/alexpovel/srgn/blob/main/./LICENSE-MIT"> <div class="Box-row Box-row--hover-gray border-top rounded-0"> <div class="text-bold">MIT</div> <span class="f6 color-fg-muted">LICENSE-MIT</span> </div> </a> </details-dialog> </details> <include-fragment src="/alexpovel/srgn/hovercards/citation/sidebar_partial?tree_name=main"> </include-fragment> <div class="mt-2"> <a href="/alexpovel/srgn/activity" data-view-component="true" class="Link Link--muted"><svg text="gray" aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-pulse mr-2"> <path d="M6 2c.306 0 .582.187.696.471L10 10.731l1.304-3.26A.751.751 0 0 1 12 7h3.25a.75.75 0 0 1 0 1.5h-2.742l-1.812 4.528a.751.751 0 0 1-1.392 0L6 4.77 4.696 8.03A.75.75 0 0 1 4 8.5H.75a.75.75 0 0 1 0-1.5h2.742l1.812-4.529A.751.751 0 0 1 6 2Z"></path> </svg> <span class="color-fg-muted">Activity</span></a> </div> <h3 class="sr-only">Stars</h3> <div class="mt-2"> <a href="/alexpovel/srgn/stargazers" data-view-component="true" class="Link Link--muted"><svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-star mr-2"> <path d="M8 .25a.75.75 0 0 1 .673.418l1.882 3.815 4.21.612a.75.75 0 0 1 .416 1.279l-3.046 2.97.719 4.192a.751.751 0 0 1-1.088.791L8 12.347l-3.766 1.98a.75.75 0 0 1-1.088-.79l.72-4.194L.818 6.374a.75.75 0 0 1 .416-1.28l4.21-.611L7.327.668A.75.75 0 0 1 8 .25Zm0 2.445L6.615 5.5a.75.75 0 0 1-.564.41l-3.097.45 2.24 2.184a.75.75 0 0 1 .216.664l-.528 3.084 2.769-1.456a.75.75 0 0 1 .698 0l2.77 1.456-.53-3.084a.75.75 0 0 1 .216-.664l2.24-2.183-3.096-.45a.75.75 0 0 1-.564-.41L8 2.694Z"></path> </svg> <strong>722</strong> stars</a> </div> <h3 class="sr-only">Watchers</h3> <div class="mt-2"> <a href="/alexpovel/srgn/watchers" data-view-component="true" class="Link Link--muted"><svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-eye mr-2"> <path d="M8 2c1.981 0 3.671.992 4.933 2.078 1.27 1.091 2.187 2.345 2.637 3.023a1.62 1.62 0 0 1 0 1.798c-.45.678-1.367 1.932-2.637 3.023C11.67 13.008 9.981 14 8 14c-1.981 0-3.671-.992-4.933-2.078C1.797 10.83.88 9.576.43 8.898a1.62 1.62 0 0 1 0-1.798c.45-.677 1.367-1.931 2.637-3.022C4.33 2.992 6.019 2 8 2ZM1.679 7.932a.12.12 0 0 0 0 .136c.411.622 1.241 1.75 2.366 2.717C5.176 11.758 6.527 12.5 8 12.5c1.473 0 2.825-.742 3.955-1.715 1.124-.967 1.954-2.096 2.366-2.717a.12.12 0 0 0 0-.136c-.412-.621-1.242-1.75-2.366-2.717C10.824 4.242 9.473 3.5 8 3.5c-1.473 0-2.825.742-3.955 1.715-1.124.967-1.954 2.096-2.366 2.717ZM8 10a2 2 0 1 1-.001-3.999A2 2 0 0 1 8 10Z"></path> </svg> <strong>6</strong> watching</a> </div> <h3 class="sr-only">Forks</h3> <div class="mt-2"> <a href="/alexpovel/srgn/forks" data-view-component="true" class="Link Link--muted"><svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-repo-forked mr-2"> <path d="M5 5.372v.878c0 .414.336.75.75.75h4.5a.75.75 0 0 0 .75-.75v-.878a2.25 2.25 0 1 1 1.5 0v.878a2.25 2.25 0 0 1-2.25 2.25h-1.5v2.128a2.251 2.251 0 1 1-1.5 0V8.5h-1.5A2.25 2.25 0 0 1 3.5 6.25v-.878a2.25 2.25 0 1 1 1.5 0ZM5 3.25a.75.75 0 1 0-1.5 0 .75.75 0 0 0 1.5 0Zm6.75.75a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5Zm-3 8.75a.75.75 0 1 0-1.5 0 .75.75 0 0 0 1.5 0Z"></path> </svg> <strong>9</strong> forks</a> </div> <div class="mt-2"> <a class="Link--muted" href="/contact/report-content?content_url=https%3A%2F%2Fgithub.com%2Falexpovel%2Fsrgn&amp;report=alexpovel+%28user%29"> Report repository </a> </div> </div> </div> </div> <div class="BorderGrid-row"> <div class="BorderGrid-cell"> <h2 class="h4 mb-3" data-pjax="#repo-content-pjax-container" data-turbo-frame="repo-content-turbo-frame"> <a href="/alexpovel/srgn/releases" data-view-component="true" class="Link--primary no-underline Link">Releases <span title="28" data-view-component="true" class="Counter">28</span></a></h2> <a class="Link--primary d-flex no-underline" data-pjax="#repo-content-pjax-container" data-turbo-frame="repo-content-turbo-frame" href="/alexpovel/srgn/releases/tag/srgn-v0.13.6"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-tag flex-shrink-0 mt-1 color-fg-success"> <path d="M1 7.775V2.75C1 1.784 1.784 1 2.75 1h5.025c.464 0 .91.184 1.238.513l6.25 6.25a1.75 1.75 0 0 1 0 2.474l-5.026 5.026a1.75 1.75 0 0 1-2.474 0l-6.25-6.25A1.752 1.752 0 0 1 1 7.775Zm1.5 0c0 .066.026.13.073.177l6.25 6.25a.25.25 0 0 0 .354 0l5.025-5.025a.25.25 0 0 0 0-.354l-6.25-6.25a.25.25 0 0 0-.177-.073H2.75a.25.25 0 0 0-.25.25ZM6 5a1 1 0 1 1 0 2 1 1 0 0 1 0-2Z"></path> </svg> <div class="ml-2 min-width-0"> <div class="d-flex"> <span class="css-truncate css-truncate-target text-bold mr-2" style="max-width: none;">srgn: v0.13.6</span> <span title="Label: Latest" data-view-component="true" class="Label Label--success flex-shrink-0"> Latest </span> </div> <div class="text-small color-fg-muted"><relative-time datetime="2025-03-23T19:10:25Z" class="no-wrap">Mar 23, 2025</relative-time></div> </div> </a> <div data-view-component="true" class="mt-3"> <a text="small" data-pjax="#repo-content-pjax-container" data-turbo-frame="repo-content-turbo-frame" href="/alexpovel/srgn/releases" data-view-component="true" class="Link">+ 27 releases</a></div> </div> </div> <div class="BorderGrid-row" hidden> <div class="BorderGrid-cell"> <include-fragment src="/alexpovel/srgn/used_by_list" accept="text/fragment+html"> </include-fragment> </div> </div> <div class="BorderGrid-row"> <div class="BorderGrid-cell"> <h2 class="h4 mb-3"> <a href="/alexpovel/srgn/graphs/contributors" data-view-component="true" class="Link--primary no-underline Link d-flex flex-items-center">Contributors <span title="9" data-view-component="true" class="Counter ml-1">9</span></a></h2> <include-fragment src="/alexpovel/srgn/contributors_list?count=9&amp;current_repository=srgn&amp;items_to_show=9" aria-busy="true" aria-label="Loading contributors"> <ul class="list-style-none d-flex flex-wrap mb-n2"> <li class="mb-2 "> <div class="Skeleton avatar avatar-user mr-2" style="width:32px;height:32px;"></div> </li> <li class="mb-2 "> <div class="Skeleton avatar avatar-user mr-2" style="width:32px;height:32px;"></div> </li> <li class="mb-2 "> <div class="Skeleton avatar avatar-user mr-2" style="width:32px;height:32px;"></div> </li> <li class="mb-2 "> <div class="Skeleton avatar avatar-user mr-2" style="width:32px;height:32px;"></div> </li> <li class="mb-2 "> <div class="Skeleton avatar avatar-user mr-2" style="width:32px;height:32px;"></div> </li> <li class="mb-2 "> <div class="Skeleton avatar avatar-user mr-2" style="width:32px;height:32px;"></div> </li> <li class="mb-2 "> <div class="Skeleton avatar avatar-user mr-2" style="width:32px;height:32px;"></div> </li> <li class="mb-2 "> <div class="Skeleton avatar avatar-user mr-2" style="width:32px;height:32px;"></div> </li> <li class="mb-2 "> <div class="Skeleton avatar avatar-user mr-2" style="width:32px;height:32px;"></div> </li> </ul> </include-fragment> </div> </div> <div class="BorderGrid-row"> <div class="BorderGrid-cell"> <h2 class="h4 mb-3">Languages</h2> <div class="mb-2"> <span data-view-component="true" class="Progress"> <span style="background-color:#dea584 !important;;width: 91.7%;" itemprop="keywords" data-view-component="true" class="Progress-item color-bg-success-emphasis"></span> <span style="background-color:#3572A5 !important;;width: 2.1%;" itemprop="keywords" data-view-component="true" class="Progress-item color-bg-success-emphasis"></span> <span style="background-color:#3178c6 !important;;width: 1.6%;" itemprop="keywords" data-view-component="true" class="Progress-item color-bg-success-emphasis"></span> <span style="background-color:#178600 !important;;width: 1.6%;" itemprop="keywords" data-view-component="true" class="Progress-item color-bg-success-emphasis"></span> <span style="background-color:#00ADD8 !important;;width: 1.6%;" itemprop="keywords" data-view-component="true" class="Progress-item color-bg-success-emphasis"></span> <span style="background-color:#844FBA !important;;width: 0.9%;" itemprop="keywords" data-view-component="true" class="Progress-item color-bg-success-emphasis"></span> <span style="background-color:#ededed !important;;width: 0.5%;" itemprop="keywords" data-view-component="true" class="Progress-item color-bg-success-emphasis"></span> </span></div> <ul class="list-style-none"> <li class="d-inline"> <a class="d-inline-flex flex-items-center flex-nowrap Link--secondary no-underline text-small mr-3" href="/alexpovel/srgn/search?l=rust" data-ga-click="Repository, language stats search click, location:repo overview"> <svg style="color:#dea584;" aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-dot-fill mr-2"> <path d="M8 4a4 4 0 1 1 0 8 4 4 0 0 1 0-8Z"></path> </svg> <span class="color-fg-default text-bold mr-1">Rust</span> <span>91.7%</span> </a> </li> <li class="d-inline"> <a class="d-inline-flex flex-items-center flex-nowrap Link--secondary no-underline text-small mr-3" href="/alexpovel/srgn/search?l=python" data-ga-click="Repository, language stats search click, location:repo overview"> <svg style="color:#3572A5;" aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-dot-fill mr-2"> <path d="M8 4a4 4 0 1 1 0 8 4 4 0 0 1 0-8Z"></path> </svg> <span class="color-fg-default text-bold mr-1">Python</span> <span>2.1%</span> </a> </li> <li class="d-inline"> <a class="d-inline-flex flex-items-center flex-nowrap Link--secondary no-underline text-small mr-3" href="/alexpovel/srgn/search?l=typescript" data-ga-click="Repository, language stats search click, location:repo overview"> <svg style="color:#3178c6;" aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-dot-fill mr-2"> <path d="M8 4a4 4 0 1 1 0 8 4 4 0 0 1 0-8Z"></path> </svg> <span class="color-fg-default text-bold mr-1">TypeScript</span> <span>1.6%</span> </a> </li> <li class="d-inline"> <a class="d-inline-flex flex-items-center flex-nowrap Link--secondary no-underline text-small mr-3" href="/alexpovel/srgn/search?l=c%23" data-ga-click="Repository, language stats search click, location:repo overview"> <svg style="color:#178600;" aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-dot-fill mr-2"> <path d="M8 4a4 4 0 1 1 0 8 4 4 0 0 1 0-8Z"></path> </svg> <span class="color-fg-default text-bold mr-1">C#</span> <span>1.6%</span> </a> </li> <li class="d-inline"> <a class="d-inline-flex flex-items-center flex-nowrap Link--secondary no-underline text-small mr-3" href="/alexpovel/srgn/search?l=go" data-ga-click="Repository, language stats search click, location:repo overview"> <svg style="color:#00ADD8;" aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-dot-fill mr-2"> <path d="M8 4a4 4 0 1 1 0 8 4 4 0 0 1 0-8Z"></path> </svg> <span class="color-fg-default text-bold mr-1">Go</span> <span>1.6%</span> </a> </li> <li class="d-inline"> <a class="d-inline-flex flex-items-center flex-nowrap Link--secondary no-underline text-small mr-3" href="/alexpovel/srgn/search?l=hcl" data-ga-click="Repository, language stats search click, location:repo overview"> <svg style="color:#844FBA;" aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-dot-fill mr-2"> <path d="M8 4a4 4 0 1 1 0 8 4 4 0 0 1 0-8Z"></path> </svg> <span class="color-fg-default text-bold mr-1">HCL</span> <span>0.9%</span> </a> </li> <li class="d-inline"> <span class="d-inline-flex flex-items-center flex-nowrap text-small mr-3"> <svg style="color:#ededed;" aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-dot-fill mr-2"> <path d="M8 4a4 4 0 1 1 0 8 4 4 0 0 1 0-8Z"></path> </svg> <span class="color-fg-default text-bold mr-1">Other</span> <span>0.5%</span> </span> </li> </ul> </div> </div> </div> </div> </div></div> </div> </div> </turbo-frame> </main> </div> </div> <footer class="footer pt-8 pb-6 f6 color-fg-muted p-responsive" role="contentinfo" > <h2 class='sr-only'>Footer</h2> <div class="d-flex flex-justify-center flex-items-center flex-column-reverse flex-lg-row flex-wrap flex-lg-nowrap"> <div class="d-flex flex-items-center flex-shrink-0 mx-2"> <a aria-label="Homepage" title="GitHub" class="footer-octicon mr-2" href="https://github.com"> <svg aria-hidden="true" height="24" viewBox="0 0 24 24" version="1.1" width="24" data-view-component="true" class="octicon octicon-mark-github"> <path d="M12 1C5.9225 1 1 5.9225 1 12C1 16.8675 4.14875 20.9787 8.52125 22.4362C9.07125 22.5325 9.2775 22.2025 9.2775 21.9137C9.2775 21.6525 9.26375 20.7862 9.26375 19.865C6.5 20.3737 5.785 19.1912 5.565 18.5725C5.44125 18.2562 4.905 17.28 4.4375 17.0187C4.0525 16.8125 3.5025 16.3037 4.42375 16.29C5.29 16.2762 5.90875 17.0875 6.115 17.4175C7.105 19.0812 8.68625 18.6137 9.31875 18.325C9.415 17.61 9.70375 17.1287 10.02 16.8537C7.5725 16.5787 5.015 15.63 5.015 11.4225C5.015 10.2262 5.44125 9.23625 6.1425 8.46625C6.0325 8.19125 5.6475 7.06375 6.2525 5.55125C6.2525 5.55125 7.17375 5.2625 9.2775 6.67875C10.1575 6.43125 11.0925 6.3075 12.0275 6.3075C12.9625 6.3075 13.8975 6.43125 14.7775 6.67875C16.8813 5.24875 17.8025 5.55125 17.8025 5.55125C18.4075 7.06375 18.0225 8.19125 17.9125 8.46625C18.6138 9.23625 19.04 10.2125 19.04 11.4225C19.04 15.6437 16.4688 16.5787 14.0213 16.8537C14.42 17.1975 14.7638 17.8575 14.7638 18.8887C14.7638 20.36 14.75 21.5425 14.75 21.9137C14.75 22.2025 14.9563 22.5462 15.5063 22.4362C19.8513 20.9787 23 16.8537 23 12C23 5.9225 18.0775 1 12 1Z"></path> </svg> </a> <span> &copy; 2025 GitHub,&nbsp;Inc. </span> </div> <nav aria-label="Footer"> <h3 class="sr-only" id="sr-footer-heading">Footer navigation</h3> <ul class="list-style-none d-flex flex-justify-center flex-wrap mb-2 mb-lg-0" aria-labelledby="sr-footer-heading"> <li class="mx-2"> <a data-analytics-event="{&quot;category&quot;:&quot;Footer&quot;,&quot;action&quot;:&quot;go to Terms&quot;,&quot;label&quot;:&quot;text:terms&quot;}" href="https://docs.github.com/site-policy/github-terms/github-terms-of-service" data-view-component="true" class="Link--secondary Link">Terms</a> </li> <li class="mx-2"> <a data-analytics-event="{&quot;category&quot;:&quot;Footer&quot;,&quot;action&quot;:&quot;go to privacy&quot;,&quot;label&quot;:&quot;text:privacy&quot;}" href="https://docs.github.com/site-policy/privacy-policies/github-privacy-statement" data-view-component="true" class="Link--secondary Link">Privacy</a> </li> <li class="mx-2"> <a data-analytics-event="{&quot;category&quot;:&quot;Footer&quot;,&quot;action&quot;:&quot;go to security&quot;,&quot;label&quot;:&quot;text:security&quot;}" href="https://github.com/security" data-view-component="true" class="Link--secondary Link">Security</a> </li> <li class="mx-2"> <a data-analytics-event="{&quot;category&quot;:&quot;Footer&quot;,&quot;action&quot;:&quot;go to status&quot;,&quot;label&quot;:&quot;text:status&quot;}" href="https://www.githubstatus.com/" data-view-component="true" class="Link--secondary Link">Status</a> </li> <li class="mx-2"> <a data-analytics-event="{&quot;category&quot;:&quot;Footer&quot;,&quot;action&quot;:&quot;go to docs&quot;,&quot;label&quot;:&quot;text:docs&quot;}" href="https://docs.github.com/" data-view-component="true" class="Link--secondary Link">Docs</a> </li> <li class="mx-2"> <a data-analytics-event="{&quot;category&quot;:&quot;Footer&quot;,&quot;action&quot;:&quot;go to contact&quot;,&quot;label&quot;:&quot;text:contact&quot;}" href="https://support.github.com?tags=dotcom-footer" data-view-component="true" class="Link--secondary Link">Contact</a> </li> <li class="mx-2" > <cookie-consent-link> <button type="button" class="Link--secondary underline-on-hover border-0 p-0 color-bg-transparent" data-action="click:cookie-consent-link#showConsentManagement" data-analytics-event="{&quot;location&quot;:&quot;footer&quot;,&quot;action&quot;:&quot;cookies&quot;,&quot;context&quot;:&quot;subfooter&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;label&quot;:&quot;cookies_link_subfooter_footer&quot;}" > Manage cookies </button> </cookie-consent-link> </li> <li class="mx-2"> <cookie-consent-link> <button type="button" class="Link--secondary underline-on-hover border-0 p-0 color-bg-transparent" data-action="click:cookie-consent-link#showConsentManagement" data-analytics-event="{&quot;location&quot;:&quot;footer&quot;,&quot;action&quot;:&quot;dont_share_info&quot;,&quot;context&quot;:&quot;subfooter&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;label&quot;:&quot;dont_share_info_link_subfooter_footer&quot;}" > Do not share my personal information </button> </cookie-consent-link> </li> </ul> </nav> </div> </footer> <ghcc-consent id="ghcc" class="position-fixed bottom-0 left-0" style="z-index: 999999" data-initial-cookie-consent-allowed="" data-cookie-consent-required="false"></ghcc-consent> <div id="ajax-error-message" class="ajax-error-message flash flash-error" hidden> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-alert"> <path d="M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z"></path> </svg> <button type="button" class="flash-close js-ajax-error-dismiss" aria-label="Dismiss error"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-x"> <path d="M3.72 3.72a.75.75 0 0 1 1.06 0L8 6.94l3.22-3.22a.749.749 0 0 1 1.275.326.749.749 0 0 1-.215.734L9.06 8l3.22 3.22a.749.749 0 0 1-.326 1.275.749.749 0 0 1-.734-.215L8 9.06l-3.22 3.22a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042L6.94 8 3.72 4.78a.75.75 0 0 1 0-1.06Z"></path> </svg> </button> You can’t perform that action at this time. </div> <template id="site-details-dialog"> <details class="details-reset details-overlay details-overlay-dark lh-default color-fg-default hx_rsm" open> <summary role="button" aria-label="Close dialog"></summary> <details-dialog class="Box Box--overlay d-flex flex-column anim-fade-in fast hx_rsm-dialog hx_rsm-modal"> <button class="Box-btn-octicon m-0 btn-octicon position-absolute right-0 top-0" type="button" aria-label="Close dialog" data-close-dialog> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-x"> <path d="M3.72 3.72a.75.75 0 0 1 1.06 0L8 6.94l3.22-3.22a.749.749 0 0 1 1.275.326.749.749 0 0 1-.215.734L9.06 8l3.22 3.22a.749.749 0 0 1-.326 1.275.749.749 0 0 1-.734-.215L8 9.06l-3.22 3.22a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042L6.94 8 3.72 4.78a.75.75 0 0 1 0-1.06Z"></path> </svg> </button> <div class="octocat-spinner my-6 js-details-dialog-spinner"></div> </details-dialog> </details> </template> <div class="Popover js-hovercard-content position-absolute" style="display: none; outline: none;"> <div class="Popover-message Popover-message--bottom-left Popover-message--large Box color-shadow-large" style="width:360px;"> </div> </div> <template id="snippet-clipboard-copy-button"> <div class="zeroclipboard-container position-absolute right-0 top-0"> <clipboard-copy aria-label="Copy" class="ClipboardButton btn js-clipboard-copy m-2 p-0" data-copy-feedback="Copied!" data-tooltip-direction="w"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-copy js-clipboard-copy-icon m-2"> <path d="M0 6.75C0 5.784.784 5 1.75 5h1.5a.75.75 0 0 1 0 1.5h-1.5a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-1.5a.75.75 0 0 1 1.5 0v1.5A1.75 1.75 0 0 1 9.25 16h-7.5A1.75 1.75 0 0 1 0 14.25Z"></path><path d="M5 1.75C5 .784 5.784 0 6.75 0h7.5C15.216 0 16 .784 16 1.75v7.5A1.75 1.75 0 0 1 14.25 11h-7.5A1.75 1.75 0 0 1 5 9.25Zm1.75-.25a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-7.5a.25.25 0 0 0-.25-.25Z"></path> </svg> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-check js-clipboard-check-icon color-fg-success d-none m-2"> <path d="M13.78 4.22a.75.75 0 0 1 0 1.06l-7.25 7.25a.75.75 0 0 1-1.06 0L2.22 9.28a.751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018L6 10.94l6.72-6.72a.75.75 0 0 1 1.06 0Z"></path> </svg> </clipboard-copy> </div> </template> <template id="snippet-clipboard-copy-button-unpositioned"> <div class="zeroclipboard-container"> <clipboard-copy aria-label="Copy" class="ClipboardButton btn btn-invisible js-clipboard-copy m-2 p-0 d-flex flex-justify-center flex-items-center" data-copy-feedback="Copied!" data-tooltip-direction="w"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-copy js-clipboard-copy-icon"> <path d="M0 6.75C0 5.784.784 5 1.75 5h1.5a.75.75 0 0 1 0 1.5h-1.5a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-1.5a.75.75 0 0 1 1.5 0v1.5A1.75 1.75 0 0 1 9.25 16h-7.5A1.75 1.75 0 0 1 0 14.25Z"></path><path d="M5 1.75C5 .784 5.784 0 6.75 0h7.5C15.216 0 16 .784 16 1.75v7.5A1.75 1.75 0 0 1 14.25 11h-7.5A1.75 1.75 0 0 1 5 9.25Zm1.75-.25a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-7.5a.25.25 0 0 0-.25-.25Z"></path> </svg> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-check js-clipboard-check-icon color-fg-success d-none"> <path d="M13.78 4.22a.75.75 0 0 1 0 1.06l-7.25 7.25a.75.75 0 0 1-1.06 0L2.22 9.28a.751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018L6 10.94l6.72-6.72a.75.75 0 0 1 1.06 0Z"></path> </svg> </clipboard-copy> </div> </template> </div> <div id="js-global-screen-reader-notice" class="sr-only mt-n1" aria-live="polite" aria-atomic="true" ></div> <div id="js-global-screen-reader-notice-assertive" class="sr-only mt-n1" aria-live="assertive" aria-atomic="true"></div> </body> </html>

Pages: 1 2 3 4 5 6 7 8 9 10