Replace across a folder
without rewriting how the files are stored.

Most folder-wide replace tools read every file as UTF-8, write every file back as UTF-8 with LF endings, and hand you a diff full of changes you did not ask for. Linelark reads each file with its own encoding and line endings and writes it back the same way.

Studio 1.4.0 · macOS 14+6.5 MB download

What happens when you press Replace in Files.

Find ▸ Replace in Files walks the open folder, decides which files are candidates, and rewrites only the ones that actually match. Each step exists to avoid a specific way that folder-wide replace goes wrong.

01

Each file keeps its own encoding

The file is decoded with the encoding it was stored in, the replacement is applied to the text, and it is written back with that same encoding and its original line endings. Nothing is normalised on the way through.

02

Line endings survive the round trip

CRLF and CR files are normalised to LF *in memory* so a pattern matching across a line break behaves the same everywhere, then written back with the endings the file arrived with.

03

Build output is skipped, not searched

.git, .svn, node_modules, .build, build, DerivedData, .venv and __pycache__ are skipped whole — the enumerator does not descend into them, so a match inside node_modules cannot be rewritten by accident.

04

Binaries are detected and left alone

A NUL byte anywhere in a file’s first kilobyte is the standard giveaway, and any file carrying one is skipped before a regex ever touches it.

05

Files you have open are never overwritten

Buffers already open in the editor are excluded from the walk, so a folder replace cannot silently discard unsaved edits in a tab behind the dialog.

06

Paths are canonicalised before comparison

Directory enumeration yields /private/var while a hand-built URL says /var. Without collapsing that, the “skip this open file” guard would look like it worked and quietly do nothing.

The limits, as they are set in the code.

These are the real constants, not rounded ones. Knowing where a tool stops is what makes it trustworthy for a repository you care about.

BehaviourValue
Largest file considered4 MB. Anything larger is skipped by both search and replace.
Results returned by a searchUp to 5,000 hits across the folder, and up to 500 matches within any single file.
Pattern syntaxICU regular expressions through NSRegularExpression, with case sensitivity and whole-word options.
File filterSpace, comma or semicolon separated. *.swift, swift and an exact filename all work.
Hidden filesSkipped. The enumerator runs with skipsHiddenFiles.
What a failed write doesThe file is recorded in the report by name and the run continues. It is never left half-written.

Read from the Linelark Studio 1.4.0 source, not from its documentation. Where the two disagree, this is the one that ships.

Where this will not help you.

A folder replace is a destructive operation on files you have not opened. These are the cases where you should reach for something else.

  • There is no preview of a replaceSearch shows you the hits; Replace in Files reports what it changed after the fact. If you want to inspect each change before it happens, replace file by file in the editor instead.
  • There is no undo across filesUndo is per buffer. A folder-wide replace is not a single undoable action, so run it in a repository with a clean working tree and read the diff.
  • Files over 4 MB are silently out of scopeThey are skipped rather than reported as skipped. A log file larger than that will not be searched and will not tell you so.
  • The skip list is not configurable.git, node_modules, DerivedData and the rest are fixed in this version. If you need to search inside one of them, this tool cannot do it.

Open it on
your own files.

Apple-notarized, macOS 14 and newer, Intel and Apple silicon.

Choose a release 6.5 MB · versioned checksums on the download page