mirror of
https://github.com/JanDeDobbeleer/oh-my-posh.git
synced 2025-03-05 20:49:04 -08:00
parent
5bf0c7687a
commit
07d6f747cb
|
@ -7,11 +7,12 @@ import (
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Version number of oh-my-posh
|
|
||||||
var (
|
var (
|
||||||
config string
|
config string
|
||||||
displayVersion bool
|
displayVersion bool
|
||||||
cliVersion string
|
|
||||||
|
// Version number of oh-my-posh
|
||||||
|
cliVersion string
|
||||||
)
|
)
|
||||||
|
|
||||||
var rootCmd = &cobra.Command{
|
var rootCmd = &cobra.Command{
|
||||||
|
|
64
src/environment/darwin.go
Normal file
64
src/environment/darwin.go
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
//go:build darwin
|
||||||
|
|
||||||
|
package environment
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"oh-my-posh/regex"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/distatus/battery"
|
||||||
|
)
|
||||||
|
|
||||||
|
func mapMostLogicalState(state string) battery.State {
|
||||||
|
switch state {
|
||||||
|
case "charging":
|
||||||
|
return battery.Charging
|
||||||
|
case "discharging":
|
||||||
|
return battery.Discharging
|
||||||
|
case "AC attached":
|
||||||
|
return battery.NotCharging
|
||||||
|
case "full":
|
||||||
|
return battery.Full
|
||||||
|
case "empty":
|
||||||
|
return battery.Empty
|
||||||
|
case "charged":
|
||||||
|
return battery.Full
|
||||||
|
default:
|
||||||
|
return battery.Unknown
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (env *ShellEnvironment) parseBatteryOutput(output string) (*BatteryInfo, error) {
|
||||||
|
matches := regex.FindNamedRegexMatch(`(?P<PERCENTAGE>[0-9]{1,3})%; (?P<STATE>[a-zA-Z\s]+);`, output)
|
||||||
|
if len(matches) != 2 {
|
||||||
|
msg := "Unable to find battery state based on output"
|
||||||
|
env.log(Error, "BatteryInfo", msg)
|
||||||
|
return nil, errors.New(msg)
|
||||||
|
}
|
||||||
|
var percentage int
|
||||||
|
var err error
|
||||||
|
if percentage, err = strconv.Atoi(matches["PERCENTAGE"]); err != nil {
|
||||||
|
env.log(Error, "BatteryInfo", err.Error())
|
||||||
|
return nil, errors.New("Unable to parse battery percentage")
|
||||||
|
}
|
||||||
|
return &BatteryInfo{
|
||||||
|
Percentage: percentage,
|
||||||
|
State: mapMostLogicalState(matches["STATE"]),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (env *ShellEnvironment) BatteryState() (*BatteryInfo, error) {
|
||||||
|
defer env.trace(time.Now(), "BatteryInfo")
|
||||||
|
output, err := env.RunCommand("pmset", "-g", "batt")
|
||||||
|
if err != nil {
|
||||||
|
env.log(Error, "BatteryInfo", err.Error())
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if !strings.Contains(output, "Battery") {
|
||||||
|
return nil, errors.New("No battery found")
|
||||||
|
}
|
||||||
|
return env.parseBatteryOutput(output)
|
||||||
|
}
|
61
src/environment/darwin_test.go
Normal file
61
src/environment/darwin_test.go
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
//go:build darwin
|
||||||
|
|
||||||
|
package environment
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/distatus/battery"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestParseBatteryOutput(t *testing.T) {
|
||||||
|
cases := []struct {
|
||||||
|
Case string
|
||||||
|
Output string
|
||||||
|
ExpectedState battery.State
|
||||||
|
ExpectedPercentage int
|
||||||
|
ExpectError bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
Case: "charging",
|
||||||
|
Output: "99%; charging;",
|
||||||
|
ExpectedState: battery.Charging,
|
||||||
|
ExpectedPercentage: 99,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Case: "charging 1%",
|
||||||
|
Output: "1%; charging;",
|
||||||
|
ExpectedState: battery.Charging,
|
||||||
|
ExpectedPercentage: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Case: "not charging 80%",
|
||||||
|
Output: "81%; AC attached;",
|
||||||
|
ExpectedState: battery.NotCharging,
|
||||||
|
ExpectedPercentage: 81,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Case: "charged",
|
||||||
|
Output: "100%; charged;",
|
||||||
|
ExpectedState: battery.Full,
|
||||||
|
ExpectedPercentage: 100,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Case: "discharging",
|
||||||
|
Output: "100%; discharging;",
|
||||||
|
ExpectedState: battery.Discharging,
|
||||||
|
ExpectedPercentage: 100,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tc := range cases {
|
||||||
|
env := ShellEnvironment{}
|
||||||
|
info, err := env.parseBatteryOutput(tc.Output)
|
||||||
|
if tc.ExpectError {
|
||||||
|
assert.Error(t, err, tc.Case)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
assert.Equal(t, tc.ExpectedState, info.State, tc.Case)
|
||||||
|
assert.Equal(t, tc.ExpectedPercentage, info.Percentage, tc.Case)
|
||||||
|
}
|
||||||
|
}
|
|
@ -9,7 +9,6 @@ import (
|
||||||
"io/fs"
|
"io/fs"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"log"
|
"log"
|
||||||
"math"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"oh-my-posh/regex"
|
"oh-my-posh/regex"
|
||||||
"os"
|
"os"
|
||||||
|
@ -566,101 +565,6 @@ func (env *ShellEnvironment) Flags() *Flags {
|
||||||
return env.CmdFlags
|
return env.CmdFlags
|
||||||
}
|
}
|
||||||
|
|
||||||
func mapMostLogicalState(currentState, newState battery.State) battery.State {
|
|
||||||
switch currentState {
|
|
||||||
case battery.Discharging, battery.NotCharging:
|
|
||||||
return battery.Discharging
|
|
||||||
case battery.Empty:
|
|
||||||
return newState
|
|
||||||
case battery.Charging:
|
|
||||||
if newState == battery.Discharging {
|
|
||||||
return battery.Discharging
|
|
||||||
}
|
|
||||||
return battery.Charging
|
|
||||||
case battery.Unknown:
|
|
||||||
return newState
|
|
||||||
case battery.Full:
|
|
||||||
return newState
|
|
||||||
}
|
|
||||||
return newState
|
|
||||||
}
|
|
||||||
|
|
||||||
func (env *ShellEnvironment) BatteryState() (*BatteryInfo, error) {
|
|
||||||
defer env.trace(time.Now(), "BatteryInfo")
|
|
||||||
|
|
||||||
parseBatteryInfo := func(batteries []*battery.Battery) *BatteryInfo {
|
|
||||||
var info BatteryInfo
|
|
||||||
var current, total float64
|
|
||||||
var state battery.State
|
|
||||||
for _, bt := range batteries {
|
|
||||||
current += bt.Current
|
|
||||||
total += bt.Full
|
|
||||||
state = mapMostLogicalState(state, bt.State)
|
|
||||||
}
|
|
||||||
batteryPercentage := current / total * 100
|
|
||||||
info.Percentage = int(math.Min(100, batteryPercentage))
|
|
||||||
info.State = state
|
|
||||||
return &info
|
|
||||||
}
|
|
||||||
|
|
||||||
batteries, err := battery.GetAll()
|
|
||||||
// actual error, return it
|
|
||||||
if err != nil && len(batteries) == 0 {
|
|
||||||
env.log(Error, "BatteryInfo", err.Error())
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
// there are no batteries found
|
|
||||||
if len(batteries) == 0 {
|
|
||||||
return nil, &NoBatteryError{}
|
|
||||||
}
|
|
||||||
// some batteries fail to get retrieved, filter them out if present
|
|
||||||
validBatteries := []*battery.Battery{}
|
|
||||||
for _, batt := range batteries {
|
|
||||||
if batt != nil {
|
|
||||||
validBatteries = append(validBatteries, batt)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// clean minor errors
|
|
||||||
unableToRetrieveBatteryInfo := "A device which does not exist was specified."
|
|
||||||
unknownChargeRate := "Unknown value received"
|
|
||||||
var fatalErr battery.Errors
|
|
||||||
ignoreErr := func(err error) bool {
|
|
||||||
if e, ok := err.(battery.ErrPartial); ok {
|
|
||||||
// ignore unknown charge rate value error
|
|
||||||
if e.Current == nil &&
|
|
||||||
e.Design == nil &&
|
|
||||||
e.DesignVoltage == nil &&
|
|
||||||
e.Full == nil &&
|
|
||||||
e.State == nil &&
|
|
||||||
e.Voltage == nil &&
|
|
||||||
e.ChargeRate != nil &&
|
|
||||||
e.ChargeRate.Error() == unknownChargeRate {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
if batErr, ok := err.(battery.Errors); ok {
|
|
||||||
for _, err := range batErr {
|
|
||||||
if !ignoreErr(err) {
|
|
||||||
fatalErr = append(fatalErr, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// when battery info fails to get retrieved but there is at least one valid battery, return it without error
|
|
||||||
if len(validBatteries) > 0 && fatalErr != nil && strings.Contains(fatalErr.Error(), unableToRetrieveBatteryInfo) {
|
|
||||||
return parseBatteryInfo(validBatteries), nil
|
|
||||||
}
|
|
||||||
// another error occurred (possibly unmapped use-case), return it
|
|
||||||
if fatalErr != nil {
|
|
||||||
env.log(Error, "BatteryInfo", fatalErr.Error())
|
|
||||||
return nil, fatalErr
|
|
||||||
}
|
|
||||||
// everything is fine
|
|
||||||
return parseBatteryInfo(validBatteries), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (env *ShellEnvironment) Shell() string {
|
func (env *ShellEnvironment) Shell() string {
|
||||||
defer env.trace(time.Now(), "Shell")
|
defer env.trace(time.Now(), "Shell")
|
||||||
if env.CmdFlags.Shell != "" {
|
if env.CmdFlags.Shell != "" {
|
||||||
|
|
|
@ -3,7 +3,6 @@ package environment
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/distatus/battery"
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -98,24 +97,3 @@ func TestDirMatchesOneOfRegexInvertedNonEscaped(t *testing.T) {
|
||||||
}()
|
}()
|
||||||
_ = dirMatchesOneOf("Projects/oh-my-posh", "", LinuxPlatform, []string{"(?!Projects/).*"})
|
_ = dirMatchesOneOf("Projects/oh-my-posh", "", LinuxPlatform, []string{"(?!Projects/).*"})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMapBatteriesState(t *testing.T) {
|
|
||||||
cases := []struct {
|
|
||||||
Case string
|
|
||||||
ExpectedState battery.State
|
|
||||||
CurrentState battery.State
|
|
||||||
NewState battery.State
|
|
||||||
}{
|
|
||||||
{Case: "charging > charged", ExpectedState: battery.Charging, CurrentState: battery.Full, NewState: battery.Charging},
|
|
||||||
{Case: "charging < discharging", ExpectedState: battery.Discharging, CurrentState: battery.Discharging, NewState: battery.Charging},
|
|
||||||
{Case: "charging == charging", ExpectedState: battery.Charging, CurrentState: battery.Charging, NewState: battery.Charging},
|
|
||||||
{Case: "discharging > charged", ExpectedState: battery.Discharging, CurrentState: battery.Full, NewState: battery.Discharging},
|
|
||||||
{Case: "discharging > unknown", ExpectedState: battery.Discharging, CurrentState: battery.Unknown, NewState: battery.Discharging},
|
|
||||||
{Case: "discharging > full", ExpectedState: battery.Discharging, CurrentState: battery.Full, NewState: battery.Discharging},
|
|
||||||
{Case: "discharging > charging 2", ExpectedState: battery.Discharging, CurrentState: battery.Charging, NewState: battery.Discharging},
|
|
||||||
{Case: "discharging > empty", ExpectedState: battery.Discharging, CurrentState: battery.Empty, NewState: battery.Discharging},
|
|
||||||
}
|
|
||||||
for _, tc := range cases {
|
|
||||||
assert.Equal(t, tc.ExpectedState, mapMostLogicalState(tc.CurrentState, tc.NewState), tc.Case)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
106
src/environment/windows_unix.go
Normal file
106
src/environment/windows_unix.go
Normal file
|
@ -0,0 +1,106 @@
|
||||||
|
//go:build !darwin
|
||||||
|
|
||||||
|
package environment
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/distatus/battery"
|
||||||
|
)
|
||||||
|
|
||||||
|
func mapMostLogicalState(currentState, newState battery.State) battery.State {
|
||||||
|
switch currentState {
|
||||||
|
case battery.Discharging, battery.NotCharging:
|
||||||
|
return battery.Discharging
|
||||||
|
case battery.Empty:
|
||||||
|
return newState
|
||||||
|
case battery.Charging:
|
||||||
|
if newState == battery.Discharging {
|
||||||
|
return battery.Discharging
|
||||||
|
}
|
||||||
|
return battery.Charging
|
||||||
|
case battery.Unknown:
|
||||||
|
return newState
|
||||||
|
case battery.Full:
|
||||||
|
return newState
|
||||||
|
}
|
||||||
|
return newState
|
||||||
|
}
|
||||||
|
|
||||||
|
func (env *ShellEnvironment) BatteryState() (*BatteryInfo, error) {
|
||||||
|
defer env.trace(time.Now(), "BatteryInfo")
|
||||||
|
|
||||||
|
parseBatteryInfo := func(batteries []*battery.Battery) *BatteryInfo {
|
||||||
|
var info BatteryInfo
|
||||||
|
var current, total float64
|
||||||
|
var state battery.State
|
||||||
|
for _, bt := range batteries {
|
||||||
|
current += bt.Current
|
||||||
|
total += bt.Full
|
||||||
|
state = mapMostLogicalState(state, bt.State)
|
||||||
|
}
|
||||||
|
batteryPercentage := current / total * 100
|
||||||
|
info.Percentage = int(math.Min(100, batteryPercentage))
|
||||||
|
info.State = state
|
||||||
|
return &info
|
||||||
|
}
|
||||||
|
|
||||||
|
batteries, err := battery.GetAll()
|
||||||
|
// actual error, return it
|
||||||
|
if err != nil && len(batteries) == 0 {
|
||||||
|
env.log(Error, "BatteryInfo", err.Error())
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// there are no batteries found
|
||||||
|
if len(batteries) == 0 {
|
||||||
|
return nil, &NoBatteryError{}
|
||||||
|
}
|
||||||
|
// some batteries fail to get retrieved, filter them out if present
|
||||||
|
validBatteries := []*battery.Battery{}
|
||||||
|
for _, batt := range batteries {
|
||||||
|
if batt != nil {
|
||||||
|
validBatteries = append(validBatteries, batt)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// clean minor errors
|
||||||
|
unableToRetrieveBatteryInfo := "A device which does not exist was specified."
|
||||||
|
unknownChargeRate := "Unknown value received"
|
||||||
|
var fatalErr battery.Errors
|
||||||
|
ignoreErr := func(err error) bool {
|
||||||
|
if e, ok := err.(battery.ErrPartial); ok {
|
||||||
|
// ignore unknown charge rate value error
|
||||||
|
if e.Current == nil &&
|
||||||
|
e.Design == nil &&
|
||||||
|
e.DesignVoltage == nil &&
|
||||||
|
e.Full == nil &&
|
||||||
|
e.State == nil &&
|
||||||
|
e.Voltage == nil &&
|
||||||
|
e.ChargeRate != nil &&
|
||||||
|
e.ChargeRate.Error() == unknownChargeRate {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if batErr, ok := err.(battery.Errors); ok {
|
||||||
|
for _, err := range batErr {
|
||||||
|
if !ignoreErr(err) {
|
||||||
|
fatalErr = append(fatalErr, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// when battery info fails to get retrieved but there is at least one valid battery, return it without error
|
||||||
|
if len(validBatteries) > 0 && fatalErr != nil && strings.Contains(fatalErr.Error(), unableToRetrieveBatteryInfo) {
|
||||||
|
return parseBatteryInfo(validBatteries), nil
|
||||||
|
}
|
||||||
|
// another error occurred (possibly unmapped use-case), return it
|
||||||
|
if fatalErr != nil {
|
||||||
|
env.log(Error, "BatteryInfo", fatalErr.Error())
|
||||||
|
return nil, fatalErr
|
||||||
|
}
|
||||||
|
// everything is fine
|
||||||
|
return parseBatteryInfo(validBatteries), nil
|
||||||
|
}
|
31
src/environment/windows_unix_test.go
Normal file
31
src/environment/windows_unix_test.go
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
//go:build !darwin
|
||||||
|
|
||||||
|
package environment
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/distatus/battery"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestMapBatteriesState(t *testing.T) {
|
||||||
|
cases := []struct {
|
||||||
|
Case string
|
||||||
|
ExpectedState battery.State
|
||||||
|
CurrentState battery.State
|
||||||
|
NewState battery.State
|
||||||
|
}{
|
||||||
|
{Case: "charging > charged", ExpectedState: battery.Charging, CurrentState: battery.Full, NewState: battery.Charging},
|
||||||
|
{Case: "charging < discharging", ExpectedState: battery.Discharging, CurrentState: battery.Discharging, NewState: battery.Charging},
|
||||||
|
{Case: "charging == charging", ExpectedState: battery.Charging, CurrentState: battery.Charging, NewState: battery.Charging},
|
||||||
|
{Case: "discharging > charged", ExpectedState: battery.Discharging, CurrentState: battery.Full, NewState: battery.Discharging},
|
||||||
|
{Case: "discharging > unknown", ExpectedState: battery.Discharging, CurrentState: battery.Unknown, NewState: battery.Discharging},
|
||||||
|
{Case: "discharging > full", ExpectedState: battery.Discharging, CurrentState: battery.Full, NewState: battery.Discharging},
|
||||||
|
{Case: "discharging > charging 2", ExpectedState: battery.Discharging, CurrentState: battery.Charging, NewState: battery.Discharging},
|
||||||
|
{Case: "discharging > empty", ExpectedState: battery.Discharging, CurrentState: battery.Empty, NewState: battery.Discharging},
|
||||||
|
}
|
||||||
|
for _, tc := range cases {
|
||||||
|
assert.Equal(t, tc.ExpectedState, mapMostLogicalState(tc.CurrentState, tc.NewState), tc.Case)
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue