func addLock(conf config.Configuration, cwd string, p powerline.Powerline) *powerline.Segment {
	if !IsWritableDir(cwd) {
		segment := powerline.Segment{Foreground: conf.Colours.Lock.Text, Background: conf.Colours.Lock.Background, Weight: conf.Weights.Segments.Lock}
		segment.Parts = append(segment.Parts, powerline.Part{Text: p.ReadOnly})
		return &segment
	}
	return nil
}
func addReturnCode(conf config.Configuration, ret_code int) *powerline.Segment {
	if ret_code != 0 {
		segment := powerline.Segment{Foreground: conf.Colours.Returncode.Text, Background: conf.Colours.Returncode.Background, Weight: conf.Weights.Segments.Returncode}
		segment.Parts = append(segment.Parts, powerline.Part{Text: fmt.Sprintf("%d", ret_code)})
		return &segment
	}
	return nil
}
func addVirtulEnvName(conf config.Configuration, virtualEnvName string) *powerline.Segment {
	if virtualEnvName != "" {
		segment := powerline.Segment{Foreground: conf.Colours.Virtualenv.Text, Background: conf.Colours.Virtualenv.Background, Weight: conf.Weights.Segments.Virtualenv}
		segment.Parts = append(segment.Parts, powerline.Part{Text: virtualEnvName})
		return &segment
	}
	return nil
}
func addBatteryWarn(conf config.Configuration) *powerline.Segment {
	battery, err := ioutil.ReadFile("/sys/class/power_supply/BAT0/capacity")
	if err == nil {
		capacity, _ := strconv.Atoi(strings.Trim(string(battery), " \n"))
		if capacity <= conf.BatteryWarn {
			segment := powerline.Segment{Foreground: conf.Colours.Battery.Text, Background: conf.Colours.Battery.Background, Weight: conf.Weights.Segments.Battery}
			segment.Parts = append(segment.Parts, powerline.Part{Text: fmt.Sprintf("%d%%", capacity)})
			return &segment
		}
	}
	return nil
}
func addHostname(conf config.Configuration, includeUsername bool, hostHash bool, p powerline.Powerline) *powerline.Segment {
	hostname, err := os.Hostname()
	if err != nil {
		return nil
	}

	if len(hostname) > conf.HostnameMaxLength {
		sml := int(conf.HostnameMaxLength/2 - 1)
		if sml > 0 {
			hostname = hostname[0:sml] + p.Ellipsis + hostname[len(hostname)-sml:]
		}
	}

	back := 12

	if hostHash {
		// create a colour hash for the hostname
		sum := 0
		for _, v := range hostname {
			sum += int(v)
		}
		back = sum % 15
	}

	if includeUsername {
		user, err := user.Current()
		if err != nil {
			return nil
		}
		if conf.HostnameMaxLength > 0 {
			hostname = user.Username + "@" + hostname
		} else {
			hostname = user.Username
		}
	}

	segment := powerline.Segment{Foreground: 16, Background: back, Weight: conf.Weights.Segments.Hostname}
	segment.Parts = append(segment.Parts, powerline.Part{Text: hostname})
	return &segment
}
func addHgInfo(conf config.Configuration, p powerline.Powerline) *powerline.Segment {
	var fmt_str string

	segment := powerline.Segment{}

	branch_colour := conf.Colours.Hg.BackgroundDefault
	text_colour := conf.Colours.Hg.Text

	hg, err := exec.Command("hg", "sum", "--color=never", "-y").Output()

	if err == nil {
		// branch:
		reBranch := regexp.MustCompile(`(?m)^branch: (.*)$`)
		matchBranch := reBranch.FindStringSubmatch(string(hg))

		// commit:
		// %d modified, %d added, %d removed, %d renamed, %d copied
		// %d deleted, %d unknown, %d unresolved, %d subrepos
		reModifed := regexp.MustCompile(`(?m)^commit:.* (.*) modified`)
		res_mod := reModifed.FindStringSubmatch(string(hg))
		reUntracked := regexp.MustCompile(`(?m)^commit:.* (.*) unknown`)
		res_untrk := reUntracked.FindStringSubmatch(string(hg))
		reAdded := regexp.MustCompile(`(?m)^commit:.* (.*) added`)
		res_added := reAdded.FindStringSubmatch(string(hg))
		reRemoved := regexp.MustCompile(`(?m)^commit:.* (.*) removed`)
		res_remove := reRemoved.FindStringSubmatch(string(hg))
		reClean := regexp.MustCompile(`(?m)^commit:.*\(clean\)`)
		res_clean := reClean.FindStringSubmatch(string(hg))

		// update:
		reUpdate := regexp.MustCompile(`(?m)^update: (.*) new`)
		res_update := reUpdate.FindStringSubmatch(string(hg))

		// phases:
		rePublic := regexp.MustCompile(`(?m)^phases:.* (.*) public`)
		res_public := rePublic.FindStringSubmatch(string(hg))
		reDraft := regexp.MustCompile(`(?m)^phases:.* (.*) draft`)
		res_draft := reDraft.FindStringSubmatch(string(hg))
		reSecret := regexp.MustCompile(`(?m)^phases:.* (.*) secret`)
		res_secret := reSecret.FindStringSubmatch(string(hg))

		if len(res_clean) == 0 {
			branch_colour = conf.Colours.Hg.BackgroundChanges
		}

		segment.Background = branch_colour
		segment.Foreground = text_colour
		segment.Weight = conf.Weights.Segments.Hg

		// branch name
		if len(matchBranch) > 0 {
			branch := matchBranch[1]
			branch_fmt := branch
			if conf.BranchMaxLength > 3 {
				if len(branch) > conf.BranchMaxLength {
					sml := int(conf.BranchMaxLength/2 - 1)
					if sml > 0 {
						branch_fmt = branch[0:sml] + p.Ellipsis + branch[len(branch)-sml:]
					}
				}
			}
			if branch != "default" {
				fmt_str = p.Branch + " " + branch_fmt
			} else {
				fmt_str = branch_fmt
			}
			segment.Parts = append(segment.Parts, powerline.Part{Text: fmt_str, Weight: conf.Weights.Parts.Branch})
		}

		// phases
		if len(res_public) > 0 || len(res_draft) > 0 || len(res_secret) > 0 {
			var public int = 0
			var draft int = 0
			var secret int = 0
			if len(res_public) > 0 {
				public, _ = strconv.Atoi(res_public[1])
			}
			if len(res_draft) > 0 {
				draft, _ = strconv.Atoi(res_draft[1])
			}
			if len(res_secret) > 0 {
				secret, _ = strconv.Atoi(res_secret[1])
			}
			total := public + draft + secret
			if total == 1 {
				fmt_str = p.Phases
			} else {
				fmt_str = fmt.Sprintf("%d%s", total, p.Phases)
			}
			segment.Parts = append(segment.Parts, powerline.Part{Text: fmt_str, Weight: conf.Weights.Parts.Phases})
		}

		// updated files
		if len(res_update) > 0 {
			if res_update[1] != "1" {
				fmt_str = fmt.Sprintf("%s%s", res_update[1], p.Behind)
			} else {
				fmt_str = p.Behind
			}
			segment.Parts = append(segment.Parts, powerline.Part{Text: fmt_str, Weight: conf.Weights.Parts.Sync})
		}

		// added files
		if len(res_added) > 0 {
			if res_added[1] != "1" {
				fmt_str = fmt.Sprintf("%s%s", res_added[1], p.Added)
			} else {
				fmt_str = p.Added
			}
			segment.Parts = append(segment.Parts, powerline.Part{Text: fmt_str, Weight: conf.Weights.Parts.Added})
		}

		// modified files
		if len(res_mod) > 0 {
			if res_mod[1] != "1" {
				fmt_str = fmt.Sprintf("%s%s", res_mod[1], p.Modified)
			} else {
				fmt_str = p.Modified
			}
			segment.Parts = append(segment.Parts, powerline.Part{Text: fmt_str, Weight: conf.Weights.Parts.Modified})
		}

		// untracked files
		if len(res_untrk) > 0 {
			if res_untrk[1] != "1" {
				fmt_str = fmt.Sprintf("%s%s", res_untrk[1], p.Untracked)
			} else {
				fmt_str = p.Untracked
			}
			segment.Parts = append(segment.Parts, powerline.Part{Text: fmt_str, Weight: conf.Weights.Parts.Untracked})
		}

		// removed files
		if len(res_remove) > 0 {
			if res_remove[1] != "1" {
				fmt_str = fmt.Sprintf("%s%s", res_remove[1], p.Removed)
			} else {
				fmt_str = p.Removed
			}
			segment.Parts = append(segment.Parts, powerline.Part{Text: fmt_str, Weight: conf.Weights.Parts.Removed})
		}

		return &segment
	} else {
		return nil
	}
}
func addDollarPrompt(conf config.Configuration, dollar string) *powerline.Segment {
	segment := powerline.Segment{Foreground: conf.Colours.Dollar.Text, Background: conf.Colours.Dollar.Background, Weight: -1000}
	segment.Parts = append(segment.Parts, powerline.Part{Text: dollar})
	return &segment
}
func addGitInfo(conf config.Configuration, porcelain string, p powerline.Powerline) *powerline.Segment {
	var fmt_str string

	segment := powerline.Segment{}

	branch_colour := conf.Colours.Git.BackgroundDefault
	text_colour := conf.Colours.Git.Text

	// what branch
	reBranch := regexp.MustCompile(`(?m)^## (([^ \.\n]+).*|.* on (\S+))$`)
	matchBranch := reBranch.FindStringSubmatch(porcelain)

	// detached?
	reDetached := regexp.MustCompile(`(?m)^## .* \(no branch\)`)
	matchDetached := reDetached.FindStringSubmatch(porcelain)

	// are we ahead/behind
	reStatus := regexp.MustCompile(`(?m)^## .* \[(ahead|behind) ([0-9]+)\]`)
	matchStatus := reStatus.FindStringSubmatch(porcelain)

	// renamed files
	rename, _ := regexp.Compile(`(?m)^R. `)
	rename_res := rename.FindAllString(porcelain, -1)

	// added files
	add, _ := regexp.Compile(`(?m)^A. `)
	add_res := add.FindAllString(porcelain, -1)

	// modified files
	mod, _ := regexp.Compile(`(?m)^.M `)
	mod_res := mod.FindAllString(porcelain, -1)

	// uncommitted files
	uncom, _ := regexp.Compile(`(?m)^\?\? `)
	uncom_res := uncom.FindAllString(porcelain, -1)

	// removed files
	del, _ := regexp.Compile(`(?m)^(D.|.D) `)
	del_res := del.FindAllString(porcelain, -1)

	// conflicted files
	cfd, _ := regexp.Compile(`(?m)^DD|AU|UD|UA|DU|AA|UU .*$`)
	cfd_res := cfd.FindAllString(porcelain, -1)

	// any changes at all?
	if len(rename_res) > 0 || len(add_res) > 0 || len(mod_res) > 0 || len(uncom_res) > 0 || len(del_res) > 0 || len(cfd_res) > 0 {
		branch_colour = conf.Colours.Git.BackgroundChanges
	}

	segment.Background = branch_colour
	segment.Foreground = text_colour
	segment.Weight = conf.Weights.Segments.Git

	// branch name
	if len(matchBranch) > 0 {
		branch := matchBranch[2]
		branch_fmt := branch
		if conf.BranchMaxLength > 3 {
			if len(branch) > conf.BranchMaxLength {
				sml := int(conf.BranchMaxLength/2 - 1)
				if sml > 0 {
					branch_fmt = branch[0:sml] + p.Ellipsis + branch[len(branch)-sml:]
				}
			}
		}

		if len(matchDetached) > 0 {
			fmt_str = p.Detached + " "
		} else {
			fmt_str = ""
		}
		if branch != "master" {
			fmt_str = fmt.Sprintf("%s%s ", fmt_str, p.Branch)
		}
		fmt_str = fmt.Sprintf("%s%s", fmt_str, branch_fmt)
		segment.Parts = append(segment.Parts, powerline.Part{Text: fmt_str, Weight: conf.Weights.Parts.Branch})
	}

	// ahead/behind
	if len(matchStatus) > 0 {
		num, _ := strconv.Atoi(matchStatus[2])

		if matchStatus[1] == "behind" {
			if num > 1 {
				fmt_str = fmt.Sprintf("%s%s", matchStatus[2], p.Behind)
			} else {
				fmt_str = p.Behind
			}
		} else if matchStatus[1] == "ahead" {
			if num > 1 {
				fmt_str = fmt.Sprintf("%s%s", matchStatus[2], p.Ahead)
			} else {
				fmt_str = p.Ahead
			}
		} else {
			fmt_str = "unk"
		}
		segment.Parts = append(segment.Parts, powerline.Part{Text: fmt_str, Weight: conf.Weights.Parts.Sync})
	}

	// renamed files
	if len(rename_res) > 0 {
		if (len(rename_res)) > 1 {
			fmt_str = fmt.Sprintf("%d%s", len(rename_res), p.Renamed)
		} else {
			fmt_str = p.Renamed
		}
		segment.Parts = append(segment.Parts, powerline.Part{Text: fmt_str, Weight: conf.Weights.Parts.Renamed})
	}

	// added files
	if len(add_res) > 0 {
		if (len(add_res)) > 1 {
			fmt_str = fmt.Sprintf("%d%s", len(add_res), p.Added)
		} else {
			fmt_str = p.Added
		}
		segment.Parts = append(segment.Parts, powerline.Part{Text: fmt_str, Weight: conf.Weights.Parts.Added})
	}

	// modified files
	if len(mod_res) > 0 {
		if (len(mod_res)) > 1 {
			fmt_str = fmt.Sprintf("%d%s", len(mod_res), p.Modified)
		} else {
			fmt_str = p.Modified
		}
		segment.Parts = append(segment.Parts, powerline.Part{Text: fmt_str, Weight: conf.Weights.Parts.Modified})
	}

	// untracked files
	if len(uncom_res) > 0 {
		if (len(uncom_res)) > 1 {
			fmt_str = fmt.Sprintf("%d%s", len(uncom_res), p.Untracked)
		} else {
			fmt_str = p.Untracked
		}
		segment.Parts = append(segment.Parts, powerline.Part{Text: fmt_str, Weight: conf.Weights.Parts.Untracked})
	}

	// deleted files
	if len(del_res) > 0 {
		if (len(del_res)) > 1 {
			fmt_str = fmt.Sprintf("%d%s", len(del_res), p.Removed)
		} else {
			fmt_str = p.Removed
		}
		segment.Parts = append(segment.Parts, powerline.Part{Text: fmt_str, Weight: conf.Weights.Parts.Deleted})
	}

	// conflicted files
	if len(cfd_res) > 0 {
		if (len(cfd_res)) > 1 {
			fmt_str = fmt.Sprintf("%d%s", len(cfd_res), p.Conflicted)
		} else {
			fmt_str = p.Conflicted
		}
		segment.Parts = append(segment.Parts, powerline.Part{Text: fmt_str, Weight: conf.Weights.Parts.Conflicted})
	}

	return &segment
}