zift Wiki
This page documents every configuration option supported by zift today, with small examples.
The full config is:
.{
.indent = .{ .spaces = 4 },
.single_item_whitespace = false,
.indent_switch_cases = true,
.braces = .{
.conditionals = .default,
.labeled = .default,
.loops = .default,
.functions = .default,
.switches = .default,
.types = .default,
},
.alignment = .{
.comments = 0,
.initializers = 0,
.declarations = 0,
.prongs = 0,
.enums = 0,
},
}
Differences with `zig fmt`
zift mostly matches zig fmt by default, with some exceptions.
Note that these won't alter code formatted by zig fmt on their own, they only preserve differences if already there.
line break after struct initializer
If a struct initializer field value is already written on the next line after =, zift keeps that line break instead of collapsing the assignment back to one line.
For example, this is allowed:
const value = .{
.x_rotation_deg =
-@as(f32, 1) / 2,
};
line break after return statement
If a return statement is followed by a line break, this is preserved, instead of the returned value being brought to the same line of the return statement.
For example, this is allowed:
return
cfg.alignment.comments > 0 or
cfg.alignment.initializers > 0 or
cfg.alignment.declarations > 0 or
cfg.alignment.prongs > 0;
line break before `orelse` or `catch`
Line breaks are preserved also before orelse expressions.
For example, this is allowed:
const range =
findMotionRange(e, motion)
orelse return .fail;
Same is true for catch:
const range =
findMotionRange(e, motion)
catch return .fail;
line break after switch prong arrow
Line breaks are preserved also after => in switch prongs. If the arrow is followd by a capture, that is kept on the line with the arrow.
For example, this is allowed:
const value = switch (v) {
0 =>
.zero,
1 => |x|
x,
else => .other,
};
empty line before `else`
If an else branch is already rendered on its own line, zift keeps one empty line before it when that empty line is already present in the source.
This applies to else if too.
For example, this is allowed:
const end =
if (vbcur) |br|
br
else if (eol)
1
else
2;
indent
Controls the indentation character and amount.
.indent = .tabs
pub fn f() void {
if (true) {
return;
}
}
.indent = .{ .spaces = 2 }
pub fn f() void {
if (true) {
return;
}
}
braces
Controls brace placement by category.
Note that every category can have different settings, so if you like .allman on conditionals/loops and .gnu on switches/labeled blocks, it's perfectly doable.
braces.conditionals
Valid values: .default, .newline_before_else, .allman, .gnu
.conditionals = .default
if (a) {
work();
} else {
fallback();
}
.conditionals = .newline_before_else
This setting only affects the placement of else statements, pushing them into their own line. It is consistent with how they look in switch statements.
if (a) {
work();
}
else {
fallback();
}
.conditionals = .allman
if (a)
{
work();
}
else
{
fallback();
}
.conditionals = .gnu
if (a)
{
work();
}
else
{
fallback();
}
braces.labeled
Valid values: .default, .allman, .gnu
This controls labeled blocks such as blk: { ... }.
When a labeled block appears in an if or else branch:
braces.labeledonly controls the placement of{after the labelbraces.conditionalsstill controls whetherelsestays on the same line or moves to the next one
.labeled = .default
const a = if (v) blk: {
break :blk 3;
} else blk: {
break :blk 3;
};
.labeled = .allman
const a = if (v) blk:
{
break :blk 3;
} else blk:
{
break :blk 3;
};
With braces.conditionals = .newline_before_else or .allman, only the else placement changes:
const a = if (v) blk:
{
break :blk 3;
}
else blk:
{
break :blk 3;
};
.labeled = .gnu
const a = if (v) blk:
{
break :blk 3;
} else blk:
{
break :blk 3;
};
With braces.conditionals = .newline_before_else or .allman:
const a = if (true) blk:
{
break :blk 3;
}
else blk:
{
break :blk 3;
};
or with if on its own line:
const a =
if (true) blk:
{
break :blk 3;
}
else blk:
{
break :blk 3;
};
braces.loops
Valid values: .default, .allman, .gnu
.loops = .default
while (i < items.len) : (i += 1) {
work(items[i]);
}
.loops = .allman
while (i < items.len) : (i += 1)
{
work(items[i]);
}
.loops = .gnu
while (i < items.len) : (i += 1)
{
work(items[i]);
}
braces.functions
Valid values: .default, .allman
.functions = .default
pub fn f() void {
work();
}
.functions = .allman
pub fn f() void
{
work();
}
braces.switches
Valid values: .default, .allman, .gnu
.switches = .default
return switch (v) {
0 => "zero",
else => "other",
};
.switches = .allman
return switch (v)
{
0 => "zero",
else => "other",
};
This also stays aligned when switch is used in an assignment:
const a = switch (v)
{
0 => "zero",
else => "other",
};
.switches = .gnu
const a = switch (v)
{
0 => "zero",
else => "other",
};
braces.types
Valid values: .default, .allman
.types = .default
const Item = struct {
value: usize,
};
.types = .allman
const Item = struct
{
value: usize,
};
alignment
These options align only consecutive matching lines.
Threshold rules:
0disables alignment1and2both mean "align groups of 2 or more lines"3+requires at least that many consecutive matching lines
Alignment is table-like on purpose. Runs with mixed indentation are skipped. Runs that contain nested blocks are also skipped.
alignment.comments
Aligns inline // comments.
.comments = 0
const a = 1; // alpha
const long_name = 2; // beta
.comments = 2
const a = 1; // alpha
const long_name = 2; // beta
.comments = 3
With only two matching lines, nothing changes:
const a = 1; // alpha
const long_name = 2; // beta
With three or more matching lines, they align:
const a = 1; // alpha
const long_name = 2; // beta
const z = 3; // gamma
alignment.initializers
Aligns = in flat struct initializer field lists.
Currently, it is only possible to align initializers in single, non-nested blocks. If a nested block is present, or if there are differences in indentation, the block is left alone, no matter the setting.
return .{
.ctx = .{
.fd = handle,
.timeout = 0,
.reader = reader,
},
};
.initializers = 0
const value = .{
.name = name,
.count = count,
.kind = .alpha,
};
.initializers = 2
const value = .{
.name = name,
.count = count,
.kind = .alpha,
};
alignment.declarations
Aligns = in consecutive const and var declarations.
.declarations = 0
const init: u8 = 3;
const a: u3 = 2;
const b: []const u8 = &.{};
.declarations = 2
const init: u8 = 3;
const a: u3 = 2;
const b: []const u8 = &.{};
.declarations = 4
With only three matching lines, nothing changes:
const init: u8 = 3;
const a: u3 = 2;
const b: []const u8 = &.{};
alignment.prongs
Aligns => in flat switch prong lists.
.prongs = 0
return switch (k) {
.a => 1,
.long_name => 2,
.b => 3,
};
.prongs = 2
return switch (k) {
.a => 1,
.long_name => 2,
.b => 3,
};
If one prong opens a block, the whole run is left alone:
return switch (k) {
.a => 1,
.long_name => blk: {
break :blk 2;
},
.b => 3,
};
alignment.enums
Aligns = in consecutive enum fields.
.enums = 0
const Signed = enum(i8) {
minus_one = -1,
zero = 0,
one = 1,
};
.enums = 2
const Signed = enum(i8) {
minus_one = -1,
zero = 0,
one = 1,
};
single_item_whitespace
Controls spaces inside single-item arrays and tuple-like literals such as .{1}.
.single_item_whitespace = false
const a = .{1};
const b = .{ .x = 1 };
.single_item_whitespace = true
const a = .{ 1 };
const b = .{ .x = 1 };
Only single-item positional literals change. Regular struct literals keep their normal formatting.
indent_switch_cases
Controls whether switch prongs are indented inside the switch body.
.indent_switch_cases = true
switch (v) {
0 => {},
else => {},
}
.indent_switch_cases = false
switch (v) {
0 => {},
else => {},
}
Example Configs
Aligned initializers and comments, `else` in own line
.{
.indent = .{ .spaces = 4 },
.single_item_whitespace = false,
.indent_switch_cases = true,
.braces = .{
.conditionals = .newline_before_else,
},
.alignment = .{
.comments = 3,
.initializers = 3,
.declarations = 0,
.prongs = 0,
.enums = 0,
},
}
Tabs and Allman braces, aligned initializers and comments
.{
.indent = .tabs,
.single_item_whitespace = false,
.indent_switch_cases = true,
.braces = .{
.conditionals = .allman,
.labeled = .allman,
.loops = .allman,
.functions = .allman,
.switches = .allman,
.types = .allman,
},
.alignment = .{
.comments = 3,
.initializers = 3,
.declarations = 0,
.prongs = 0,
.enums = 0,
},
}