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
- decorder
- durationcheck
- err113
- errcheck
- errchkjson
- errorlint
- exptostd
- ginkgolinter
- gocheckcompilerdirectives
- gocritic
- godoclint
- godot
- godox
- goprintffuncname
- gosec
- gosmopolitan
- govet
- grouper
- importas
- ineffassign
- intrange
- ireturn
- makezero
- mirror
- misspell
- modernize
- nakedret
- nilerr
- nilnil
@@ -38,6 +44,7 @@ linters:
- noctx
- nolintlint
- nonamedreturns
- perfsprint
- predeclared
- promlinter
- reassign
@@ -46,14 +53,731 @@ linters:
- staticcheck
- unconvert
- unused
- usestdlibvars
- wastedassign
- whitespace
- wsl
- wsl_v5
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:
- 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:
generated: lax
presets:
@@ -62,8 +786,6 @@ linters:
- legacy
- std-error-handling
paths:
- data
- vendor
- third_party$
- builtin$
- examples$
@@ -74,8 +796,6 @@ formatters:
exclusions:
generated: lax
paths:
- data
- vendor
- third_party$
- builtin$
- examples$

View File

@@ -18,7 +18,7 @@ It is i3bar text generator.
## 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

View File

@@ -1,3 +1,4 @@
// Package main simple test for battery funtionality.
package main
import (
@@ -20,3 +21,5 @@ func main() {
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.
"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",
// Can be omitted, then Liberation Mono will be used.
@@ -12,7 +12,7 @@
// ‘smaller’ or ‘larger’
"font_size": "medium",
"separator" : {
"separator": {
"left": {
// Set to false if omitted.
"enabled": true,
@@ -778,6 +778,19 @@
"app_buttons": {
"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.
"separator": {
"left": {
@@ -821,31 +834,36 @@
// ‘smaller’ or ‘larger’. If omitted set to default font size defined for separator up here.
"font_size": "medium"
}
},
}
},
// Buttons - application launch "buttons"
"apps": [
{
// Text dispalyed on button
// Text displayed on button, pango markup supported.
"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",
// Command itself
// Command itself.
"cmd" : "thunar",
// Array of command args, optional
// Array of command args, optional.
"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$",
// 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$",
// text color in html notation
// Text color in html notation.
"color": "#ffa500",
// background color in html notation
// background color in html notation.
"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 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",
// 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.

View File

@@ -1,3 +1,4 @@
// Package main status string generator for i3bar.
package main
import (
@@ -8,6 +9,7 @@ import (
"log"
"os"
"os/signal"
"strconv"
"strings"
"syscall"
@@ -15,7 +17,7 @@ import (
)
//go:embed default-config.json
var DefaultConfig []byte
var DefaultConfig []byte //nolint: godoclint, grouper, nolintlint
// Program entry point.
func main() {
@@ -42,15 +44,11 @@ func main() {
// Conf.Values.PA
Conf.Values.SoundVolume = "🔊:0%"
// TODO: Проставить дефолтные значения для глобальных переменных модулей.
Conf.Values.BatteryString = fmt.Sprintf(
"<span color='%s' background='%s' font='%s' size='%s'>%s</span>",
Conf.Battery.Color,
Conf.Battery.Background,
Conf.Battery.SymbolFont,
Conf.Battery.SymbolFontSize,
Conf.Battery.Symbol,
)
Conf.Values.BatteryString = "<span color='" + Conf.Battery.Color +
"' background='" + Conf.Battery.Background +
"' font='" + Conf.Battery.SymbolFont +
"' size='" + Conf.Battery.SymbolFontSize +
"'>" + Conf.Battery.Symbol + "</span>"
Conf.Values.BatteryString += fmt.Sprintf(
"<span color='%s' background='%s' font='%s' size='%s'> ??%% •</span>",
@@ -104,6 +102,7 @@ func main() {
// Kick signal handler
go Conf.SigHandler()
signal.Notify(Conf.Channels.SigChan,
syscall.SIGUSR1,
syscall.SIGUSR2,
@@ -178,33 +177,10 @@ func main() {
// TODO: впилить для первого и последнего батона separator
if Conf.AppButtons.Enabled {
for num, app := range Conf.Apps {
for _, app := range Conf.Apps {
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
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.Color = app.Color
b.Instance = app.Instance
@@ -229,42 +205,55 @@ func main() {
}
if Conf.CPUTemp.Enabled {
var b lib.I3BarOutBlock
var (
b lib.I3BarOutBlock
sb strings.Builder
)
b.Color = Conf.CPUTemp.Color
b.Background = Conf.CPUTemp.Background
if Conf.CPUTemp.Separator.Left.Enabled {
b.FullText = fmt.Sprintf(
"<span color='%s' background='%s' font='%s' size='%s'>%s</span>",
Conf.CPUTemp.Separator.Left.Color,
Conf.CPUTemp.Separator.Left.Background,
Conf.CPUTemp.Separator.Left.Font,
Conf.CPUTemp.Separator.Left.FontSize,
Conf.CPUTemp.Separator.Left.Symbol,
)
sb.WriteString("<span color='")
sb.WriteString(Conf.CPUTemp.Separator.Left.Color)
sb.WriteString("' background='")
sb.WriteString(Conf.CPUTemp.Separator.Left.Background)
sb.WriteString("' font='")
sb.WriteString(Conf.CPUTemp.Separator.Left.Font)
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(
"<span color='%s' background='%s' font='%s' size='%s'>CPU: %d°</span>",
Conf.CPUTemp.Color,
Conf.CPUTemp.Background,
Conf.CPUTemp.Font,
Conf.CPUTemp.FontSize,
Conf.Values.CPUTemperature,
)
sb.WriteString("<span color='")
sb.WriteString(Conf.CPUTemp.Color)
sb.WriteString("' background='")
sb.WriteString(Conf.CPUTemp.Background)
sb.WriteString("' font='")
sb.WriteString(Conf.CPUTemp.Font)
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 {
b.FullText += fmt.Sprintf(
"<span color='%s' background='%s' font='%s' size='%s'>%s</span>",
Conf.CPUTemp.Separator.Right.Color,
Conf.CPUTemp.Separator.Right.Background,
Conf.CPUTemp.Separator.Right.Font,
Conf.CPUTemp.Separator.Right.FontSize,
Conf.CPUTemp.Separator.Right.Symbol,
)
sb.WriteString("<span color='")
sb.WriteString(Conf.CPUTemp.Separator.Right.Color)
sb.WriteString("' background='")
sb.WriteString(Conf.CPUTemp.Separator.Right.Background)
sb.WriteString("' font='")
sb.WriteString(Conf.CPUTemp.Separator.Right.Font)
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.Separator = false
@@ -272,56 +261,66 @@ func main() {
}
if Conf.Mem.Enabled {
var b lib.I3BarOutBlock
var (
b lib.I3BarOutBlock
sb strings.Builder
)
b.Color = Conf.Mem.Color
b.Background = Conf.Mem.Background
if Conf.Mem.Separator.Left.Enabled {
b.FullText = fmt.Sprintf(
"<span color='%s' background='%s' font='%s' size='%s'>%s</span>",
Conf.Mem.Separator.Left.Color,
Conf.Mem.Separator.Left.Background,
Conf.Mem.Separator.Left.Font,
Conf.Mem.Separator.Left.FontSize,
Conf.Mem.Separator.Left.Symbol,
)
sb.WriteString("<span color='")
sb.WriteString(Conf.Mem.Separator.Left.Color)
sb.WriteString("' background='")
sb.WriteString(Conf.Mem.Separator.Left.Background)
sb.WriteString("' font='")
sb.WriteString(Conf.Mem.Separator.Left.Font)
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 {
b.FullText += fmt.Sprintf(
"<span color='%s' background='%s' font='%s' size='%s'>M:%d%% SHM:%dM SW:%dM</span>",
Conf.Mem.Color,
Conf.Mem.Background,
Conf.Mem.Font,
Conf.Mem.FontSize,
Conf.Values.Memory.Usedpct,
Conf.Values.Memory.Shared,
Conf.Values.Memory.Swap,
)
sb.WriteString("% SW:")
sb.WriteString(strconv.FormatUint(Conf.Values.Memory.Swap, 10))
sb.WriteString("M")
} else {
b.FullText += fmt.Sprintf(
"<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("%")
}
sb.WriteString("</span>")
if Conf.Mem.Separator.Right.Enabled {
b.FullText += fmt.Sprintf(
"<span color='%s' background='%s' font='%s' size='%s'>%s</span>",
Conf.Mem.Separator.Right.Color,
Conf.Mem.Separator.Right.Background,
Conf.Mem.Separator.Right.Font,
Conf.Mem.Separator.Right.FontSize,
Conf.Mem.Separator.Right.Symbol,
)
sb.WriteString("<span color='")
sb.WriteString(Conf.Mem.Separator.Right.Color)
sb.WriteString("' background='")
sb.WriteString(Conf.Mem.Separator.Right.Background)
sb.WriteString("' font='")
sb.WriteString(Conf.Mem.Separator.Right.Font)
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.Separator = false
@@ -329,42 +328,55 @@ func main() {
}
if Conf.LA.Enabled {
var b lib.I3BarOutBlock
var (
b lib.I3BarOutBlock
sb strings.Builder
)
b.Color = Conf.LA.Color
b.Background = Conf.LA.Background
if Conf.LA.Separator.Left.Enabled {
b.FullText = fmt.Sprintf(
"<span color='%s' background='%s' font='%s' size='%s'>%s</span>",
Conf.LA.Separator.Left.Color,
Conf.LA.Separator.Left.Background,
Conf.LA.Separator.Left.Font,
Conf.LA.Separator.Left.FontSize,
Conf.LA.Separator.Left.Symbol,
)
sb.WriteString("<span color='")
sb.WriteString(Conf.LA.Separator.Left.Color)
sb.WriteString("' background='")
sb.WriteString(Conf.LA.Separator.Left.Background)
sb.WriteString("' font='")
sb.WriteString(Conf.LA.Separator.Left.Font)
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(
"<span color='%s' background='%s' font='%s' size='%s'>LA:%s</span>",
Conf.LA.Color,
Conf.LA.Background,
Conf.LA.Font,
Conf.LA.FontSize,
Conf.Values.La,
)
sb.WriteString("<span color='")
sb.WriteString(Conf.LA.Color)
sb.WriteString("' background='")
sb.WriteString(Conf.LA.Background)
sb.WriteString("' font='")
sb.WriteString(Conf.LA.Font)
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 {
b.FullText += fmt.Sprintf(
"<span color='%s' background='%s' font='%s' size='%s'>%s</span>",
Conf.LA.Separator.Right.Color,
Conf.LA.Separator.Right.Background,
Conf.LA.Separator.Right.Font,
Conf.LA.Separator.Right.FontSize,
Conf.LA.Separator.Right.Symbol,
)
sb.WriteString("<span color='")
sb.WriteString(Conf.LA.Separator.Right.Color)
sb.WriteString("' background='")
sb.WriteString(Conf.LA.Separator.Right.Background)
sb.WriteString("' font='")
sb.WriteString(Conf.LA.Separator.Right.Font)
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.Separator = false
@@ -576,43 +588,56 @@ func main() {
}
if Conf.Clock.Enabled {
var b lib.I3BarOutBlock
var (
b lib.I3BarOutBlock
sb strings.Builder
)
b.Name = `wallclock`
b.Color = Conf.Clock.Color
b.Background = Conf.Clock.Background
if Conf.Clock.Separator.Left.Enabled {
b.FullText = fmt.Sprintf(
"<span color='%s' background='%s' font='%s' size='%s'>%s</span>",
Conf.Clock.Separator.Left.Color,
Conf.Clock.Separator.Left.Background,
Conf.Clock.Separator.Left.Font,
Conf.Clock.Separator.Left.FontSize,
Conf.Clock.Separator.Left.Symbol,
)
sb.WriteString("<span color='")
sb.WriteString(Conf.Clock.Separator.Left.Color)
sb.WriteString("' background='")
sb.WriteString(Conf.Clock.Separator.Left.Background)
sb.WriteString("' font='")
sb.WriteString(Conf.Clock.Separator.Left.Font)
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(
"<span color='%s' background='%s' font='%s' size='%s'>%s</span>",
Conf.Clock.Color,
Conf.Clock.Background,
Conf.Clock.Font,
Conf.Clock.FontSize,
Conf.Values.ClockTime,
)
sb.WriteString("<span color='")
sb.WriteString(Conf.Clock.Color)
sb.WriteString("' background='")
sb.WriteString(Conf.Clock.Background)
sb.WriteString("' font='")
sb.WriteString(Conf.Clock.Font)
sb.WriteString("' size='")
sb.WriteString(Conf.Clock.FontSize)
sb.WriteString("'>")
sb.WriteString(Conf.Values.ClockTime)
sb.WriteString("</span>")
if Conf.Clock.Separator.Right.Enabled {
b.FullText += fmt.Sprintf(
"<span color='%s' background='%s' font='%s' size='%s'>%s</span>",
Conf.Clock.Separator.Right.Color,
Conf.Clock.Separator.Right.Background,
Conf.Clock.Separator.Right.Font,
Conf.Clock.Separator.Right.FontSize,
Conf.Clock.Separator.Right.Symbol,
)
sb.WriteString("<span color='")
sb.WriteString(Conf.Clock.Separator.Right.Color)
sb.WriteString("' background='")
sb.WriteString(Conf.Clock.Separator.Right.Background)
sb.WriteString("' font='")
sb.WriteString(Conf.Clock.Separator.Right.Font)
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.Separator = false
@@ -641,3 +666,5 @@ func PrintToI3bar(c *lib.MyConfig) {
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
import (
@@ -29,7 +30,7 @@ func (c *MyConfig) UpdateBatteryInfo() {
}
var (
batteries []*battery.Battery = []*battery.Battery{}
batteries = []*battery.Battery{}
Batts string
ch int
status string
@@ -52,23 +53,26 @@ func (c *MyConfig) UpdateBatteryInfo() {
if err != nil {
log.Printf("Unable to read file %s: %s", file, err)
continue
}
myCharge = strings.Trim(string(b), "\n")
myCharge = strings.TrimSpace(string(b))
statusFile := filepath.Dir(file) + "/status"
// If file exists.
_, err = os.Stat(statusFile)
if !os.IsNotExist(err) {
b, err := os.ReadFile(statusFile)
if err != nil {
log.Printf("Unable to read file %s: %s", statusFile, err)
continue
}
myStatus = strings.Trim(string(b), "\n")
myStatus = strings.TrimSpace(string(b))
} else {
continue
}
@@ -91,6 +95,7 @@ func (c *MyConfig) UpdateBatteryInfo() {
if err != nil {
log.Printf("Unable to convert string from file %s to integer", file)
continue
}
@@ -100,9 +105,13 @@ func (c *MyConfig) UpdateBatteryInfo() {
}
}
} else {
batteries, _ = battery.GetAll()
// 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.
var err error
batteries, err = battery.GetAll()
if err != nil {
log.Printf("Unable to get battery info: %s", err)
}
}
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.
type Collection struct {
items sync.Map
close chan struct{}
}
// Item just interface for stoing any data.
@@ -17,9 +16,7 @@ type item struct {
// NewCollection creates new instance of "collection".
func NewCollection() *Collection {
c := &Collection{ //nolint:exhaustruct
close: make(chan struct{}),
}
c := &Collection{}
return c
}
@@ -32,9 +29,12 @@ func (collection *Collection) Get(key any) (any, bool) {
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".
@@ -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) {
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)
@@ -62,7 +65,6 @@ func (collection *Collection) Delete(key any) {
// Close frees memory occupied by collection and deletes collection itself.
func (collection *Collection) Close() {
collection.close <- struct{}{}
collection.items = sync.Map{}
}

File diff suppressed because it is too large Load Diff

View File

@@ -23,6 +23,7 @@ func (c *MyConfig) UpdateCPUTemperature() {
temperature = make([]int64, n)
tSum int64
tAvg int64
validCount int
)
if Delay == InitialDelay {
@@ -35,47 +36,50 @@ func (c *MyConfig) UpdateCPUTemperature() {
if err != nil {
log.Printf("Unable to open %s: %s", filename, err)
} else {
reader := bufio.NewReader(file)
line, _, err := reader.ReadLine()
if err != nil {
log.Printf("Unable to read from %s: %s", filename, err)
err = file.Close()
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)
if err != nil {
log.Printf("Unable to convert string to number from file %s: %s", filename, err)
} else {
if temp > 1000 {
temp /= 1000
}
temperature[i] = temp
}
}
}
continue
}
defer file.Close()
reader := bufio.NewReader(file)
line, _, err := reader.ReadLine()
if err != nil {
log.Printf("Unable to read from %s: %s", filename, err)
continue
}
temp, err := strconv.ParseInt(string(line), 10, 32)
if err != nil {
log.Printf("Unable to convert string to number from file %s: %s", filename, err)
continue
}
if temp > 1000 {
temp /= 1000
}
temperature[i] = temp
validCount++
}
if len(temperature) == 1 {
tAvg = temperature[0]
if validCount == 0 {
continue
}
if validCount == 1 {
for _, t := range temperature {
if t != 0 {
tAvg = t
break
}
}
} else {
for _, t := range temperature {
tSum += t
}
tAvg = tSum / int64(len(temperature))
tAvg = tSum / int64(validCount)
}
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.
var myCron gocron.Scheduler
var (
myCron gocron.Scheduler
)
// RunCron parses config part, related to cron tasks and kicks cron to run.
func (c MyConfig) RunCron() {
@@ -25,14 +27,11 @@ func (c MyConfig) RunCron() {
_, err := myCron.NewJob(
gocron.CronJob(job.Time, false),
gocron.NewTask(
// Сука, просто заспавнить бинарь, ну почему это надо делать через жопу-то?
any(
func() bool {
c.Channels.RunChan <- job.Cmd
func() bool {
c.Channels.RunChan <- job.Cmd
return true
},
),
return true
},
),
)
@@ -43,3 +42,5 @@ func (c MyConfig) RunCron() {
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.
func (c *MyConfig) UpdateI3WinList() {
// TODO: Здесь получить начальный список окон, управляемых i3wm (через GetTree()) и сложить их атрибутику в переменную WL
Tree, err := i3.GetTree()
if err != nil {
log.Printf("Unable to get list of windows: %s", err)
return
}
c.ExtractProps(Tree.Root)
c.Channels.UpdateReady <- true
i3wm := i3.Subscribe(i3.WindowEventType)
for i3wm.Next() {
@@ -105,9 +108,11 @@ func (c *MyConfig) I3EventParser(e *i3.WindowEvent) {
// interfaceToUint превращает данный интерфейс в Uint64.
// Если может, конечно :) .
func interfaceToUint64(iface interface{}) uint64 {
// А теперь мы начинаем дурдом, нам надо превратить ёбанный interface{} в []string
// Поскольку interface{} может быть чем угодно, перестрахуемся
func interfaceToUint64(iface any) uint64 {
if iface == nil {
return 0
}
if reflect.TypeOf(iface).Kind() == reflect.Uint64 {
return reflect.ValueOf(iface).Uint()
}
@@ -152,18 +157,16 @@ func HasWindows(className string, instanceName string) bool {
func FindWindowInstance(regexpStr string) bool {
var found = false
re, err := regexp.Compile(regexpStr)
if err != nil {
log.Printf("Unable to perform regexp match: %s", err)
return false
}
f := func(key any, value any) bool { //nolint: revive
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 {
log.Printf("Unable to perform regexp match: %s", err)
return true
}
if re.Match([]byte(keyStr)) { //nolint:mirror
found = true
@@ -183,18 +186,16 @@ func FindWindowInstance(regexpStr string) bool {
func FindWindowClass(regexpStr string) bool {
var found = false
re, err := regexp.Compile(regexpStr)
if err != nil {
log.Printf("Unable to perform regexp match: %s", err)
return false
}
f := func(key any, value any) bool { //nolint: revive
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 {
log.Printf("Unable to perform regexp match: %s", err)
return true
}
if re.Match([]byte(keyStr)) { //nolint:mirror
found = true
@@ -225,3 +226,5 @@ func (c *MyConfig) ExtractProps(n *i3.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 {
switch strings.TrimSpace(string(operstate)) {
case "up":
StatusStr := fmt.Sprintf("<span foreground=\"%s\">⍋</span>", c.NetIf.UpColor)
operstate = []byte(StatusStr)
statusStr := fmt.Sprintf("<span foreground=\"%s\">⍋</span>", c.NetIf.UpColor)
operstate = []byte(statusStr)
case "down":
statusStr := fmt.Sprintf("<span foreground=\"%s\">⍒</span>", c.NetIf.DownColor)
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 (
"fmt"
"log"
"time"
"github.com/shirou/gopsutil/load"
@@ -22,7 +23,13 @@ func (c *MyConfig) UpdateLaStats() {
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)
@@ -32,3 +39,5 @@ func (c *MyConfig) UpdateLaStats() {
}
}
}
/* vim: set ft=go noet ai ts=4 sw=4 sts=4: */

View File

@@ -38,20 +38,20 @@ func (c *MyConfig) UpdateMemStats() {
continue
}
sw, err := mem.SwapMemory()
if err != nil {
log.Printf("Unable to get swap statistics: %s", err)
time.Sleep(1 * time.Second)
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 != v.SwapTotal-v.SwapFree {
sw, err := mem.SwapMemory()
if err != nil {
log.Printf("Unable to get swap statistics: %s", err)
time.Sleep(1 * time.Second)
continue
}
if c.Values.Memory.Usedpct != uint64(v.UsedPercent) || c.Values.Memory.Shared != v.Shared/1024/1024 || c.Values.Memory.Swap != sw.Used/1024/1024 {
c.Values.Memory.Usedpct = uint64(v.UsedPercent)
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
}
} 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
// 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 {
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 {
return fmt.Errorf("unable to kill pulseaudio: %w", err)
@@ -127,7 +127,7 @@ func (c *MyConfig) PaReinit() error {
cnt := 0
for {
cmd := exec.Command("pulseaudio", "--check")
cmd := exec.Command("pulseaudio", "--check") //nolint: noctx
// PA not running. Breakout of loop.
if err := cmd.Run(); err != nil {
@@ -154,10 +154,10 @@ func (c *MyConfig) PaReinit() error {
// audio.
if c.SimpleVolumePa.DontExitOnLogin {
// 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 {
// 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 {
@@ -173,6 +173,8 @@ func (c *MyConfig) PaReinit() error {
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() {
for e := range c.Channels.SVPAHandlerChan {
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"
)
var PrintOutput = true
// SigHandler OS signal handler.
func (c *MyConfig) SigHandler() {
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.
func (c *MyConfig) Spawner() {
for prg := range c.Channels.RunChan {
<-time.After(25 * time.Millisecond)
devnullR, _ := os.Open(os.DevNull)
devnullW, _ := os.OpenFile(os.DevNull, os.O_WRONLY|os.O_APPEND, 0644)
time.Sleep(25 * time.Millisecond)
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{
Setsid: true,
@@ -33,6 +45,7 @@ func (c *MyConfig) Spawner() {
if err != nil {
log.Printf("Unable to spawn %s: %s", prg[0], err)
continue
}
_, err = syscall.ForkExec(bin, prg, &pa)
@@ -40,10 +53,6 @@ func (c *MyConfig) Spawner() {
if err != nil {
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{}
for {
_, _ = syscall.Wait4(-1, nil, 0, &r)
pid, _ := syscall.Wait4(-1, nil, syscall.WNOHANG, &r)
if pid > 0 {
continue
}
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.
func RunProcess(command []string) string {
var (
@@ -68,9 +81,9 @@ func RunProcess(command []string) string {
switch len(command) {
case 1:
cmd = exec.Command(command[0], "")
cmd = exec.Command(command[0], "") //nolint: gosec
default:
cmd = exec.Command(command[0], command[1:]...)
cmd = exec.Command(command[0], command[1:]...) //nolint: gosec
}
cmd.Dir = "/"
@@ -87,11 +100,13 @@ func RunProcess(command []string) string {
}
return ""
} else {
if stderr.String() != "" {
log.Printf("%s: %s", strings.Join(command, " "), stderr.String())
}
}
if stderr.String() != "" {
log.Printf("%s: %s", strings.Join(command, " "), stderr.String())
}
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
}
for i := 0; i < len(buf); i++ {
if strings.HasPrefix(buf, "{") {
break
}
buf = buf[1:]
}
if len(buf) == 0 {
log.Print("String from stdin has zero length, skipping")
buf = strings.TrimLeftFunc(buf, func(r rune) bool {
return r != '{'
})
if !strings.HasPrefix(buf, "{") {
continue
}
@@ -116,18 +110,24 @@ func (c *MyConfig) ParseStdin() {
break
}
case app.Name != "" && e.Name == app.Name:
prg := append([]string{}, app.Cmd)
prg = append(prg, app.Args...)
c.Channels.RunChan <- prg
break
case app.Instance != "" && e.Instance == app.Instance:
prg := append([]string{}, app.Cmd)
prg = append(prg, app.Args...)
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"
"net"
"os"
"strings"
"time"
)
@@ -11,8 +12,8 @@ import (
func (c *MyConfig) UpdateVPNStatus() {
var (
vpnCStatus string
tcpCheck string
vpnCheck string
b strings.Builder
InitialDelay = 100 * time.Millisecond
LoopIterationDelay = 3 * time.Second
Delay = InitialDelay
@@ -27,36 +28,47 @@ func (c *MyConfig) UpdateVPNStatus() {
if c.VPNFileCheck() {
if c.Vpn.UpColor == "" {
vpnCheck = `⍋`
b.WriteRune('⍋')
} else {
vpnCheck = fmt.Sprintf(`<span foreground="%s">⍋</span>`, c.Vpn.UpColor)
b.WriteString("<span foreground=\"")
b.WriteString(c.Vpn.UpColor)
b.WriteString("\">⍋</span>")
}
} else {
if c.Vpn.DownColor == "" {
vpnCheck = `⍒`
b.WriteRune('⍒')
} 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.VPNTCPCheck() {
if c.Vpn.UpColor == "" {
tcpCheck = `✔`
b.WriteRune('✔')
} else {
tcpCheck = fmt.Sprintf(`<span foreground="%s">✔</span>`, c.Vpn.UpColor)
b.WriteString("<span foreground=\"")
b.WriteString(c.Vpn.UpColor)
b.WriteString("\">✔</span>")
}
} else {
if c.Vpn.DownColor == "" {
tcpCheck = `✘`
b.WriteRune('✘')
} 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 {
vpnCStatus = fmt.Sprintf("VPN:%s", vpnCheck)
vpnCStatus = "VPN:" + vpnCheck
}
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 {
conn, err := net.DialTimeout(
conn, err := net.DialTimeout( //nolint: noctx
"tcp",
fmt.Sprintf("%s:%d", c.Vpn.TCPCheck.Host, c.Vpn.TCPCheck.Port), //nolint: hostport
time.Second*time.Duration(c.Vpn.TCPCheck.Timeout),
@@ -100,3 +112,5 @@ func (c *MyConfig) VPNFileCheck() bool {
return true
}
/* vim: set ft=go noet ai ts=4 sw=4 sts=4: */