Instantly share code, notes, and snippets.

@DeaR /z.lua
Last active Dec 11, 2015

Embed
What would you like to do?
Porting z.sh for NYAOS 3.x
-- Porting z.sh for NYAOS 3.x
--
-- Maintainer: DeaR <nayuri@kuonn.mydns.jp>
-- Last Change: 13-Aug-2013.
-- License: MIT License {{{
-- Copyright (c) 2013 DeaR <nayuri@kuonn.mydns.jp>
--
-- Permission is hereby granted, free of charge, to any person obtaining a
-- copy of this software and associated documentation files (the
-- "Software"), to deal in the Software without restriction, including
-- without limitation the rights to use, copy, modify, merge, publish,
-- distribute, sublicense, and/or sell copies of the Software, and to
-- permit persons to whom the Software is furnished to do so, subject to
-- the following conditions:
--
-- The above copyright notice and this permission notice shall be included
-- in all copies or substantial portions of the Software.
--
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-- OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
-- IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
-- CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
-- TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
-- SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-- }}}
-- Copyright (c) 2009 rupa deadwyler under the WTFPL license
--
-- maintains a jump-list of the directories you actually use
--
-- INSTALL:
-- * put something like this in your .bashrc/.zshrc:
-- . /path/to/z.sh
-- * cd around for a while to build up the db
-- * PROFIT!!
-- * optionally:
-- set $_Z_CMD in .bashrc/.zshrc to change the command (default z).
-- set $_Z_DATA in .bashrc/.zshrc to change the datafile (default ~/.z).
-- set $_Z_NO_RESOLVE_SYMLINKS to prevent symlink resolution.
-- set $_Z_NO_PROMPT_COMMAND if you're handling PROMPT_COMMAND yourself.
-- set $_Z_EXCLUDE_DIRS to an array of directories to exclude.
--
-- USE:
-- * z foo # cd to most frecent dir matching foo
-- * z foo bar # cd to most frecent dir matching foo and bar
-- * z -r foo # cd to highest ranked dir matching foo
-- * z -t foo # cd to most recently accessed dir matching foo
-- * z -l foo # list all dirs matching foo (by frecency)
-- * z -c foo # restrict matches to subdirs of $PWD
local function _init()
local home = (os.getenv('HOME') or os.getenv('USERPROFILE')):gsub('/', '\\')
local datafile = os.getenv('_Z_DATA') or (home .. '\\_z')
local stat = nyaos.stat(datafile)
if stat and stat.directory then
print('ERROR: z.lua\039s datafile (' .. datafile .. ') is a directory.')
end
end
_init()
function _z(...)
function _shortest_match(s1, s2)
local ret = s1
for i = 1, (#s1 < #s2 and #s1 or #s2) do
if string.sub(s1, 1, i):lower() ~= string.sub(s2, 1, i):lower() then
return ret
end
ret = string.sub(s1, 1, i)
end
return ret
end
local arg = {...}
local home = (os.getenv('HOME') or os.getenv('USERPROFILE')):gsub('/', '\\')
local datafile = os.getenv('_Z_DATA') or (home .. '\\_z')
-- bail out if we don't own ~/_z (we're another user but our ENV is still set)
if not nyaos.access(datafile, 0) then
local f = io.open(datafile, 'w')
f:close()
elseif not nyaos.access(datafile, 2) then
return
end
if arg[1] == '--add' then
-- add entries
local arg2 = arg[2]:gsub('/', '\\')
-- $HOME isn't worth matching
if arg2 == home then
return
end
-- don't track excluded dirs
for exclude in string.gmatch(os.getenv('_Z_EXCLUDE_DIRS') or '', '[^;]+') do
if arg2 == exclude:gsub('/', '\\') then
return
end
end
-- maintain the file
local temp = {}
local count = 0
temp[arg2] = {rank = 1, time = os.time()}
for l in io.lines(datafile) do
local _dir, _rank, _time = l:match('^(.+)%|(%d+)%|(%d+)$')
if(_dir == arg2) then
temp[_dir] = {rank = tonumber(_rank) + 1, time = os.time()}
else
temp[_dir] = {rank = tonumber(_rank), time = tonumber(_time)}
end
count = count + tonumber(_rank)
end
local f = io.open(datafile, 'w')
for k, v in pairs(temp) do
local stat = nyaos.stat(k)
if stat and stat.directory then
if(count > 6000) then
f:write(k .. '|' .. v.rank * 0.99 .. '|' .. v.time .. '\n')
else
f:write(k .. '|' .. v.rank .. '|' .. v.time .. '\n')
end
end
end
f:close()
elseif arg[1] == '--complete' then
-- tab completion
local ret = {}
for l in io.lines(datafile) do
local _dir, _rank, _time = l:match('^(.+)%|(%d+)%|(%d+)$')
local stat = nyaos.stat(_dir)
if stat and stat.directory then
if _dir:lower():match((arg2 or ''):lower()) then
table.insert(ret, {_dir, (_dir:match('[^/\\]+$') or '') .. '\\'})
end
end
end
return ret
elseif arg[1] == '--shortest-match' then
-- shortest match
local arg2 = arg[2]:gsub('/', '\\')
local base, opt = arg2:match('^(.-)([^/\\]*)$')
if opt:len() == 0 then
return arg2
end
local m = {}
for l in io.lines(datafile) do
local _dir, _rank, _time = l:match('^(.+)%|(%d+)%|(%d+)$')
local stat = nyaos.stat(_dir)
if stat and stat.directory then
if _dir:lower() == arg2:lower() then
return _dir
elseif _dir:lower():match(base:lower()) and _dir:lower():match(opt:lower()) then
table.insert(m, _dir)
end
end
end
if #m == 0 then
return nil
end
local ret = m[1]
for i = 1, #m do
ret = _shortest_match(ret, m[i])
end
return ret
else
-- list/go
local list, typ
local last = ''
local fnd = {}
local pwd = nyaos.eval('pwd')
for i = 1, #arg do
if arg[i] == '--' then
for j = i, #arg do
table.insert(fnd, arg[j])
end
i = #arg
elseif arg[i]:match('^-.') then
if arg[i]:match('c') then
table.insert(fnd, pwd)
table.insert(fnd, arg[i])
elseif arg[i]:match('h') then
return (os.getenv('_Z_CMD') or 'z') .. ' [-chlrt] arg'
elseif arg[i]:match('l') then
list = 1
elseif arg[i]:match('r') then
typ = 'rank'
elseif arg[i]:match('-t') then
typ = 'recent'
end
else
table.insert(fnd, arg[i])
end
last = arg[i]
end
if #fnd == 1 and fnd[1] == pwd then
list = 1
end
-- if we hit enter on a completion just go there
local dir = last:gsub('\034', ''):gsub('\\$', ''):gsub('/', '\\')
local stat = nyaos.stat(dir)
if stat and stat.directory then
nyaos.exec('cd ' .. last)
end
function frecent(rank, time)
local dx = os.time() - time
if dx < 3600 then
return rank * 4
elseif dx < 86400 then
return rank * 2
elseif dx < 604800 then
return rank / 2
end
return rank / 4
end
function output(files, toopen, override)
if list then
local r = {}
for k, v in pairs(files) do
if v and v ~= 0 then
table.insert(r, {v, k})
end
end
table.sort(r, function(a, b) return (a[1] < b[1]) end)
if override then
print(string.format('%-10s %s', 'common:', override))
end
for i = 1, #r do
print(string.format('%-10s %s', r[i][1], r[i][2]))
end
else
if override then
return override
else
return toopen
end
end
end
function common(matches)
-- shortest match
local ret = nil
for k, v in pairs(matches) do
if ret then
ret = _shortest_match(ret, k)
else
ret = k
end
end
for k, v in pairs(matches) do
if k == ret then
return ret
end
end
end
local cd, cx, ncx
local wcase = {}
local nocase = {}
local oldf = -9999999999
local noldf = -9999999999
for l in io.lines(datafile) do
local _dir, _rank, _time = l:match('^(.+)%|(%d+)%|(%d+)$')
local stat = nyaos.stat(_dir)
if stat and stat.directory then
local f
if typ == 'rank' then
f = tonumber(_rank)
elseif typ == 'recent' then
f = tonumber(_time) - os.time()
else
f = frecent(tonumber(_rank), tonumber(_time))
end
wcase[_dir] = f
nocase[_dir] = f
for i = 1, #fnd do
local fndi = fnd[i]:gsub('/', '\\')
if not _dir:match(fndi) then
wcase[_dir] = nil
end
if not _dir:lower():match(fndi:lower()) then
nocase[_dir] = nil
end
end
if wcase[_dir] and wcase[_dir] > oldf then
cx = _dir
oldf = wcase[_dir]
elseif nocase[_dir] and nocase[_dir] > noldf then
ncx = _dir
noldf = nocase[_dir]
end
end
end
if cx then
cd = output(wcase, cx, common(wcase))
else
cd = output(nocase, ncx, common(nocase))
end
if cd then
nyaos.exec('cd ' .. cd)
end
end
end
function nyaos.command._z(...)
local r = _z(...)
local arg = {...}
if r then
if arg[1] == '--complete' then
for i = 1, #r do
print(r[i][1])
end
else
print(r)
end
end
end
nyaos.alias[os.getenv('_Z_CMD') or 'z'] = '_z'
function nyaos.keyhook._z(t)
function _is_tab()
for k in string.gmatch(os.getenv('_Z_TAB') or 'TAB;CTRL_I', '[^;]+') do
if t.key == nyaos.key[k] then
return true
end
end
return false
end
local cl = t.text:match('[;|]') and t.text:match('[^;|]+$') or t.text
local cmd = (cl:match('^%s*\034([^\034]+)\034') or cl:match('^%s*([^%s]+)') or ''):match('[^/\\]+$')
if cmd == (os.getenv('_Z_CMD') or 'z') then
local arg = cl:match(cmd .. '%s+(.*)')
if arg and _is_tab() then
local s = _z('--shortest-match', arg:gsub('/', '\\'))
if s and s ~= arg then
local t = {}
for i = 1, #arg do
table.insert(t, nyaos.key[os.getenv('_Z_BACKSPACE') or 'BACKSPACE'])
end
table.insert(t, s)
return t
end
end
end
end
-- nyaos tab completion. avoid clobbering other nyaos.complete.
if not os.getenv('_Z_NO_COMPLETE') then
if nyaos_complete_by then
nyaos_complete_by[os.getenv('_Z_CMD') or 'z'] = function(basestring, pos, misc)
return _z('--complete', basestring)
end
else
function nyaos.complete(basestring, pos, misc)
local cl = misc.text:match('[;|]') and misc.text:match('[^;|]+$') or misc.text
local cmd = (cl:match('^%s*\034([^\034]+)\034') or cl:match('^%s*([^%s]+)') or ''):match('[^/\\]+$')
if cmd == (os.getenv('_Z_CMD') or 'z') then
return _z('--complete', basestring)
end
return nyaos.default_complete(basestring, pos)
end
end
end
-- nyaos populate directory list. avoid clobbering other nyaos.prompt.
if not os.getenv('_Z_NO_PROMPT_COMMAND') then
function nyaos.prompt(p)
_z('--add', nyaos.eval('pwd'))
end
end
-- vim: ft=lua

z.lua

Porting z.sh for NYAOS 3.x

Install

  1. Checkout the source from repository

    git clone https://gist.github.com/4554687.git z
  2. add to _nya

    # change the command (default z). 
    # set _Z_CMD=j
    
    # change the datafile (default ~/_z).
    # set _Z_DATA=C:/_z
    
    # if you're handling nyaos.prompt yourself.
    # set _Z_NO_PROMPT_COMMAND=1
    
    # an array of directories to exclude.
    # set _Z_EXCLUDE_DIRS=C:\;D:\;E:\
    
    # if you're handling nyaos.complete yourself.
    # set _Z_NO_COMPLETE=1
    
    # if you're binding complete-or-list other keys (default TAB;CTRL_I).
    # set _Z_TAB=CTRL_T;CTRL_A
    
    # if you're binding backward-delete-char other keys (default BACKSPACE).
    # set _Z_BACKSPACE=CTRL_H
    
    source z/z.lua
  3. if set _Z_NO_PROMPT_COMMAND=1 add to nyaos.prompt

    _z('--add', nyaos.eval('pwd'))
  4. if set _Z_NO_COMPLETE=1 add to nyaos.complete

    return _z('--complete', BASESTRING)

Usage

  • z foo : cd to most frecent dir matching foo
  • z foo bar : cd to most frecent dir matching foo and bar
  • z -r foo : cd to highest ranked dir matching foo
  • z -t foo : cd to most recently accessed dir matching foo
  • z -l foo : list all dirs matching foo (by frecency)

Issue

Author

DeaR (nayuri@kuonn.mydns.jp)

@nayuri_aohime

License

Copyright (c) 2013 DeaR <nayuri@kuonn.mydns.jp>

Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies
or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment