1if not modules then modules = { } end modules ['mtx-fcd'] = {
2 version = 1.002,
3 comment = "companion to mtxrun.lua",
4 author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
5 copyright = "PRAGMA ADE / ConTeXt Development Team",
6 license = "see context related readme files",
7 comment = "based on the ruby version from 2005",
8}
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24local helpinfo = [[
25<?xml version="1.0"?>
26<application>
27 <metadata>
28 <entry name="name">mtx-fcd</entry>
29 <entry name="detail">Fast Directory Change</entry>
30 <entry name="version">1.00</entry>
31 </metadata>
32 <flags>
33 <category name="basic">
34 <subcategory>
35 <flag name="clear"><short>clear the cache</short></flag>
36 <flag name="clear"><short><ref name="history"/> [entry] clear the history</short></flag>
37 <flag name="scan"><short>clear the cache and add given path(s)</short></flag>
38 <flag name="add"><short>add given path(s)</short></flag>
39 <flag name="find"><short>find given path (can be substring)</short></flag>
40 <flag name="find"><short><ref name="nohistory"/> find given path (can be substring) but don't use history</short></flag>
41 <flag name="stub"><short>print platform stub file</short></flag>
42 <flag name="list"><short>show roots of cached dirs</short></flag>
43 <flag name="list"><short><ref name="history"/> show history of chosen dirs</short></flag>
44 <flag name="help"><short>show this help</short></flag>
45 </subcategory>
46 </category>
47 </flags>
48 <examples>
49 <category>
50 <title>Example</title>
51 <subcategory>
52 <example><command>fcd --scan t:\</command></example>
53 <example><command>fcd --add f:\project</command></example>
54 <example><command>fcd [--find] whatever</command></example>
55 <example><command>fcd --list</command></example>
56 </subcategory>
57 </category>
58 </examples>
59</application>
60]]
61
62local application = logs.application {
63 name = "mtx-fcd",
64 banner = "Fast Directory Change 1.00",
65 helpinfo = helpinfo,
66}
67
68local report = application.report
69local writeln = (logs and logs.writer) or (texio and texio.write_nl) or print
70
71local find, char, byte, lower, gsub, format = string.find, string.char, string.byte, string.lower, string.gsub, string.format
72
73local mswinstub = [[@echo off
74
75rem this is: fcd.cmd
76
77@echo off
78
79if not exist "%HOME%" goto homepath
80
81:home
82
83mtxrun --script mtx-fcd.lua %1 %2 %3 %4 %5 %6 %7 %8 %9
84
85if exist "%HOME%\mtx-fcd-goto.cmd" call "%HOME%\mtx-fcd-goto.cmd"
86
87goto end
88
89:homepath
90
91if not exist "%HOMEDRIVE%\%HOMEPATH%" goto end
92
93mtxrun --script mtx-fcd.lua %1 %2 %3 %4 %5 %6 %7 %8 %9
94
95if exist "%HOMEDRIVE%\%HOMEPATH%\mtx-fcd-goto.cmd" call "%HOMEDRIVE%\%HOMEPATH%\mtx-fcd-goto.cmd"
96
97goto end
98
99:end
100]]
101
102local unixstub = [[#!/usr/bin/env sh
103
104# this is: fcd.sh
105
106# mv fcd.sh fcd
107# chmod fcd 755
108# . fcd [args]
109
110ruby -S fcd_start.rb $1 $2 $3 $4 $5 $6 $7 $8 $9
111
112if test -f "$HOME/fcd_stage.sh" ; then
113 . $HOME/fcd_stage.sh ;
114fi;
115
116]]
117
118local gotofile
119local datafile
120local stubfile
121local stubdata
122local stubdummy
123local stubchdir
124
125
126if os.type == 'windows' then
127 local shell = "cmd"
128
129 if shell == "powershell" then
130 gotofile = 'mtx-fcd-goto.ps1'
131 datafile = 'mtx-fcd-data.lua'
132 stubfile = 'fcd.cmd'
133 stubdata = mswinstub
134 stubdummy = '# no dir to change to'
135 stubchdir = '. Set-Location %s'
136 else
137 gotofile = 'mtx-fcd-goto.cmd'
138 datafile = 'mtx-fcd-data.lua'
139 stubfile = 'fcd.cmd'
140 stubdata = mswinstub
141 stubdummy = 'rem no dir to change to'
142 stubchdir = 'cd /d "%s"'
143 end
144else
145 gotofile = 'mtx-fcd-goto.sh'
146 datafile = 'mtx-fcd-data.lua'
147 stubfile = 'fcd.sh'
148 stubdata = unixstub
149 stubdummy = '# no dir to change to'
150 stubchdir = '# cd "%s"'
151end
152
153local homedir = os.env["HOME"] or ""
154
155if homedir == "" then
156 homedir = format("%s/%s",os.env["HOMEDRIVE"] or "",os.env["HOMEPATH"] or "")
157end
158
159if homedir == "/" or not lfs.isdir(homedir) then
160 os.exit()
161end
162
163local datafile = file.join(homedir,datafile)
164local gotofile = file.join(homedir,gotofile)
165local hash = nil
166local found = { }
167local pattern = ""
168local version = modules['mtx-fcd'].version
169
170io.savedata(gotofile,stubdummy)
171
172if not lfs.isfile(gotofile) then
173
174 os.exit()
175end
176
177local function fcd_clear(onlyhistory,what)
178 if onlyhistory and hash and hash.history then
179 if what and what ~= "" then
180 hash.history[what] = nil
181 else
182 hash.history = { }
183 end
184 else
185 hash = {
186 name = "fcd cache",
187 comment = "generated by mtx-fcd.lua",
188 created = os.date(),
189 version = version,
190 paths = { },
191 history = { },
192 }
193 end
194end
195
196local function fcd_changeto(dir)
197 if dir and dir ~= "" then
198 io.savedata(gotofile,format(stubchdir,dir,dir))
199 end
200end
201
202local function fcd_load(forcecreate)
203 if lfs.isfile(datafile) then
204 hash = dofile(datafile)
205 end
206 if not hash or hash.version ~= version then
207 if forcecache then
208 fcd_clear()
209 else
210 writeln("empty dir cache")
211 fcd_clear()
212 os.exit()
213 end
214 end
215end
216
217local function fcd_save()
218 if hash then
219 io.savedata(datafile,table.serialize(hash,true))
220 end
221end
222
223local function fcd_list(onlyhistory)
224 if hash then
225 writeln("")
226 if onlyhistory then
227 if next(hash.history) then
228 for k, v in table.sortedhash(hash.history) do
229 writeln(format("%s => %s",k,v))
230 end
231 else
232 writeln("no history")
233 end
234 else
235 local paths = hash.paths
236 if #paths > 0 then
237 for i=1,#paths do
238 local path = paths[i]
239 writeln(format("%4i %s",#path[2],path[1]))
240 end
241 else
242 writeln("empty cache")
243 end
244 end
245 end
246end
247
248local function fcd_find()
249 found = { }
250 pattern = lower(environment.files[1] or "")
251 if pattern ~= "" then
252 pattern = string.escapedpattern(pattern)
253 local paths = hash.paths
254 for i=1,#paths do
255 local paths = paths[i][2]
256 for i=1,#paths do
257 local path = paths[i]
258 if find(lower(path),pattern) then
259 found[#found+1] = path
260 end
261 end
262 end
263 end
264end
265
266local function fcd_choose(new)
267 if pattern == "" then
268 writeln(format("staying in dir %q",(gsub(lfs.currentdir(),"\\","/"))))
269 return
270 end
271 if #found == 0 then
272 writeln(format("dir %q not found",pattern))
273 return
274 end
275 local okay = #found == 1 and found[1] or (not new and hash.history[pattern])
276 if okay then
277 writeln(format("changing to %q",okay))
278 fcd_changeto(okay)
279 return
280 end
281 local offset = 0
282 while true do
283 if not found[offset] then
284 offset = 0
285 end
286 io.write("\n")
287 for i=1,26 do
288 local v = found[i+offset]
289 if v then
290 writeln(format("%s %3i %s",char(i+96),offset+i,v))
291 else
292 break
293 end
294 end
295 offset = offset + 26
296 if found[offset+1] then
297 io.write("\n[press enter for more or select letter]\n\n>> ")
298 else
299 io.write("\n[select letter]\n\n>> ")
300 end
301 local answer = lower(io.read() or "")
302 if not answer or answer == 'quit' then
303 break
304 elseif #answer > 0 then
305 local choice = tonumber(answer)
306 if not choice then
307 if answer >= "a" and answer <= "z" then
308 choice = byte(answer) - 96 + offset - 26
309 end
310 end
311 local newdir = found[choice]
312 if newdir then
313 hash.history[pattern] = newdir
314 writeln(format("changing to %q",newdir))
315 fcd_changeto(newdir)
316 fcd_save()
317 return
318 end
319 else
320
321 end
322 end
323end
324
325local function globdirs(path,dirs)
326 local dirs = dirs or { }
327 for name in lfs.dir(path) do
328 if not find(name,"%.$") then
329 local fullname = path .. "/" .. name
330 if lfs.isdir(fullname) and not find(fullname,"/%.") then
331 dirs[#dirs+1] = fullname
332 globdirs(fullname,dirs)
333 end
334 end
335 end
336 return dirs
337end
338
339local function fcd_scan()
340 if hash then
341 local paths = hash.paths
342 for i=1,#environment.files do
343 local name = environment.files[i]
344 local name = gsub(name,"\\","/")
345 local name = gsub(name,"/$","")
346 local list = globdirs(name)
347 local done = false
348 for i=1,#paths do
349 if paths[i][1] == name then
350 paths[i][2] = list
351 done = true
352 break
353 end
354 end
355 if not done then
356 paths[#paths+1] = { name, list }
357 end
358 end
359 end
360end
361
362local argument = environment.argument
363
364if argument("clear") then
365 if argument("history") then
366 fcd_load()
367 fcd_clear(true)
368 else
369 fcd_clear()
370 end
371 fcd_save()
372elseif argument("scan") then
373 fcd_clear()
374 fcd_scan()
375 fcd_save()
376elseif argument("add") then
377 fcd_load(true)
378 fcd_scan()
379 fcd_save()
380elseif argument("stub") then
381 writeln(stubdata)
382elseif argument("list") then
383 fcd_load()
384 if argument("history") then
385 fcd_list(true)
386 else
387 fcd_list()
388 end
389elseif argument("help") then
390 application.help()
391elseif argument("exporthelp") then
392 application.export(argument("exporthelp"),environment.files[1])
393else
394 fcd_load()
395 fcd_find()
396 fcd_choose(argument("nohistory"))
397end
398
399 |