Skip to content

Commit 2f039fc

Browse files
committed
Create ansi.lua and implement --no-ansi
1 parent abbf780 commit 2f039fc

8 files changed

Lines changed: 142 additions & 55 deletions

File tree

core/ansi.lua

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
local M = {}
2+
3+
---@param code number
4+
---@param close_code number?
5+
local apply_code = function(code, close_code)
6+
close_code = close_code or 39
7+
---@param str string
8+
---@return string
9+
return function(str)
10+
return string.format("\27[%dm%s\27[%dm", code, str, close_code)
11+
end
12+
end
13+
14+
---@alias ANSI_Func (fun(s: string): string)|({ __call: ANSI_Func})
15+
16+
---@param code number
17+
---@return { __call: ANSI_Func; bg: ANSI_Func; bright: ANSI_Func; bright_bg: ANSI_Func}
18+
local function color(code)
19+
return setmetatable({
20+
bg = apply_code(code + 10, 49),
21+
bright = apply_code(code + 60),
22+
bright_bg = apply_code(code + 70, 49),
23+
}, {
24+
__call = function(_, str)
25+
return apply_code(code)(str)
26+
end,
27+
})
28+
end
29+
30+
---@param func1 ANSI_Func
31+
---@param func2 ANSI_Func
32+
---@return ANSI_Func
33+
M.compose = function(func1, func2)
34+
---@param str string
35+
---@return string
36+
return function(str)
37+
return func1(func2(str))
38+
end
39+
end
40+
41+
M.black = color(30)
42+
M.red = color(31)
43+
M.green = color(32)
44+
M.yellow = color(33)
45+
M.blue = color(34)
46+
M.magenta = color(35)
47+
M.cyan = color(36)
48+
M.white = color(37)
49+
50+
M.none = apply_code(0, 0)
51+
M.bold = apply_code(1, 22)
52+
M.italic = apply_code(3, 23)
53+
54+
return M

core/context.lua

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,9 @@ local Config = require("core.config")
5454
--- associated with the mock filesystem. Otherwise, will be the Lua `io`
5555
--- library.
5656
--- @field io iolib
57+
---
58+
--- Specifies if `--no-ansi` was not passed.
59+
--- @field ansi_enabled boolean
5760

