@@ -34,17 +34,45 @@ local json = require('json')
3434local gui = require (' gui' )
3535local widgets = require (' gui.widgets' )
3636
37+ local CONFIG_FILE_BACKUP = ' dfhack-config/quickcmd.json.bak'
3738local CONFIG_FILE = ' dfhack-config/quickcmd.json'
3839local HOTKEYWIDTH = 7
40+ local OUTWIDTH = 4
3941local HOTKEYS = ' asdfghjklqwertyuiopzxcvbnm'
4042
43+ local function save_commands (data )
44+ json .encode_file ({version = 2 , commands = data }, CONFIG_FILE )
45+ end
46+
47+ local function migrate_to_v2 (data )
48+ json .encode_file (data , CONFIG_FILE_BACKUP )
49+
50+ local commands = {}
51+ for i , cmd in ipairs (data ) do
52+ if type (cmd ) == ' string' then
53+ table.insert (commands , {command = cmd , name = nil , show_output = false })
54+ end
55+ end
56+
57+ save_commands (commands )
58+ return commands
59+ end
60+
4161local function load_commands ()
4262 local ok , data = pcall (json .decode_file , CONFIG_FILE )
43- return ok and data or {}
44- end
63+ if ok then
64+ if type (data ) == ' table' and data .version then
65+ if data .version == 2 then
66+ return data .commands or {}
67+ end
68+ end
69+ -- Old format: array of strings
70+ if type (data ) == ' table' and # data > 0 then
71+ return migrate_to_v2 (data )
72+ end
73+ end
4574
46- local function save_commands (data )
47- json .encode_file (data , CONFIG_FILE )
75+ return {}
4876end
4977
5078QCMDDialog = defclass (QCMDDialog , widgets .Window )
@@ -61,12 +89,12 @@ function QCMDDialog:init(info)
6189 self :addviews {
6290 widgets .Label {
6391 frame = {t = 0 },
64- text = {{text = ' Hotkey' , width = HOTKEYWIDTH }, ' Command' },
92+ text = {{text = ' Hotkey' , width = HOTKEYWIDTH }, { text = ' Out ' , width = OUTWIDTH }, ' Name/ Command' },
6593 visible = function () return # self .commands > 0 end ,
6694 },
6795 widgets .List {
6896 view_id = ' list' ,
69- frame = {t = 2 , b = 3 },
97+ frame = {t = 2 , b = 4 },
7098 on_submit = self :callback (' submit' ),
7199 },
72100 widgets .Label {
@@ -75,53 +103,128 @@ function QCMDDialog:init(info)
75103 visible = function () return # self .commands == 0 end ,
76104 },
77105 widgets .HotkeyLabel {
78- frame = {b = 1 , l = 0 },
106+ frame = {b = 2 , l = 0 },
79107 key = ' CUSTOM_SHIFT_A' ,
80108 label = ' Add command' ,
81109 auto_width = true ,
82110 on_activate = self :callback (' onAddCommand' ),
83111 },
84112 widgets .HotkeyLabel {
85- frame = {b = 1 , l = 19 },
113+ frame = {b = 2 , l = 19 },
86114 key = ' CUSTOM_SHIFT_D' ,
87115 label = ' Delete command' ,
88116 auto_width = true ,
89117 on_activate = self :callback (' onDelCommand' ),
90118 },
91119 widgets .HotkeyLabel {
92- frame = {b = 0 , l = 0 },
120+ frame = {b = 1 , l = 0 },
93121 key = ' CUSTOM_SHIFT_E' ,
94122 label = ' Edit command' ,
95123 auto_width = true ,
96124 on_activate = self :callback (' onEditCommand' ),
97125 },
126+ widgets .HotkeyLabel {
127+ frame = {b = 1 , l = 19 },
128+ key = ' CUSTOM_SHIFT_N' ,
129+ label = ' Edit name' ,
130+ auto_width = true ,
131+ on_activate = self :callback (' onSetName' ),
132+ },
133+ widgets .HotkeyLabel {
134+ frame = {b = 0 , l = 0 },
135+ key = ' CUSTOM_SHIFT_O' ,
136+ label = ' Capture output' ,
137+ auto_width = true ,
138+ on_activate = self :callback (' onToggleOutput' ),
139+ },
98140 }
99141
100142 self :updateList ()
101143end
102144
103145function QCMDDialog :submit (idx , choice )
146+ local cmd_obj = self .commands [idx ]
147+
148+ if cmd_obj .show_output then
149+ self :showCommandOutput (cmd_obj .command , cmd_obj .name )
150+ else
151+ local screen = self .parent_view
152+ dfhack .screen .hideGuard (screen , function ()
153+ dfhack .run_command (cmd_obj .command )
154+ end )
155+ screen :dismiss ()
156+ end
157+ end
158+
159+ function QCMDDialog :showCommandOutput (command , name )
160+ local output = dfhack .run_command_silent (command )
161+
162+ -- Dismiss the quickcmd dialog before showing output
104163 local screen = self .parent_view
105- dfhack .screen .hideGuard (screen , function ()
106- dfhack .run_command (choice .command )
107- end )
108164 screen :dismiss ()
165+
166+ local OutputDialog = defclass (OutputDialog , gui .ZScreen )
167+ OutputDialog .ATTRS {
168+ focus_path = ' quickcmd_output' ,
169+ command = ' ' ,
170+ name = ' ' ,
171+ output = ' ' ,
172+ }
173+
174+ function OutputDialog :init ()
175+ local title = (' %s%s' ):format (self .name ~= ' ' and self .name .. ' : ' or ' ' , self .command )
176+
177+ self :addviews {
178+ widgets .Window {
179+ frame_title = title ,
180+ frame = {w = 80 , h = 25 },
181+ resizable = true ,
182+ resize_min = {h = 10 , w = 40 },
183+ subviews = {
184+ widgets .WrappedLabel {
185+ view_id = ' output' ,
186+ frame = {t = 0 , l = 0 , r = 0 , b = 2 },
187+ text_to_wrap = self .output or ' No output' ,
188+ scroll_keys = widgets .STANDARDSCROLL ,
189+ },
190+ widgets .HotkeyLabel {
191+ frame = {b = 0 , l = 0 },
192+ key = ' LEAVESCREEN' ,
193+ label = ' Close' ,
194+ auto_width = true ,
195+ on_activate = self :callback (' dismiss' ),
196+ },
197+ }
198+ }
199+ }
200+ end
201+
202+ if # output == 0 then
203+ output = ' Command finished successfully'
204+ end
205+
206+ OutputDialog {command = command , name = name , output = output }:show ()
109207end
110208
111209function QCMDDialog :updateList ()
112210 -- Build the list entries.
113211 local choices = {}
114- for i ,command in ipairs (self .commands ) do
212+ for i ,cmd_obj in ipairs (self .commands ) do
115213 -- Get the hotkey for this entry.
116214 local hotkey = nil
117215 if i <= HOTKEYS :len () then
118216 hotkey = HOTKEYS :sub (i , i )
119217 end
120218
219+ -- Display name if set, otherwise display command
220+ local display_text = cmd_obj .name or cmd_obj .command
221+
121222 -- Store the entry.
122223 table.insert (choices , {
123- text = {{text = hotkey or ' ' , width = HOTKEYWIDTH }, ' ' , command },
124- command = command ,
224+ text = {{text = hotkey or ' ' , width = HOTKEYWIDTH }, {text = cmd_obj .show_output and ' [X]' or ' [ ]' , width = OUTWIDTH }, display_text },
225+ command = cmd_obj .command ,
226+ name = cmd_obj .name ,
227+ show_output = cmd_obj .show_output ,
125228 hotkey = hotkey and (' CUSTOM_' .. hotkey :upper ()) or ' ' ,
126229 })
127230 end
@@ -148,7 +251,7 @@ function QCMDDialog:onAddCommand()
148251 COLOR_GREEN ,
149252 ' ' ,
150253 function (command )
151- table.insert (self .commands , command )
254+ table.insert (self .commands , { command = command , name = nil , show_output = false } )
152255 save_commands (self .commands )
153256 self :updateList ()
154257 end
@@ -165,7 +268,7 @@ function QCMDDialog:onDelCommand()
165268 -- Prompt for confirmation.
166269 dlg .showYesNoPrompt (
167270 ' Delete command' ,
168- ' Are you sure you want to delete this command: ' .. NEWLINE .. item .command ,
271+ ' Are you sure you want to delete this command: ' .. NEWLINE .. self . commands [ index ] .command ,
169272 COLOR_GREEN ,
170273 function ()
171274 table.remove (self .commands , index )
@@ -187,15 +290,49 @@ function QCMDDialog:onEditCommand()
187290 ' Edit command' ,
188291 ' Enter command:' ,
189292 COLOR_GREEN ,
190- item .command ,
293+ self . commands [ index ] .command ,
191294 function (command )
192- self .commands [index ] = command
295+ self .commands [index ]. command = command
193296 save_commands (self .commands )
194297 self :updateList ()
195298 end
196299 )
197300end
198301
302+ function QCMDDialog :onSetName ()
303+ -- Get the selected command.
304+ local index , item = self .subviews .list :getSelected ()
305+ if not item then
306+ return
307+ end
308+
309+ -- Prompt for new name.
310+ dlg .showInputPrompt (
311+ ' Set name' ,
312+ ' Enter name:' ,
313+ COLOR_GREEN ,
314+ self .commands [index ].name or ' ' ,
315+ function (name )
316+ self .commands [index ].name = name ~= ' ' and name or nil
317+ save_commands (self .commands )
318+ self :updateList ()
319+ end
320+ )
321+ end
322+
323+ function QCMDDialog :onToggleOutput ()
324+ -- Get the selected command.
325+ local index , item = self .subviews .list :getSelected ()
326+ if not item then
327+ return
328+ end
329+
330+ -- Toggle the show_output flag.
331+ self .commands [index ].show_output = not self .commands [index ].show_output
332+ save_commands (self .commands )
333+ self :updateList ()
334+ end
335+
199336QCMDScreen = defclass (QCMDScreen , gui .ZScreen )
200337QCMDScreen .ATTRS {
201338 focus_path = ' quickcmd' ,
0 commit comments