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

How to show active python virtual environment in prompt? #5

Open
Tset-Noitamotua opened this issue Jan 3, 2017 · 17 comments
Open

How to show active python virtual environment in prompt? #5

Tset-Noitamotua opened this issue Jan 3, 2017 · 17 comments
Assignees

Comments

@Tset-Noitamotua
Copy link

I have used below code (in file C:\tools\cmder\config\pyenv_prompt_config.lua) to display which virtual python env is activated. It's not my code, I have found it on Github or Stackoverflow and I have no clue about Lua :(

Could it be combined somehow with your cmder-powerline-prompt?

local clink_path_lua_file = clink.get_env('CMDER_ROOT')..'\\vendor\\clink-completions\\modules\\path.lua'
dofile(clink_path_lua_file)

function get_virtual_env(env_var)
    env_path = clink.get_env(env_var)
    if env_path then
        basen = exports.basename(env_path)
        return basen
    end
    return false
end

---
 -- add python virutual env name 
---
function conda_prompt_filter()
    -- add in python virtual env name
    local python_env = get_virtual_env('DEFAULT_ENV')
    if python_env then
        clink.prompt.value = string.gsub(clink.prompt.value, "λ", "["..python_env.."] λ")
    end
end

---
 -- add virtual env name 
---
function venv_prompt_filter()
    -- add in virtual env name
    local venv = get_virtual_env('VIRTUAL_ENV')
    if venv then
        clink.prompt.value = string.gsub(clink.prompt.value, "λ", "["..venv.."] λ")
    end
end

Thats how it looked:

example_prompt

Cheers
Tset

@AmrEldib
Copy link
Owner

AmrEldib commented Jan 4, 2017

Hi @Tset-Noitamotua This looks promising!
You can register a function as a filter and assign it a rank, and Clink (which Cmder uses in the background) will apply this filter to the prompt. See this line in the powerline_prompt.lua file.

clink.prompt.register_filter(colorful_git_prompt_filter, 60)

Here colorful_git_prompt_filter is the function, and 60 is the rank.
This way you can create one lua file for each group of filter that are related, and choose to apply them as you want. To activate a lua file, just place it in the %CMDER_ROOT%/config folder.

@Tset-Noitamotua
Copy link
Author

I'll try it.

What is the rank for? Is it kind of a prioraty to which filter will apply?

@Tset-Noitamotua
Copy link
Author

yep yep yep

image
(... font is missing on my recent machine)

cmder-powerline-venv-prompt :)

powerline_venv_prompt.lua

-- Resets the prompt 
function lambda_prompt_filter()
    cwd = clink.get_cwd()
    prompt = "\x1b[37;44m{cwd} {git}{hg}\n\x1b[1;30;40m{lamb} \x1b[0m"
    new_value = string.gsub(prompt, "{cwd}", cwd)
    clink.prompt.value = string.gsub(new_value, "{lamb}", "λ")
end

--- copied from clink.lua
 -- Resolves closest directory location for specified directory.
 -- Navigates subsequently up one level and tries to find specified directory
 -- @param  {string} path    Path to directory will be checked. If not provided
 --                          current directory will be used
 -- @param  {string} dirname Directory name to search for
 -- @return {string} Path to specified directory or nil if such dir not found
local function get_dir_contains(path, dirname)

    -- return parent path for specified entry (either file or directory)
    local function pathname(path)
        local prefix = ""
        local i = path:find("[\\/:][^\\/:]*$")
        if i then
            prefix = path:sub(1, i-1)
        end
        return prefix
    end

    -- Navigates up one level
    local function up_one_level(path)
        if path == nil then path = '.' end
        if path == '.' then path = clink.get_cwd() end
        return pathname(path)
    end

    -- Checks if provided directory contains git directory
    local function has_specified_dir(path, specified_dir)
        if path == nil then path = '.' end
        local found_dirs = clink.find_dirs(path..'/'..specified_dir)
        if #found_dirs > 0 then return true end
        return false
    end

    -- Set default path to current directory
    if path == nil then path = '.' end

    -- If we're already have .git directory here, then return current path
    if has_specified_dir(path, dirname) then
        return path..'/'..dirname
    else
        -- Otherwise go up one level and make a recursive call
        local parent_path = up_one_level(path)
        if parent_path == path then
            return nil
        else
            return get_dir_contains(parent_path, dirname)
        end
    end
end

-- copied from clink.lua
-- clink.lua is saved under %CMDER_ROOT%\vendor
local function get_hg_dir(path)
    return get_dir_contains(path, '.hg')
end

-- adopted from clink.lua
-- clink.lua is saved under %CMDER_ROOT%\vendor
function colorful_hg_prompt_filter()

    -- Colors for mercurial status
    local colors = {
        clean = "\x1b[1;37;40m",
        dirty = "\x1b[31;1m",
    }

    if get_hg_dir() then
        -- if we're inside of mercurial repo then try to detect current branch
        local branch = get_hg_branch()
        if branch then
            -- Has branch => therefore it is a mercurial folder, now figure out status
            if get_hg_status() then
                color = colors.clean
            else
                color = colors.dirty
            end

            clink.prompt.value = string.gsub(clink.prompt.value, "{hg}", color.."("..branch..")")
            return false
        end
    end

    -- No mercurial present or not in mercurial file
    clink.prompt.value = string.gsub(clink.prompt.value, "{hg}", "")
    return false
end

-- copied from clink.lua
-- clink.lua is saved under %CMDER_ROOT%\vendor
local function get_git_dir(path)

    -- return parent path for specified entry (either file or directory)
    local function pathname(path)
        local prefix = ""
        local i = path:find("[\\/:][^\\/:]*$")
        if i then
            prefix = path:sub(1, i-1)
        end
        return prefix
    end

    -- Checks if provided directory contains git directory
    local function has_git_dir(dir)
        return #clink.find_dirs(dir..'/.git') > 0 and dir..'/.git'
    end

    local function has_git_file(dir)
        local gitfile = io.open(dir..'/.git')
        if not gitfile then return false end

        local git_dir = gitfile:read():match('gitdir: (.*)')
        gitfile:close()

        return git_dir and dir..'/'..git_dir
    end

    -- Set default path to current directory
    if not path or path == '.' then path = clink.get_cwd() end

    -- Calculate parent path now otherwise we won't be
    -- able to do that inside of logical operator
    local parent_path = pathname(path)

    return has_git_dir(path)
        or has_git_file(path)
        -- Otherwise go up one level and make a recursive call
        or (parent_path ~= path and get_git_dir(parent_path) or nil)
end

---
 -- Get the status of working dir
 -- @return {bool}
---
function get_git_status()
    return os.execute("git diff --quiet --ignore-submodules HEAD")
end

-- adopted from clink.lua
-- Modified to add colors and arrow symbols
function colorful_git_prompt_filter()

    -- Colors for git status
    local colors = {
        clean = "\x1b[34;42m\x1b[37;42m ",
        dirty = "\x1b[34;43m\x1b[30;43m ",
    }

    local closingcolors = {
        clean = " \x1b[32;40m",
        dirty = "± \x1b[33;40m",
    }

    local git_dir = get_git_dir()
    if git_dir then
        -- if we're inside of git repo then try to detect current branch
        local branch = get_git_branch(git_dir)
        if branch then
            -- Has branch => therefore it is a git folder, now figure out status
            if get_git_status() then
                color = colors.clean
                closingcolor = closingcolors.clean
            else
                color = colors.dirty
                closingcolor = closingcolors.dirty
            end

            clink.prompt.value = string.gsub(clink.prompt.value, "{git}", color..""..branch..closingcolor)
            return false
        end
    end

    -- No git present or not in git file
    clink.prompt.value = string.gsub(clink.prompt.value, "{git}", "\x1b[34;40m")
    return false
end


---
 -- add virtual env name 
---
function venv_prompt_filter()
    -- add in virtual env name
    local venv = get_virtual_env('VIRTUAL_ENV')
    if venv then
        clink.prompt.value = string.gsub(clink.prompt.value, "λ", "["..venv.."] λ")
    end
end

-- override the built-in filters
clink.prompt.register_filter(lambda_prompt_filter, 55)
clink.prompt.register_filter(colorful_hg_prompt_filter, 60)
clink.prompt.register_filter(colorful_git_prompt_filter, 60)
clink.prompt.register_filter(venv_prompt_filter, 65)

Thanke You!

Cheers
Tset

@Tset-Noitamotua
Copy link
Author

... if I just could code as good as this looks - damn it!!! :-)))

Font name is (in case somebody cares) Roboto Mono Medium for Powerline, Size 14, Anti-aliasing=ClearType

image

@AmrEldib
Copy link
Owner

AmrEldib commented Jan 4, 2017

That's great @Tset-Noitamotua
I suggest that this becomes its own plugin in a separate repo. This way, those who are interested in the Git integration get that only, and those interested in Python integration get that only.
See the README for this project on how to easily install a plugin.

@Tset-Noitamotua
Copy link
Author

I did a fork. New repo is here: cmder-powerline-venv-prompt

Cheers
Tset

@mattdkerr
Copy link
Contributor

@AmrEldib can we link out to their repository in the readme.md here?

@JorgeGRC
Copy link

JorgeGRC commented May 30, 2018

Hi, I tried your solution @Tset-Noitamotua but unfortunately when I'm activating any of the virtualenvs I get this:

\powerline_venv_prompt.lua:193: attempt to index global 'exports' (a nil value)

image

image

Any idea what might be causing it?

@AmrEldib AmrEldib self-assigned this May 30, 2018
@1600
Copy link

1600 commented Jun 14, 2018

Up with JorgeGRC, debugging right now.

@Kbman99
Copy link

Kbman99 commented Jul 14, 2018

@JorgeGRC Did you ever figure out the cause? I can't seem to find the exports variable in any of the .lua files.

@Kbman99
Copy link

Kbman99 commented Jul 15, 2018

Fixed my issue. For anyone who may be running into the attempt to index global 'exports' (a nil value) . It seems that exports.basename(path) is a global function created in the cmder/vendor/clink-completions/modules/path.lua. I simple copied the function and modified it to be a locally defined function within the cmder/config/powerline_venv_prompt.lua file. Below are the two solutions I have found:

Solution 1:
Add local exports = require('path') into the cmder/config/powerline_venv_prompt.lua file.

Solution 2:
Insert this code below in the the cmder/config/powerline_venv_prompt.lua file to create a locally defined basename function.

function basename(path)
    local prefix = path
    local i = path:find("[\\/:][^\\/:]*$")
    if i then
        prefix = path:sub(i + 1)
    end
    return prefix
end

Then modify the line which is set to access the function as written here in the same filebasen = exports.basename(env_path) and replace it with basen = basename(env_path).

I'm sure there is another solution to the issue which seems to be causing the script to not be able to access the path.lua script which sets the exports object, but either of these fixed the issue for myself.

@steveoh
Copy link

steveoh commented Oct 3, 2018

so if cmder supports showing env's by default, and powerline breaks this feature and this enhancement no longer works... what is the proper solution?

this is my solution for conda

local function get_py_env(env_var)
    env = clink.get_env(env_var)
    if env then
        return env
    end

    return false
end

local function get_conda_env_filter()
    local env = get_py_env("CONDA_DEFAULT_ENV")

    if env then
        env = addTextWithColor("", env.." ", ansiFgClrYellow, ansiBgClrBlack)
        clink.prompt.value = string.gsub(clink.prompt.value, plc_prompt_lambSymbol, env..plc_prompt_lambSymbol)
    end

    return false
end

clink.prompt.register_filter(get_conda_env_filter, 100)

@xNinjaKittyx
Copy link

Is there a way to add virtualenv next to the git as another prompt module?

Also anyone have a working solution for pipenv (without the hash values)

@sn0rlacks
Copy link

So, Is this something that could work with the portable version?

@Tset-Noitamotua
Copy link
Author

Tset-Noitamotua commented Apr 2, 2019 via email

@sn0rlacks
Copy link

@Tset-Noitamotua A simple creation of the pyenv_prompt_config.lua didn't do anything. No errors, and the env seems to have been activated, but theres no change in the console.

Im also using activate <env_name> rather than workon... not sure if clink cares about that? Very unfamiliar with all this lua config.

@Tset-Noitamotua
Copy link
Author

Tset-Noitamotua commented Apr 2, 2019 via email

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

9 participants