5861
local Context = {}
5962
Context.__index = Context
@@ -86,6 +89,7 @@ Context.errors = {
8689
---@param plan_stream Stream
8790
---@param text_stream Stream
8891
---@param preserve boolean
92+
---@param ansi_enabled boolean
8993
---@return Context?, string?
9094
function Context:new(
9195
config,
@@ -97,7 +101,8 @@ function Context:new(
97101
auto_confirm,
98102
plan_stream,
99103
text_stream,
100-
preserve
104+
preserve,
105+
ansi_enabled
101106
)
102107
self = {}
103108
---@cast self Context
@@ -125,6 +130,7 @@ function Context:new(
125130
{ auto_confirm, "boolean", "auto_confirm" },
126131
{ preserve, "boolean", "preserve" },
127132
{ is_dry_run, "boolean", "is_dry_run" },
133+
{ ansi_enabled, "boolean", "ansi_enabled" },
128134
})
129135
if err then
130136
return nil, err
@@ -148,6 +154,7 @@ function Context:new(
148154
self.lines = {}
149155
self.io = mock_filesystem and mock_filesystem.io or io
150156
self.preserve = preserve
157+
self.ansi_enabled = ansi_enabled
151158
self.is_dry_run = is_dry_run
152159

153160
local lines = {}

core/fold.lua

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -260,7 +260,7 @@ end
260260
M.execute = function(section_root, ctx, is_dry_run)
261261
is_dry_run = is_dry_run or false
262262
local io = ctx.io
263-
local plan = Plan:new()
263+
local plan = Plan:new(ctx.ansi_enabled)
264264
local created_or_modified_paths = {}
265265

266266
---@param path_str string?

core/plan/action.lua

Lines changed: 39 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
local utils = require("core.utils")
22
local Path = require("core.path")
3+
local ansi = require("core.ansi")
34

4-
---@alias CREATE_ACTION { type: "CREATE", path: Path, lines: string[], tostring: fun(self: Action): string }
5-
---@alias OVERWRITE_ACTION { type: "OVERWRITE", path: Path, lines: string[], tostring: fun(self: Action): string }
6-
---@alias MKDIR_ACTION { type: "MKDIR", path: Path, tostring: fun(self: Action): string }
7-
---@alias IGNORE_ACTION { type: "IGNORE", path: Path, lines: string[], tostring: fun(self: Action): string }
8-
---@alias RENAME_ACTION { type: "RENAME", path: Path, new_path: Path }
5+
---@alias CREATE_ACTION { type: "CREATE", path: Path, lines: string[], tostring: fun(self: Action, enable_ansi: boolean?): string }
6+
---@alias OVERWRITE_ACTION { type: "OVERWRITE", path: Path, lines: string[], tostring: fun(self: Action, enable_ansi: boolean?): string }
7+
---@alias MKDIR_ACTION { type: "MKDIR", path: Path, tostring: fun(self: Action, enable_ansi: boolean?): string }
8+
---@alias IGNORE_ACTION { type: "IGNORE", path: Path, lines: string[], tostring: fun(self: Action, enable_ansi: boolean?): string }
9+
---@alias RENAME_ACTION { type: "RENAME", path: Path, new_path: Path, tostring: fun(self: Action, enable_ansi: boolean?): string }
910

1011
---@alias Action CREATE_ACTION|OVERWRITE_ACTION|MKDIR_ACTION|IGNORE_ACTION|RENAME_ACTION
1112

@@ -17,21 +18,26 @@ M.MKDIR = "MKDIR"
1718
M.IGNORE = "IGNORE"
1819
M.RENAME = "RENAME"
1920

20-
--- TODO(gitpushjoe): add option for no colors
2121
--- @param self Action
22+
--- @param enable_ansi boolean
2223
--- @return string
23-
local tostring = function(self)
24-
local text = self.type == M.CREATE and "\27[32m"
25-
or self.type == M.MKDIR and "\27[33m"
26-
or self.type == M.OVERWRITE and "\27[35m"
27-
or self.type == M.IGNORE and "\27[31m"
28-
or self.type == M.RENAME and "\27[96m"
29-
or error("Unknown action type: " .. self.type)
30-
text = text
31-
.. "[ "
32-
.. string.rep(" ", #"OVERWRITE" - #self.type)
33-
.. self.type
34-
.. " ] "
24+
local tostring = function(self, enable_ansi)
25+
local color = enable_ansi
26+
and (({
27+
[M.CREATE] = ansi.green,
28+
[M.MKDIR] = ansi.yellow,
29+
[M.OVERWRITE] = ansi.magenta,
30+
[M.IGNORE] = ansi.red,
31+
[M.RENAME] = ansi.cyan,
32+
})[self.type] or error("Unknown action type: " .. self.type))
33+
or ansi.none
34+
local bold = enable_ansi and ansi.bold or ansi.none
35+
local text = bold(
36+
"[ "
37+
.. string.rep(" ", #"OVERWRITE" - #self.type)
38+
.. self.type
39+
.. " ] "
40+
)
3541
local line_count_str = "-"
3642
local char_count_str = "-"
3743
if self.lines then
@@ -42,19 +48,21 @@ local tostring = function(self)
4248
end
4349
char_count_str = tostring(char_count)
4450
end
45-
return text
46-
.. string.rep(" ", #"lines " - #line_count_str)
47-
.. line_count_str
48-
.. " "
49-
.. string.rep(" ", #"chars " - #char_count_str)
50-
.. char_count_str
51-
.. " "
52-
.. tostring(self.path)
53-
.. (self.type == M.RENAME and "\n" .. string.rep(
54-
" ",
55-
#"action lines chars " - #"-> "
56-
) .. "-> " .. tostring(self.new_path) or "")
57-
.. "\27[0m"
51+
return color(
52+
text
53+
.. string.rep(" ", #"lines " - #line_count_str)
54+
.. line_count_str
55+
.. " "
56+
.. string.rep(" ", #"chars " - #char_count_str)
57+
.. char_count_str
58+
.. " "
59+
.. tostring(self.path)
60+
.. (self.type == M.RENAME and "\n" .. string.rep(
61+
" ",
62+
#"action lines chars " - #"-> "
63+
) .. "-> " .. tostring(self.new_path) or "")
64+
.. "\27[0m"
65+
)
5866
end
5967

6068
---@param path Path

core/plan/plan.lua

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,19 @@
11
---@class Plan
22
---@field actions Action[]
3+
---@field enable_ansi boolean
34
Plan = {}
45
Plan.__index = Plan
56
Plan.__name = "Plan"
67

8+
---@param enable_ansi boolean?
79
---@return Plan
8-
function Plan:new()
10+
function Plan:new(enable_ansi)
11+
enable_ansi = enable_ansi == nil and true or enable_ansi
912
self = {}
1013
setmetatable(self, Plan)
14+
---@cast self Plan
1115
self.actions = {}
16+
self.enable_ansi = not not enable_ansi
1217
return self
1318
end
1419

@@ -23,7 +28,7 @@ end
2328
function Plan:__tostring()
2429
local text = "action lines chars path"
2530
for _, action in ipairs(self.actions) do
26-
text = text .. "\n" .. action:tostring()
31+
text = text .. "\n" .. action:tostring(self.enable_ansi)
2732
end
2833
return text
2934
end

core/section.lua

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -231,9 +231,9 @@ function Section:__tostring()
231231
.. "}"
232232
.. ",\n\tpath = "
233233
.. (self.path and ('"' .. tostring(self.path) .. '"') or "nil")
234-
.. ",\n\tlines = {"
234+
.. ",\n\tlines = "
235235
.. (function()
236-
local text = ""
236+
local text = "{"
237237
local lines = self:get_lines()
238238
for i, line in ipairs(lines) do
239239
if line then
@@ -248,7 +248,7 @@ function Section:__tostring()
248248
.. (i ~= #lines and ", " or "")
249249
end
250250
end
251-
return text
251+
return text .. "}"
252252
end)()
253253
.. ",\n\ttransformed_lines = "
254254
.. (function()
@@ -260,18 +260,19 @@ function Section:__tostring()
260260
for i, line in ipairs(lines) do
261261
if line then
262262
text = text
263-
.. '"'
264-
.. line:gsub("\\", "\\\\")
265-
:gsub("\n", "\\n")
266-
:gsub("\r", "\\r")
267-
:gsub("\t", "\\t")
268-
:gsub('"', '\\"')
269-
.. '"'
270-
.. (i ~= #lines and ", " or "")
263+
.. '"'
264+
.. line:gsub("\\", "\\\\")
265+
:gsub("\n", "\\n")
266+
:gsub("\r", "\\r")
267+
:gsub("\t", "\\t")
268+
:gsub('"', '\\"')
269+
.. '"'
270+
.. (i ~= #lines and ", " or "")
271271
end
272272
end
273273
return text .. "}"
274274
end)()
275+
.. "\n}"
275276
end
276277

277278
return Section

main.lua

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,14 +20,7 @@ local custom_configs = require("configs")
2020
local Parser = require("core.parser")
2121
local streams = require("core.streams")
2222
local utils = require("core.utils")
23-
24-
---@param err string?
25-
local error = function(err)
26-
io.stderr:write(
27-
"\27[1;31m" .. "ERROR: \27[0;91m" .. (err or "") .. "\n \27[0m"
28-
)
29-
os.exit(1)
30-
end
23+
local ansi = require("core.ansi")
3124

3225
---@param text string
3326
---@param stream Stream
@@ -61,6 +54,11 @@ local parser = assert(Parser:new({
6154
"-p",
6255
"Will not edit the source file.",
6356
},
57+
{
58+
"--no-ansi",
59+
"-na",
60+
"Disables ANSI coloring."
61+
},
6462
}, {
6563
{
6664
"--plan-stream <stream>",
@@ -84,11 +82,23 @@ local parser = assert(Parser:new({
8482
},
8583
}))
8684

85+
local ansi_enabled = false
86+
87+
---@param err string?
88+
local error = function(err)
89+
local red = ansi_enabled and ansi.red or ansi.none
90+
local bold = ansi_enabled and ansi.bold or ansi.none
91+
io.stderr:write(red("ERROR: " .. bold(err or "")))
92+
os.exit(1)
93+
end
94+
8795
local success, err = parser:parse(arg)
8896
if not success then
8997
error(err)
9098
end
9199

100+
ansi_enabled = parser:find("--no-ansi") == nil
101+
92102
if parser:find("--help") then
93103
print(parser:get_helptext())
94104
os.exit(0)
@@ -142,7 +152,8 @@ ctx, err = Context:new(
142152
parser:find("--yes") ~= nil,
143153
plan_stream or streams.STDOUT,
144154
text_stream or streams.STDOUT,
145-
parser:find("--preserve") ~= nil
155+
parser:find("--preserve") ~= nil,
156+
ansi_enabled
146157
)
147158

148159
if not ctx then

readme.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,7 @@ To run crazywall on a file, you can simply run `$ cw <file>`. You can add any of
186186
|`--config <config>`, `-c <config>`|Uses the config named <config> in `configs.lua`. Defaults to `"DEFAULT"`.
187187
|`--dry-run`, `-dr`|Enable dry-run, which will not modify or add any new files or directories.
188188
|`--help`, `-h`|Prints the helptext.
189+
|`--no-ansi`, `-na`|Disables ANSI coloring.
189190
|`--out <file>`, `-o <file>`|Sets the destination for the new source text to `<file>`. Defaults to the path to the source file.
190191
|`--plan_stream <stream>`, `-ps <stream>`|The stream to print the crazywall plan object to. (0 for none, 1 for stdout, 2 for stderr.) Defaults to 1.
191192
|`--preserve`, `-p`|Will not edit the source file.

0 commit comments

Comments
 (0)