mirror of
https://github.com/JanDeDobbeleer/oh-my-posh.git
synced 2024-12-27 11:59:40 -08:00
feat(wifi): added wifi segment for windows and wsl
This commit is contained in:
parent
fd81f4a00c
commit
4a68c444c6
47
docs/docs/segment-wifi.md
Normal file
47
docs/docs/segment-wifi.md
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
---
|
||||||
|
id: wifi
|
||||||
|
title: WiFi
|
||||||
|
sidebar_label: WiFi
|
||||||
|
---
|
||||||
|
|
||||||
|
## What
|
||||||
|
|
||||||
|
Show details about the connected WiFi network.
|
||||||
|
|
||||||
|
## Sample Configuration
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"type": "wifi",
|
||||||
|
"style": "powerline",
|
||||||
|
"background": "#8822ee",
|
||||||
|
"foreground": "#eeeeee",
|
||||||
|
"powerline_symbol": "\uE0B0",
|
||||||
|
"properties": {
|
||||||
|
"template": "{{if .Connectected}}\uFAA8{{else}}\uFAA9{{end}}{{if .Connected}}{{.SSID}} {{.Signal}}% {{.ReceiveRate}}Mbps{{else}}{{.State}}{{end}}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Properties
|
||||||
|
|
||||||
|
- connected_icon: `string` - the icon to use when WiFi is connected - defaults to `\uFAA8`
|
||||||
|
- connected_icon: `string` - the icon to use when WiFi is disconnected - defaults to `\uFAA9`
|
||||||
|
- template: `string` - A go [text/template][go-text-template] template extended with [sprig][sprig]
|
||||||
|
utilizing the properties below -
|
||||||
|
defaults to `{{if .Connectected}}\uFAA8{{else}}\uFAA9{{end}}{{if .Connected}}{{.SSID}} {{.Signal}}% {{.ReceiveRate}}Mbps{{else}}{{.State}}{{end}}`
|
||||||
|
|
||||||
|
## Template Properties
|
||||||
|
|
||||||
|
- `.Connected`: `bool` - if WiFi is currently connected
|
||||||
|
- `.State`: `string` - WiFi connection status - e.g. connected or disconnected
|
||||||
|
- `.SSID`: `string` - the SSID of the current wifi network
|
||||||
|
- `.RadioType`: `string` - the radio type - e.g. 802.11ac, 802.11ax, 802.11n, etc.
|
||||||
|
- `.Authentication`: `string` - the authentication type - e.g. WPA2-Personal, WPA2-Enterprise, etc.
|
||||||
|
- `.Channel`: `int` - the current channel number
|
||||||
|
- `.ReceiveRate`: `int` - the receive rate (Mbps)
|
||||||
|
- `.TransmitRate`: `int` - the transmit rate (Mbps)
|
||||||
|
- `.Signal`: `int` - the signal strength (%)
|
||||||
|
|
||||||
|
[go-text-template]: https://golang.org/pkg/text/template/
|
||||||
|
[sprig]: https://masterminds.github.io/sprig/
|
|
@ -72,6 +72,7 @@ module.exports = {
|
||||||
"terraform",
|
"terraform",
|
||||||
"text",
|
"text",
|
||||||
"time",
|
"time",
|
||||||
|
"wifi",
|
||||||
"ytm",
|
"ytm",
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
|
|
@ -132,6 +132,8 @@ const (
|
||||||
PHP SegmentType = "php"
|
PHP SegmentType = "php"
|
||||||
// Nightscout is an open source diabetes system
|
// Nightscout is an open source diabetes system
|
||||||
Nightscout SegmentType = "nightscout"
|
Nightscout SegmentType = "nightscout"
|
||||||
|
// WiFi writes details about the current WiFi connection
|
||||||
|
WiFi SegmentType = "wifi"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (segment *Segment) string() string {
|
func (segment *Segment) string() string {
|
||||||
|
@ -266,6 +268,7 @@ func (segment *Segment) mapSegmentWithWriter(env environmentInfo) error {
|
||||||
Angular: &angular{},
|
Angular: &angular{},
|
||||||
PHP: &php{},
|
PHP: &php{},
|
||||||
Nightscout: &nightscout{},
|
Nightscout: &nightscout{},
|
||||||
|
WiFi: &wifi{},
|
||||||
}
|
}
|
||||||
if writer, ok := functions[segment.Type]; ok {
|
if writer, ok := functions[segment.Type]; ok {
|
||||||
props := &properties{
|
props := &properties{
|
||||||
|
|
114
src/segment_wifi.go
Normal file
114
src/segment_wifi.go
Normal file
|
@ -0,0 +1,114 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type wifi struct {
|
||||||
|
props *properties
|
||||||
|
env environmentInfo
|
||||||
|
Connected bool
|
||||||
|
State string
|
||||||
|
SSID string
|
||||||
|
RadioType string
|
||||||
|
Authentication string
|
||||||
|
Channel int
|
||||||
|
ReceiveRate int
|
||||||
|
TransmitRate int
|
||||||
|
Signal int
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
defaultTemplate = "{{ if .Connected }}\uFAA8{{ else }}\uFAA9{{ end }}{{ if .Connected }}{{ .SSID }} {{ .Signal }}% {{ .ReceiveRate }}Mbps{{ else }}{{ .State }}{{ end }}"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (w *wifi) enabled() bool {
|
||||||
|
// This segment only supports Windows/WSL for now
|
||||||
|
if w.env.getPlatform() != windowsPlatform && !w.env.isWsl() {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bail out of no netsh command found
|
||||||
|
cmd := "netsh.exe"
|
||||||
|
if !w.env.hasCommand(cmd) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Attempt to retrieve output from netsh command
|
||||||
|
cmdResult, err := w.env.runCommand(cmd, "wlan", "show", "interfaces")
|
||||||
|
displayError := w.props.getBool(DisplayError, false)
|
||||||
|
if err != nil && displayError {
|
||||||
|
w.State = fmt.Sprintf("WIFI ERR: %s", err)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract data from netsh cmdResult
|
||||||
|
parseNetshCmdResult(cmdResult, w)
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *wifi) string() string {
|
||||||
|
segmentTemplate := w.props.getString(SegmentTemplate, defaultTemplate)
|
||||||
|
template := &textTemplate{
|
||||||
|
Template: segmentTemplate,
|
||||||
|
Context: w,
|
||||||
|
Env: w.env,
|
||||||
|
}
|
||||||
|
text, err := template.render()
|
||||||
|
if err != nil {
|
||||||
|
return err.Error()
|
||||||
|
}
|
||||||
|
|
||||||
|
return text
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *wifi) init(props *properties, env environmentInfo) {
|
||||||
|
w.props = props
|
||||||
|
w.env = env
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseNetshCmdResult(netshCmdResult string, w *wifi) {
|
||||||
|
lines := strings.Split(netshCmdResult, "\n")
|
||||||
|
for _, line := range lines {
|
||||||
|
matches := strings.Split(line, " : ")
|
||||||
|
if len(matches) != 2 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
name := strings.TrimSpace(matches[0])
|
||||||
|
value := strings.TrimSpace(matches[1])
|
||||||
|
|
||||||
|
switch name {
|
||||||
|
case "State":
|
||||||
|
w.State = value
|
||||||
|
w.Connected = value == "connected"
|
||||||
|
case "SSID":
|
||||||
|
w.SSID = value
|
||||||
|
case "Radio type":
|
||||||
|
w.RadioType = value
|
||||||
|
case "Authentication":
|
||||||
|
w.Authentication = value
|
||||||
|
case "Channel":
|
||||||
|
if intValue, err := strconv.Atoi(value); err == nil {
|
||||||
|
w.Channel = intValue
|
||||||
|
}
|
||||||
|
case "Receive rate (Mbps)":
|
||||||
|
if intValue, err := strconv.Atoi(strings.Split(value, ".")[0]); err == nil {
|
||||||
|
w.ReceiveRate = intValue
|
||||||
|
}
|
||||||
|
case "Transmit rate (Mbps)":
|
||||||
|
if intValue, err := strconv.Atoi(strings.Split(value, ".")[0]); err == nil {
|
||||||
|
w.TransmitRate = intValue
|
||||||
|
}
|
||||||
|
case "Signal":
|
||||||
|
if intValue, err := strconv.Atoi(strings.TrimRight(value, "%")); err == nil {
|
||||||
|
w.Signal = intValue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
138
src/segment_wifi_test.go
Normal file
138
src/segment_wifi_test.go
Normal file
|
@ -0,0 +1,138 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/mock"
|
||||||
|
)
|
||||||
|
|
||||||
|
type netshStringArgs struct {
|
||||||
|
state string
|
||||||
|
ssid string
|
||||||
|
radioType string
|
||||||
|
authentication string
|
||||||
|
channel int
|
||||||
|
receiveRate int
|
||||||
|
transmitRate int
|
||||||
|
signal int
|
||||||
|
}
|
||||||
|
|
||||||
|
func getNetshString(args *netshStringArgs) string {
|
||||||
|
const netshString string = `
|
||||||
|
There is 1 interface on the system:
|
||||||
|
|
||||||
|
Name : Wi-Fi
|
||||||
|
Description : Intel(R) Wireless-AC 9560 160MHz
|
||||||
|
GUID : 6bb8def2-9af2-4bd4-8be2-6bd54e46bdc9
|
||||||
|
Physical address : d4:3b:04:e6:10:40
|
||||||
|
State : %s
|
||||||
|
SSID : %s
|
||||||
|
BSSID : 5c:7d:7d:82:c5:73
|
||||||
|
Network type : Infrastructure
|
||||||
|
Radio type : %s
|
||||||
|
Authentication : %s
|
||||||
|
Cipher : CCMP
|
||||||
|
Connection mode : Profile
|
||||||
|
Channel : %d
|
||||||
|
Receive rate (Mbps) : %d
|
||||||
|
Transmit rate (Mbps) : %d
|
||||||
|
Signal : %d%%
|
||||||
|
Profile : ohsiggy
|
||||||
|
|
||||||
|
Hosted network status : Not available`
|
||||||
|
|
||||||
|
return fmt.Sprintf(netshString, args.state, args.ssid, args.radioType, args.authentication, args.channel, args.receiveRate, args.transmitRate, args.signal)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestWiFiSegment(t *testing.T) {
|
||||||
|
cases := []struct {
|
||||||
|
Case string
|
||||||
|
ExpectedString string
|
||||||
|
ExpectedEnabled bool
|
||||||
|
CommandNotFound bool
|
||||||
|
CommandOutput string
|
||||||
|
CommandError error
|
||||||
|
DisplayError bool
|
||||||
|
Template string
|
||||||
|
ExpectedState string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
Case: "not enabled on windows when netsh command not found",
|
||||||
|
ExpectedEnabled: false,
|
||||||
|
ExpectedString: "",
|
||||||
|
CommandNotFound: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Case: "not enabled on windows when netsh command fails",
|
||||||
|
ExpectedEnabled: false,
|
||||||
|
ExpectedString: "",
|
||||||
|
CommandError: errors.New("intentional testing failure"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Case: "enabled on windows with DisplayError=true",
|
||||||
|
ExpectedEnabled: true,
|
||||||
|
ExpectedString: "WIFI ERR: intentional testing failure",
|
||||||
|
CommandError: errors.New("intentional testing failure"),
|
||||||
|
DisplayError: true,
|
||||||
|
Template: "{{.State}}",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Case: "enabled on windows with every property in template",
|
||||||
|
ExpectedEnabled: true,
|
||||||
|
ExpectedString: "connected testing 802.11ac WPA2-Personal 99 500 400 80",
|
||||||
|
CommandOutput: getNetshString(&netshStringArgs{
|
||||||
|
state: "connected",
|
||||||
|
ssid: "testing",
|
||||||
|
radioType: "802.11ac",
|
||||||
|
authentication: "WPA2-Personal",
|
||||||
|
channel: 99,
|
||||||
|
receiveRate: 500.0,
|
||||||
|
transmitRate: 400.0,
|
||||||
|
signal: 80,
|
||||||
|
}),
|
||||||
|
Template: "{{.State}} {{.SSID}} {{.RadioType}} {{.Authentication}} {{.Channel}} {{.ReceiveRate}} {{.TransmitRate}} {{.Signal}}",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Case: "enabled on windows but wifi not connected",
|
||||||
|
ExpectedEnabled: true,
|
||||||
|
ExpectedString: "disconnected",
|
||||||
|
CommandOutput: getNetshString(&netshStringArgs{
|
||||||
|
state: "disconnected",
|
||||||
|
}),
|
||||||
|
Template: "{{if not .Connected}}{{.State}}{{end}}",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Case: "enabled on windows but template is invalid",
|
||||||
|
ExpectedEnabled: true,
|
||||||
|
ExpectedString: "unable to create text based on template",
|
||||||
|
CommandOutput: getNetshString(&netshStringArgs{}),
|
||||||
|
Template: "{{.DoesNotExist}}",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range cases {
|
||||||
|
env := new(MockedEnvironment)
|
||||||
|
env.On("getPlatform", nil).Return(windowsPlatform)
|
||||||
|
env.On("isWsl", nil).Return(false)
|
||||||
|
env.On("hasCommand", "netsh.exe").Return(!tc.CommandNotFound)
|
||||||
|
env.On("runCommand", mock.Anything, mock.Anything).Return(tc.CommandOutput, tc.CommandError)
|
||||||
|
|
||||||
|
props := &properties{
|
||||||
|
values: map[Property]interface{}{
|
||||||
|
DisplayError: tc.DisplayError,
|
||||||
|
SegmentTemplate: tc.Template,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
w := &wifi{
|
||||||
|
env: env,
|
||||||
|
props: props,
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.Equal(t, tc.ExpectedEnabled, w.enabled(), tc.Case)
|
||||||
|
assert.Equal(t, tc.ExpectedString, w.string(), tc.Case)
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue