Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for cmd.exe #218

Open
fabioz opened this issue Jun 1, 2021 · 15 comments
Open

Support for cmd.exe #218

fabioz opened this issue Jun 1, 2021 · 15 comments
Labels
integration Request for supporting another shell, application, etc.

Comments

@fabioz
Copy link

fabioz commented Jun 1, 2021

Usually I use cmder as a shell which mostly wraps cmd in Windows -- and I'm really happy with it -- i.e.: https://cmder.net/ (https://github.com/cmderdev/cmder).

Is it possible to use zoxide in it? I only found instructions for power shell in windows, not really cmd, but maybe I missed something...

@ajeetdsouza ajeetdsouza changed the title Support for cmder Support for cmd.exe Jun 1, 2021
@ajeetdsouza
Copy link
Owner

Hey @fabioz, cmd.exe is not supported at the moment, you'd only be able to use cmder with the Bash and PowerShell modes. I don't know cmd.exe, so I can't be very helpful here -- but if you're proficient with it, it shouldn't take very long to implement:

  • z calls zoxide query
  • cd calls zoxide add
  • zoxide init <SHELL> is a useful reference for how this is implemented in other shells.

Unless this issue gains a lot of traction, I'd be hesitant to support it officially:

  • Microsoft is moving everything over to PowerShell as the new default
  • cmd.exe has been deprecated for years now

However, if you do end up implementing it on your own, do post it here -- I'm sure other cmd.exe users would find it helpful.

@mwaitzman
Copy link

I use cmd too and I would like support for zoxide. Powershell is terrible.

@rashil2000
Copy link

rashil2000 commented Aug 5, 2021

@ajeetdsouza FWIW, cmd on its own isn't very configurable. Cmder uses a framework called Clink which adds Bash's Readline support to it and makes it highly extensible (there's a comprehensive documentation available here).

However, if z and cd are the only two commands/functions as you specified above, then they can be easily added through doskey aliases:

  • doskey z=zoxide query $*
  • doskey cd=zoxide add $1 $T cd /d $1

@Lunchb0ne
Copy link

Yeah, is it possible to get clink support for this?

It's quite powerful and I think z.lua already does support it.

@shunsambongi
Copy link

Here's a lua script I wrote for cmd.exe with clink. Put this into a zoxide.lua file in clink's lua scripts location. For cmder you can put it in %cmder_root%\config\zoxide.lua.

I only did some manual testing but it should be able to support many of zoxide's features including:

  • zoxide init options --cmd, --hook, and --no-alias (using clink settings)
  • _ZO_ECHO environment variable
  • fzf integration via zi command
-- =============================================================================
--
-- Settings copied from 'zoxide init'. Run `clink set` to modify these options, e.g. `clink set zoxide.cmd f`
--

settings.add('zoxide.cmd', 'z', 'Changes the prefix of the aliases')
settings.add('zoxide.hook', { 'pwd', 'prompt', 'none' }, 'Changes when directory scores are incremented')
settings.add('zoxide.no_aliases', false, "Don't define aliases")

-- =============================================================================
--
-- Utility functions for zoxide.
--

-- Generate `cd` command
local function __zoxide_cd(dir)
  if os.getenv '_ZO_ECHO' == '1' then
    print(dir)
  end

  -- 'cd /d -' doesn't work for clink versions before v1.2.41 (https://github.com/chrisant996/clink/issues/191)
  -- lastest cmder release (v1.3.18) uses clink v1.1.45
  if dir == '-' and (clink.version_encoded or 0) < 10020042 then
    return 'cd -'
  end

  return 'cd /d ' .. dir
end

-- Run `zoxide query` and generate `cd` command from result
local function __zoxide_query(options, keywords)
  options = table.concat(options, ' ')
  keywords = table.concat(keywords, ' ')

  local file = io.popen('zoxide query ' .. options .. ' -- ' .. keywords)
  local result = file:read '*line'
  local ok = file:close()

  if ok then
    return __zoxide_cd(result)
  else
    return 'call' -- no-op that just sets %ERRORLEVEL% to 1
  end
end

-- Add directory to the database.
local function __zoxide_add(dir)
  os.execute('zoxide add -- "' .. dir .. '"')
end

-- =============================================================================
--
-- Hook configuration for zoxide.
--

local __zoxide_oldpwd
local __zoxide_prompt = clink.promptfilter()

function __zoxide_prompt:filter()
  local zoxide_hook = settings.get 'zoxide.hook'

  if zoxide_hook == 'none' then
    -- do nothing
    return
  elseif zoxide_hook == 'prompt' then
    -- run `zoxide add` on every prompt
    __zoxide_add(os.getcwd())
  elseif zoxide_hook == 'pwd' then
    -- run `zoxide add` when the working directory changes
    local cwd = os.getcwd()
    if __zoxide_oldpwd and __zoxide_oldpwd ~= cwd then
      __zoxide_add(cwd)
    end
    __zoxide_oldpwd = cwd
  end
end

-- =============================================================================
--
-- Define aliases.
--

-- 'z' alias
local function __zoxide_z(keywords)
  if #keywords == 0 then
    return __zoxide_cd(os.getenv 'USERPROFILE')
  elseif #keywords == 1 then
    local keyword = keywords[1]
    if keyword == '-' then
      return __zoxide_cd '-'
    elseif os.isdir(keyword) then
      return __zoxide_cd(keyword)
    end
  end

  local cwd = '"' .. os.getcwd() .. '"'
  return __zoxide_query({ '--exclude', cwd }, keywords)
end

-- 'zi' alias
local function __zoxide_zi(keywords)
  return __zoxide_query({ '--interactive' }, keywords)
end

-- =============================================================================
--
-- Clink input text filter.
--

local function onfilterinput(text)
  args = string.explode(text, ' ', '"')
  if #args == 0 then
    return
  end

  -- settings
  zoxide_cmd = settings.get 'zoxide.cmd'
  zoxide_no_aliases = settings.get 'zoxide.no_aliases'

  -- edge case:
  -- * zoxide command prefix is 'cd'
  -- * clink converted 'cd -' -> 'cd /d "some_directory"'
  local cd_regex = '^%s*cd%s+/d%s+"(.-)"%s*$'
  if zoxide_cmd == 'cd' and text:match(cd_regex) then
    if zoxide_no_aliases then
      -- clink handles it
      return
    else
      -- zoxide handles it
      return __zoxide_cd(text:gsub(cd_regex, '%1')), false
    end
  end

  local cmd = table.remove(args, 1)
  if cmd == '__zoxide_z' or (cmd == zoxide_cmd and not zoxide_no_aliases) then
    return __zoxide_z(args), false
  elseif cmd == '__zoxide_zi' or (cmd == zoxide_cmd .. 'i' and not zoxide_no_aliases) then
    return __zoxide_zi(args), false
  else
    return
  end
end

if clink.onfilterinput then
  clink.onfilterinput(onfilterinput)
else
  clink.onendedit(onfilterinput)
end

-- =============================================================================
--
-- To initalize zoxide, add this script to one of clink's lua script locations (e.g. zoxide.lua)
-- (see https://chrisant996.github.io/clink/clink.html#location-of-lua-scripts)

It can definitely be optimized some more, especially if the script was rendered using a template like the other shells supported by zoxide. @ajeetdsouza if you ever feel like you want to officially support cmd.exe, I would be happy to try to submit a PR for this.

@rashil2000
Copy link

Wow, beautiful script.

@shunsambongi in the meanwhile you can also share this script on the Clink repo (maybe the author will mention it in Clink's docs) :)

@Lunchb0ne
Copy link

Wow, beautiful script.

@shunsambongi in the meanwhile you can also share this script on the Clink repo (maybe the author will mention it in Clink's docs) :)

Yes, I think this would be really helpful too!

@shunsambongi
Copy link

@rashil2000 @Lunchb0ne I'm glad you like the script! I shared the script in clink's repo like you suggested. I also put the script in its own repo so people might find it easier. https://github.com/shunsambongi/clink-zoxide

@ajeetdsouza ajeetdsouza added the integration Request for supporting another shell, application, etc. label Jan 20, 2022
@hacki11
Copy link

hacki11 commented Jan 23, 2022

I have added your lua script but there is an issue not having the clink settings.

%CMDER_ROOT%\config\zoxide.lua:6: attempt to index global 'settings' (a nil value)

Are there additional steps using this script?

Edit: Never mind, my cmder installation was outdated. I thought the cmder updater would update cmder but it is only conemu.

@RESDXChgfore9hing
Copy link

Its already working.now

rashil2000 commented Aug 5, 2021

@ajeetdsouza FWIW, cmd on its own isn't very configurable. Cmder uses a framework called Clink which adds Bash's Readline support to it and makes it highly extensible (there's a comprehensive documentation available here).

However, if z and cd are the only two commands/functions as you specified above, then they can be easily added through doskey aliases:

doskey z=zoxide query $*
doskey cd=zoxide add $1 $T cd /d $1

for example
X:\XJava\apps>z
X:\apps\inpath\lang

as you can see the z shortcut is perfectly working.it suggest a path i used before but is totally at other place.

@RESDXChgfore9hing
Copy link

maybe someone can just do a documentation pr and can close this issue.

@RESDXChgfore9hing
Copy link

it however has this repeatedly echo currentdir when cd .. bug.
X:\XJava>cd ..

X:\XJava>
X:>

@RESDXChgfore9hing
Copy link

maybe a small patch when cd .. will not call
zoxide add
or just simply make zoxide not respond to cd .. ??

@mataha
Copy link
Contributor

mataha commented May 10, 2023

I'm interested in getting this running; I actually have a prototype that's working... almost.

  • z calls zoxide query
  • cd calls zoxide add

What path format do these commands expect? I can't use UNC as cmd.exe does not support it:

C:\Users\user>2>&1 chdir \\?\C:\Users
'\\?\C:\Users'
CMD does not support UNC paths as current directories.

@ajeetdsouza
Copy link
Owner

@mataha zoxide add takes in any kind of path and handles the normalization on its own. Most shells just use something like zoxide add "$PWD" or zoxide add "$(pwd -L)", but you could even use zoxide add . and it should work correctly.

zoxide query is just simple query strings, it does not take a path as an argument.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
integration Request for supporting another shell, application, etc.
Projects
None yet
Development

No branches or pull requests

9 participants