39 Commits
v1.6 ... master

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
20 changed files with 1792 additions and 605 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

@@ -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.
@@ -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{}
}

View File

@@ -14,19 +14,22 @@ import (
p "github.com/mafik/pulseaudio"
)
type (
// I3BarOutBlock is structure element for I3BarOut, it represents i3bar output json block format.
type I3BarOutBlock struct {
I3BarOutBlock struct {
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"`
Color string `json:"color,omitempty"`
Background string `json:"background,omitempty"`
Font string `json:"font,omitempty"`
FontSize string `json:"font_size,omitempty"`
Border string `json:"border,omitempty"`
BorderTop int `json:"border_top"`
BorderRight int `json:"border_right"`
BorderBottom int `json:"border_bottom"`
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"`
Align string `json:"align,omitempty"`
Name string `json:"name,omitempty"`
@@ -37,27 +40,29 @@ type I3BarOutBlock struct {
Markup string `json:"markup,omitempty"`
}
type Separator struct {
// Separator usually is a bymbol that separates fields in i3 status string.
Separator struct {
Left struct {
Enabled bool `json:"enabled,omitempty"`
Color string `json:"color,omitempty"`
Background string `json:"background,omitempty"`
Symbol string `json:"symbol,omitempty"`
Font string `json:"font,omitempty"`
FontSize string `json:"font_size,omitempty"`
} `json:"left,omitempty"`
Enabled bool `json:"enabled,omitempty"`
} `json:"left"`
Right struct {
Enabled bool `json:"enabled,omitempty"`
Color string `json:"color,omitempty"`
Background string `json:"background,omitempty"`
Symbol string `json:"symbol,omitempty"`
Font string `json:"font,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 {
PrintOutput bool
CPUTemperature int64
@@ -80,21 +85,22 @@ type MyConfig struct {
RunChan chan []string
}
// Default text color
// Color default text color.
Color string `json:"color,omitempty"`
// Default background color
// Background default background color.
Background string `json:"background,omitempty"`
// Default text font
// Font default text font.
Font string `json:"font,omitempty"`
// Default text font size
// FontSize default text font size.
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 {
Enabled bool `json:"enabled,omitempty"`
Color string `json:"color,omitempty"`
@@ -102,9 +108,9 @@ type MyConfig struct {
Font string `json:"font,omitempty"`
FontSize string `json:"font_size,omitempty"`
Separator Separator `json:"separator,omitempty"`
} `json:"la,omitempty"`
} `json:"la"`
// Mem plugin
// Mem plugin.
Mem struct {
Enabled bool `json:"enabled,omitempty"`
Color string `json:"color,omitempty"`
@@ -113,8 +119,9 @@ type MyConfig struct {
FontSize string `json:"font_size,omitempty"`
ShowSwap bool `json:"show_swap,omitempty"`
Separator Separator `json:"separator,omitempty"`
} `json:"mem,omitempty"`
} `json:"mem"`
// Clock plugin.
Clock struct {
Enabled bool `json:"enabled,omitempty"`
Color string `json:"color,omitempty"`
@@ -126,14 +133,15 @@ type MyConfig struct {
LeftClick struct {
Enabled bool `json:"enabled,omitempty"`
Cmd []string `json:"cmd,omitempty"`
} `json:"left_click,omitempty"`
} `json:"left_click"`
RightClick struct {
Enabled bool `json:"enabled,omitempty"`
Cmd []string `json:"cmd,omitempty"`
} `json:"right_click,omitempty"`
} `json:"clock,omitempty"`
} `json:"right_click"`
} `json:"clock"`
// Battery plugin.
Battery struct {
Enabled bool `json:"enabled,omitempty"`
UseSysfs bool `json:"use_sysfs,omitempty"`
@@ -151,11 +159,12 @@ type MyConfig struct {
Empty string `json:"empty,omitempty"`
AlmostFull string `json:"almost_full,omitempty"`
AlmostEmpty string `json:"almost_empty,omitempty"`
} `json:"charge_color,omitempty"`
} `json:"charge_color"`
Separator Separator `json:"separator,omitempty"`
} `json:"battery,omitempty"`
} `json:"battery"`
// CPUTemp plugin.
CPUTemp struct {
Enabled bool `json:"enabled,omitempty"`
Color string `json:"color,omitempty"`
@@ -165,8 +174,9 @@ type MyConfig struct {
Separator Separator `json:"separator,omitempty"`
File []string `json:"file,omitempty"`
} `json:"cpu_temp,omitempty"`
} `json:"cpu_temp"`
// Vpn plugin.
Vpn struct {
Enabled bool `json:"enabled,omitempty"`
Color string `json:"color,omitempty"`
@@ -177,16 +187,17 @@ type MyConfig struct {
MtimeThreshold int `json:"mtime_threshold,omitempty"`
DownColor string `json:"down_color,omitempty"`
UpColor string `json:"up_color,omitempty"`
Separator Separator `json:"separator,omitempty"`
Separator Separator `json:"separator"`
TCPCheck struct {
Enabled bool `json:"enabled,omitempty"`
Host string `json:"host,omitempty"`
Port int `json:"port,omitempty"`
Timeout int `json:"timeout,omitempty"`
} `json:"tcp_check,omitempty"`
} `json:"vpn,omitempty"`
} `json:"tcp_check"`
} `json:"vpn"`
// SimpleVolumePa plugin.
SimpleVolumePa struct {
Enabled bool `json:"enabled,omitempty"`
Color string `json:"color,omitempty"`
@@ -204,8 +215,9 @@ type MyConfig struct {
WheelUp int `json:"wheel_up,omitempty"`
WheelDown int `json:"wheel_down,omitempty"`
MaxVolumeLimit int `json:"max_volume_limit,omitempty"`
} `json:"simple-volume-pa,omitempty"`
} `json:"simple-volume-pa"`
// NrtIf plugin.
NetIf struct {
Enabled bool `json:"enabled,omitempty"`
DownColor string `json:"down_color,omitempty"`
@@ -219,9 +231,10 @@ type MyConfig struct {
If []struct {
Name string `json:"name,omitempty"`
Dir string `json:"dir,omitempty"`
} `json:"if,omitempty"`
} `json:"net-if,omitempty"`
} `json:"if"`
} `json:"net-if"`
// Cron plugin.
Cron struct {
Enabled bool `json:"enabled,omitempty"`
TimeZone string `json:"timezone,omitempty"`
@@ -229,26 +242,33 @@ type MyConfig struct {
Tasks []struct {
Time string `json:"time,omitempty"`
Cmd []string `json:"cmd,omitempty"`
} `json:"tasks,omitempty"`
} `json:"cron,omitempty"`
} `json:"tasks"`
} `json:"cron"`
// CmdRun plugin.
CmdRun struct {
Enabled bool `json:"enabled,omitempty"`
Color string `json:"color,omitempty"`
Background string `json:"background,omitempty"`
Font string `json:"font,omitempty"`
FontSize string `json:"font_size,omitempty"`
Separator Separator `json:"separator,omitempty"`
Cmd string `json:"cmd,omitempty"`
Delay int `json:"delay,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 {
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"`
Separator Separator `json:"separator,omitempty"`
} `json:"app_buttons,omitempty"`
} `json:"app_buttons"`
// Apps descriptions for AppButtons plugin.
Apps []struct {
FullText string `json:"full_text,omitempty"`
Name string `json:"name,omitempty"`
@@ -258,14 +278,17 @@ type MyConfig struct {
Class string `json:"class,omitempty"`
Color string `json:"color,omitempty"`
Background string `json:"background,omitempty"`
Font string `json:"font,omitempty"`
FontSize string `json:"font_size,omitempty"`
Border string `json:"border,omitempty"`
BorderActive string `json:"border_active,omitempty"`
Separator bool `json:"separator,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.
func ReadConf(defaultConfig []byte) (*MyConfig, error) {
var (
@@ -464,6 +487,30 @@ func ReadConf(defaultConfig []byte) (*MyConfig, error) {
if sampleConfig.LA.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 == "" {
@@ -518,22 +565,6 @@ func ReadConf(defaultConfig []byte) (*MyConfig, error) {
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 == "" {
sampleConfig.LA.Separator.Right.Symbol = sampleConfig.Separator.Right.Symbol
}
@@ -584,6 +615,30 @@ func ReadConf(defaultConfig []byte) (*MyConfig, error) {
if sampleConfig.Mem.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 == "" {
@@ -688,6 +743,30 @@ func ReadConf(defaultConfig []byte) (*MyConfig, error) {
if sampleConfig.Clock.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 {
@@ -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 {
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 {
sampleConfig.Clock.RightClick.Cmd = append(sampleConfig.Clock.RightClick.Cmd, "true")
}
// sampleConfig.Battery.Enabled will be false if not set in config
// sampleConfig.Battery.UseSysfs 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.
if len(sampleConfig.Battery.SysfsFiles) == 0 {
sampleConfig.Battery.SysfsFiles = append(
@@ -816,6 +895,30 @@ func ReadConf(defaultConfig []byte) (*MyConfig, error) {
if sampleConfig.Battery.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 == "" {
@@ -827,13 +930,37 @@ func ReadConf(defaultConfig []byte) (*MyConfig, error) {
}
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.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 !matched {
log.Printf(
"Unable to set sampleConfig.Battery.SymbolFontSize, fallback to %s",
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 == "" {
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 {
sampleConfig.CPUTemp.Enabled = false
}
@@ -943,6 +1070,30 @@ func ReadConf(defaultConfig []byte) (*MyConfig, error) {
if sampleConfig.CPUTemp.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 {
@@ -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 == "" {
sampleConfig.Vpn.Enabled = false
}
@@ -1049,23 +1200,47 @@ func ReadConf(defaultConfig []byte) (*MyConfig, error) {
}
if sampleConfig.Vpn.Font == "" {
sampleConfig.Vpn.FontSize = sampleConfig.Font
sampleConfig.Vpn.Font = sampleConfig.Font
}
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
}
// 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 {
log.Printf("vpn.mtime_threshold not set, using 3")
sampleConfig.Vpn.MtimeThreshold = 3
}
// 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.TcpCheck.Enabled will false if not 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.TcpCheck.Enabled will false if not set in config.
if sampleConfig.Vpn.Separator.Left.Enabled {
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.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
}
// Disable plugin if value indaquate
// Disable plugin if value indaquate.
if sampleConfig.Vpn.TCPCheck.Host == "" {
if sampleConfig.Vpn.TCPCheck.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.SimpleVolumePa.Enabled will false if not set in config
// sampleConfig.SimpleVolumePa.Enabled will false if not set in config.
if sampleConfig.SimpleVolumePa.Color == "" {
sampleConfig.SimpleVolumePa.Color = sampleConfig.Color
}
@@ -1198,6 +1373,30 @@ func ReadConf(defaultConfig []byte) (*MyConfig, error) {
if sampleConfig.SimpleVolumePa.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 == "" {
@@ -1210,6 +1409,30 @@ func ReadConf(defaultConfig []byte) (*MyConfig, error) {
if sampleConfig.SimpleVolumePa.SymbolFontSize == "" {
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 {
@@ -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 {
sampleConfig.Cron.Enabled = false
@@ -1342,7 +1565,7 @@ func ReadConf(defaultConfig []byte) (*MyConfig, error) {
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 {
sampleConfig.NetIf.Enabled = false
@@ -1370,6 +1593,29 @@ func ReadConf(defaultConfig []byte) (*MyConfig, error) {
if sampleConfig.NetIf.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 == "" {
@@ -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 {
sampleConfig.CmdRun.Enabled = false
log.Print(
"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 == "" {
sampleConfig.CmdRun.Color = sampleConfig.Color
@@ -1484,6 +1731,30 @@ func ReadConf(defaultConfig []byte) (*MyConfig, error) {
if sampleConfig.CmdRun.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 == "" {
@@ -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 == "" {
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.Class can be missing.
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.
if app.Cmd == "" {
app.Cmd = "true"
// If command omitted it will be just /usr/bin/true.
sampleConfig.Apps[num].Cmd = "true"
}
if app.Color == "" {
app.Color = sampleConfig.Color
sampleConfig.Apps[num].Color = sampleConfig.AppButtons.Color
}
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 == "" {
app.Border = sampleConfig.Color
sampleConfig.Apps[num].Border = sampleConfig.AppButtons.Color
}
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.SeparatorBlockWidth can be missing
// app.Separator can be omitted, in that case it is false.
// app.SeparatorBlockWidth can be missing.
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
}
/* 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)
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 {
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)
err = file.Close()
if err != nil {
log.Printf("Unable to close %s: %s", filename, err)
continue
}
} 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 {
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,15 +27,12 @@ func (c MyConfig) RunCron() {
_, err := myCron.NewJob(
gocron.CronJob(job.Time, false),
gocron.NewTask(
// Сука, просто заспавнить бинарь, ну почему это надо делать через жопу-то?
any(
func() bool {
c.Channels.RunChan <- job.Cmd
return true
},
),
),
)
if err != nil {
@@ -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
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.
re, err := regexp.Compile(regexpStr)
if err != nil {
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
found = true
@@ -183,18 +186,16 @@ func FindWindowInstance(regexpStr string) bool {
func FindWindowClass(regexpStr string) bool {
var found = 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.
re, err := regexp.Compile(regexpStr)
if err != nil {
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
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,6 +38,7 @@ func (c *MyConfig) UpdateMemStats() {
continue
}
if c.Mem.ShowSwap {
sw, err := mem.SwapMemory()
if err != nil {
@@ -47,11 +48,10 @@ func (c *MyConfig) UpdateMemStats() {
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 {
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

@@ -5,7 +5,7 @@ import (
"time"
)
// RunCommands gets list of commands runs them sequentally and conacatenates their output.
// RunCommand gets list of commands runs them sequentally and conacatenates their output.
func (c *MyConfig) RunCommand() {
var (
InitialDelay = 100 * time.Millisecond
@@ -31,7 +31,7 @@ func (c *MyConfig) RunCommand() {
outputString += RunProcess(command)
log.Println(c.Values.RunCommandOutput)
log.Println(outputString)
if c.Values.RunCommandOutput != outputString {
c.Values.RunCommandOutput = outputString
@@ -39,3 +39,5 @@ func (c *MyConfig) RunCommand() {
}
}
}
/* 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())
}
}
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: */