Quick Utils

Change case, encode, hash, reformat JSON, generate values and test regular
expressions — on the selection you already have, without leaving the editor and
without anything reaching the network.
The small conversions you'd otherwise paste into a website.
Status: Active (best-effort maintenance)
Table of Contents
Features
- 29 Transforms, One Prompt:
Ctrl+Alt+T opens a grouped list — case styles, encoders, line operations, JSON. Ctrl+Alt+Shift+T repeats the last one
- Multi-Cursor Aware: Every transform applies to all selections at once, as a single undo. A multi-cursor "insert UUID" gives each cursor a different UUID
- Pipelines: Tick several transforms and run them in order — trim, dedupe, sort — as one undo step
- Scratchpad: A sidebar panel for converting text you are not editing, without pasting it into a file first
- Nothing Half-Done: A transform that rejects its input — decoding prose as Base64, reformatting broken JSON — says so with the document untouched, never partway through
- Digests and HMAC: SHA-256/384/512, SHA-1 and MD5, plus HMAC against a secret held in the OS keychain rather than in your settings — read as text, hex or Base64, because a 64-character hex secret is a 32-byte key
- Regex Tester That Cannot Hang: Patterns run in a worker thread with a time budget, so a catastrophically backtracking pattern is abandoned instead of freezing the editor
- Selection Statistics: Characters, graphemes, words, lines and UTF-8 bytes — word counts come from Unicode segmentation, so they are right for Japanese and Chinese too
- Local by Design: No network requests, no telemetry, no bundled service client
- Localised: English and Japanese, for both the UI and the command palette
Installation
Install from VS Code Marketplace (recommended)
- Open the Extensions view (
Ctrl+Shift+X)
- Search for Quick Utils
- Click Install
You can also open the Marketplace page directly:
Build from Source (for contributors)
If you just want to use Quick Utils, installing from the Marketplace is the easiest option.
git clone https://github.com/kkdev92/quick-utils.git
cd quick-utils
npm install
npm run install-local
Quick Start
- Select some text
- Press
Ctrl+Alt+T (Cmd+Alt+T on macOS)
- Pick a transform — start typing to filter
- Press
Ctrl+Alt+Shift+T to apply the same one again somewhere else
With nothing selected, case and encoding transforms act on the word under the
cursor, and line and JSON transforms act on the whole document. Everything is
also in the Command Palette under Quick Utils, and in the sidebar's Tools
view — where the checkbox next to a tool pins it to a per-workspace Favorites
group.
See sample.md for text to try each transform against.
Why Quick Utils
Base64, URL encoding, case conversion and JSON formatting are things most
people end up doing on a website: paste in, click, paste back. That is fine
until the text is a customer identifier, a signed token, or a fragment of a
config file that is not supposed to leave the building.
Quick Utils does those conversions in the editor. It has no network client of
any kind — there is nothing to configure, nothing to trust, and nothing to
review before pasting a production value into it.
Two consequences shape the rest of the design:
- Everything is local, so everything must be correct locally. Decoders
reject malformed input instead of returning something plausible, word counts
use Unicode segmentation rather than splitting on spaces, and line operations
keep the file's own line endings.
- Local also means it runs on your editor's thread. The one operation that
can genuinely run forever — a regular expression — is the one operation that
does not (see How It Works).
Usage
| Group |
Operations |
| Change Case |
UPPER CASE, lower case, camelCase, PascalCase, snake_case, kebab-case, CONSTANT_CASE, Title Case |
| Encode / Decode |
Base64 (standard and URL-safe), URL, HTML entities, hexadecimal, JSON string escaping |
| Lines |
Sort (A→Z, Z→A, numeric), remove duplicates, reverse, trim trailing whitespace, remove blank lines |
| JSON |
Format, minify, sort keys recursively |
The eight case styles and the common encoders also have commands of their own,
so they can be bound to keys. Quick Utils: Transform Clipboard… applies any
transform to the clipboard instead of the document, and Run Transform
Pipeline… runs several in sequence — ticked in one prompt, applied top to
bottom, undone in one step.
Generators
| Command |
Notes |
| Insert UUID (v4) |
Random. One per cursor |
| Insert UUID (v7, time-ordered) |
Timestamp-prefixed, so ids sort by creation order — the property that keeps database inserts clustered at the end of an index |
| Insert Password… |
Length and character classes; guarantees one character from each class you enable, and is never recorded in history |
| Insert Lorem Ipsum… |
1–10 paragraphs |
| Insert Date / Time… |
Your configured patterns, a pattern typed on the spot, or your editor's locale formatting |
| Convert Unix Timestamp… |
Reads seconds or milliseconds, shows the local and ISO 8601 forms, and can replace the selection |
Hashing
Hash Selection… replaces each selection with its digest; with nothing
selected, it copies the digest of the whole document instead. HMAC
Selection… does the same with a keyed digest, using a secret you store once
via Manage Secrets… — which keeps it in the OS keychain, not in
settings.json.
MD5 and SHA-1 are offered because checksums in the wild still use them. Picking
one asks for confirmation the first time, with a "don't ask again" option.
Replace by Pattern
Prompts for a regular expression, flags and a replacement ($1, $<name> and
$& are expanded), shows what the first few replacements will look like, and
applies the whole set as one undo step. With text selected, only matches inside
the selection are replaced.
Extract Matches from Selection… replaces the selection with the list of
matches found inside it, one per line. When the pattern declares exactly one
capture group, that group is extracted instead of the whole match —
href="([^"]+)" is asked about the URL, not the attribute around it.
Regex Tester
Open Regex Tester opens a panel beside the editor: type a pattern, see
matches highlighted in the subject text with their capture groups listed, and
click a match to select it in the editor. The subject can be typed in, taken
from the editor, loaded from a file, or gathered from a glob — file and glob
subjects are re-read when anything they cover changes on disk, which is what
makes them useful against logs that are still being written.
The Scratchpad view converts text without touching any document: paste,
pick a transform, then copy the result, insert it at the cursor, or feed it
back in to chain another transform.
The Tools view lists everything by category; tick a checkbox to add a tool
to Favorites, and drag favourites to reorder them. The History view
records what you ran, with the produced value where it is small enough to be
worth keeping — hover for it, or use the row's buttons to copy it or apply the
same operation again.
Known Limitations
- Case conversion is not locale-aware.
toUpperCase follows the default
Unicode mappings, so Turkish dotless ı and a few other locale-specific
rules are not applied
- Date patterns substitute every token letter.
Date: YYYY turns the D
and a of "Date" into a day number and a meridiem — wrap literal text in
square brackets: [Date:] YYYY
- The regex tester collects at most 500 matches per run, and reports when it
stopped early
- Word counts depend on the display language. Segmentation for Chinese,
Japanese and Thai is dictionary-based, so the same text can count differently
under a different VS Code display language
- A pipeline runs in list order, not in the order you ticked the boxes —
the API reports the former and not the latter, and the prompt says so
- No file-level batch operations. Everything acts on the active editor;
there is no "run this across the workspace"
Configuration
| Setting |
Default |
Description |
quickUtils.logLevel |
info |
Log level for the Quick Utils output channel |
quickUtils.datePatterns |
8 patterns |
Patterns offered by Insert Date / Time |
quickUtils.jsonIndent |
editor |
JSON indentation. editor follows editor.tabSize |
quickUtils.historySize |
100 |
Operations kept in History. 0 records nothing |
quickUtils.historyPageSize |
50 |
Rows shown before a "Load more…" entry |
quickUtils.hashAlgorithm |
sha256 |
Algorithm preselected in the digest picker |
quickUtils.hmacKeyEncoding |
utf8 |
How a stored signing secret is read into key bytes |
quickUtils.passwordLength |
20 |
Length proposed by Insert Password |
quickUtils.regexTimeoutMs |
2000 |
How long a pattern may run before it is abandoned |
quickUtils.showStatusBar |
true |
Show selection statistics in the status bar |
Every setting is validated on read: a hand-edited or stale value falls back to
the default and is reported in the output channel rather than reaching the
operation.
How It Works
Most of this extension is unremarkable — pure functions over the selected text,
applied through a single atomic editor edit. Two parts are worth explaining.
Regular expressions run in a worker thread. A pattern like /(a+)+$/
against forty as and a b backtracks for longer than anyone will wait, and
there is no way to interrupt RegExp.exec from the thread running it — no
timeout on the caller helps, because the event loop never gets control back.
So patterns are sent to a worker_threads worker and raced against
quickUtils.regexTimeoutMs. On expiry the worker is terminated (which V8
honours even inside a tight loop) and a fresh one serves the next request. The
editor stays responsive, and the tester reports that the pattern was abandoned.
scripts/verify-vsix.mjs runs exactly that scenario against the packaged
worker on every build.
Outputs are computed before anything is edited. Each transform runs against
every selection first, and the edit is only applied once all of them have
succeeded. Transforming inside the edit callback would leave the first
selections changed and the rest not, which is a worse outcome than a clear
error message.
Security and Privacy
- No network I/O: The extension contains no HTTP client, and neither bundle
requires Node's
http, https, net, tls or dns modules. CI checks the
packaged bundles for exactly that
- No telemetry: No usage data is collected
- Secrets in the keychain: HMAC keys go to
SecretStorage — the OS keychain
— never to settings.json or global state, and never to Settings Sync. The
state report lists secret names only
- History stays on the machine: The operation log is not synced, because it
can contain fragments of whatever you were editing
- Passwords are not recorded: A generated password is inserted and nothing
else
- The webview cannot reach the workspace: The Regex Tester's page script has
no file system access and does not evaluate the pattern; it sends the pattern
to the extension host, which validates it against a schema before running it
in the worker
- Untrusted and virtual workspaces supported: No workspace file is read
unless you pick one, and no process is spawned other than the extension's own
regex worker
MD5 and SHA-1 are provided for compatibility with existing checksums and are not
collision resistant; the UI says so at the point of choosing. For the full
threat model and for vulnerability reporting, see SECURITY.md.
- VS Code 1.125 or later
- Windows, macOS or Linux, on x64 or ARM64
CI runs the test suite on Windows, macOS and Linux (x64 on Windows and Linux,
ARM64 on macOS). The extension is plain JavaScript, so other combinations are
expected to work; please open an issue if one does not.
The 1.125 floor comes from @kkdev92/vscode-ext-kit 2.0, which raised its own
engines.vscode to ^1.125.0. Quick Utils 0.1.x works on VS Code 1.96 and up;
installations older than 1.125 keep that version and simply stop receiving
updates.
Troubleshooting
- "Select some text first" with something clearly selected: the command ran
against a different editor than you expected — click into the editor first, so
it is the active one
- A transform reports invalid input: that is the decoder refusing to guess.
Base64 and hex decoding reject text outside their alphabet, and bytes that do
not form valid UTF-8, rather than producing replacement characters
- The regex tester says the pattern was abandoned: the pattern is
backtracking. Anchor it, or make a quantifier less greedy; raising
quickUtils.regexTimeoutMs only makes the wait longer
- A date pattern produced nonsense: literal letters in a pattern are
substituted as tokens. Wrap them in square brackets
- A signature never matches: check
quickUtils.hmacKeyEncoding. A secret
issued as hex or Base64 read as text is a different key, and nothing about
the failure says so
- Something looks wrong and you want to report it: run Quick Utils:
Report State, which opens a Markdown summary of your settings, their
sources, and what the extension has stored. Attach it to the issue.
Collect Diagnostics to Output writes the same report to a dedicated
output channel and copies it to the clipboard
Contributing
Contributions are welcome — thank you for helping make Quick Utils better 🙌
Please see CONTRIBUTING.md for guidelines.
If you're planning a larger change, opening an issue first is appreciated (it
helps align direction and avoids duplicate work). Note that anything requiring a
network request is out of scope by design.
Support & Maintenance Policy
Quick Utils is a personal hobby project maintained in spare time.
The project is active, but support is best-effort: I'll do my best to review
issues and PRs, and releases may be a bit slow sometimes — thank you for your
patience.
Helpful things when reporting bugs:
- The output of Quick Utils: Report State
- The smallest input that reproduces the issue
- Output from Output → Quick Utils at
logLevel: debug
Security-related reports should follow SECURITY.md.
Really appreciate you using Quick Utils 💛
License
Quick Utils is licensed under the MIT License — see LICENSE.
Copyright and licence notices for the third-party code shipped inside the VSIX
are collected in THIRD_PARTY_NOTICES.md.
Acknowledgments
- Extension utilities by @kkdev92/vscode-ext-kit.
Quick Utils doubles as that library's integration test bed: nearly every part of
its API is exercised somewhere in here
- Word, grapheme and collation behaviour comes from ICU via
Intl.Segmenter,
Intl.Collator and friends, which ship with Node