Home Code Other Software

Table of Contents


sbt-editsource is a text substitution plugin for SBT 0.13.x and greater. In a way, it’s a poor man’s sed(1), for SBT. It provides the ability to apply line-by-line substitutions to a source text file, producing an edited output file. It supports two kinds of edits:

Each of these capabilities is explained in more detail, below.

This plugin only works with SBT 0.11.x or better. If you’re using SBT 0.7, there’s an older version (with fewer features and a different variable syntax) here.

Getting the Plugin

Within your SBT project, create project/plugins/build.sbt (if it doesn’t already exist) and add the following:

addSbtPlugin("org.clapper" % "sbt-editsource" % "0.7.0")

Settings and Tasks

The plugin provides the following new settings and tasks.

Note: sbt-editsource uses predefined SBT settings, where possible (e.g., sources). Of course, that’s not always possible. To be sure you’re updating the correct setting, always use the form:

settingName in EditSource

For instance:

flatten in EditSource := false


The plugin provides the following new settings.


The source files to be edited. For instance, suppose you want to edit all files under “src” ending in “.txt”. To do so, use:

sources in EditSource <++= baseDirectory.map(d => (d / "src" ** "*.txt").get)

If you also want to apply the edits to all files ending in “.md”, use either:

sources in EditSource <++= baseDirectory.map(d => (d / "src" ** "*.txt").get)
sources in EditSource <++= baseDirectory.map(d => (d / "src" ** "*.md").get)

or, more succinctly:

sources in EditSource <++= baseDirectory.map { dir =>
    (dir / "src" ** "*.txt").get ++
    (dir / "src" ** "*.md").get


The directory to which to write the edited versions of the source files. For example:

targetDirectory in EditSource <<= baseDirectory(_ / "target")

See also flatten, below.


If flatten is true, then the edited files will all be placed directly in targetDirectory; if there are name clashes, then some files will be overwritten. If flatten is false, then the partial path to each source file is preserved in the target directory.

An example will help clarify. Consider the following file tree:

Directory tree

Let’s assume you’re editing all the files ending in “.md”, into the target directory.

sources in EditSource <++= baseDirectory(
  d => (d / "src" ** "*.md").get

targetDirectory in EditSource <<= baseDirectory(_ / "target")

If you also set:

flatten in EditSource := true

the edit operation will put all the edited versions of all three files directly in the target directory.

If, instead, you set:

flatten in EditSource := false

you’ll end up with the following edited versions:


EditSource.variables is a sequence of (variableName, value) pairs. Let’s take a look at some examples. We’re going to define substitutions for three keys:

variables in EditSource <+= name {s => ("projectName", s)}
variables in EditSource += ("version", version.value)
variables in EditSource += ("author", "Brian Clapper")

Let’s look at each of these, one at a time.

The first setting—the one setting the “projectName” key—is sort of like a map() operation:

variables in EditSource <+= name {s => ("projectName", s)}

In effect, we’re mapping over the SBT name setting, passing its string value to the supplied block. The block returns a key-value pair which is added to the EditSource mappings via the SBT <+= operator. Any reference to $projectName in our source files will be replaced with the project name.

The second example also defines a mapping from an SBT configuration value, but it does it much more simply:

variables in EditSource += ("version", version.value)

In this case, we just use the += SBT operator to add a key-value pair to the mappings. To get the string associated with the SBT version setting, we just use version.value. (This method is preferred over the first one, because it’s much easier to read and remember.)

The third setting is just a variation of the second one, adding a constant key-value string tuple to the mappings.

Using Variables in your Source Files

Inside a source file to be edited, variable references are of the form ${varname}, as in the Unix shell. A shortened $varname is also support. The ${} long form also supports a default syntax: ${varname?default}. If the reference variable has no value, then the default value is supplied, instead. (The ?default syntax is not supported for the short form reference.)

With the above definitions in place, when the source files are edited, any reference to ${projectName} is replaced with “my-project”, and any reference to ${author} is replaced with “Brian Clapper”.

You can define any number of variables. If the edit logic encounters a variable that isn’t defined, it simply replaces the variable reference with an empty string (like bash does).

In addition to the variables you define in your build file, the sbt-editsource also honors the following special variable prefixes:


substitutions is a sequence of regular expression substitutions, of the form:

sub(regex, replacement)
sub(regex, replacement, flags)

There’s only one (optional) flag right now:

Additional flags can be specified inline, as indicated in the documentation for the java.util.regex.Pattern class.

For example, to replace the first occurrence of the word “test” in each line with “TEST”, without regard to case, you might use:

substitutions in EditSource += sub("""(?i)\btest\b""".r, "TEST")

The “(?i)” is the embedded option sequence that tells the regular expression parser to use case-blind comparison.

Similarly, to replace all occurrences of the word “test”, with regard to case, you might use:

substitutions in EditSource += sub("""\btest\b""".r, "TEST", SubAll)

You can specify multiple substitutions, of course:

substitutions in EditSource ++= Seq(
    sub("""^#""".r, "//"),
    sub("""\b(?i)simple build tool\b""".r, "Scalable Build Tool", SubAll)

Also, regular expression capturing groups are supported, so you can use more complex regular expression substitutions like this:

// Remove everything up to, but not including the word "foo", but save
// the "foo" and everything after.

sub("""^.*(foo.*)$""".r, "$1")

NOTE: Regular expression substitutions are run after variable substitutions.


The plugin provides two new SBT tasks.

Hooking the edit task into the compile phase

If you want the run editsource:edit every time you run compile, just add this line to your build.sbt:

compile in Compile <<= (compile in Compile) dependsOn (edit in EditSource)


Change log

The change log for all releases is here.


Brian M. Clapper, bmc@clapper.org

Copyright and License

This software is copyright © 2010-2011 Brian M. Clapper and is released under a BSD License.


I gladly accept patches from their original authors. Feel free to email patches to me or to fork the GitHub repository and send me a pull request. Along with any patch you send: