Created
February 28, 2018 16:45
-
-
Save wictorwilen/29da3662cca5642a14f136c301b08172 to your computer and use it in GitHub Desktop.
cmder custom prompt with git and npm support
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-- 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