41 Commits
v1.5 ... v1.10

Author SHA1 Message Date
eleksir
05eab972d7 Looks like we do not need separators for buttons 2026-03-31 02:07:17 +03:00
eleksir
eeddce7225 Merge branch 'master' of http://git.lan/eleksir/i3status-go 2026-03-31 01:32:28 +03:00
eleksir
56aa0f7e5e Fix rendering in main.go - separators never handled in formally correct way. 2026-03-31 01:26:46 +03:00
eleksir
86596461a1 More efficiently reap zombeis in spawn.go 2026-03-31 01:23:02 +03:00
eleksir
cd57dbc770 More efficient look for leading "{" symbold in stdin.go 2026-03-31 01:18:33 +03:00
eleksir
f2c24bc0ec Render buttons border immedialtely after windo list population 2026-03-31 01:12:32 +03:00
eleksir
bd6aa31c4d Discard unneccessary cast to any 2026-03-31 01:04:47 +03:00
eleksir
f59ac30f51 Handle error in batteries.go in battery.GetAll(), maybe it is bad idea 2026-03-31 01:02:17 +03:00
eleksir
4beda1639e Fix hypotetical file leakage in cputemp.go 2026-03-31 00:59:34 +03:00
eleksir
7a133f3867 Fix possinble division by zero in cputemp.go 2026-03-31 00:57:37 +03:00
eleksir
3f1adbe126 Log error in la.go if unable to open file 2026-03-31 00:55:38 +03:00
eleksir
0d3f805a2d Inconsistent string trimming in batteries.go 2026-03-31 00:53:51 +03:00
eleksir
2855b9e612 Eliminate unused variable in signal.go 2026-03-31 00:51:44 +03:00
eleksir
217948ade6 Inconsistent variable name in ifmon.go 2026-03-31 00:49:52 +03:00
eleksir
c621d03a71 Fix issue while getting windows tree in i3.go 2026-03-31 00:40:10 +03:00
eleksir
13efa0393c Do not exec() if binary path is empty 2026-03-31 00:38:15 +03:00
eleksir
d5f81e9fd6 Remove redundant close of /dev/null in spawn.go 2026-03-31 00:36:12 +03:00
eleksir
8f742709b6 Make delay before execution command in more efficient way 2026-03-31 00:32:02 +03:00
eleksir
40213ba5c3 Read swap statistics only if swap stats enabled 2026-03-31 00:29:09 +03:00
eleksir
deeb0dfbf0 Formally check open() result for /dev/null 2026-03-31 00:27:18 +03:00
eleksir
ad013fb8f5 Cache regex evaluation in i3.go 2026-03-31 00:23:48 +03:00
eleksir
6def26ef02 Add missing modeline to cmd/battery-test/main.go 2026-03-31 00:21:57 +03:00
eleksir
a16816e862 Avoid busy loop in zombies reap procedure. 2026-03-31 00:21:06 +03:00
eleksir
cc6cc192cb Fix battery detection. 2026-03-31 00:19:02 +03:00
eleksir
f59b735f38 Fix possible multiple command execution in rare case. 2026-03-31 00:17:12 +03:00
eleksir
53c7fe292e In runcommand.go logged incorrect variable 2026-03-31 00:14:29 +03:00
eleksir
fe0b0bf6dd Fix inconsistent swap calculation 2026-03-31 00:11:54 +03:00
eleksir
8f3f6c77bd Fix bug - right-most separator never displayed 2026-03-31 00:09:19 +03:00
eleksir
5750894336 Add vim modeline to all *.go files 2026-03-31 00:08:15 +03:00
eleksir
63f1a142d8 Fix couple nasty bugs in collection.go, safer type assertions. 2026-03-30 23:49:06 +03:00
eleksir
9bea626f7c Fix potential panic in i3.go, check interface{} for nil 2026-03-30 23:36:06 +03:00
eleksir
3f5704237a [WIP] Update linter config + speed optimizations 2025-11-23 16:41:20 +03:00
eleksir
d9ce425981 Finally fix parsing of app buttons, now settings and fallback values should work as expected 2025-07-15 14:29:27 +03:00
eleksir
069b09e5ec Update default config example 2025-07-12 14:00:55 +03:00
eleksir
8f2afa0441 Fix font size checks and fallbacks 2025-07-12 13:43:10 +03:00
eleksir
8fa1c6d596 Allow to override (in config) color and font settings for AppButtons block 2025-07-12 12:41:13 +03:00
eleksir
12f4dc75f0 Fix linter warnings 2025-06-24 16:13:36 +03:00
eleksir
913fcc34ee Fix incorrect display measurement units in swap calculation in mem plugin 2025-06-24 16:12:48 +03:00
eleksir
ac856f4174 Fix empty font name and incorrect font size name in VPN plugin output 2025-06-24 16:11:43 +03:00
eleksir
a5d793926b Fix typo in README.md 2025-06-01 18:59:15 +03:00
eleksir
40a94bd001 Add missing runcommand.go 2025-06-01 18:57:47 +03:00
21 changed files with 1832 additions and 604 deletions

View File

@@ -14,23 +14,29 @@ linters:
- contextcheck - contextcheck
- decorder - decorder
- durationcheck - durationcheck
- err113
- errcheck - errcheck
- errchkjson - errchkjson
- errorlint - errorlint
- exptostd
- ginkgolinter - ginkgolinter
- gocheckcompilerdirectives - gocheckcompilerdirectives
- gocritic - gocritic
- godoclint
- godot - godot
- godox
- goprintffuncname
- gosec - gosec
- gosmopolitan - gosmopolitan
- govet - govet
- grouper - grouper
- importas - importas
- ineffassign - ineffassign
- intrange
- ireturn - ireturn
- makezero - makezero
- mirror - mirror
- misspell
- modernize
- nakedret - nakedret
- nilerr - nilerr
- nilnil - nilnil
@@ -38,6 +44,7 @@ linters:
- noctx - noctx
- nolintlint - nolintlint
- nonamedreturns - nonamedreturns
- perfsprint
- predeclared - predeclared
- promlinter - promlinter
- reassign - reassign
@@ -46,14 +53,731 @@ linters:
- staticcheck - staticcheck
- unconvert - unconvert
- unused - unused
- usestdlibvars
- wastedassign - wastedassign
- whitespace - wsl_v5
- wsl
settings: settings:
gosec: decorder:
dec-order:
- type
- const
- var
- func
gocritic:
disable-all: false
enable-all: true
disabled-checks:
- singleCaseSwitch
- octalLiteral
- regexpSimplify
- paramTypeCombine
- whyNoLint
- hugeParam
godoclint:
default: all
ignore-unexported: false
ignore-exported: false
include-unexported: true
disable:
- max-len
godot:
scope: all
exclude:
# Exclude todo and fixme comments.
- "^fixme:"
- "^todo:"
period: true
capital: false
godox:
keywords:
- FIXME
gosec: # go-fucking-sic
excludes: excludes:
- G404 # Боже, как же вы затрахали своей крипто-ебучкой, наркоманы хреновы!
- G306 - G405 # Detect the usage of DES or RC4
- G406 # Detect the usage of MD4 or RIPEMD160
# Оно не используется для повышения безопасности или каких-то таких секъюрных вещей, оно используется для выборки
# произвольного элемента из массива, так что ИДИ НАХУЙ с этой проверкой и не еби мозги липовой безопасностью.
- G404 # Insecure random number source (rand)
- G501 # Import blocklist: crypto/md5
- G502 # Import blocklist: crypto/des
- G503 # Import blocklist: crypto/rc4
- G504 # Import blocklist: net/http/cgi
- G505 # Import blocklist: crypto/sha1
- G506 # Import blocklist: golang.org/x/crypto/md4
- G507 # Import blocklist: golang.org/x/crypto/ripemd160
config:
global:
audit: true
# Ваша сраная паранойя при создании файлов и каталогов мешает нормальной работе сервисов. Группы придуманы для
# удобства, группе удобно давать право чтения. Поэтому идите нахуй со своими ограничениями на чтение для
# группы, "безопасные" клоуны.
G301: "0755"
G306: "0644"
govet:
disable-all: false
enable-all: true
disable:
- shadow
- fieldalignment
grouper:
# Require the use of a single global 'const' declaration only.
# Default: false
const-require-single-const: true
# Require the use of grouped global 'const' declarations.
# Default: false
const-require-grouping: true
# Require the use of a single 'import' declaration only.
# Default: false
import-require-single-import: true
# Require the use of grouped 'import' declarations.
# Default: false
import-require-grouping: true
# Require the use of a single global 'type' declaration only.
# Default: false
type-require-single-type: true
# Require the use of grouped global 'type' declarations.
# Default: false
type-require-grouping: true
# Require the use of a single global 'var' declaration only.
# Default: false
var-require-single-var: true
# Require the use of grouped global 'var' declarations.
# Default: false
var-require-grouping: true
misspell:
# Correct spellings using locale preferences for US or UK.
# Setting locale to US will correct the British spelling of 'colour' to 'color'.
# Default is to use a neutral variety of English.
locale: US
# Typos to ignore.
# Should be in lower case.
# Default: []
ignore-rules:
- someword
# Extra word corrections.
# `typo` and `correction` should only contain letters.
# The words are case-insensitive.
# Default: []
extra-words:
- typo: "iff"
correction: "if"
- typo: "cancelation"
correction: "cancellation"
# Mode of the analysis:
# - default: checks all the file content.
# - restricted: checks only comments.
# Default: ""
mode: restricted
nonamedreturns:
# Report named error if it is assigned inside defer.
# Default: false
report-error-in-defer: true
perfsprint:
integer-format: true
int-conversion: true
error-format: true
err-error: false
errorf: true
string-format: true
sprintf1: true
strconcat: true
bool-format: true
hex-format: true
concat-loop: true
loop-other-ops: false
revive:
enable-all-rules: false
staticcheck:
# https://staticcheck.dev/docs/configuration/options/#dot_import_whitelist
# Default: ["github.com/mmcloughlin/avo/build", "github.com/mmcloughlin/avo/operand", "github.com/mmcloughlin/avo/reg"]
dot-import-whitelist:
- fmt
# https://staticcheck.dev/docs/configuration/options/#initialisms
# Default: ["ACL", "API", "ASCII", "CPU", "CSS", "DNS", "EOF", "GUID", "HTML", "HTTP", "HTTPS", "ID", "IP", "JSON", "QPS", "RAM", "RPC", "SLA", "SMTP", "SQL", "SSH", "TCP", "TLS", "TTL", "UDP", "UI", "GID", "UID", "UUID", "URI", "URL", "UTF8", "VM", "XML", "XMPP", "XSRF", "XSS", "SIP", "RTP", "AMQP", "DB", "TS"]
initialisms:
[
"ACL",
"API",
"ASCII",
"CPU",
"CSS",
"DNS",
"EOF",
"GUID",
"HTML",
"HTTP",
"HTTPS",
"ID",
"IP",
"JSON",
"QPS",
"RAM",
"RPC",
"SLA",
"SMTP",
"SQL",
"SSH",
"TCP",
"TLS",
"TTL",
"UDP",
"UI",
"GID",
"UID",
"UUID",
"URI",
"URL",
"UTF8",
"VM",
"XML",
"XMPP",
"XSRF",
"XSS",
"SIP",
"RTP",
"AMQP",
"DB",
"TS",
]
# https://staticcheck.dev/docs/configuration/options/#http_status_code_whitelist
# Default: ["200", "400", "404", "500"]
http-status-code-whitelist: ["200", "400", "404", "500"]
# SAxxxx checks in https://staticcheck.dev/docs/configuration/options/#checks
# Example (to disable some checks): [ "all", "-SA1000", "-SA1001"]
# Run `GL_DEBUG=staticcheck golangci-lint run --enable=staticcheck` to see all available checks and enabled by config checks.
# Default: ["all", "-ST1000", "-ST1003", "-ST1016", "-ST1020", "-ST1021", "-ST1022"]
checks:
# Invalid regular expression.
# https://staticcheck.dev/docs/checks/#SA1000
- SA1000
# Invalid template.
# https://staticcheck.dev/docs/checks/#SA1001
- SA1001
# Invalid format in 'time.Parse'.
# https://staticcheck.dev/docs/checks/#SA1002
- SA1002
# Unsupported argument to functions in 'encoding/binary'.
# https://staticcheck.dev/docs/checks/#SA1003
- SA1003
# Suspiciously small untyped constant in 'time.Sleep'.
# https://staticcheck.dev/docs/checks/#SA1004
- SA1004
# Invalid first argument to 'exec.Command'.
# https://staticcheck.dev/docs/checks/#SA1005
- SA1005
# 'Printf' with dynamic first argument and no further arguments.
# https://staticcheck.dev/docs/checks/#SA1006
- SA1006
# Invalid URL in 'net/url.Parse'.
# https://staticcheck.dev/docs/checks/#SA1007
- SA1007
# Non-canonical key in 'http.Header' map.
# https://staticcheck.dev/docs/checks/#SA1008
- SA1008
# '(*regexp.Regexp).FindAll' called with 'n == 0', which will always return zero results.
# https://staticcheck.dev/docs/checks/#SA1010
- SA1010
# Various methods in the "strings" package expect valid UTF-8, but invalid input is provided.
# https://staticcheck.dev/docs/checks/#SA1011
- SA1011
# A nil 'context.Context' is being passed to a function, consider using 'context.TODO' instead.
# https://staticcheck.dev/docs/checks/#SA1012
- SA1012
# 'io.Seeker.Seek' is being called with the whence constant as the first argument, but it should be the second.
# https://staticcheck.dev/docs/checks/#SA1013
- SA1013
# Non-pointer value passed to 'Unmarshal' or 'Decode'.
# https://staticcheck.dev/docs/checks/#SA1014
- SA1014
# Using 'time.Tick' in a way that will leak. Consider using 'time.NewTicker', and only use 'time.Tick' in tests, commands and endless functions.
# https://staticcheck.dev/docs/checks/#SA1015
- SA1015
# Trapping a signal that cannot be trapped.
# https://staticcheck.dev/docs/checks/#SA1016
- SA1016
# Channels used with 'os/signal.Notify' should be buffered.
# https://staticcheck.dev/docs/checks/#SA1017
- SA1017
# 'strings.Replace' called with 'n == 0', which does nothing.
# https://staticcheck.dev/docs/checks/#SA1018
- SA1018
# Using a deprecated function, variable, constant or field.
# https://staticcheck.dev/docs/checks/#SA1019
- SA1019
# Using an invalid host:port pair with a 'net.Listen'-related function.
# https://staticcheck.dev/docs/checks/#SA1020
- SA1020
# Using 'bytes.Equal' to compare two 'net.IP'.
# https://staticcheck.dev/docs/checks/#SA1021
- SA1021
# Modifying the buffer in an 'io.Writer' implementation.
# https://staticcheck.dev/docs/checks/#SA1023
- SA1023
# A string cutset contains duplicate characters.
# https://staticcheck.dev/docs/checks/#SA1024
- SA1024
# It is not possible to use '(*time.Timer).Reset''s return value correctly.
# https://staticcheck.dev/docs/checks/#SA1025
- SA1025
# Cannot marshal channels or functions.
# https://staticcheck.dev/docs/checks/#SA1026
- SA1026
# Atomic access to 64-bit variable must be 64-bit aligned.
# https://staticcheck.dev/docs/checks/#SA1027
- SA1027
# 'sort.Slice' can only be used on slices.
# https://staticcheck.dev/docs/checks/#SA1028
- SA1028
# Inappropriate key in call to 'context.WithValue'.
# https://staticcheck.dev/docs/checks/#SA1029
- SA1029
# Invalid argument in call to a 'strconv' function.
# https://staticcheck.dev/docs/checks/#SA1030
- SA1030
# Overlapping byte slices passed to an encoder.
# https://staticcheck.dev/docs/checks/#SA1031
- SA1031
# Wrong order of arguments to 'errors.Is'.
# https://staticcheck.dev/docs/checks/#SA1032
- SA1032
# 'sync.WaitGroup.Add' called inside the goroutine, leading to a race condition.
# https://staticcheck.dev/docs/checks/#SA2000
- SA2000
# Empty critical section, did you mean to defer the unlock?.
# https://staticcheck.dev/docs/checks/#SA2001
- SA2001
# Called 'testing.T.FailNow' or 'SkipNow' in a goroutine, which isn't allowed.
# https://staticcheck.dev/docs/checks/#SA2002
- SA2002
# Deferred 'Lock' right after locking, likely meant to defer 'Unlock' instead.
# https://staticcheck.dev/docs/checks/#SA2003
- SA2003
# 'TestMain' doesn't call 'os.Exit', hiding test failures.
# https://staticcheck.dev/docs/checks/#SA3000
- SA3000
# Assigning to 'b.N' in benchmarks distorts the results.
# https://staticcheck.dev/docs/checks/#SA3001
- SA3001
# Binary operator has identical expressions on both sides.
# https://staticcheck.dev/docs/checks/#SA4000
- SA4000
# '&*x' gets simplified to 'x', it does not copy 'x'.
# https://staticcheck.dev/docs/checks/#SA4001
- SA4001
# Comparing unsigned values against negative values is pointless.
# https://staticcheck.dev/docs/checks/#SA4003
- SA4003
# The loop exits unconditionally after one iteration.
# https://staticcheck.dev/docs/checks/#SA4004
- SA4004
# Field assignment that will never be observed. Did you mean to use a pointer receiver?.
# https://staticcheck.dev/docs/checks/#SA4005
- SA4005
# A value assigned to a variable is never read before being overwritten. Forgotten error check or dead code?.
# https://staticcheck.dev/docs/checks/#SA4006
- SA4006
# The variable in the loop condition never changes, are you incrementing the wrong variable?.
# https://staticcheck.dev/docs/checks/#SA4008
- SA4008
# A function argument is overwritten before its first use.
# https://staticcheck.dev/docs/checks/#SA4009
- SA4009
# The result of 'append' will never be observed anywhere.
# https://staticcheck.dev/docs/checks/#SA4010
- SA4010
# Break statement with no effect. Did you mean to break out of an outer loop?.
# https://staticcheck.dev/docs/checks/#SA4011
- SA4011
# Comparing a value against NaN even though no value is equal to NaN.
# https://staticcheck.dev/docs/checks/#SA4012
- SA4012
# Negating a boolean twice ('!!b') is the same as writing 'b'. This is either redundant, or a typo.
# https://staticcheck.dev/docs/checks/#SA4013
- SA4013
# An if/else if chain has repeated conditions and no side-effects; if the condition didn't match the first time, it won't match the second time, either.
# https://staticcheck.dev/docs/checks/#SA4014
- SA4014
# Calling functions like 'math.Ceil' on floats converted from integers doesn't do anything useful.
# https://staticcheck.dev/docs/checks/#SA4015
- SA4015
# Certain bitwise operations, such as 'x ^ 0', do not do anything useful.
# https://staticcheck.dev/docs/checks/#SA4016
- SA4016
# Discarding the return values of a function without side effects, making the call pointless.
# https://staticcheck.dev/docs/checks/#SA4017
- SA4017
# Self-assignment of variables.
# https://staticcheck.dev/docs/checks/#SA4018
- SA4018
# Multiple, identical build constraints in the same file.
# https://staticcheck.dev/docs/checks/#SA4019
- SA4019
# Unreachable case clause in a type switch.
# https://staticcheck.dev/docs/checks/#SA4020
- SA4020
# "x = append(y)" is equivalent to "x = y".
# https://staticcheck.dev/docs/checks/#SA4021
- SA4021
# Comparing the address of a variable against nil.
# https://staticcheck.dev/docs/checks/#SA4022
- SA4022
# Impossible comparison of interface value with untyped nil.
# https://staticcheck.dev/docs/checks/#SA4023
- SA4023
# Checking for impossible return value from a builtin function.
# https://staticcheck.dev/docs/checks/#SA4024
- SA4024
# Integer division of literals that results in zero.
# https://staticcheck.dev/docs/checks/#SA4025
- SA4025
# Go constants cannot express negative zero.
# https://staticcheck.dev/docs/checks/#SA4026
- SA4026
# '(*net/url.URL).Query' returns a copy, modifying it doesn't change the URL.
# https://staticcheck.dev/docs/checks/#SA4027
- SA4027
# 'x % 1' is always zero.
# https://staticcheck.dev/docs/checks/#SA4028
- SA4028
# Ineffective attempt at sorting slice.
# https://staticcheck.dev/docs/checks/#SA4029
- SA4029
# Ineffective attempt at generating random number.
# https://staticcheck.dev/docs/checks/#SA4030
- SA4030
# Checking never-nil value against nil.
# https://staticcheck.dev/docs/checks/#SA4031
- SA4031
# Comparing 'runtime.GOOS' or 'runtime.GOARCH' against impossible value.
# https://staticcheck.dev/docs/checks/#SA4032
- SA4032
# Assignment to nil map.
# https://staticcheck.dev/docs/checks/#SA5000
- SA5000
# Deferring 'Close' before checking for a possible error.
# https://staticcheck.dev/docs/checks/#SA5001
- SA5001
# The empty for loop ("for {}") spins and can block the scheduler.
# https://staticcheck.dev/docs/checks/#SA5002
- SA5002
# Defers in infinite loops will never execute.
# https://staticcheck.dev/docs/checks/#SA5003
- SA5003
# "for { select { ..." with an empty default branch spins.
# https://staticcheck.dev/docs/checks/#SA5004
- SA5004
# The finalizer references the finalized object, preventing garbage collection.
# https://staticcheck.dev/docs/checks/#SA5005
- SA5005
# Infinite recursive call.
# https://staticcheck.dev/docs/checks/#SA5007
- SA5007
# Invalid struct tag.
# https://staticcheck.dev/docs/checks/#SA5008
- SA5008
# Invalid Printf call.
# https://staticcheck.dev/docs/checks/#SA5009
- SA5009
# Impossible type assertion.
# https://staticcheck.dev/docs/checks/#SA5010
- SA5010
# Possible nil pointer dereference.
# https://staticcheck.dev/docs/checks/#SA5011
- SA5011
# Passing odd-sized slice to function expecting even size.
# https://staticcheck.dev/docs/checks/#SA5012
- SA5012
# Using 'regexp.Match' or related in a loop, should use 'regexp.Compile'.
# https://staticcheck.dev/docs/checks/#SA6000
- SA6000
# Missing an optimization opportunity when indexing maps by byte slices.
# https://staticcheck.dev/docs/checks/#SA6001
- SA6001
# Storing non-pointer values in 'sync.Pool' allocates memory.
# https://staticcheck.dev/docs/checks/#SA6002
- SA6002
# Converting a string to a slice of runes before ranging over it.
# https://staticcheck.dev/docs/checks/#SA6003
- SA6003
# Inefficient string comparison with 'strings.ToLower' or 'strings.ToUpper'.
# https://staticcheck.dev/docs/checks/#SA6005
- SA6005
# Using io.WriteString to write '[]byte'.
# https://staticcheck.dev/docs/checks/#SA6006
- SA6006
# Defers in range loops may not run when you expect them to.
# https://staticcheck.dev/docs/checks/#SA9001
- SA9001
# Using a non-octal 'os.FileMode' that looks like it was meant to be in octal.
# https://staticcheck.dev/docs/checks/#SA9002
- SA9002
# Empty body in an if or else branch.
# https://staticcheck.dev/docs/checks/#SA9003
- SA9003
# Only the first constant has an explicit type.
# https://staticcheck.dev/docs/checks/#SA9004
- SA9004
# Trying to marshal a struct with no public fields nor custom marshaling.
# https://staticcheck.dev/docs/checks/#SA9005
- SA9005
# Dubious bit shifting of a fixed size integer value.
# https://staticcheck.dev/docs/checks/#SA9006
- SA9006
# Deleting a directory that shouldn't be deleted.
# https://staticcheck.dev/docs/checks/#SA9007
- SA9007
# 'else' branch of a type assertion is probably not reading the right value.
# https://staticcheck.dev/docs/checks/#SA9008
- SA9008
# Ineffectual Go compiler directive.
# https://staticcheck.dev/docs/checks/#SA9009
- SA9009
# Incorrect or missing package comment.
# https://staticcheck.dev/docs/checks/#ST1000
- ST1000
# Dot imports are discouraged.
# https://staticcheck.dev/docs/checks/#ST1001
- ST1001
# Poorly chosen identifier.
# https://staticcheck.dev/docs/checks/#ST1003
- ST1003
# Incorrectly formatted error string.
# https://staticcheck.dev/docs/checks/#ST1005
- ST1005
# Poorly chosen receiver name.
# https://staticcheck.dev/docs/checks/#ST1006
- ST1006
# A function's error value should be its last return value.
# https://staticcheck.dev/docs/checks/#ST1008
- ST1008
# Poorly chosen name for variable of type 'time.Duration'.
# https://staticcheck.dev/docs/checks/#ST1011
- ST1011
# Poorly chosen name for error variable.
# https://staticcheck.dev/docs/checks/#ST1012
- ST1012
# Should use constants for HTTP error codes, not magic numbers.
# https://staticcheck.dev/docs/checks/#ST1013
- ST1013
# A switch's default case should be the first or last case.
# https://staticcheck.dev/docs/checks/#ST1015
- ST1015
# Use consistent method receiver names.
# https://staticcheck.dev/docs/checks/#ST1016
- ST1016
# Don't use Yoda conditions.
# https://staticcheck.dev/docs/checks/#ST1017
- ST1017
# Avoid zero-width and control characters in string literals.
# https://staticcheck.dev/docs/checks/#ST1018
- ST1018
# Importing the same package multiple times.
# https://staticcheck.dev/docs/checks/#ST1019
- ST1019
# The documentation of an exported function should start with the function's name.
# https://staticcheck.dev/docs/checks/#ST1020
- ST1020
# The documentation of an exported type should start with type's name.
# https://staticcheck.dev/docs/checks/#ST1021
- ST1021
# The documentation of an exported variable or constant should start with variable's name.
# https://staticcheck.dev/docs/checks/#ST1022
- ST1022
# Redundant type in variable declaration.
# https://staticcheck.dev/docs/checks/#ST1023
- ST1023
# Use plain channel send or receive instead of single-case select.
# https://staticcheck.dev/docs/checks/#S1000
- S1000
# Replace for loop with call to copy.
# https://staticcheck.dev/docs/checks/#S1001
- S1001
# Omit comparison with boolean constant.
# https://staticcheck.dev/docs/checks/#S1002
- S1002
# Replace call to 'strings.Index' with 'strings.Contains'.
# https://staticcheck.dev/docs/checks/#S1003
- S1003
# Replace call to 'bytes.Compare' with 'bytes.Equal'.
# https://staticcheck.dev/docs/checks/#S1004
- S1004
# Drop unnecessary use of the blank identifier.
# https://staticcheck.dev/docs/checks/#S1005
- S1005
# Use "for { ... }" for infinite loops.
# https://staticcheck.dev/docs/checks/#S1006
- S1006
# Simplify regular expression by using raw string literal.
# https://staticcheck.dev/docs/checks/#S1007
- S1007
# Simplify returning boolean expression.
# https://staticcheck.dev/docs/checks/#S1008
- S1008
# Omit redundant nil check on slices, maps, and channels.
# https://staticcheck.dev/docs/checks/#S1009
- S1009
# Omit default slice index.
# https://staticcheck.dev/docs/checks/#S1010
- S1010
# Use a single 'append' to concatenate two slices.
# https://staticcheck.dev/docs/checks/#S1011
- S1011
# Replace 'time.Now().Sub(x)' with 'time.Since(x)'.
# https://staticcheck.dev/docs/checks/#S1012
- S1012
# Use a type conversion instead of manually copying struct fields.
# https://staticcheck.dev/docs/checks/#S1016
- S1016
# Replace manual trimming with 'strings.TrimPrefix'.
# https://staticcheck.dev/docs/checks/#S1017
- S1017
# Use "copy" for sliding elements.
# https://staticcheck.dev/docs/checks/#S1018
- S1018
# Simplify "make" call by omitting redundant arguments.
# https://staticcheck.dev/docs/checks/#S1019
- S1019
# Omit redundant nil check in type assertion.
# https://staticcheck.dev/docs/checks/#S1020
- S1020
# Merge variable declaration and assignment.
# https://staticcheck.dev/docs/checks/#S1021
- S1021
# Omit redundant control flow.
# https://staticcheck.dev/docs/checks/#S1023
- S1023
# Replace 'x.Sub(time.Now())' with 'time.Until(x)'.
# https://staticcheck.dev/docs/checks/#S1024
- S1024
# Don't use 'fmt.Sprintf("%s", x)' unnecessarily.
# https://staticcheck.dev/docs/checks/#S1025
- S1025
# Simplify error construction with 'fmt.Errorf'.
# https://staticcheck.dev/docs/checks/#S1028
- S1028
# Range over the string directly.
# https://staticcheck.dev/docs/checks/#S1029
- S1029
# Use 'bytes.Buffer.String' or 'bytes.Buffer.Bytes'.
# https://staticcheck.dev/docs/checks/#S1030
- S1030
# Omit redundant nil check around loop.
# https://staticcheck.dev/docs/checks/#S1031
- S1031
# Use 'sort.Ints(x)', 'sort.Float64s(x)', and 'sort.Strings(x)'.
# https://staticcheck.dev/docs/checks/#S1032
- S1032
# Unnecessary guard around call to "delete".
# https://staticcheck.dev/docs/checks/#S1033
- S1033
# Use result of type assertion to simplify cases.
# https://staticcheck.dev/docs/checks/#S1034
- S1034
# Redundant call to 'net/http.CanonicalHeaderKey' in method call on 'net/http.Header'.
# https://staticcheck.dev/docs/checks/#S1035
- S1035
# Unnecessary guard around map access.
# https://staticcheck.dev/docs/checks/#S1036
- S1036
# Elaborate way of sleeping.
# https://staticcheck.dev/docs/checks/#S1037
- S1037
# Unnecessarily complex way of printing formatted string.
# https://staticcheck.dev/docs/checks/#S1038
- S1038
# Unnecessary use of 'fmt.Sprint'.
# https://staticcheck.dev/docs/checks/#S1039
- S1039
# Type assertion to current type.
# https://staticcheck.dev/docs/checks/#S1040
- S1040
# Apply De Morgan's law.
# https://staticcheck.dev/docs/checks/#QF1001
- QF1001
# Convert untagged switch to tagged switch.
# https://staticcheck.dev/docs/checks/#QF1002
- QF1002
# Convert if/else-if chain to tagged switch.
# https://staticcheck.dev/docs/checks/#QF1003
- QF1003
# Use 'strings.ReplaceAll' instead of 'strings.Replace' with 'n == -1'.
# https://staticcheck.dev/docs/checks/#QF1004
- QF1004
# Expand call to 'math.Pow'.
# https://staticcheck.dev/docs/checks/#QF1005
- QF1005
# Lift 'if'+'break' into loop condition.
# https://staticcheck.dev/docs/checks/#QF1006
- QF1006
# Merge conditional assignment into variable declaration.
# https://staticcheck.dev/docs/checks/#QF1007
- QF1007
# Omit embedded fields from selector expression.
# https://staticcheck.dev/docs/checks/#QF1008
- QF1008
# Use 'time.Time.Equal' instead of '==' operator.
# https://staticcheck.dev/docs/checks/#QF1009
- QF1009
# Convert slice of bytes to string when printing it.
# https://staticcheck.dev/docs/checks/#QF1010
- QF1010
# Omit redundant type from variable declaration.
# https://staticcheck.dev/docs/checks/#QF1011
- QF1011
# Use 'fmt.Fprintf(x, ...)' instead of 'x.Write(fmt.Sprintf(...))'.
# https://staticcheck.dev/docs/checks/#QF1012
- QF1012
unconvert:
# Remove conversions that force intermediate rounding.
# Default: false
fast-math: true
# Be more conservative (experimental).
# Default: false
safe: true
usestdlibvars:
# Suggest the use of http.MethodXX.
# Default: true
http-method: false
# Suggest the use of http.StatusXX.
# Default: true
http-status-code: false
# Suggest the use of time.Month in time.Date.
# Default: false
time-date-month: true
# Suggest the use of time.Weekday.String().
# Default: true
time-weekday: true
# Suggest the use of time.Month.String().
# Default: false
time-month: true
# Suggest the use of time.Layout.
# Default: false
time-layout: true
# Suggest the use of crypto.Hash.String().
# Default: false
crypto-hash: true
# Suggest the use of rpc.DefaultXXPath.
# Default: false
default-rpc-path: true
# Suggest the use of sql.LevelXX.String().
# Default: false
sql-isolation-level: true
# Suggest the use of tls.SignatureScheme.String().
# Default: false
tls-signature-scheme: true
# Suggest the use of constant.Kind.String().
# Default: false
constant-kind: true
wsl_v5:
allow-first-in-block: true
allow-whole-block: true
branch-max-lines: 2
case-max-lines: 2
default: all
disable:
- if
- err
exclusions: exclusions:
generated: lax generated: lax
presets: presets:
@@ -62,8 +786,6 @@ linters:
- legacy - legacy
- std-error-handling - std-error-handling
paths: paths:
- data
- vendor
- third_party$ - third_party$
- builtin$ - builtin$
- examples$ - examples$
@@ -74,8 +796,6 @@ formatters:
exclusions: exclusions:
generated: lax generated: lax
paths: paths:
- data
- vendor
- third_party$ - third_party$
- builtin$ - builtin$
- examples$ - examples$

