mirror of
https://github.com/JanDeDobbeleer/oh-my-posh.git
synced 2024-12-26 19:39:39 -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",
|
||||
"text",
|
||||
"time",
|
||||
"wifi",
|
||||
"ytm",
|
||||
],
|
||||
},
|
||||
|
|
|
@ -132,6 +132,8 @@ const (
|
|||
PHP SegmentType = "php"
|
||||
// Nightscout is an open source diabetes system
|
||||
Nightscout SegmentType = "nightscout"
|
||||
// WiFi writes details about the current WiFi connection
|
||||
WiFi SegmentType = "wifi"
|
||||
)
|
||||
|
||||
func (segment *Segment) string() string {
|
||||
|
@ -266,6 +268,7 @@ func (segment *Segment) mapSegmentWithWriter(env environmentInfo) error {
|
|||
Angular: &angular{},
|
||||
PHP: &php{},
|
||||
Nightscout: &nightscout{},
|
||||
WiFi: &wifi{},
|
||||
}
|
||||
if writer, ok := functions[segment.Type]; ok {
|
||||
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