|
1 | 1 | #! /usr/bin/env lua |
2 | 2 | --===================================================================== |
3 | 3 | -- |
4 | | --- z.lua - a cd command that learns, by skywind 2018, 2019 |
| 4 | +-- z.lua - a cd command that learns, by skywind 2018, 2019, 2020 |
5 | 5 | -- Licensed under MIT license. |
6 | 6 | -- |
7 | | --- Version 1.7.4, Last Modified: 2019/12/29 04:52 |
| 7 | +-- Version 1.8.1, Last Modified: 2020/02/09 23:33 |
8 | 8 | -- |
9 | 9 | -- * 10x faster than fasd and autojump, 3x faster than z.sh |
10 | 10 | -- * available for posix shells: bash, zsh, sh, ash, dash, busybox |
@@ -1585,7 +1585,7 @@ function z_cd(patterns) |
1585 | 1585 | io.stderr:write('> ') |
1586 | 1586 | io.stderr:flush() |
1587 | 1587 | local input = io.read('*l') |
1588 | | - if input == nil then |
| 1588 | + if input == nil or input == '' then |
1589 | 1589 | return nil |
1590 | 1590 | end |
1591 | 1591 | local index = tonumber(input) |
@@ -1767,6 +1767,103 @@ function cd_minus(args, options) |
1767 | 1767 | end |
1768 | 1768 |
|
1769 | 1769 |
|
| 1770 | +----------------------------------------------------------------------- |
| 1771 | +-- cd breadcrumbs: z -b -i, z -b -I |
| 1772 | +----------------------------------------------------------------------- |
| 1773 | +function cd_breadcrumbs(pwd, interactive) |
| 1774 | + local pwd = (pwd == nil or pwd == '') and os.pwd() or pwd |
| 1775 | + local pwd = os.path.normpath(pwd) |
| 1776 | + local path, _ = os.path.split(pwd) |
| 1777 | + local elements = {} |
| 1778 | + local interactive = interactive and interactive or 1 |
| 1779 | + local fullname = os.environ('_ZL_FULL_PATH', false) |
| 1780 | + -- fullname = true |
| 1781 | + while true do |
| 1782 | + local head, name = os.path.split(path) |
| 1783 | + if head == path then -- reached root |
| 1784 | + table.insert(elements, {head, head}) |
| 1785 | + break |
| 1786 | + elseif name ~= '' then |
| 1787 | + table.insert(elements, {name, path}) |
| 1788 | + else |
| 1789 | + break |
| 1790 | + end |
| 1791 | + path = head |
| 1792 | + end |
| 1793 | + -- printT(elements) |
| 1794 | + local tmpname = '/tmp/zlua.txt' |
| 1795 | + local fp = io.stderr |
| 1796 | + if interactive == 2 then |
| 1797 | + if not windows then |
| 1798 | + tmpname = os.tmpname() |
| 1799 | + else |
| 1800 | + tmpname = os.tmpname():gsub('\\', ''):gsub('%.', '') |
| 1801 | + tmpname = os.environ('TMP', '') .. '\\zlua_' .. tmpname .. '.txt' |
| 1802 | + end |
| 1803 | + fp = io.open(tmpname, 'w') |
| 1804 | + end |
| 1805 | + -- print table |
| 1806 | + local maxsize = string.len(tostring(#elements)) |
| 1807 | + for i = #elements, 1, -1 do |
| 1808 | + local item = elements[i] |
| 1809 | + local name = item[1] |
| 1810 | + local text = string.rep(' ', maxsize - string.len(i)) .. tostring(i) |
| 1811 | + text = text .. ': ' .. (fullname and item[2] or item[1]) |
| 1812 | + fp:write(text .. '\n') |
| 1813 | + end |
| 1814 | + if fp ~= io.stderr then |
| 1815 | + fp:close() |
| 1816 | + end |
| 1817 | + -- select from stdin or fzf |
| 1818 | + if interactive == 1 then |
| 1819 | + io.stderr:write('> ') |
| 1820 | + io.stderr:flush() |
| 1821 | + local input = io.read('*l') |
| 1822 | + if input == nil or input == '' then |
| 1823 | + return nil |
| 1824 | + end |
| 1825 | + local index = tonumber(input) |
| 1826 | + if index < 1 or index > #elements then |
| 1827 | + return nil |
| 1828 | + end |
| 1829 | + retval = elements[index][2] |
| 1830 | + elseif interactive == 2 then |
| 1831 | + local fzf = os.environ('_ZL_FZF', 'fzf') |
| 1832 | + local cmd = '--reverse --inline-info --tac ' |
| 1833 | + local flag = os.environ('_ZL_FZF_FLAG', '') |
| 1834 | + flag = (flag == '' or flag == nil) and '+s -e' or flag |
| 1835 | + cmd = ((fzf == '') and 'fzf' or fzf) .. ' ' .. cmd .. ' ' .. flag |
| 1836 | + if not windows then |
| 1837 | + local height = os.environ('_ZL_FZF_HEIGHT', '35%') |
| 1838 | + if height ~= nil and height ~= '' and height ~= '0' then |
| 1839 | + cmd = cmd .. ' --height ' .. height |
| 1840 | + end |
| 1841 | + cmd = cmd .. '< "' .. tmpname .. '"' |
| 1842 | + else |
| 1843 | + cmd = 'type "' .. tmpname .. '" | ' .. cmd |
| 1844 | + end |
| 1845 | + retval = os.call(cmd) |
| 1846 | + os.remove(tmpname) |
| 1847 | + if retval == '' or retval == nil then |
| 1848 | + return nil |
| 1849 | + end |
| 1850 | + local pos = retval:find(':') |
| 1851 | + if not pos then |
| 1852 | + return nil |
| 1853 | + end |
| 1854 | + retval = retval:sub(1, pos - 1):gsub('^%s*', '') |
| 1855 | + index = tonumber((retval == nil) and '0' or retval) |
| 1856 | + if index == nil then |
| 1857 | + return nil |
| 1858 | + elseif index < 1 or index > #elements then |
| 1859 | + return nil |
| 1860 | + end |
| 1861 | + retval = elements[index][2] |
| 1862 | + end |
| 1863 | + return retval |
| 1864 | +end |
| 1865 | + |
| 1866 | + |
1770 | 1867 | ----------------------------------------------------------------------- |
1771 | 1868 | -- main entry |
1772 | 1869 | ----------------------------------------------------------------------- |
@@ -1801,7 +1898,11 @@ function main(argv) |
1801 | 1898 | if options['--cd'] or options['-e'] then |
1802 | 1899 | local path = '' |
1803 | 1900 | if options['-b'] then |
1804 | | - path = cd_backward(args, options) |
| 1901 | + if Z_INTERACTIVE == 0 then |
| 1902 | + path = cd_backward(args, options) |
| 1903 | + else |
| 1904 | + path = cd_breadcrumbs('', Z_INTERACTIVE) |
| 1905 | + end |
1805 | 1906 | elseif options['-'] then |
1806 | 1907 | path = cd_minus(args, options) |
1807 | 1908 | elseif #args == 0 then |
|
0 commit comments