View File

@@ -18,7 +18,7 @@ It is i3bar text generator.
## How to build it ## How to build it
This appliction was tested to compile with go v1.24. This application was tested to compile with go v1.24.
All you need is go lang compiler and gnu make utility. Invoke All you need is go lang compiler and gnu make utility. Invoke

View File

@@ -1,3 +1,4 @@
// Package main simple test for battery funtionality.
package main package main
import ( import (
@@ -20,3 +21,5 @@ func main() {
time.Sleep(1 * time.Second) time.Sleep(1 * time.Second)
} }
} }
/* vim: set ft=go noet ai ts=4 sw=4 sts=4: */

View File

@@ -2,7 +2,7 @@
// Default text and *block* border colors. If not set #3e78fd is used. // Default text and *block* border colors. If not set #3e78fd is used.
"color" : "#3e78fd", "color" : "#3e78fd",
// Default backbround color. If not set value of #edeceb is used. // Default background color. If not set value of #edeceb is used.
"background" : "#000000", "background" : "#000000",
// Can be omitted, then Liberation Mono will be used. // Can be omitted, then Liberation Mono will be used.
@@ -778,6 +778,19 @@
"app_buttons": { "app_buttons": {
"enabled": true, "enabled": true,
// If omitted set to default color defined up here.
"color": "#3e78fd",
// If omitted set to default background color defined up here.
"background": "#000000",
// If omitted set to default font defined up here.
"font": "Noto Sans",
// ‘xx-small’, ‘x-small’, ‘small’, ‘medium’, ‘large’, ‘x-large’, ‘xx-large’, or one of relative sizes
// ‘smaller’ or ‘larger’. If omitted set to default font size defined up here.
"font_size": "medium",
// Re-define separator parameters for net-if block here. // Re-define separator parameters for net-if block here.
"separator": { "separator": {
"left": { "left": {
@@ -821,31 +834,36 @@
// ‘smaller’ or ‘larger’. If omitted set to default font size defined for separator up here. // ‘smaller’ or ‘larger’. If omitted set to default font size defined for separator up here.
"font_size": "medium" "font_size": "medium"
} }
}, }
}, },
// Buttons - application launch "buttons" // Buttons - application launch "buttons"
"apps": [ "apps": [
{ {
// Text dispalyed on button // Text displayed on button, pango markup supported.
"full_text" : "📂", "full_text" : "📂",
// Internal name, can be any string, but unique for each app button // Internal name, can be any string, but unique for each app button.
"name" : "thunar", "name" : "thunar",
// Command itself // Command itself.
"cmd" : "thunar", "cmd" : "thunar",
// Array of command args, optional // Array of command args, optional.
"args": [ "." ], "args": [ "." ],
// Regexp that match with Instance component of WM_CLASS(STRING) of xprop output // Regexp that match with Instance component of WM_CLASS(STRING) of xprop output.
"instance": "^thunar$", "instance": "^thunar$",
// Regexp that match with Class component of WM_CLASS(STRING) of xprop output // Regexp that match with Class component of WM_CLASS(STRING) of xprop output.
"class": "^Thunar$", "class": "^Thunar$",
// text color in html notation // Text color in html notation.
"color": "#ffa500", "color": "#ffa500",
// background color in html notation // background color in html notation.
"background" : "#000000", "background" : "#000000",
// border color in html notation // If omitted set to default font defined for app_buttons up here.
"font": "Noto Sans",
// ‘xx-small’, ‘x-small’, ‘small’, ‘medium’, ‘large’, ‘x-large’, ‘xx-large’, or one of relative sizes
// ‘smaller’ or ‘larger’. If omitted set to default font size defined for app_buttons up here.
"font_size": "medium",
// Border color in html notation.
"border": "#666666", "border": "#666666",
// border color if there is at least one window with given Instance and/or Class exist // Border color if there is at least one window with given Instance and/or Class exist.
"border_active": "#3e78fd", "border_active": "#3e78fd",
// Vertical line between objects on bar - if omitted true value is assumed by i3bar, but we set it to false // Vertical line between objects on bar - if omitted true value is assumed by i3bar, but we set it to false
// in that case. It is limitation of golang json parser. // in that case. It is limitation of golang json parser.

View File

@@ -1,3 +1,4 @@
// Package main status string generator for i3bar.
package main package main
import ( import (
@@ -8,6 +9,7 @@ import (
"log" "log"
"os" "os"
"os/signal" "os/signal"
"strconv"
"strings" "strings"
"syscall" "syscall"
@@ -15,7 +17,7 @@ import (
) )
//go:embed default-config.json //go:embed default-config.json
var DefaultConfig []byte var DefaultConfig []byte //nolint: godoclint, grouper, nolintlint
// Program entry point. // Program entry point.
func main() { func main() {
@@ -42,15 +44,11 @@ func main() {
// Conf.Values.PA // Conf.Values.PA
Conf.Values.SoundVolume = "🔊:0%" Conf.Values.SoundVolume = "🔊:0%"
// TODO: Проставить дефолтные значения для глобальных переменных модулей. Conf.Values.BatteryString = "<span color='" + Conf.Battery.Color +
Conf.Values.BatteryString = fmt.Sprintf( "' background='" + Conf.Battery.Background +
"<span color='%s' background='%s' font='%s' size='%s'>%s</span>", "' font='" + Conf.Battery.SymbolFont +
Conf.Battery.Color, "' size='" + Conf.Battery.SymbolFontSize +
Conf.Battery.Background, "'>" + Conf.Battery.Symbol + "</span>"
Conf.Battery.SymbolFont,
Conf.Battery.SymbolFontSize,
Conf.Battery.Symbol,
)
Conf.Values.BatteryString += fmt.Sprintf( Conf.Values.BatteryString += fmt.Sprintf(
"<span color='%s' background='%s' font='%s' size='%s'> ??%% •</span>", "<span color='%s' background='%s' font='%s' size='%s'> ??%% •</span>",
@@ -104,6 +102,7 @@ func main() {
// Kick signal handler // Kick signal handler
go Conf.SigHandler() go Conf.SigHandler()
signal.Notify(Conf.Channels.SigChan, signal.Notify(Conf.Channels.SigChan,
syscall.SIGUSR1, syscall.SIGUSR1,
syscall.SIGUSR2, syscall.SIGUSR2,
@@ -178,33 +177,10 @@ func main() {
// TODO: впилить для первого и последнего батона separator // TODO: впилить для первого и последнего батона separator
if Conf.AppButtons.Enabled { if Conf.AppButtons.Enabled {
for num, app := range Conf.Apps { for _, app := range Conf.Apps {
var b lib.I3BarOutBlock var b lib.I3BarOutBlock
if num == 0 {
b.FullText = fmt.Sprintf(
"<span color='%s' background='%s' font='%s' size='%s'>%s</span>",
Conf.AppButtons.Separator.Left.Color,
Conf.AppButtons.Separator.Left.Background,
Conf.AppButtons.Separator.Left.Font,
Conf.AppButtons.Separator.Left.FontSize,
Conf.AppButtons.Separator.Left.Symbol,
)
}
b.FullText = app.FullText b.FullText = app.FullText
if num == len(Conf.Apps) {
b.FullText = fmt.Sprintf(
"<span color='%s' background='%s' font='%s' size='%s'>%s</span>",
Conf.AppButtons.Separator.Right.Color,
Conf.AppButtons.Separator.Right.Background,
Conf.AppButtons.Separator.Right.Font,
Conf.AppButtons.Separator.Right.FontSize,
Conf.AppButtons.Separator.Right.Symbol,
)
}
b.Background = app.Background b.Background = app.Background
b.Color = app.Color b.Color = app.Color
b.Instance = app.Instance b.Instance = app.Instance
@@ -229,42 +205,55 @@ func main() {
} }
if Conf.CPUTemp.Enabled { if Conf.CPUTemp.Enabled {
var b lib.I3BarOutBlock var (
b lib.I3BarOutBlock
sb strings.Builder
)
b.Color = Conf.CPUTemp.Color b.Color = Conf.CPUTemp.Color
b.Background = Conf.CPUTemp.Background b.Background = Conf.CPUTemp.Background
if Conf.CPUTemp.Separator.Left.Enabled { if Conf.CPUTemp.Separator.Left.Enabled {
b.FullText = fmt.Sprintf( sb.WriteString("<span color='")
"<span color='%s' background='%s' font='%s' size='%s'>%s</span>", sb.WriteString(Conf.CPUTemp.Separator.Left.Color)
Conf.CPUTemp.Separator.Left.Color, sb.WriteString("' background='")
Conf.CPUTemp.Separator.Left.Background, sb.WriteString(Conf.CPUTemp.Separator.Left.Background)
Conf.CPUTemp.Separator.Left.Font, sb.WriteString("' font='")
Conf.CPUTemp.Separator.Left.FontSize, sb.WriteString(Conf.CPUTemp.Separator.Left.Font)
Conf.CPUTemp.Separator.Left.Symbol, sb.WriteString("' size='")
) sb.WriteString(Conf.CPUTemp.Separator.Left.FontSize)
sb.WriteString("'>")
sb.WriteString(Conf.CPUTemp.Separator.Left.Symbol)
sb.WriteString("</span>")
} }
b.FullText += fmt.Sprintf( sb.WriteString("<span color='")
"<span color='%s' background='%s' font='%s' size='%s'>CPU: %d°</span>", sb.WriteString(Conf.CPUTemp.Color)
Conf.CPUTemp.Color, sb.WriteString("' background='")
Conf.CPUTemp.Background, sb.WriteString(Conf.CPUTemp.Background)
Conf.CPUTemp.Font, sb.WriteString("' font='")
Conf.CPUTemp.FontSize, sb.WriteString(Conf.CPUTemp.Font)
Conf.Values.CPUTemperature, sb.WriteString("' size='")
) sb.WriteString(Conf.CPUTemp.FontSize)
sb.WriteString("'>CPU: ")
sb.WriteString(strconv.FormatInt(Conf.Values.CPUTemperature, 10))
sb.WriteString("°</span>")
if Conf.CPUTemp.Separator.Right.Enabled { if Conf.CPUTemp.Separator.Right.Enabled {
b.FullText += fmt.Sprintf( sb.WriteString("<span color='")
"<span color='%s' background='%s' font='%s' size='%s'>%s</span>", sb.WriteString(Conf.CPUTemp.Separator.Right.Color)
Conf.CPUTemp.Separator.Right.Color, sb.WriteString("' background='")
Conf.CPUTemp.Separator.Right.Background, sb.WriteString(Conf.CPUTemp.Separator.Right.Background)
Conf.CPUTemp.Separator.Right.Font, sb.WriteString("' font='")
Conf.CPUTemp.Separator.Right.FontSize, sb.WriteString(Conf.CPUTemp.Separator.Right.Font)
Conf.CPUTemp.Separator.Right.Symbol, sb.WriteString("' size='")
) sb.WriteString(Conf.CPUTemp.Separator.Right.FontSize)
sb.WriteString("'>")
sb.WriteString(Conf.CPUTemp.Separator.Right.Symbol)
sb.WriteString("</span>")
} }
b.FullText = sb.String()
b.Markup = "pango" b.Markup = "pango"
b.Separator = false b.Separator = false
@@ -272,56 +261,66 @@ func main() {
} }
if Conf.Mem.Enabled { if Conf.Mem.Enabled {
var b lib.I3BarOutBlock var (
b lib.I3BarOutBlock
sb strings.Builder
)
b.Color = Conf.Mem.Color b.Color = Conf.Mem.Color
b.Background = Conf.Mem.Background b.Background = Conf.Mem.Background
if Conf.Mem.Separator.Left.Enabled { if Conf.Mem.Separator.Left.Enabled {
b.FullText = fmt.Sprintf( sb.WriteString("<span color='")
"<span color='%s' background='%s' font='%s' size='%s'>%s</span>", sb.WriteString(Conf.Mem.Separator.Left.Color)
Conf.Mem.Separator.Left.Color, sb.WriteString("' background='")
Conf.Mem.Separator.Left.Background, sb.WriteString(Conf.Mem.Separator.Left.Background)
Conf.Mem.Separator.Left.Font, sb.WriteString("' font='")
Conf.Mem.Separator.Left.FontSize, sb.WriteString(Conf.Mem.Separator.Left.Font)
Conf.Mem.Separator.Left.Symbol, sb.WriteString("' size='")
) sb.WriteString(Conf.Mem.Separator.Left.FontSize)
sb.WriteString("'>")
sb.WriteString(Conf.Mem.Separator.Left.Symbol)
sb.WriteString("</span>")
} }
sb.WriteString("<span color='")
sb.WriteString(Conf.Mem.Color)
sb.WriteString("' background='")
sb.WriteString(Conf.Mem.Background)
sb.WriteString("' font='")
sb.WriteString(Conf.Mem.Font)
sb.WriteString("' size='")
sb.WriteString(Conf.Mem.FontSize)
sb.WriteString("'>M:")
sb.WriteString(strconv.FormatUint(Conf.Values.Memory.Usedpct, 10))
sb.WriteString("% SHM:")
sb.WriteString(strconv.FormatUint(Conf.Values.Memory.Shared, 10))
if Conf.Mem.ShowSwap { if Conf.Mem.ShowSwap {
b.FullText += fmt.Sprintf( sb.WriteString("% SW:")
"<span color='%s' background='%s' font='%s' size='%s'>M:%d%% SHM:%dM SW:%dM</span>", sb.WriteString(strconv.FormatUint(Conf.Values.Memory.Swap, 10))
Conf.Mem.Color, sb.WriteString("M")
Conf.Mem.Background,
Conf.Mem.Font,
Conf.Mem.FontSize,
Conf.Values.Memory.Usedpct,
Conf.Values.Memory.Shared,
Conf.Values.Memory.Swap,
)
} else { } else {
b.FullText += fmt.Sprintf( sb.WriteString("%")
"<span color='%s' background='%s' font='%s' size='%s'>M:%d%% SHM:%dM</span>",
Conf.Mem.Color,
Conf.Mem.Background,
Conf.Mem.Font,
Conf.Mem.FontSize,
Conf.Values.Memory.Usedpct,
Conf.Values.Memory.Shared,
)
} }
sb.WriteString("</span>")
if Conf.Mem.Separator.Right.Enabled { if Conf.Mem.Separator.Right.Enabled {
b.FullText += fmt.Sprintf( sb.WriteString("<span color='")
"<span color='%s' background='%s' font='%s' size='%s'>%s</span>", sb.WriteString(Conf.Mem.Separator.Right.Color)
Conf.Mem.Separator.Right.Color, sb.WriteString("' background='")
Conf.Mem.Separator.Right.Background, sb.WriteString(Conf.Mem.Separator.Right.Background)
Conf.Mem.Separator.Right.Font, sb.WriteString("' font='")
Conf.Mem.Separator.Right.FontSize, sb.WriteString(Conf.Mem.Separator.Right.Font)
Conf.Mem.Separator.Right.Symbol, sb.WriteString("' size='")
) sb.WriteString(Conf.Mem.Separator.Right.FontSize)
sb.WriteString("'>")
sb.WriteString(Conf.Mem.Separator.Right.Symbol)
sb.WriteString("</span>")
} }
b.FullText = sb.String()
b.Markup = "pango" b.Markup = "pango"
b.Separator = false b.Separator = false
@@ -329,42 +328,55 @@ func main() {
} }
if Conf.LA.Enabled { if Conf.LA.Enabled {
var b lib.I3BarOutBlock var (
b lib.I3BarOutBlock
sb strings.Builder
)
b.Color = Conf.LA.Color b.Color = Conf.LA.Color
b.Background = Conf.LA.Background b.Background = Conf.LA.Background
if Conf.LA.Separator.Left.Enabled { if Conf.LA.Separator.Left.Enabled {
b.FullText = fmt.Sprintf( sb.WriteString("<span color='")
"<span color='%s' background='%s' font='%s' size='%s'>%s</span>", sb.WriteString(Conf.LA.Separator.Left.Color)
Conf.LA.Separator.Left.Color, sb.WriteString("' background='")
Conf.LA.Separator.Left.Background, sb.WriteString(Conf.LA.Separator.Left.Background)
Conf.LA.Separator.Left.Font, sb.WriteString("' font='")
Conf.LA.Separator.Left.FontSize, sb.WriteString(Conf.LA.Separator.Left.Font)
Conf.LA.Separator.Left.Symbol, sb.WriteString("' size='")
) sb.WriteString(Conf.LA.Separator.Left.FontSize)
sb.WriteString("'>")
sb.WriteString(Conf.LA.Separator.Left.Symbol)
sb.WriteString("</span>")
} }
b.FullText += fmt.Sprintf( sb.WriteString("<span color='")
"<span color='%s' background='%s' font='%s' size='%s'>LA:%s</span>", sb.WriteString(Conf.LA.Color)
Conf.LA.Color, sb.WriteString("' background='")
Conf.LA.Background, sb.WriteString(Conf.LA.Background)
Conf.LA.Font, sb.WriteString("' font='")
Conf.LA.FontSize, sb.WriteString(Conf.LA.Font)
Conf.Values.La, sb.WriteString("' size='")
) sb.WriteString(Conf.LA.FontSize)
sb.WriteString("'>LA:")
sb.WriteString(Conf.Values.La)
sb.WriteString("</span>")
if Conf.LA.Separator.Right.Enabled { if Conf.LA.Separator.Right.Enabled {
b.FullText += fmt.Sprintf( sb.WriteString("<span color='")
"<span color='%s' background='%s' font='%s' size='%s'>%s</span>", sb.WriteString(Conf.LA.Separator.Right.Color)
Conf.LA.Separator.Right.Color, sb.WriteString("' background='")
Conf.LA.Separator.Right.Background, sb.WriteString(Conf.LA.Separator.Right.Background)
Conf.LA.Separator.Right.Font, sb.WriteString("' font='")
Conf.LA.Separator.Right.FontSize, sb.WriteString(Conf.LA.Separator.Right.Font)
Conf.LA.Separator.Right.Symbol, sb.WriteString("' size='")
) sb.WriteString(Conf.LA.Separator.Right.FontSize)
sb.WriteString("'>")
sb.WriteString(Conf.LA.Separator.Right.Symbol)
sb.WriteString("</span>")
} }
b.FullText = sb.String()
b.Markup = "pango" b.Markup = "pango"
b.Separator = false b.Separator = false
@@ -576,43 +588,56 @@ func main() {
} }
if Conf.Clock.Enabled { if Conf.Clock.Enabled {
var b lib.I3BarOutBlock var (
b lib.I3BarOutBlock
sb strings.Builder
)
b.Name = `wallclock` b.Name = `wallclock`
b.Color = Conf.Clock.Color b.Color = Conf.Clock.Color
b.Background = Conf.Clock.Background b.Background = Conf.Clock.Background
if Conf.Clock.Separator.Left.Enabled { if Conf.Clock.Separator.Left.Enabled {
b.FullText = fmt.Sprintf( sb.WriteString("<span color='")
"<span color='%s' background='%s' font='%s' size='%s'>%s</span>", sb.WriteString(Conf.Clock.Separator.Left.Color)
Conf.Clock.Separator.Left.Color, sb.WriteString("' background='")
Conf.Clock.Separator.Left.Background, sb.WriteString(Conf.Clock.Separator.Left.Background)
Conf.Clock.Separator.Left.Font, sb.WriteString("' font='")
Conf.Clock.Separator.Left.FontSize, sb.WriteString(Conf.Clock.Separator.Left.Font)
Conf.Clock.Separator.Left.Symbol, sb.WriteString("' size='")
) sb.WriteString(Conf.Clock.Separator.Left.FontSize)
sb.WriteString("'>")
sb.WriteString(Conf.Clock.Separator.Left.Symbol)
sb.WriteString("</span>")
} }
b.FullText += fmt.Sprintf( sb.WriteString("<span color='")
"<span color='%s' background='%s' font='%s' size='%s'>%s</span>", sb.WriteString(Conf.Clock.Color)
Conf.Clock.Color, sb.WriteString("' background='")
Conf.Clock.Background, sb.WriteString(Conf.Clock.Background)
Conf.Clock.Font, sb.WriteString("' font='")
Conf.Clock.FontSize, sb.WriteString(Conf.Clock.Font)
Conf.Values.ClockTime, sb.WriteString("' size='")
) sb.WriteString(Conf.Clock.FontSize)
sb.WriteString("'>")
sb.WriteString(Conf.Values.ClockTime)
sb.WriteString("</span>")
if Conf.Clock.Separator.Right.Enabled { if Conf.Clock.Separator.Right.Enabled {
b.FullText += fmt.Sprintf( sb.WriteString("<span color='")
"<span color='%s' background='%s' font='%s' size='%s'>%s</span>", sb.WriteString(Conf.Clock.Separator.Right.Color)
Conf.Clock.Separator.Right.Color, sb.WriteString("' background='")
Conf.Clock.Separator.Right.Background, sb.WriteString(Conf.Clock.Separator.Right.Background)
Conf.Clock.Separator.Right.Font, sb.WriteString("' font='")
Conf.Clock.Separator.Right.FontSize, sb.WriteString(Conf.Clock.Separator.Right.Font)
Conf.Clock.Separator.Right.Symbol, sb.WriteString("' size='")
) sb.WriteString(Conf.Clock.Separator.Right.FontSize)
sb.WriteString("'>")
sb.WriteString(Conf.Clock.Separator.Right.Symbol)
sb.WriteString("</span>")
} }
b.FullText = sb.String()
b.Markup = "pango" b.Markup = "pango"
b.Separator = false b.Separator = false
@@ -641,3 +666,5 @@ func PrintToI3bar(c *lib.MyConfig) {
fmt.Println(strings.TrimSuffix(buf.String(), "\n") + ",") fmt.Println(strings.TrimSuffix(buf.String(), "\n") + ",")
} }
} }
/* vim: set ft=go noet ai ts=4 sw=4 sts=4: */

View File

@@ -1,3 +1,4 @@
// Package lib represents guts of i3status-go.
package lib package lib
import ( import (
@@ -29,7 +30,7 @@ func (c *MyConfig) UpdateBatteryInfo() {
} }
var ( var (
batteries []*battery.Battery = []*battery.Battery{} batteries = []*battery.Battery{}
Batts string Batts string
ch int ch int
status string status string
@@ -52,23 +53,26 @@ func (c *MyConfig) UpdateBatteryInfo() {
if err != nil { if err != nil {
log.Printf("Unable to read file %s: %s", file, err) log.Printf("Unable to read file %s: %s", file, err)
continue continue
} }
myCharge = strings.Trim(string(b), "\n") myCharge = strings.TrimSpace(string(b))
statusFile := filepath.Dir(file) + "/status" statusFile := filepath.Dir(file) + "/status"
// If file exists. _, err = os.Stat(statusFile)
if !os.IsNotExist(err) { if !os.IsNotExist(err) {
b, err := os.ReadFile(statusFile) b, err := os.ReadFile(statusFile)
if err != nil { if err != nil {
log.Printf("Unable to read file %s: %s", statusFile, err) log.Printf("Unable to read file %s: %s", statusFile, err)
continue continue
} }
myStatus = strings.Trim(string(b), "\n") myStatus = strings.TrimSpace(string(b))
} else { } else {
continue continue
} }
@@ -91,6 +95,7 @@ func (c *MyConfig) UpdateBatteryInfo() {
if err != nil { if err != nil {
log.Printf("Unable to convert string from file %s to integer", file) log.Printf("Unable to convert string from file %s to integer", file)
continue continue
} }
@@ -100,9 +105,13 @@ func (c *MyConfig) UpdateBatteryInfo() {
} }
} }
} else { } else {
batteries, _ = battery.GetAll() var err error
// In theory, this module should give for each entry its separate err, but in practice it gives
// one single err for all entries, so we cannot detemine whist exatly entry errored. batteries, err = battery.GetAll()
if err != nil {
log.Printf("Unable to get battery info: %s", err)
}
} }
var ( var (
@@ -250,3 +259,5 @@ func (c *MyConfig) UpdateBatteryInfo() {
} }
} }
} }
/* vim: set ft=go noet ai ts=4 sw=4 sts=4: */

View File

@@ -35,3 +35,5 @@ func (c *MyConfig) UpdateClock() {
} }
} }
} }
/* vim: set ft=go noet ai ts=4 sw=4 sts=4: */

View File

@@ -7,7 +7,6 @@ import (
// Collection is sync.Map, that stores arbitrary data. // Collection is sync.Map, that stores arbitrary data.
type Collection struct { type Collection struct {
items sync.Map items sync.Map
close chan struct{}
} }
// Item just interface for stoing any data. // Item just interface for stoing any data.
@@ -17,9 +16,7 @@ type item struct {
// NewCollection creates new instance of "collection". // NewCollection creates new instance of "collection".
func NewCollection() *Collection { func NewCollection() *Collection {
c := &Collection{ //nolint:exhaustruct c := &Collection{}
close: make(chan struct{}),
}
return c return c
} }
@@ -32,9 +29,12 @@ func (collection *Collection) Get(key any) (any, bool) {
return nil, false return nil, false
} }
item := obj.(item) it, ok := obj.(item)
if !ok {
return nil, false
}
return item.data, true return it.data, true
} }
// Set saves value to given "collection". // Set saves value to given "collection".
@@ -44,12 +44,15 @@ func (collection *Collection) Set(key any, value any) {
}) })
} }
// Range apply function f to all keys/values in collection. Retuns immediatly on first error. // Range apply function f to all keys/values in collection. Returns immediately on first error.
func (collection *Collection) Range(f func(key, value any) bool) { func (collection *Collection) Range(f func(key, value any) bool) {
fn := func(key, value any) bool { fn := func(key, value any) bool {
item := value.(item) it, ok := value.(item)
if !ok {
return true
}
return f(key, item.data) return f(key, it.data)
} }
collection.items.Range(fn) collection.items.Range(fn)
@@ -62,7 +65,6 @@ func (collection *Collection) Delete(key any) {
// Close frees memory occupied by collection and deletes collection itself. // Close frees memory occupied by collection and deletes collection itself.
func (collection *Collection) Close() { func (collection *Collection) Close() {
collection.close <- struct{}{}
collection.items = sync.Map{} collection.items = sync.Map{}
} }

View File

@@ -14,19 +14,22 @@ import (
p "github.com/mafik/pulseaudio" p "github.com/mafik/pulseaudio"
) )
type (
// I3BarOutBlock is structure element for I3BarOut, it represents i3bar output json block format. // I3BarOutBlock is structure element for I3BarOut, it represents i3bar output json block format.
type I3BarOutBlock struct { I3BarOutBlock struct {
FullText string `json:"full_text"` FullText string `json:"full_text"`
// ShortText will be shown if not enough room for FullText, threshold width defined in MinWidth // ShortText will be shown if not enough room for FullText, threshold width defined in MinWidth.
ShortText string `json:"short_text,omitempty"` ShortText string `json:"short_text,omitempty"`
Color string `json:"color,omitempty"` Color string `json:"color,omitempty"`
Background string `json:"background,omitempty"` Background string `json:"background,omitempty"`
Font string `json:"font,omitempty"`
FontSize string `json:"font_size,omitempty"`
Border string `json:"border,omitempty"` Border string `json:"border,omitempty"`
BorderTop int `json:"border_top"` BorderTop int `json:"border_top"`
BorderRight int `json:"border_right"` BorderRight int `json:"border_right"`
BorderBottom int `json:"border_bottom"` BorderBottom int `json:"border_bottom"`
BorderLeft int `json:"border_left"` BorderLeft int `json:"border_left"`
// measured either in pixels or in characters, so either int or string, let's make it string :) // measured either in pixels or in characters, so either int or string, let's make it string :) .
MinWidth string `json:"min_width,omitempty"` MinWidth string `json:"min_width,omitempty"`
Align string `json:"align,omitempty"` Align string `json:"align,omitempty"`
Name string `json:"name,omitempty"` Name string `json:"name,omitempty"`
@@ -37,27 +40,29 @@ type I3BarOutBlock struct {
Markup string `json:"markup,omitempty"` Markup string `json:"markup,omitempty"`
} }
type Separator struct { // Separator usually is a bymbol that separates fields in i3 status string.
Separator struct {
Left struct { Left struct {
Enabled bool `json:"enabled,omitempty"`
Color string `json:"color,omitempty"` Color string `json:"color,omitempty"`
Background string `json:"background,omitempty"` Background string `json:"background,omitempty"`
Symbol string `json:"symbol,omitempty"` Symbol string `json:"symbol,omitempty"`
Font string `json:"font,omitempty"` Font string `json:"font,omitempty"`
FontSize string `json:"font_size,omitempty"` FontSize string `json:"font_size,omitempty"`
} `json:"left,omitempty"` Enabled bool `json:"enabled,omitempty"`
} `json:"left"`
Right struct { Right struct {
Enabled bool `json:"enabled,omitempty"`
Color string `json:"color,omitempty"` Color string `json:"color,omitempty"`
Background string `json:"background,omitempty"` Background string `json:"background,omitempty"`
Symbol string `json:"symbol,omitempty"` Symbol string `json:"symbol,omitempty"`
Font string `json:"font,omitempty"` Font string `json:"font,omitempty"`
FontSize string `json:"font_size,omitempty"` FontSize string `json:"font_size,omitempty"`
} `json:"right,omitempty"` Enabled bool `json:"enabled,omitempty"`
} `json:"right"`
} }
type MyConfig struct { // MyConfig internal represetation of running config state.
MyConfig struct {
Values struct { Values struct {
PrintOutput bool PrintOutput bool
CPUTemperature int64 CPUTemperature int64
@@ -80,21 +85,22 @@ type MyConfig struct {
RunChan chan []string RunChan chan []string
} }
// Default text color // Color default text color.
Color string `json:"color,omitempty"` Color string `json:"color,omitempty"`
// Default background color // Background default background color.
Background string `json:"background,omitempty"` Background string `json:"background,omitempty"`
// Default text font // Font default text font.
Font string `json:"font,omitempty"` Font string `json:"font,omitempty"`
// Default text font size // FontSize default text font size.
FontSize string `json:"font_size,omitempty"` FontSize string `json:"font_size,omitempty"`
Separator Separator `json:"separator,omitempty"` // Separator i3status string separator configuration.
Separator Separator `json:"separator"`
// LA Plugin // LA Plugin.
LA struct { LA struct {
Enabled bool `json:"enabled,omitempty"` Enabled bool `json:"enabled,omitempty"`
Color string `json:"color,omitempty"` Color string `json:"color,omitempty"`
@@ -102,9 +108,9 @@ type MyConfig struct {
Font string `json:"font,omitempty"` Font string `json:"font,omitempty"`
FontSize string `json:"font_size,omitempty"` FontSize string `json:"font_size,omitempty"`
Separator Separator `json:"separator,omitempty"` Separator Separator `json:"separator,omitempty"`
} `json:"la,omitempty"` } `json:"la"`
// Mem plugin // Mem plugin.
Mem struct { Mem struct {
Enabled bool `json:"enabled,omitempty"` Enabled bool `json:"enabled,omitempty"`
Color string `json:"color,omitempty"` Color string `json:"color,omitempty"`
@@ -113,8 +119,9 @@ type MyConfig struct {
FontSize string `json:"font_size,omitempty"` FontSize string `json:"font_size,omitempty"`
ShowSwap bool `json:"show_swap,omitempty"` ShowSwap bool `json:"show_swap,omitempty"`
Separator Separator `json:"separator,omitempty"` Separator Separator `json:"separator,omitempty"`
} `json:"mem,omitempty"` } `json:"mem"`
// Clock plugin.
Clock struct { Clock struct {
Enabled bool `json:"enabled,omitempty"` Enabled bool `json:"enabled,omitempty"`
Color string `json:"color,omitempty"` Color string `json:"color,omitempty"`
@@ -126,14 +133,15 @@ type MyConfig struct {
LeftClick struct { LeftClick struct {
Enabled bool `json:"enabled,omitempty"` Enabled bool `json:"enabled,omitempty"`
Cmd []string `json:"cmd,omitempty"` Cmd []string `json:"cmd,omitempty"`
} `json:"left_click,omitempty"` } `json:"left_click"`
RightClick struct { RightClick struct {
Enabled bool `json:"enabled,omitempty"` Enabled bool `json:"enabled,omitempty"`
Cmd []string `json:"cmd,omitempty"` Cmd []string `json:"cmd,omitempty"`
} `json:"right_click,omitempty"` } `json:"right_click"`
} `json:"clock,omitempty"` } `json:"clock"`
// Battery plugin.
Battery struct { Battery struct {
Enabled bool `json:"enabled,omitempty"` Enabled bool `json:"enabled,omitempty"`
UseSysfs bool `json:"use_sysfs,omitempty"` UseSysfs bool `json:"use_sysfs,omitempty"`
@@ -151,11 +159,12 @@ type MyConfig struct {
Empty string `json:"empty,omitempty"` Empty string `json:"empty,omitempty"`
AlmostFull string `json:"almost_full,omitempty"` AlmostFull string `json:"almost_full,omitempty"`
AlmostEmpty string `json:"almost_empty,omitempty"` AlmostEmpty string `json:"almost_empty,omitempty"`
} `json:"charge_color,omitempty"` } `json:"charge_color"`
Separator Separator `json:"separator,omitempty"` Separator Separator `json:"separator,omitempty"`
} `json:"battery,omitempty"` } `json:"battery"`
// CPUTemp plugin.
CPUTemp struct { CPUTemp struct {
Enabled bool `json:"enabled,omitempty"` Enabled bool `json:"enabled,omitempty"`
Color string `json:"color,omitempty"` Color string `json:"color,omitempty"`
@@ -165,8 +174,9 @@ type MyConfig struct {
Separator Separator `json:"separator,omitempty"` Separator Separator `json:"separator,omitempty"`
File []string `json:"file,omitempty"` File []string `json:"file,omitempty"`
} `json:"cpu_temp,omitempty"` } `json:"cpu_temp"`
// Vpn plugin.
Vpn struct { Vpn struct {
Enabled bool `json:"enabled,omitempty"` Enabled bool `json:"enabled,omitempty"`
Color string `json:"color,omitempty"` Color string `json:"color,omitempty"`
@@ -177,16 +187,17 @@ type MyConfig struct {
MtimeThreshold int `json:"mtime_threshold,omitempty"` MtimeThreshold int `json:"mtime_threshold,omitempty"`
DownColor string `json:"down_color,omitempty"` DownColor string `json:"down_color,omitempty"`
UpColor string `json:"up_color,omitempty"` UpColor string `json:"up_color,omitempty"`
Separator Separator `json:"separator,omitempty"` Separator Separator `json:"separator"`
TCPCheck struct { TCPCheck struct {
Enabled bool `json:"enabled,omitempty"` Enabled bool `json:"enabled,omitempty"`
Host string `json:"host,omitempty"` Host string `json:"host,omitempty"`
Port int `json:"port,omitempty"` Port int `json:"port,omitempty"`
Timeout int `json:"timeout,omitempty"` Timeout int `json:"timeout,omitempty"`
} `json:"tcp_check,omitempty"` } `json:"tcp_check"`
} `json:"vpn,omitempty"` } `json:"vpn"`
// SimpleVolumePa plugin.
SimpleVolumePa struct { SimpleVolumePa struct {
Enabled bool `json:"enabled,omitempty"` Enabled bool `json:"enabled,omitempty"`
Color string `json:"color,omitempty"` Color string `json:"color,omitempty"`
@@ -204,8 +215,9 @@ type MyConfig struct {
WheelUp int `json:"wheel_up,omitempty"` WheelUp int `json:"wheel_up,omitempty"`
WheelDown int `json:"wheel_down,omitempty"` WheelDown int `json:"wheel_down,omitempty"`
MaxVolumeLimit int `json:"max_volume_limit,omitempty"` MaxVolumeLimit int `json:"max_volume_limit,omitempty"`
} `json:"simple-volume-pa,omitempty"` } `json:"simple-volume-pa"`
// NrtIf plugin.
NetIf struct { NetIf struct {
Enabled bool `json:"enabled,omitempty"` Enabled bool `json:"enabled,omitempty"`
DownColor string `json:"down_color,omitempty"` DownColor string `json:"down_color,omitempty"`
@@ -219,9 +231,10 @@ type MyConfig struct {
If []struct { If []struct {
Name string `json:"name,omitempty"` Name string `json:"name,omitempty"`
Dir string `json:"dir,omitempty"` Dir string `json:"dir,omitempty"`
} `json:"if,omitempty"` } `json:"if"`
} `json:"net-if,omitempty"` } `json:"net-if"`
// Cron plugin.
Cron struct { Cron struct {
Enabled bool `json:"enabled,omitempty"` Enabled bool `json:"enabled,omitempty"`
TimeZone string `json:"timezone,omitempty"` TimeZone string `json:"timezone,omitempty"`
@@ -229,26 +242,33 @@ type MyConfig struct {
Tasks []struct { Tasks []struct {
Time string `json:"time,omitempty"` Time string `json:"time,omitempty"`
Cmd []string `json:"cmd,omitempty"` Cmd []string `json:"cmd,omitempty"`
} `json:"tasks,omitempty"` } `json:"tasks"`
} `json:"cron,omitempty"` } `json:"cron"`
// CmdRun plugin.
CmdRun struct { CmdRun struct {
Enabled bool `json:"enabled,omitempty"`
Color string `json:"color,omitempty"` Color string `json:"color,omitempty"`
Background string `json:"background,omitempty"` Background string `json:"background,omitempty"`
Font string `json:"font,omitempty"` Font string `json:"font,omitempty"`
FontSize string `json:"font_size,omitempty"` FontSize string `json:"font_size,omitempty"`
Separator Separator `json:"separator,omitempty"`
Cmd string `json:"cmd,omitempty"` Cmd string `json:"cmd,omitempty"`
Delay int `json:"delay,omitempty"`
Args []string `json:"args,omitempty"` Args []string `json:"args,omitempty"`
} Enabled bool `json:"enabled,omitempty"`
Delay int `json:"delay,omitempty"`
Separator Separator `json:"separator,omitempty"`
} `json:"cmdrun"`
// AppButtons plugin.
AppButtons struct { AppButtons struct {
Color string `json:"color,omitempty"`
Background string `json:"background,omitempty"`
Font string `json:"font,omitempty"`
FontSize string `json:"font_size,omitempty"`
Enabled bool `json:"enabled,omitempty"` Enabled bool `json:"enabled,omitempty"`
Separator Separator `json:"separator,omitempty"` Separator Separator `json:"separator,omitempty"`
} `json:"app_buttons,omitempty"` } `json:"app_buttons"`
// Apps descriptions for AppButtons plugin.
Apps []struct { Apps []struct {
FullText string `json:"full_text,omitempty"` FullText string `json:"full_text,omitempty"`
Name string `json:"name,omitempty"` Name string `json:"name,omitempty"`
@@ -258,14 +278,17 @@ type MyConfig struct {
Class string `json:"class,omitempty"` Class string `json:"class,omitempty"`
Color string `json:"color,omitempty"` Color string `json:"color,omitempty"`
Background string `json:"background,omitempty"` Background string `json:"background,omitempty"`
Font string `json:"font,omitempty"`
FontSize string `json:"font_size,omitempty"`
Border string `json:"border,omitempty"` Border string `json:"border,omitempty"`
BorderActive string `json:"border_active,omitempty"` BorderActive string `json:"border_active,omitempty"`
Separator bool `json:"separator,omitempty"` Separator bool `json:"separator,omitempty"`
SeparatorBlockWidth int `json:"separator_block_width,omitempty"` SeparatorBlockWidth int `json:"separator_block_width,omitempty"`
} `json:"apps,omitempty"` } `json:"apps"`
} }
)
// readConf reads and validates config if config does not exist, it puts default config to the same dir where i3 config // ReadConf reads and validates config if config does not exist, it puts default config to the same dir where i3 config
// is located. // is located.
func ReadConf(defaultConfig []byte) (*MyConfig, error) { func ReadConf(defaultConfig []byte) (*MyConfig, error) {
var ( var (
@@ -464,6 +487,30 @@ func ReadConf(defaultConfig []byte) (*MyConfig, error) {
if sampleConfig.LA.FontSize == "" { if sampleConfig.LA.FontSize == "" {
sampleConfig.LA.FontSize = sampleConfig.FontSize sampleConfig.LA.FontSize = sampleConfig.FontSize
} else {
matched, err := regexp.MatchString(
`^(xx-small|x-small|small|medium|large|x-large|xx-large|smaller|larger)$`,
sampleConfig.LA.FontSize,
)
if err != nil {
log.Printf(
"Unable to set sampleConfig.LA.FontSize: %s, fallback to %s",
err,
sampleConfig.FontSize,
)
sampleConfig.LA.FontSize = sampleConfig.FontSize
}
if !matched {
log.Printf(
"Unable to set sampleConfig.LA.FontSize, fallback to %s",
sampleConfig.FontSize,
)
sampleConfig.LA.FontSize = sampleConfig.FontSize
}
} }
if sampleConfig.LA.Separator.Left.Color == "" { if sampleConfig.LA.Separator.Left.Color == "" {
@@ -518,22 +565,6 @@ func ReadConf(defaultConfig []byte) (*MyConfig, error) {
sampleConfig.LA.Separator.Right.Background = sampleConfig.Separator.Right.Background sampleConfig.LA.Separator.Right.Background = sampleConfig.Separator.Right.Background
} }
if sampleConfig.LA.Separator.Right.Font == "" {
sampleConfig.LA.Separator.Right.Font = sampleConfig.Separator.Right.Font
}
if sampleConfig.LA.Separator.Right.FontSize == "" {
sampleConfig.LA.Separator.Right.FontSize = sampleConfig.Separator.Right.FontSize
}
if sampleConfig.LA.Separator.Right.Color == "" {
sampleConfig.LA.Separator.Right.Color = sampleConfig.Separator.Right.Color
}
if sampleConfig.LA.Separator.Right.Background == "" {
sampleConfig.LA.Separator.Right.Background = sampleConfig.Separator.Right.Background
}
if sampleConfig.LA.Separator.Right.Symbol == "" { if sampleConfig.LA.Separator.Right.Symbol == "" {
sampleConfig.LA.Separator.Right.Symbol = sampleConfig.Separator.Right.Symbol sampleConfig.LA.Separator.Right.Symbol = sampleConfig.Separator.Right.Symbol
} }
@@ -584,6 +615,30 @@ func ReadConf(defaultConfig []byte) (*MyConfig, error) {
if sampleConfig.Mem.FontSize == "" { if sampleConfig.Mem.FontSize == "" {
sampleConfig.Mem.FontSize = sampleConfig.FontSize sampleConfig.Mem.FontSize = sampleConfig.FontSize
} else {
matched, err := regexp.MatchString(
`^(xx-small|x-small|small|medium|large|x-large|xx-large|smaller|larger)$`,
sampleConfig.Mem.FontSize,
)
if err != nil {
log.Printf(
"Unable to set sampleConfig.Mem.FontSize: %s, fallback to %s",
err,
sampleConfig.FontSize,
)
sampleConfig.Mem.FontSize = sampleConfig.FontSize
}
if !matched {
log.Printf(
"Unable to set sampleConfig.Mem.FontSize, fallback to %s",
sampleConfig.FontSize,
)
sampleConfig.Mem.FontSize = sampleConfig.FontSize
}
} }
if sampleConfig.Mem.Separator.Left.Color == "" { if sampleConfig.Mem.Separator.Left.Color == "" {
@@ -688,6 +743,30 @@ func ReadConf(defaultConfig []byte) (*MyConfig, error) {
if sampleConfig.Clock.FontSize == "" { if sampleConfig.Clock.FontSize == "" {
sampleConfig.Clock.FontSize = sampleConfig.FontSize sampleConfig.Clock.FontSize = sampleConfig.FontSize
} else {
matched, err := regexp.MatchString(
`^(xx-small|x-small|small|medium|large|x-large|xx-large|smaller|larger)$`,
sampleConfig.Clock.FontSize,
)
if err != nil {
log.Printf(
"Unable to set sampleConfig.Clock.FontSize: %s, fallback to %s",
err,
sampleConfig.FontSize,
)
sampleConfig.Clock.FontSize = sampleConfig.FontSize
}
if !matched {
log.Printf(
"Unable to set sampleConfig.Clock.FontSize, fallback to %s",
sampleConfig.FontSize,
)
sampleConfig.Clock.FontSize = sampleConfig.FontSize
}
} }
if sampleConfig.Clock.Separator.Left.Enabled { if sampleConfig.Clock.Separator.Left.Enabled {
@@ -780,20 +859,20 @@ func ReadConf(defaultConfig []byte) (*MyConfig, error) {
} }
} }
// sampleConfig.Clock.LeftClick.Enabled will be false if not set in config // sampleConfig.Clock.LeftClick.Enabled will be false if not set in config.
if len(sampleConfig.Clock.LeftClick.Cmd) == 0 { if len(sampleConfig.Clock.LeftClick.Cmd) == 0 {
sampleConfig.Clock.LeftClick.Cmd = append(sampleConfig.Clock.LeftClick.Cmd, "true") sampleConfig.Clock.LeftClick.Cmd = append(sampleConfig.Clock.LeftClick.Cmd, "true")
} }
// sampleConfig.Clock.RightClick.Enabled will be false if not set in config // sampleConfig.Clock.RightClick.Enabled will be false if not set in config.
if len(sampleConfig.Clock.RightClick.Cmd) == 0 { if len(sampleConfig.Clock.RightClick.Cmd) == 0 {
sampleConfig.Clock.RightClick.Cmd = append(sampleConfig.Clock.RightClick.Cmd, "true") sampleConfig.Clock.RightClick.Cmd = append(sampleConfig.Clock.RightClick.Cmd, "true")
} }
// sampleConfig.Battery.Enabled will be false if not set in config // sampleConfig.Battery.Enabled will be false if not set in config.
// sampleConfig.Battery.UseSysfs will be false if not set in config // sampleConfig.Battery.UseSysfs will be false if not set in config.
if len(sampleConfig.Battery.SysfsFiles) == 0 { if len(sampleConfig.Battery.SysfsFiles) == 0 {
sampleConfig.Battery.SysfsFiles = append( sampleConfig.Battery.SysfsFiles = append(
@@ -816,6 +895,30 @@ func ReadConf(defaultConfig []byte) (*MyConfig, error) {
if sampleConfig.Battery.FontSize == "" { if sampleConfig.Battery.FontSize == "" {
sampleConfig.Battery.FontSize = sampleConfig.FontSize sampleConfig.Battery.FontSize = sampleConfig.FontSize
} else {
matched, err := regexp.MatchString(
`^(xx-small|x-small|small|medium|large|x-large|xx-large|smaller|larger)$`,
sampleConfig.Battery.FontSize,
)
if err != nil {
log.Printf(
"Unable to set sampleConfig.Battery.FontSize: %s, fallback to %s",
err,
sampleConfig.FontSize,
)
sampleConfig.Battery.FontSize = sampleConfig.FontSize
}
if !matched {
log.Printf(
"Unable to set sampleConfig.Battery.FontSize, fallback to %s",
sampleConfig.FontSize,
)
sampleConfig.Battery.FontSize = sampleConfig.FontSize
}
} }
if sampleConfig.Battery.Symbol == "" { if sampleConfig.Battery.Symbol == "" {
@@ -827,13 +930,37 @@ func ReadConf(defaultConfig []byte) (*MyConfig, error) {
} }
if sampleConfig.Battery.SymbolFontSize == "" { if sampleConfig.Battery.SymbolFontSize == "" {
sampleConfig.Battery.SymbolFontSize = sampleConfig.Battery.FontSize
} else {
matched, err := regexp.MatchString(
`^(xx-small|x-small|small|medium|large|x-large|xx-large|smaller|larger)$`,
sampleConfig.Battery.SymbolFontSize,
)
if err != nil {
log.Printf(
"Unable to set sampleConfig.Battery.SymbolFontSize: %s, fallback to %s",
err,
sampleConfig.Battery.FontSize,
)
sampleConfig.Battery.SymbolFontSize = sampleConfig.Battery.FontSize sampleConfig.Battery.SymbolFontSize = sampleConfig.Battery.FontSize
} }
// sampleConfig.Battery.ChargeColor.Full will be empty string if not set if !matched {
// sampleConfig.Battery.ChargeColor.Empty will be empty string if not set log.Printf(
// sampleConfig.Battery.ChargeColor.AlmostFull will be empty string if not set "Unable to set sampleConfig.Battery.SymbolFontSize, fallback to %s",
// sampleConfig.Battery.ChargeColor.AlmostEmpty will be empty string if not set sampleConfig.Battery.FontSize,
)
sampleConfig.Battery.SymbolFontSize = sampleConfig.Battery.FontSize
}
}
// sampleConfig.Battery.ChargeColor.Full will be empty string if not set.
// sampleConfig.Battery.ChargeColor.Empty will be empty string if not set.
// sampleConfig.Battery.ChargeColor.AlmostFull will be empty string if not set.
// sampleConfig.Battery.ChargeColor.AlmostEmpty will be empty string if not set.
if sampleConfig.Battery.Separator.Left.Color == "" { if sampleConfig.Battery.Separator.Left.Color == "" {
sampleConfig.Battery.Separator.Left.Color = sampleConfig.Separator.Left.Color sampleConfig.Battery.Separator.Left.Color = sampleConfig.Separator.Left.Color
} }
@@ -922,9 +1049,9 @@ func ReadConf(defaultConfig []byte) (*MyConfig, error) {
} }
} }
// sampleConfig.CpuTemp.Enabled will be false if not set in config // sampleConfig.CpuTemp.Enabled will be false if not set in config.
// No files configured - disable plugin // No files configured - disable plugin.
if len(sampleConfig.CPUTemp.File) == 0 { if len(sampleConfig.CPUTemp.File) == 0 {
sampleConfig.CPUTemp.Enabled = false sampleConfig.CPUTemp.Enabled = false
} }
@@ -943,6 +1070,30 @@ func ReadConf(defaultConfig []byte) (*MyConfig, error) {
if sampleConfig.CPUTemp.FontSize == "" { if sampleConfig.CPUTemp.FontSize == "" {
sampleConfig.CPUTemp.FontSize = sampleConfig.FontSize sampleConfig.CPUTemp.FontSize = sampleConfig.FontSize
} else {
matched, err := regexp.MatchString(
`^(xx-small|x-small|small|medium|large|x-large|xx-large|smaller|larger)$`,
sampleConfig.CPUTemp.FontSize,
)
if err != nil {
log.Printf(
"Unable to set sampleConfig.CPUTemp.FontSize: %s, fallback to %s",
err,
sampleConfig.FontSize,
)
sampleConfig.CPUTemp.FontSize = sampleConfig.FontSize
}
if !matched {
log.Printf(
"Unable to set sampleConfig.CPUTemp.FontSize, fallback to %s",
sampleConfig.FontSize,
)
sampleConfig.CPUTemp.FontSize = sampleConfig.FontSize
}
} }
if sampleConfig.CPUTemp.Separator.Left.Enabled { if sampleConfig.CPUTemp.Separator.Left.Enabled {
@@ -1033,9 +1184,9 @@ func ReadConf(defaultConfig []byte) (*MyConfig, error) {
} }
} }
// sampleConfig.Vpn.Enabled will false if not set in config // sampleConfig.Vpn.Enabled will false if not set in config.
// No status file - disable plugin // No status file - disable plugin.
if sampleConfig.Vpn.StatusFile == "" { if sampleConfig.Vpn.StatusFile == "" {
sampleConfig.Vpn.Enabled = false sampleConfig.Vpn.Enabled = false
} }
@@ -1049,23 +1200,47 @@ func ReadConf(defaultConfig []byte) (*MyConfig, error) {
} }
if sampleConfig.Vpn.Font == "" { if sampleConfig.Vpn.Font == "" {
sampleConfig.Vpn.FontSize = sampleConfig.Font sampleConfig.Vpn.Font = sampleConfig.Font
} }
if sampleConfig.Vpn.FontSize == "" { if sampleConfig.Vpn.FontSize == "" {
sampleConfig.Vpn.FontSize = sampleConfig.FontSize
} else {
matched, err := regexp.MatchString(
`^(xx-small|x-small|small|medium|large|x-large|xx-large|smaller|larger)$`,
sampleConfig.Vpn.FontSize,
)
if err != nil {
log.Printf(
"Unable to set sampleConfig.Vpn.FontSize: %s, fallback to %s",
err,
sampleConfig.FontSize,
)
sampleConfig.Vpn.FontSize = sampleConfig.FontSize sampleConfig.Vpn.FontSize = sampleConfig.FontSize
} }
// Check status file at least once per 3 seconds if !matched {
log.Printf(
"Unable to set sampleConfig.Vpn.FontSize, fallback to %s",
sampleConfig.FontSize,
)
sampleConfig.Vpn.FontSize = sampleConfig.FontSize
}
}
// Check status file at least once per 3 seconds.
if sampleConfig.Vpn.MtimeThreshold < 3 { if sampleConfig.Vpn.MtimeThreshold < 3 {
log.Printf("vpn.mtime_threshold not set, using 3") log.Printf("vpn.mtime_threshold not set, using 3")
sampleConfig.Vpn.MtimeThreshold = 3 sampleConfig.Vpn.MtimeThreshold = 3
} }
// sampleConfig.Vpn.DownColor will be empty string if no value set in config // sampleConfig.Vpn.DownColor will be empty string if no value set in config.
// sampleConfig.Vpn.UpColor will be empty string if no value set in config // sampleConfig.Vpn.UpColor will be empty string if no value set in config.
// sampleConfig.Vpn.TcpCheck.Enabled will false if not set in config // sampleConfig.Vpn.TcpCheck.Enabled will false if not set in config.
if sampleConfig.Vpn.Separator.Left.Enabled { if sampleConfig.Vpn.Separator.Left.Enabled {
if sampleConfig.Vpn.Separator.Left.Color == "" { if sampleConfig.Vpn.Separator.Left.Color == "" {
@@ -1157,7 +1332,7 @@ func ReadConf(defaultConfig []byte) (*MyConfig, error) {
} }
} }
// Disable plugin if value inadequate // Disable plugin if value inadequate.
if sampleConfig.Vpn.TCPCheck.Port > 65535 { if sampleConfig.Vpn.TCPCheck.Port > 65535 {
if sampleConfig.Vpn.TCPCheck.Enabled { if sampleConfig.Vpn.TCPCheck.Enabled {
log.Printf("vpn.tcp_check.port > 65535, disabling vpn.tcp_check.enabled") log.Printf("vpn.tcp_check.port > 65535, disabling vpn.tcp_check.enabled")
@@ -1166,7 +1341,7 @@ func ReadConf(defaultConfig []byte) (*MyConfig, error) {
sampleConfig.Vpn.TCPCheck.Enabled = false sampleConfig.Vpn.TCPCheck.Enabled = false
} }
// Disable plugin if value indaquate // Disable plugin if value indaquate.
if sampleConfig.Vpn.TCPCheck.Host == "" { if sampleConfig.Vpn.TCPCheck.Host == "" {
if sampleConfig.Vpn.TCPCheck.Enabled { if sampleConfig.Vpn.TCPCheck.Enabled {
log.Printf("vpn.tcp_check.host not set, disabling vpn.tcp_check.enabled") log.Printf("vpn.tcp_check.host not set, disabling vpn.tcp_check.enabled")
@@ -1183,7 +1358,7 @@ func ReadConf(defaultConfig []byte) (*MyConfig, error) {
sampleConfig.Vpn.TCPCheck.Timeout = 3 sampleConfig.Vpn.TCPCheck.Timeout = 3
} }
// sampleConfig.SimpleVolumePa.Enabled will false if not set in config // sampleConfig.SimpleVolumePa.Enabled will false if not set in config.
if sampleConfig.SimpleVolumePa.Color == "" { if sampleConfig.SimpleVolumePa.Color == "" {
sampleConfig.SimpleVolumePa.Color = sampleConfig.Color sampleConfig.SimpleVolumePa.Color = sampleConfig.Color
} }
@@ -1198,6 +1373,30 @@ func ReadConf(defaultConfig []byte) (*MyConfig, error) {
if sampleConfig.SimpleVolumePa.FontSize == "" { if sampleConfig.SimpleVolumePa.FontSize == "" {
sampleConfig.SimpleVolumePa.FontSize = sampleConfig.FontSize sampleConfig.SimpleVolumePa.FontSize = sampleConfig.FontSize
} else {
matched, err := regexp.MatchString(
`^(xx-small|x-small|small|medium|large|x-large|xx-large|smaller|larger)$`,
sampleConfig.SimpleVolumePa.FontSize,
)
if err != nil {
log.Printf(
"Unable to set sampleConfig.SimpleVolumePa.FontSize: %s, fallback to %s",
err,
sampleConfig.FontSize,
)
sampleConfig.SimpleVolumePa.FontSize = sampleConfig.FontSize
}
if !matched {
log.Printf(
"Unable to set sampleConfig.SimpleVolumePa.FontSize, fallback to %s",
sampleConfig.FontSize,
)
sampleConfig.SimpleVolumePa.FontSize = sampleConfig.FontSize
}
} }
if sampleConfig.SimpleVolumePa.Symbol == "" { if sampleConfig.SimpleVolumePa.Symbol == "" {
@@ -1210,6 +1409,30 @@ func ReadConf(defaultConfig []byte) (*MyConfig, error) {
if sampleConfig.SimpleVolumePa.SymbolFontSize == "" { if sampleConfig.SimpleVolumePa.SymbolFontSize == "" {
sampleConfig.SimpleVolumePa.SymbolFontSize = sampleConfig.SimpleVolumePa.FontSize sampleConfig.SimpleVolumePa.SymbolFontSize = sampleConfig.SimpleVolumePa.FontSize
} else {
matched, err := regexp.MatchString(
`^(xx-small|x-small|small|medium|large|x-large|xx-large|smaller|larger)$`,
sampleConfig.SimpleVolumePa.SymbolFontSize,
)
if err != nil {
log.Printf(
"Unable to set sampleConfig.SimpleVolumePa.SymbolFontSize: %s, fallback to %s",
err,
sampleConfig.SimpleVolumePa.FontSize,
)
sampleConfig.SimpleVolumePa.SymbolFontSize = sampleConfig.SimpleVolumePa.FontSize
}
if !matched {
log.Printf(
"Unable to set sampleConfig.SimpleVolumePa.SymbolFontSize, fallback to %s",
sampleConfig.SimpleVolumePa.FontSize,
)
sampleConfig.SimpleVolumePa.SymbolFontSize = sampleConfig.SimpleVolumePa.FontSize
}
} }
if sampleConfig.SimpleVolumePa.Step == 0 { if sampleConfig.SimpleVolumePa.Step == 0 {
@@ -1332,7 +1555,7 @@ func ReadConf(defaultConfig []byte) (*MyConfig, error) {
} }
} }
// sampleConfig.Cron.Enabled will false if not set in config // sampleConfig.Cron.Enabled will false if not set in config.
if len(sampleConfig.Cron.Tasks) == 0 { if len(sampleConfig.Cron.Tasks) == 0 {
sampleConfig.Cron.Enabled = false sampleConfig.Cron.Enabled = false
@@ -1342,7 +1565,7 @@ func ReadConf(defaultConfig []byte) (*MyConfig, error) {
sampleConfig.Cron.TimeZone = "GMT+0" sampleConfig.Cron.TimeZone = "GMT+0"
} }
// sampleConfig.NetIf.Enabled will false if not set in config // sampleConfig.NetIf.Enabled will false if not set in config.
if len(sampleConfig.NetIf.If) == 0 { if len(sampleConfig.NetIf.If) == 0 {
sampleConfig.NetIf.Enabled = false sampleConfig.NetIf.Enabled = false
@@ -1370,6 +1593,29 @@ func ReadConf(defaultConfig []byte) (*MyConfig, error) {
if sampleConfig.NetIf.FontSize == "" { if sampleConfig.NetIf.FontSize == "" {
sampleConfig.NetIf.FontSize = sampleConfig.FontSize sampleConfig.NetIf.FontSize = sampleConfig.FontSize
} else {
matched, err := regexp.MatchString(
`^(xx-small|x-small|small|medium|large|x-large|xx-large|smaller|larger)$`,
sampleConfig.NetIf.FontSize,
)
if err != nil {
log.Printf(
"Unable to set sampleConfig.NetIf.FontSize: %s, fallback to %s",
err,
sampleConfig.FontSize,
)
sampleConfig.NetIf.FontSize = sampleConfig.FontSize
}
if !matched {
log.Printf("Unable to set sampleConfig.NetIf.FontSize, fallback to %s",
sampleConfig.FontSize,
)
sampleConfig.NetIf.FontSize = sampleConfig.FontSize
}
} }
if sampleConfig.NetIf.Separator.Left.Color == "" { if sampleConfig.NetIf.Separator.Left.Color == "" {
@@ -1459,16 +1705,17 @@ func ReadConf(defaultConfig []byte) (*MyConfig, error) {
} }
} }
// sampleConfig.CmdRun.Enabled will false if not set in config // sampleConfig.CmdRun.Enabled will false if not set in config.
if sampleConfig.CmdRun.Cmd == "" && sampleConfig.CmdRun.Enabled { if sampleConfig.CmdRun.Cmd == "" && sampleConfig.CmdRun.Enabled {
sampleConfig.CmdRun.Enabled = false sampleConfig.CmdRun.Enabled = false
log.Print( log.Print(
"Setting sampleConfig.CmdRun.Enabled to false because sampleConfig.CmdRun.Cmd is not set", "Setting sampleConfig.CmdRun.Enabled to false because sampleConfig.CmdRun.Cmd is not set",
) )
} }
// sampleConfig.CmdRun.Args can be empty // sampleConfig.CmdRun.Args can be empty.
if sampleConfig.CmdRun.Color == "" { if sampleConfig.CmdRun.Color == "" {
sampleConfig.CmdRun.Color = sampleConfig.Color sampleConfig.CmdRun.Color = sampleConfig.Color
@@ -1484,6 +1731,30 @@ func ReadConf(defaultConfig []byte) (*MyConfig, error) {
if sampleConfig.CmdRun.FontSize == "" { if sampleConfig.CmdRun.FontSize == "" {
sampleConfig.CmdRun.FontSize = sampleConfig.FontSize sampleConfig.CmdRun.FontSize = sampleConfig.FontSize
} else {
matched, err := regexp.MatchString(
`^(xx-small|x-small|small|medium|large|x-large|xx-large|smaller|larger)$`,
sampleConfig.CmdRun.FontSize,
)
if err != nil {
log.Printf(
"Unable to set sampleConfig.CmdRun.FontSize: %s, fallback to %s",
err,
sampleConfig.FontSize,
)
sampleConfig.CmdRun.FontSize = sampleConfig.FontSize
}
if !matched {
log.Printf(
"Unable to set sampleConfig.CmdRun.FontSize, fallback to %s",
sampleConfig.FontSize,
)
sampleConfig.CmdRun.FontSize = sampleConfig.FontSize
}
} }
if sampleConfig.CmdRun.Separator.Left.Color == "" { if sampleConfig.CmdRun.Separator.Left.Color == "" {
@@ -1574,7 +1845,46 @@ func ReadConf(defaultConfig []byte) (*MyConfig, error) {
} }
} }
// sampleConfig.AppButtons.Enabled will false if not set in config // sampleConfig.AppButtons.Enabled will false if not set in config.
if sampleConfig.AppButtons.Color == "" {
sampleConfig.AppButtons.Color = sampleConfig.Color
}
if sampleConfig.AppButtons.Background == "" {
sampleConfig.AppButtons.Background = sampleConfig.Background
}
if sampleConfig.AppButtons.Font == "" {
sampleConfig.AppButtons.Font = sampleConfig.Font
}
if sampleConfig.AppButtons.FontSize == "" {
sampleConfig.AppButtons.FontSize = sampleConfig.FontSize
} else {
matched, err := regexp.MatchString(
`^(xx-small|x-small|small|medium|large|x-large|xx-large|smaller|larger)$`,
sampleConfig.AppButtons.FontSize,
)
if err != nil {
log.Printf(
"Unable to set sampleConfig.AppButtons.FontSize: %s, fallback to %s",
err,
sampleConfig.FontSize,
)
sampleConfig.AppButtons.FontSize = sampleConfig.FontSize
}
if !matched {
log.Printf(
"Unable to set sampleConfig.AppButtons.FontSize, fallback to %s",
sampleConfig.FontSize,
)
sampleConfig.AppButtons.FontSize = sampleConfig.FontSize
}
}
if sampleConfig.AppButtons.Separator.Left.Color == "" { if sampleConfig.AppButtons.Separator.Left.Color == "" {
sampleConfig.AppButtons.Separator.Left.Color = sampleConfig.Separator.Left.Color sampleConfig.AppButtons.Separator.Left.Color = sampleConfig.Separator.Left.Color
@@ -1670,34 +1980,68 @@ func ReadConf(defaultConfig []byte) (*MyConfig, error) {
// app.Instance can be missing. // app.Instance can be missing.
// app.Class can be missing. // app.Class can be missing.
if app.Name == "" { if app.Name == "" {
app.Name = fmt.Sprintf("app%d", num) sampleConfig.Apps[num].Name = fmt.Sprintf("app%d", num)
} }
// app.Args can be empty slice. In that case command will be run without aruments. // app.Args can be empty slice. In that case command will be run without aruments.
if app.Cmd == "" { if app.Cmd == "" {
app.Cmd = "true" // If command omitted it will be just /usr/bin/true.
sampleConfig.Apps[num].Cmd = "true"
} }
if app.Color == "" { if app.Color == "" {
app.Color = sampleConfig.Color sampleConfig.Apps[num].Color = sampleConfig.AppButtons.Color
} }
if app.Background == "" { if app.Background == "" {
app.Background = sampleConfig.Background sampleConfig.Apps[num].Background = sampleConfig.AppButtons.Background
}
if app.Font == "" {
sampleConfig.Apps[num].Font = sampleConfig.AppButtons.Font
}
if app.FontSize == "" {
sampleConfig.Apps[num].FontSize = sampleConfig.AppButtons.FontSize
} else {
matched, err := regexp.MatchString(
`^(xx-small|x-small|small|medium|large|x-large|xx-large|smaller|larger)$`,
app.FontSize,
)
if err != nil {
log.Printf(
"Unable to set %s.FontSize: %s, fallback to %s",
app.Name,
err,
sampleConfig.AppButtons.FontSize,
)
sampleConfig.Apps[num].FontSize = sampleConfig.AppButtons.FontSize
}
if !matched {
log.Printf("Unable to set %s.FontSize, fallback to %s",
app.Name,
sampleConfig.AppButtons.FontSize,
)
sampleConfig.Apps[num].FontSize = sampleConfig.AppButtons.FontSize
}
} }
if app.Border == "" { if app.Border == "" {
app.Border = sampleConfig.Color sampleConfig.Apps[num].Border = sampleConfig.AppButtons.Color
} }
if app.BorderActive == "" { if app.BorderActive == "" {
app.BorderActive = sampleConfig.Color sampleConfig.Apps[num].BorderActive = sampleConfig.AppButtons.Color
} }
// app.Separator can be omitted, in that case it is false // app.Separator can be omitted, in that case it is false.
// app.SeparatorBlockWidth can be missing // app.SeparatorBlockWidth can be missing.
if app.FullText == "" { if app.FullText == "" {
app.FullText = fmt.Sprintf(" %d ", num) sampleConfig.Apps[num].FullText = fmt.Sprintf(" %d ", num)
} }
} }
} }
@@ -1719,3 +2063,5 @@ func LocateConfFile() (string, error) {
return filepath.Dir(i3ConfigPath) + "/i3status-go.json", nil return filepath.Dir(i3ConfigPath) + "/i3status-go.json", nil
} }
/* vim: set ft=go noet ai ts=4 sw=4 sts=4: */

View File

@@ -23,6 +23,7 @@ func (c *MyConfig) UpdateCPUTemperature() {
temperature = make([]int64, n) temperature = make([]int64, n)
tSum int64 tSum int64
tAvg int64 tAvg int64
validCount int
) )
if Delay == InitialDelay { if Delay == InitialDelay {
@@ -35,47 +36,50 @@ func (c *MyConfig) UpdateCPUTemperature() {
if err != nil { if err != nil {
log.Printf("Unable to open %s: %s", filename, err) log.Printf("Unable to open %s: %s", filename, err)
} else { continue
}
defer file.Close()
reader := bufio.NewReader(file) reader := bufio.NewReader(file)
line, _, err := reader.ReadLine() line, _, err := reader.ReadLine()
if err != nil { if err != nil {
log.Printf("Unable to read from %s: %s", filename, err) log.Printf("Unable to read from %s: %s", filename, err)
err = file.Close() continue
if err != nil {
log.Printf("Unable to close %s: %s", filename, err)
} }
} else {
err = file.Close()
if err != nil {
log.Printf("Unable to close %s: %s", filename, err)
} else {
temp, err := strconv.ParseInt(string(line), 10, 32) temp, err := strconv.ParseInt(string(line), 10, 32)
if err != nil { if err != nil {
log.Printf("Unable to convert string to number from file %s: %s", filename, err) log.Printf("Unable to convert string to number from file %s: %s", filename, err)
} else { continue
}
if temp > 1000 { if temp > 1000 {
temp /= 1000 temp /= 1000
} }
temperature[i] = temp temperature[i] = temp
} validCount++
}
}
}
} }
if len(temperature) == 1 { if validCount == 0 {
tAvg = temperature[0] continue
}
if validCount == 1 {
for _, t := range temperature {
if t != 0 {
tAvg = t
break
}
}
} else { } else {
for _, t := range temperature { for _, t := range temperature {
tSum += t tSum += t
} }
tAvg = tSum / int64(len(temperature)) tAvg = tSum / int64(validCount)
} }
if c.Values.CPUTemperature != tAvg { if c.Values.CPUTemperature != tAvg {
@@ -84,3 +88,5 @@ func (c *MyConfig) UpdateCPUTemperature() {
} }
} }
} }
/* vim: set ft=go noet ai ts=4 sw=4 sts=4: */

View File

@@ -7,7 +7,9 @@ import (
) )
// myCron contains cron handler. // myCron contains cron handler.
var myCron gocron.Scheduler var (
myCron gocron.Scheduler
)
// RunCron parses config part, related to cron tasks and kicks cron to run. // RunCron parses config part, related to cron tasks and kicks cron to run.
func (c MyConfig) RunCron() { func (c MyConfig) RunCron() {
@@ -25,15 +27,12 @@ func (c MyConfig) RunCron() {
_, err := myCron.NewJob( _, err := myCron.NewJob(
gocron.CronJob(job.Time, false), gocron.CronJob(job.Time, false),
gocron.NewTask( gocron.NewTask(
// Сука, просто заспавнить бинарь, ну почему это надо делать через жопу-то?
any(
func() bool { func() bool {
c.Channels.RunChan <- job.Cmd c.Channels.RunChan <- job.Cmd
return true return true
}, },
), ),
),
) )
if err != nil { if err != nil {
@@ -43,3 +42,5 @@ func (c MyConfig) RunCron() {
myCron.Start() myCron.Start()
} }
/* vim: set ft=go noet ai ts=4 sw=4 sts=4: */

View File

@@ -19,15 +19,18 @@ var WL WinList
// UpdateI3WinList subsribes to all window-related events and send them to I3EventParser() for more detailed parsing. // UpdateI3WinList subsribes to all window-related events and send them to I3EventParser() for more detailed parsing.
func (c *MyConfig) UpdateI3WinList() { func (c *MyConfig) UpdateI3WinList() {
// TODO: Здесь получить начальный список окон, управляемых i3wm (через GetTree()) и сложить их атрибутику в переменную WL
Tree, err := i3.GetTree() Tree, err := i3.GetTree()
if err != nil { if err != nil {
log.Printf("Unable to get list of windows: %s", err) log.Printf("Unable to get list of windows: %s", err)
return
} }
c.ExtractProps(Tree.Root) c.ExtractProps(Tree.Root)
c.Channels.UpdateReady <- true
i3wm := i3.Subscribe(i3.WindowEventType) i3wm := i3.Subscribe(i3.WindowEventType)
for i3wm.Next() { for i3wm.Next() {
@@ -105,9 +108,11 @@ func (c *MyConfig) I3EventParser(e *i3.WindowEvent) {
// interfaceToUint превращает данный интерфейс в Uint64. // interfaceToUint превращает данный интерфейс в Uint64.
// Если может, конечно :) . // Если может, конечно :) .
func interfaceToUint64(iface interface{}) uint64 { func interfaceToUint64(iface any) uint64 {
// А теперь мы начинаем дурдом, нам надо превратить ёбанный interface{} в []string if iface == nil {
// Поскольку interface{} может быть чем угодно, перестрахуемся return 0
}
if reflect.TypeOf(iface).Kind() == reflect.Uint64 { if reflect.TypeOf(iface).Kind() == reflect.Uint64 {
return reflect.ValueOf(iface).Uint() return reflect.ValueOf(iface).Uint()
} }
@@ -152,18 +157,16 @@ func HasWindows(className string, instanceName string) bool {
func FindWindowInstance(regexpStr string) bool { func FindWindowInstance(regexpStr string) bool {
var found = false var found = false
f := func(key any, value any) bool { //nolint: revive re, err := regexp.Compile(regexpStr)
keyStr := reflect.ValueOf(key).String()
re, err := regexp.Compile(regexpStr) // we do not want shit our pants and panic on
// erroneous regexp, we want log it to stderr, that it.
if err != nil { if err != nil {
log.Printf("Unable to perform regexp match: %s", err) log.Printf("Unable to perform regexp match: %s", err)
return true return false
} }
f := func(key any, value any) bool { //nolint: revive
keyStr := reflect.ValueOf(key).String()
if re.Match([]byte(keyStr)) { //nolint:mirror if re.Match([]byte(keyStr)) { //nolint:mirror
found = true found = true
@@ -183,18 +186,16 @@ func FindWindowInstance(regexpStr string) bool {
func FindWindowClass(regexpStr string) bool { func FindWindowClass(regexpStr string) bool {
var found = false var found = false
f := func(key any, value any) bool { //nolint: revive re, err := regexp.Compile(regexpStr)
keyStr := reflect.ValueOf(key).String()
re, err := regexp.Compile(regexpStr) // we do not want shit our pants and panic on
// erroneous regexp, we want log it to stderr, that it.
if err != nil { if err != nil {
log.Printf("Unable to perform regexp match: %s", err) log.Printf("Unable to perform regexp match: %s", err)
return true return false
} }
f := func(key any, value any) bool { //nolint: revive
keyStr := reflect.ValueOf(key).String()
if re.Match([]byte(keyStr)) { //nolint:mirror if re.Match([]byte(keyStr)) { //nolint:mirror
found = true found = true
@@ -225,3 +226,5 @@ func (c *MyConfig) ExtractProps(n *i3.Node) {
c.ExtractProps(node) c.ExtractProps(node)
} }
} }
/* vim: set ft=go noet ai ts=4 sw=4 sts=4: */

View File

@@ -44,8 +44,8 @@ func (c *MyConfig) UpdateIfStatus() {
} else { } else {
switch strings.TrimSpace(string(operstate)) { switch strings.TrimSpace(string(operstate)) {
case "up": case "up":
StatusStr := fmt.Sprintf("<span foreground=\"%s\">⍋</span>", c.NetIf.UpColor) statusStr := fmt.Sprintf("<span foreground=\"%s\">⍋</span>", c.NetIf.UpColor)
operstate = []byte(StatusStr) operstate = []byte(statusStr)
case "down": case "down":
statusStr := fmt.Sprintf("<span foreground=\"%s\">⍒</span>", c.NetIf.DownColor) statusStr := fmt.Sprintf("<span foreground=\"%s\">⍒</span>", c.NetIf.DownColor)
operstate = []byte(statusStr) operstate = []byte(statusStr)
@@ -67,3 +67,5 @@ func (c *MyConfig) UpdateIfStatus() {
} }
} }
} }
/* vim: set ft=go noet ai ts=4 sw=4 sts=4: */

View File

@@ -2,6 +2,7 @@ package lib
import ( import (
"fmt" "fmt"
"log"
"time" "time"
"github.com/shirou/gopsutil/load" "github.com/shirou/gopsutil/load"
@@ -22,7 +23,13 @@ func (c *MyConfig) UpdateLaStats() {
ticker.Reset(Delay) ticker.Reset(Delay)
} }
l, _ := load.Avg() l, err := load.Avg()
if err != nil {
log.Printf("Unable to get LA stats: %s", err)
continue
}
lav := fmt.Sprintf("%.2f", l.Load1) lav := fmt.Sprintf("%.2f", l.Load1)
@@ -32,3 +39,5 @@ func (c *MyConfig) UpdateLaStats() {
} }
} }
} }
/* vim: set ft=go noet ai ts=4 sw=4 sts=4: */

View File

@@ -38,6 +38,7 @@ func (c *MyConfig) UpdateMemStats() {
continue continue
} }
if c.Mem.ShowSwap {
sw, err := mem.SwapMemory() sw, err := mem.SwapMemory()
if err != nil { if err != nil {
@@ -47,11 +48,10 @@ func (c *MyConfig) UpdateMemStats() {
continue continue
} }
if c.Mem.ShowSwap { if c.Values.Memory.Usedpct != uint64(v.UsedPercent) || c.Values.Memory.Shared != v.Shared/1024/1024 || c.Values.Memory.Swap != sw.Used/1024/1024 {
if c.Values.Memory.Usedpct != uint64(v.UsedPercent) || c.Values.Memory.Shared != v.Shared/1024/1024 || c.Values.Memory.Swap != v.SwapTotal-v.SwapFree {
c.Values.Memory.Usedpct = uint64(v.UsedPercent) c.Values.Memory.Usedpct = uint64(v.UsedPercent)
c.Values.Memory.Shared = v.Shared / 1024 / 1024 c.Values.Memory.Shared = v.Shared / 1024 / 1024
c.Values.Memory.Swap = sw.Used c.Values.Memory.Swap = sw.Used / 1024 / 1024
c.Channels.UpdateReady <- true c.Channels.UpdateReady <- true
} }
} else { } else {
@@ -63,3 +63,5 @@ func (c *MyConfig) UpdateMemStats() {
} }
} }
} }
/* vim: set ft=go noet ai ts=4 sw=4 sts=4: */

View File

@@ -113,12 +113,12 @@ func (c *MyConfig) PaReinit() error {
var err error var err error
// If we out of updates, seems someone killed pulseaudio server. Restart it. // If we out of updates, seems someone killed pulseaudio server. Restart it.
cmd := exec.Command("pulseaudio", "--check") cmd := exec.Command("pulseaudio", "--check") //nolint: noctx
if err := cmd.Run(); err == nil { if err := cmd.Run(); err == nil {
log.Printf("pulseaudio already running, but seems not responding, try gracefully kill it") log.Printf("pulseaudio already running, but seems not responding, try gracefully kill it")
cmd = exec.Command("pulseaudio", "--kill") cmd = exec.Command("pulseaudio", "--kill") //nolint: noctx
if err := cmd.Run(); err != nil { if err := cmd.Run(); err != nil {
return fmt.Errorf("unable to kill pulseaudio: %w", err) return fmt.Errorf("unable to kill pulseaudio: %w", err)
@@ -127,7 +127,7 @@ func (c *MyConfig) PaReinit() error {
cnt := 0 cnt := 0
for { for {
cmd := exec.Command("pulseaudio", "--check") cmd := exec.Command("pulseaudio", "--check") //nolint: noctx
// PA not running. Breakout of loop. // PA not running. Breakout of loop.
if err := cmd.Run(); err != nil { if err := cmd.Run(); err != nil {
@@ -154,10 +154,10 @@ func (c *MyConfig) PaReinit() error {
// audio. // audio.
if c.SimpleVolumePa.DontExitOnLogin { if c.SimpleVolumePa.DontExitOnLogin {
// Do not exit on any kind of login/logout events. // Do not exit on any kind of login/logout events.
cmd = exec.Command("pulseaudio", "--exit-idle-time=-1", "--start") cmd = exec.Command("pulseaudio", "--exit-idle-time=-1", "--start") //nolint: noctx
} else { } else {
// Exit immediately on logout(?). // Exit immediately on logout(?).
cmd = exec.Command("pulseaudio", "--exit-idle-time=0", "--start") cmd = exec.Command("pulseaudio", "--exit-idle-time=0", "--start") //nolint: noctx
} }
if err := cmd.Run(); err != nil { if err := cmd.Run(); err != nil {
@@ -173,6 +173,8 @@ func (c *MyConfig) PaReinit() error {
return err return err
} }
// SVPAHandler simple volume pulse audio handler works with events sent to SVPAHandlerChan cahnnel. Left/right clicks,
// wheel turning events etc.
func (c *MyConfig) SVPAHandler() { func (c *MyConfig) SVPAHandler() {
for e := range c.Channels.SVPAHandlerChan { for e := range c.Channels.SVPAHandlerChan {
if e.Button == 3 { if e.Button == 3 {
@@ -220,3 +222,5 @@ func (c *MyConfig) SVPAHandler() {
} }
} }
} }
/* vim: set ft=go noet ai ts=4 sw=4 sts=4: */

View File

@@ -0,0 +1,43 @@
package lib
import (
"log"
"time"
)
// RunCommand gets list of commands runs them sequentally and conacatenates their output.
func (c *MyConfig) RunCommand() {
var (
InitialDelay = 100 * time.Millisecond
LoopIterationDelay = time.Duration(c.CmdRun.Delay) * time.Second
Delay = InitialDelay
ticker = time.NewTicker(Delay)
)
for range ticker.C {
if Delay == InitialDelay {
Delay = LoopIterationDelay
ticker.Reset(Delay)
}
var (
outputString string
command = []string{c.CmdRun.Cmd}
)
if len(c.CmdRun.Args) > 0 {
command = append(command, c.CmdRun.Args...)
}
outputString += RunProcess(command)
log.Println(outputString)
if c.Values.RunCommandOutput != outputString {
c.Values.RunCommandOutput = outputString
c.Channels.UpdateReady <- true
}
}
}
/* vim: set ft=go noet ai ts=4 sw=4 sts=4: */

View File

@@ -6,8 +6,6 @@ import (
"syscall" "syscall"
) )
var PrintOutput = true
// SigHandler OS signal handler. // SigHandler OS signal handler.
func (c *MyConfig) SigHandler() { func (c *MyConfig) SigHandler() {
for s := range c.Channels.SigChan { for s := range c.Channels.SigChan {
@@ -33,3 +31,5 @@ func (c *MyConfig) SigHandler() {
} }
} }
} }
/* vim: set ft=go noet ai ts=4 sw=4 sts=4: */

View File

@@ -13,9 +13,21 @@ import (
// Spawner forks and execs given program, and also detaches form its control tty. // Spawner forks and execs given program, and also detaches form its control tty.
func (c *MyConfig) Spawner() { func (c *MyConfig) Spawner() {
for prg := range c.Channels.RunChan { for prg := range c.Channels.RunChan {
<-time.After(25 * time.Millisecond) time.Sleep(25 * time.Millisecond)
devnullR, _ := os.Open(os.DevNull)
devnullW, _ := os.OpenFile(os.DevNull, os.O_WRONLY|os.O_APPEND, 0644) devnullR, err := os.Open(os.DevNull)
if err != nil {
log.Printf("Unable to open /dev/null for reading: %s", err)
continue
}
defer devnullR.Close()
devnullW, err := os.OpenFile(os.DevNull, os.O_WRONLY|os.O_APPEND, 0644)
if err != nil {
log.Printf("Unable to open /dev/null for writing: %s", err)
continue
}
defer devnullW.Close()
spa := syscall.SysProcAttr{ spa := syscall.SysProcAttr{
Setsid: true, Setsid: true,
@@ -33,6 +45,7 @@ func (c *MyConfig) Spawner() {
if err != nil { if err != nil {
log.Printf("Unable to spawn %s: %s", prg[0], err) log.Printf("Unable to spawn %s: %s", prg[0], err)
continue
} }
_, err = syscall.ForkExec(bin, prg, &pa) _, err = syscall.ForkExec(bin, prg, &pa)
@@ -40,10 +53,6 @@ func (c *MyConfig) Spawner() {
if err != nil { if err != nil {
log.Printf("Unable to spawn %s: %s", prg[0], err) log.Printf("Unable to spawn %s: %s", prg[0], err)
} }
// Close file errors we don't handle :) at all.
_ = devnullR.Close()
_ = devnullW.Close()
} }
} }
@@ -52,13 +61,17 @@ func (c *MyConfig) CleanZombies() {
r := syscall.Rusage{} r := syscall.Rusage{}
for { for {
_, _ = syscall.Wait4(-1, nil, 0, &r) pid, _ := syscall.Wait4(-1, nil, syscall.WNOHANG, &r)
if pid > 0 {
continue
}
time.Sleep(1 * time.Minute) time.Sleep(1 * time.Minute)
} }
} }
// RunProcess runs given command and returns contens of command stdout. On error prints error on stderr and returns // RunProcess runs given command and returns contents of command stdout. On error prints error on stderr and returns
// empty syting. // empty syting.
func RunProcess(command []string) string { func RunProcess(command []string) string {
var ( var (
@@ -68,9 +81,9 @@ func RunProcess(command []string) string {
switch len(command) { switch len(command) {
case 1: case 1:
cmd = exec.Command(command[0], "") cmd = exec.Command(command[0], "") //nolint: gosec
default: default:
cmd = exec.Command(command[0], command[1:]...) cmd = exec.Command(command[0], command[1:]...) //nolint: gosec
} }
cmd.Dir = "/" cmd.Dir = "/"
@@ -87,11 +100,13 @@ func RunProcess(command []string) string {
} }
return "" return ""
} else { }
if stderr.String() != "" { if stderr.String() != "" {
log.Printf("%s: %s", strings.Join(command, " "), stderr.String()) log.Printf("%s: %s", strings.Join(command, " "), stderr.String())
} }
}
return strings.TrimRight(stdout.String(), "\n") return strings.TrimRight(stdout.String(), "\n")
} }
/* vim: set ft=go noet ai ts=4 sw=4 sts=4: */

View File

@@ -51,17 +51,11 @@ func (c *MyConfig) ParseStdin() {
continue continue
} }
for i := 0; i < len(buf); i++ { buf = strings.TrimLeftFunc(buf, func(r rune) bool {
if strings.HasPrefix(buf, "{") { return r != '{'
break })
}
buf = buf[1:]
}
if len(buf) == 0 {
log.Print("String from stdin has zero length, skipping")
if !strings.HasPrefix(buf, "{") {
continue continue
} }
@@ -116,18 +110,24 @@ func (c *MyConfig) ParseStdin() {
break break
} }
case app.Name != "" && e.Name == app.Name: case app.Name != "" && e.Name == app.Name:
prg := append([]string{}, app.Cmd) prg := append([]string{}, app.Cmd)
prg = append(prg, app.Args...) prg = append(prg, app.Args...)
c.Channels.RunChan <- prg c.Channels.RunChan <- prg
break
case app.Instance != "" && e.Instance == app.Instance: case app.Instance != "" && e.Instance == app.Instance:
prg := append([]string{}, app.Cmd) prg := append([]string{}, app.Cmd)
prg = append(prg, app.Args...) prg = append(prg, app.Args...)
c.Channels.RunChan <- prg c.Channels.RunChan <- prg
break
} }
} }
} }
} }
/* vim: set ft=go noet ai ts=4 sw=4 sts=4: */

View File

@@ -4,6 +4,7 @@ import (
"fmt" "fmt"
"net" "net"
"os" "os"
"strings"
"time" "time"
) )
@@ -11,8 +12,8 @@ import (
func (c *MyConfig) UpdateVPNStatus() { func (c *MyConfig) UpdateVPNStatus() {
var ( var (
vpnCStatus string vpnCStatus string
tcpCheck string
vpnCheck string vpnCheck string
b strings.Builder
InitialDelay = 100 * time.Millisecond InitialDelay = 100 * time.Millisecond
LoopIterationDelay = 3 * time.Second LoopIterationDelay = 3 * time.Second
Delay = InitialDelay Delay = InitialDelay
@@ -27,36 +28,47 @@ func (c *MyConfig) UpdateVPNStatus() {
if c.VPNFileCheck() { if c.VPNFileCheck() {
if c.Vpn.UpColor == "" { if c.Vpn.UpColor == "" {
vpnCheck = `⍋` b.WriteRune('⍋')
} else { } else {
vpnCheck = fmt.Sprintf(`<span foreground="%s">⍋</span>`, c.Vpn.UpColor) b.WriteString("<span foreground=\"")
b.WriteString(c.Vpn.UpColor)
b.WriteString("\">⍋</span>")
} }
} else { } else {
if c.Vpn.DownColor == "" { if c.Vpn.DownColor == "" {
vpnCheck = `⍒` b.WriteRune('⍒')
} else { } else {
vpnCheck = fmt.Sprintf(`<span foreground="%s">⍒</span>`, c.Vpn.DownColor) b.WriteString("<span foreground=\"")
b.WriteString(c.Vpn.DownColor)
b.WriteString("\">⍒</span>")
} }
} }
vpnCheck = b.String()
b.Reset()
if c.Vpn.TCPCheck.Enabled { if c.Vpn.TCPCheck.Enabled {
if c.VPNTCPCheck() { if c.VPNTCPCheck() {
if c.Vpn.UpColor == "" { if c.Vpn.UpColor == "" {
tcpCheck = `✔` b.WriteRune('✔')
} else { } else {
tcpCheck = fmt.Sprintf(`<span foreground="%s">✔</span>`, c.Vpn.UpColor) b.WriteString("<span foreground=\"")
b.WriteString(c.Vpn.UpColor)
b.WriteString("\">✔</span>")
} }
} else { } else {
if c.Vpn.DownColor == "" { if c.Vpn.DownColor == "" {
tcpCheck = `✘` b.WriteRune('✘')
} else { } else {
tcpCheck = fmt.Sprintf(`<span foreground="%s">✘</span>`, c.Vpn.DownColor) b.WriteString("<span foreground=\"")
b.WriteString(c.Vpn.DownColor)
b.WriteString("\">✘</span>")
} }
} }
vpnCStatus = fmt.Sprintf("VPN:%s:%s", vpnCheck, tcpCheck) vpnCStatus = "VPN:" + vpnCheck + ":" + b.String()
} else { } else {
vpnCStatus = fmt.Sprintf("VPN:%s", vpnCheck) vpnCStatus = "VPN:" + vpnCheck
} }
if c.Values.VPNStatus != vpnCStatus { if c.Values.VPNStatus != vpnCStatus {
@@ -66,9 +78,9 @@ func (c *MyConfig) UpdateVPNStatus() {
} }
} }
// VPNTCPCheck intended to check arbitrary service inside vpn segment, to indicate that openvpn sevice not stoned. // VPNTCPCheck intended to check arbitrary service inside vpn segment, to indicate that openvpn service not stoned.
func (c *MyConfig) VPNTCPCheck() bool { func (c *MyConfig) VPNTCPCheck() bool {
conn, err := net.DialTimeout( conn, err := net.DialTimeout( //nolint: noctx
"tcp", "tcp",
fmt.Sprintf("%s:%d", c.Vpn.TCPCheck.Host, c.Vpn.TCPCheck.Port), //nolint: hostport fmt.Sprintf("%s:%d", c.Vpn.TCPCheck.Host, c.Vpn.TCPCheck.Port), //nolint: hostport
time.Second*time.Duration(c.Vpn.TCPCheck.Timeout), time.Second*time.Duration(c.Vpn.TCPCheck.Timeout),
@@ -100,3 +112,5 @@ func (c *MyConfig) VPNFileCheck() bool {
return true return true
} }
/* vim: set ft=go noet ai ts=4 sw=4 sts=4: */