Skip to content

Instantly share code, notes, and snippets.

@wictorwilen
Created February 28, 2018 16:45
Show Gist options
  • Save wictorwilen/29da3662cca5642a14f136c301b08172 to your computer and use it in GitHub Desktop.
Save wictorwilen/29da3662cca5642a14f136c301b08172 to your computer and use it in GitHub Desktop.
cmder custom prompt with git and npm support
-- Source: https://github.com/AmrEldib/cmder-powerline-prompt
--- promptValue is whether the displayed prompt is the full path or only the folder name
-- Use:
-- "full" for full path like C:\Windows\System32
local promptValueFull = "full"
-- "folder" for folder name only like System32
local promptValueFolder = "folder"
-- default is promptValueFull
local promptValue = promptValueFull
local function get_folder_name(path)
local reversePath = string.reverse(path)
local slashIndex = string.find(reversePath, "\\")
return string.sub(path, string.len(path) - slashIndex + 2)
end
-- Resets the prompt
function lambda_prompt_filter()
cwd = clink.get_cwd()
if promptValue == promptValueFolder then
cwd = get_folder_name(cwd)
end
prompt = "\x1b[37;44m{cwd} {npm}{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
local arrowSymbol = ""
local branchSymbol = ""
--- 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()
local file = io.popen("git status --no-lock-index --porcelain 2>nul")
for line in file:lines() do
file:close()
return false
end
file:close()
return true
end
function get_git_branch()
for line in io.popen("git branch 2>nul"):lines() do
local m = line:match("%* (.+)$")
if m then
return m
end
end
return false
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"..arrowSymbol.."\x1b[37;42m ",
dirty = "\x1b[34;43m"..arrowSymbol.."\x1b[30;43m ",
}
local closingcolors = {
clean = " \x1b[32;40m"..arrowSymbol,
dirty = "± \x1b[33;40m"..arrowSymbol,
}
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)
clink.prompt.value = string.gsub(clink.prompt.value, "{git}", color.." "..branchSymbol.." "..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"..arrowSymbol)
return false
end
local JSON = require("JSON")
-- silence JSON parsing errors
function JSON:assert () end -- luacheck: no unused args
local color = require('color')
local function npm_prompt_filter()
local colors = {
pub = "\x1b[37m",
pri = "\x1b[33m ",
}
local closingcolors = {
pub = " \x1b[40m",
pri = "± \x1b[40m",
}
local package_file = io.open('package.json')
if not package_file then
clink.prompt.value = clink.prompt.value:gsub('{npm}', '')
return false
end
local package_data = package_file:read('*a')
package_file:close()
local package = JSON:decode(package_data)
-- Bail out if package.json is malformed
if not package then
clink.prompt.value = clink.prompt.value:gsub('{npm}', '')
return false
end
-- Don't print package info when the package is private or both version and name are missing
if package.private or (not package.name and not package.version) then
startcolor = colors.pri
endcolor = colors.pri
else
startcolor = colors.pub
endcolor = colors.pub
end
local package_name = package.name or "<no name>"
local package_version = package.version and "@"..package.version or ""
local package_string = startcolor.."("..package.name..package_version..")"..endcolor
clink.prompt.value = clink.prompt.value:gsub('{npm}', ''..package_string)
return false
end
-- override the built-in filters
clink.prompt.register_filter(lambda_prompt_filter, 55)
clink.prompt.register_filter(npm_prompt_filter, 70)
clink.prompt.register_filter(colorful_hg_prompt_filter, 60)
clink.prompt.register_filter(colorful_git_prompt_filter, 60)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment