From d9ce42598127a502dc87b0c71d9d0f0c530d9248 Mon Sep 17 00:00:00 2001 From: eleksir Date: Tue, 15 Jul 2025 14:08:34 +0300 Subject: [PATCH 1/2] Finally fix parsing of app buttons, now settings and fallback values should work as expected --- cmd/i3status-go/default-config.json | 30 ++++++++++++++--------------- cmd/i3status-go/main.go | 11 ++++++++--- internal/lib/config.go | 24 ++++++++++++----------- 3 files changed, 36 insertions(+), 29 deletions(-) diff --git a/cmd/i3status-go/default-config.json b/cmd/i3status-go/default-config.json index 8046716..e3d4e1c 100644 --- a/cmd/i3status-go/default-config.json +++ b/cmd/i3status-go/default-config.json @@ -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. @@ -834,36 +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 separator up here. + // 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 separator up here. - "font_size": "medium" + // ‘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. diff --git a/cmd/i3status-go/main.go b/cmd/i3status-go/main.go index aebc5f6..909b5fe 100644 --- a/cmd/i3status-go/main.go +++ b/cmd/i3status-go/main.go @@ -192,7 +192,14 @@ func main() { ) } - b.FullText = app.FullText + b.FullText = fmt.Sprintf( + "%s", + app.Color, + app.Background, + app.Font, + app.FontSize, + app.FullText, + ) if num == len(Conf.Apps) { b.FullText = fmt.Sprintf( @@ -205,8 +212,6 @@ func main() { ) } - b.Background = app.Background - b.Color = app.Color b.Instance = app.Instance b.Markup = `pango` b.Separator = app.Separator diff --git a/internal/lib/config.go b/internal/lib/config.go index 97d24a9..4f8379d 100644 --- a/internal/lib/config.go +++ b/internal/lib/config.go @@ -21,6 +21,8 @@ type I3BarOutBlock struct { 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"` @@ -1963,29 +1965,29 @@ 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 == "" { // If command omitted it will be just /usr/bin/true. - app.Cmd = "true" + sampleConfig.Apps[num].Cmd = "true" } if app.Color == "" { - app.Color = sampleConfig.AppButtons.Color + sampleConfig.Apps[num].Color = sampleConfig.AppButtons.Color } if app.Background == "" { - app.Background = sampleConfig.AppButtons.Background + sampleConfig.Apps[num].Background = sampleConfig.AppButtons.Background } if app.Font == "" { - app.Font = sampleConfig.AppButtons.Font + sampleConfig.Apps[num].Font = sampleConfig.AppButtons.Font } if app.FontSize == "" { - app.FontSize = sampleConfig.AppButtons.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)$`, @@ -2000,7 +2002,7 @@ func ReadConf(defaultConfig []byte) (*MyConfig, error) { sampleConfig.AppButtons.FontSize, ) - app.FontSize = sampleConfig.AppButtons.FontSize + sampleConfig.Apps[num].FontSize = sampleConfig.AppButtons.FontSize } if !matched { @@ -2009,22 +2011,22 @@ func ReadConf(defaultConfig []byte) (*MyConfig, error) { sampleConfig.AppButtons.FontSize, ) - app.FontSize = sampleConfig.AppButtons.FontSize + sampleConfig.Apps[num].FontSize = sampleConfig.AppButtons.FontSize } } if app.Border == "" { - app.Border = sampleConfig.AppButtons.Color + sampleConfig.Apps[num].Border = sampleConfig.AppButtons.Color } if app.BorderActive == "" { - app.BorderActive = sampleConfig.AppButtons.Color + sampleConfig.Apps[num].BorderActive = sampleConfig.AppButtons.Color } // 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) } } } From 3f5704237af049c51040d9f51eb0a44bde421d48 Mon Sep 17 00:00:00 2001 From: eleksir Date: Sun, 23 Nov 2025 16:41:20 +0300 Subject: [PATCH 2/2] [WIP] Update linter config + speed optimizations --- .golangci.yml | 740 ++++++++++++++++++++++++++++++++++++- cmd/battery-test/main.go | 1 + cmd/i3status-go/main.go | 336 +++++++++-------- internal/lib/batteries.go | 1 + internal/lib/collection.go | 23 +- internal/lib/config.go | 575 ++++++++++++++-------------- internal/lib/cputemp.go | 1 + internal/lib/cron.go | 4 +- internal/lib/i3.go | 6 +- internal/lib/pulseaudio.go | 12 +- internal/lib/runcommand.go | 2 +- internal/lib/spawn.go | 2 +- internal/lib/stdin.go | 1 + internal/lib/vpn.go | 38 +- 14 files changed, 1267 insertions(+), 475 deletions(-) diff --git a/.golangci.yml b/.golangci.yml index 384c8ec..71406f1 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -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$ diff --git a/cmd/battery-test/main.go b/cmd/battery-test/main.go index 41fbf76..d062799 100644 --- a/cmd/battery-test/main.go +++ b/cmd/battery-test/main.go @@ -1,3 +1,4 @@ +// Package main simple test for battery funtionality. package main import ( diff --git a/cmd/i3status-go/main.go b/cmd/i3status-go/main.go index 909b5fe..ad6d5ba 100644 --- a/cmd/i3status-go/main.go +++ b/cmd/i3status-go/main.go @@ -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() { @@ -43,14 +45,11 @@ func main() { Conf.Values.SoundVolume = "🔊:0%" // TODO: Проставить дефолтные значения для глобальных переменных модулей. - Conf.Values.BatteryString = fmt.Sprintf( - "%s", - Conf.Battery.Color, - Conf.Battery.Background, - Conf.Battery.SymbolFont, - Conf.Battery.SymbolFontSize, - Conf.Battery.Symbol, - ) + Conf.Values.BatteryString = "" + Conf.Battery.Symbol + "" Conf.Values.BatteryString += fmt.Sprintf( " ??%% •", @@ -104,6 +103,7 @@ func main() { // Kick signal handler go Conf.SigHandler() + signal.Notify(Conf.Channels.SigChan, syscall.SIGUSR1, syscall.SIGUSR2, @@ -178,40 +178,25 @@ func main() { // TODO: впилить для первого и последнего батона separator if Conf.AppButtons.Enabled { - for num, app := range Conf.Apps { - var b lib.I3BarOutBlock - - if num == 0 { - b.FullText = fmt.Sprintf( - "%s", - 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 = fmt.Sprintf( - "%s", - app.Color, - app.Background, - app.Font, - app.FontSize, - app.FullText, + for _, app := range Conf.Apps { + var ( + b lib.I3BarOutBlock + sb strings.Builder ) - if num == len(Conf.Apps) { - b.FullText = fmt.Sprintf( - "%s", - 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, - ) - } + sb.WriteString("") + sb.WriteString(app.FullText) + sb.WriteString("") + b.FullText = sb.String() b.Instance = app.Instance b.Markup = `pango` b.Separator = app.Separator @@ -234,42 +219,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( - "%s", - 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("") + sb.WriteString(Conf.CPUTemp.Separator.Left.Symbol) + sb.WriteString("") } - b.FullText += fmt.Sprintf( - "CPU: %d°", - Conf.CPUTemp.Color, - Conf.CPUTemp.Background, - Conf.CPUTemp.Font, - Conf.CPUTemp.FontSize, - Conf.Values.CPUTemperature, - ) + sb.WriteString("CPU: ") + sb.WriteString(strconv.FormatInt(Conf.Values.CPUTemperature, 10)) + sb.WriteString("°") if Conf.CPUTemp.Separator.Right.Enabled { - b.FullText += fmt.Sprintf( - "%s", - 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("") + sb.WriteString(Conf.CPUTemp.Separator.Right.Symbol) + sb.WriteString("") } + b.FullText = sb.String() b.Markup = "pango" b.Separator = false @@ -277,56 +275,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( - "%s", - 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("") + sb.WriteString(Conf.Mem.Separator.Left.Symbol) + sb.WriteString("") } + 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( - "M:%d%% SHM:%dM SW:%dM", - 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( - "M:%d%% SHM:%dM", - Conf.Mem.Color, - Conf.Mem.Background, - Conf.Mem.Font, - Conf.Mem.FontSize, - Conf.Values.Memory.Usedpct, - Conf.Values.Memory.Shared, - ) + sb.WriteString("%") } + sb.WriteString("") + if Conf.Mem.Separator.Right.Enabled { - b.FullText += fmt.Sprintf( - "%s", - 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("") + sb.WriteString(Conf.Mem.Separator.Right.Symbol) + sb.WriteString("") } + b.FullText = sb.String() b.Markup = "pango" b.Separator = false @@ -334,42 +342,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( - "%s", - 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("") + sb.WriteString(Conf.LA.Separator.Left.Symbol) + sb.WriteString("") } - b.FullText += fmt.Sprintf( - "LA:%s", - Conf.LA.Color, - Conf.LA.Background, - Conf.LA.Font, - Conf.LA.FontSize, - Conf.Values.La, - ) + sb.WriteString("LA:") + sb.WriteString(Conf.Values.La) + sb.WriteString("") if Conf.LA.Separator.Right.Enabled { - b.FullText += fmt.Sprintf( - "%s", - 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("") + sb.WriteString(Conf.LA.Separator.Right.Symbol) + sb.WriteString("") } + b.FullText = sb.String() b.Markup = "pango" b.Separator = false @@ -581,43 +602,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( - "%s", - 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("") + sb.WriteString(Conf.Clock.Separator.Left.Symbol) + sb.WriteString("") } - b.FullText += fmt.Sprintf( - "%s", - Conf.Clock.Color, - Conf.Clock.Background, - Conf.Clock.Font, - Conf.Clock.FontSize, - Conf.Values.ClockTime, - ) + sb.WriteString("") + sb.WriteString(Conf.Values.ClockTime) + sb.WriteString("") if Conf.Clock.Separator.Right.Enabled { - b.FullText += fmt.Sprintf( - "%s", - 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("") + sb.WriteString(Conf.Clock.Separator.Right.Symbol) + sb.WriteString("") } + b.FullText = sb.String() b.Markup = "pango" b.Separator = false diff --git a/internal/lib/batteries.go b/internal/lib/batteries.go index 54944d9..fe9993c 100644 --- a/internal/lib/batteries.go +++ b/internal/lib/batteries.go @@ -1,3 +1,4 @@ +// Package lib represents guts of i3status-go. package lib import ( diff --git a/internal/lib/collection.go b/internal/lib/collection.go index 6a9cba3..debb4ff 100644 --- a/internal/lib/collection.go +++ b/internal/lib/collection.go @@ -4,16 +4,18 @@ import ( "sync" ) -// Collection is sync.Map, that stores arbitrary data. -type Collection struct { - items sync.Map - close chan struct{} -} +type ( + // Collection is sync.Map, that stores arbitrary data. + Collection struct { + close chan struct{} + items sync.Map + } -// Item just interface for stoing any data. -type item struct { - data any -} + // Item just interface for stoing any data. + item struct { + data any + } +) // NewCollection creates new instance of "collection". func NewCollection() *Collection { @@ -44,7 +46,7 @@ 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) @@ -63,6 +65,7 @@ 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{} } diff --git a/internal/lib/config.go b/internal/lib/config.go index 4f8379d..b9ce7f9 100644 --- a/internal/lib/config.go +++ b/internal/lib/config.go @@ -14,266 +14,281 @@ import ( p "github.com/mafik/pulseaudio" ) -// I3BarOutBlock is structure element for I3BarOut, it represents i3bar output json block format. -type I3BarOutBlock struct { - FullText string `json:"full_text"` - // 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 :) - MinWidth string `json:"min_width,omitempty"` - Align string `json:"align,omitempty"` - Name string `json:"name,omitempty"` - Instance string `json:"instance,omitempty"` - Urgent bool `json:"urgent,omitempty"` - Separator bool `json:"separator"` - SeparatorBlockWidth int `json:"separator_block_width"` - Markup string `json:"markup,omitempty"` -} +type ( + // I3BarOutBlock is structure element for I3BarOut, it represents i3bar output json block format. + I3BarOutBlock struct { + FullText string `json:"full_text"` + // 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 :) . + MinWidth string `json:"min_width,omitempty"` + Align string `json:"align,omitempty"` + Name string `json:"name,omitempty"` + Instance string `json:"instance,omitempty"` + Urgent bool `json:"urgent,omitempty"` + Separator bool `json:"separator"` + SeparatorBlockWidth int `json:"separator_block_width"` + Markup string `json:"markup,omitempty"` + } -type Separator struct { - Left struct { - Enabled bool `json:"enabled,omitempty"` - Color string `json:"color,omitempty"` + // Separator usually is a bymbol that separates fields in i3 status string. + Separator struct { + Left struct { + 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"` + Enabled bool `json:"enabled,omitempty"` + } `json:"left"` + + Right struct { + 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"` + Enabled bool `json:"enabled,omitempty"` + } `json:"right"` + } + + // MyConfig internal represetation of running config state. + MyConfig struct { + Values struct { + PrintOutput bool + CPUTemperature int64 + BatteryString string + ClockTime string + IfStatus string + VPNStatus string + Memory Mem + La string + PA *p.Client + SoundVolume string + RunCommandOutput string + } + + Channels struct { + UpdateReady chan bool + MsgChan chan []I3BarOutBlock + SigChan chan os.Signal + SVPAHandlerChan chan ClickEvent + RunChan chan []string + } + + // Color default text color. + Color string `json:"color,omitempty"` + + // Background default background color. Background string `json:"background,omitempty"` - Symbol string `json:"symbol,omitempty"` - Font string `json:"font,omitempty"` - FontSize string `json:"font_size,omitempty"` - } `json:"left,omitempty"` - 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"` -} + // Font default text font. + Font string `json:"font,omitempty"` -type MyConfig struct { - Values struct { - PrintOutput bool - CPUTemperature int64 - BatteryString string - ClockTime string - IfStatus string - VPNStatus string - Memory Mem - La string - PA *p.Client - SoundVolume string - RunCommandOutput string + // FontSize default text font size. + FontSize string `json:"font_size,omitempty"` + + // Separator i3status string separator configuration. + Separator Separator `json:"separator"` + + // LA Plugin. + LA 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"` + } `json:"la"` + + // Mem plugin. + Mem 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"` + ShowSwap bool `json:"show_swap,omitempty"` + Separator Separator `json:"separator,omitempty"` + } `json:"mem"` + + // Clock plugin. + Clock 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"` + + LeftClick struct { + Enabled bool `json:"enabled,omitempty"` + Cmd []string `json:"cmd,omitempty"` + } `json:"left_click"` + + RightClick struct { + Enabled bool `json:"enabled,omitempty"` + Cmd []string `json:"cmd,omitempty"` + } `json:"right_click"` + } `json:"clock"` + + // Battery plugin. + Battery struct { + Enabled bool `json:"enabled,omitempty"` + UseSysfs bool `json:"use_sysfs,omitempty"` + SysfsFiles []string `json:"sysfs_files,omitempty"` + Color string `json:"color,omitempty"` + Background string `json:"background,omitempty"` + Font string `json:"font,omitempty"` + FontSize string `json:"font_size,omitempty"` + Symbol string `json:"symbol,omitempty"` + SymbolFont string `json:"symbol_font,omitempty"` + SymbolFontSize string `json:"symbol_font_size,omitempty"` + + ChargeColor struct { + Full string `json:"full,omitempty"` + Empty string `json:"empty,omitempty"` + AlmostFull string `json:"almost_full,omitempty"` + AlmostEmpty string `json:"almost_empty,omitempty"` + } `json:"charge_color"` + + Separator Separator `json:"separator,omitempty"` + } `json:"battery"` + + // CPUTemp plugin. + CPUTemp 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"` + + File []string `json:"file,omitempty"` + } `json:"cpu_temp"` + + // Vpn plugin. + Vpn 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"` + StatusFile string `json:"statusFile,omitempty"` + MtimeThreshold int `json:"mtime_threshold,omitempty"` + DownColor string `json:"down_color,omitempty"` + UpColor string `json:"up_color,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"` + } `json:"vpn"` + + // SimpleVolumePa plugin. + SimpleVolumePa 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"` + Symbol string `json:"symbol,omitempty"` + SymbolFont string `json:"symbol_font,omitempty"` + SymbolFontSize string `json:"symbol_font_size,omitempty"` + DontExitOnLogin bool `json:"dont_exit_on_login,omitempty"` + Separator Separator `json:"separator,omitempty"` + + Step int `json:"step,omitempty"` + RightClickCmd []string `json:"right_click_cmd,omitempty"` + WheelUp int `json:"wheel_up,omitempty"` + WheelDown int `json:"wheel_down,omitempty"` + MaxVolumeLimit int `json:"max_volume_limit,omitempty"` + } `json:"simple-volume-pa"` + + // NrtIf plugin. + NetIf struct { + Enabled bool `json:"enabled,omitempty"` + DownColor string `json:"down_color,omitempty"` + UpColor string `json:"up_color,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"` + + If []struct { + Name string `json:"name,omitempty"` + Dir string `json:"dir,omitempty"` + } `json:"if"` + } `json:"net-if"` + + // Cron plugin. + Cron struct { + Enabled bool `json:"enabled,omitempty"` + TimeZone string `json:"timezone,omitempty"` + + Tasks []struct { + Time string `json:"time,omitempty"` + Cmd []string `json:"cmd,omitempty"` + } `json:"tasks"` + } `json:"cron"` + + // CmdRun plugin. + CmdRun struct { + Color string `json:"color,omitempty"` + Background string `json:"background,omitempty"` + Font string `json:"font,omitempty"` + FontSize string `json:"font_size,omitempty"` + Cmd string `json:"cmd,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"` + + // Apps descriptions for AppButtons plugin. + Apps []struct { + FullText string `json:"full_text,omitempty"` + Name string `json:"name,omitempty"` + Cmd string `json:"cmd,omitempty"` + Args []string `json:"args,omitempty"` + Instance string `json:"instance,omitempty"` + 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"` } +) - Channels struct { - UpdateReady chan bool - MsgChan chan []I3BarOutBlock - SigChan chan os.Signal - SVPAHandlerChan chan ClickEvent - RunChan chan []string - } - - // Default text color - Color string `json:"color,omitempty"` - - // Default background color - Background string `json:"background,omitempty"` - - // Default text font - Font string `json:"font,omitempty"` - - // Default text font size - FontSize string `json:"font_size,omitempty"` - - Separator Separator `json:"separator,omitempty"` - - // LA Plugin - LA 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"` - } `json:"la,omitempty"` - - // Mem plugin - Mem 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"` - ShowSwap bool `json:"show_swap,omitempty"` - Separator Separator `json:"separator,omitempty"` - } `json:"mem,omitempty"` - - Clock 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"` - - LeftClick struct { - Enabled bool `json:"enabled,omitempty"` - Cmd []string `json:"cmd,omitempty"` - } `json:"left_click,omitempty"` - - RightClick struct { - Enabled bool `json:"enabled,omitempty"` - Cmd []string `json:"cmd,omitempty"` - } `json:"right_click,omitempty"` - } `json:"clock,omitempty"` - - Battery struct { - Enabled bool `json:"enabled,omitempty"` - UseSysfs bool `json:"use_sysfs,omitempty"` - SysfsFiles []string `json:"sysfs_files,omitempty"` - Color string `json:"color,omitempty"` - Background string `json:"background,omitempty"` - Font string `json:"font,omitempty"` - FontSize string `json:"font_size,omitempty"` - Symbol string `json:"symbol,omitempty"` - SymbolFont string `json:"symbol_font,omitempty"` - SymbolFontSize string `json:"symbol_font_size,omitempty"` - - ChargeColor struct { - Full string `json:"full,omitempty"` - Empty string `json:"empty,omitempty"` - AlmostFull string `json:"almost_full,omitempty"` - AlmostEmpty string `json:"almost_empty,omitempty"` - } `json:"charge_color,omitempty"` - - Separator Separator `json:"separator,omitempty"` - } `json:"battery,omitempty"` - - CPUTemp 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"` - - File []string `json:"file,omitempty"` - } `json:"cpu_temp,omitempty"` - - Vpn 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"` - StatusFile string `json:"statusFile,omitempty"` - MtimeThreshold int `json:"mtime_threshold,omitempty"` - DownColor string `json:"down_color,omitempty"` - UpColor string `json:"up_color,omitempty"` - Separator Separator `json:"separator,omitempty"` - - 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"` - - SimpleVolumePa 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"` - Symbol string `json:"symbol,omitempty"` - SymbolFont string `json:"symbol_font,omitempty"` - SymbolFontSize string `json:"symbol_font_size,omitempty"` - DontExitOnLogin bool `json:"dont_exit_on_login,omitempty"` - Separator Separator `json:"separator,omitempty"` - - Step int `json:"step,omitempty"` - RightClickCmd []string `json:"right_click_cmd,omitempty"` - WheelUp int `json:"wheel_up,omitempty"` - WheelDown int `json:"wheel_down,omitempty"` - MaxVolumeLimit int `json:"max_volume_limit,omitempty"` - } `json:"simple-volume-pa,omitempty"` - - NetIf struct { - Enabled bool `json:"enabled,omitempty"` - DownColor string `json:"down_color,omitempty"` - UpColor string `json:"up_color,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"` - - If []struct { - Name string `json:"name,omitempty"` - Dir string `json:"dir,omitempty"` - } `json:"if,omitempty"` - } `json:"net-if,omitempty"` - - Cron struct { - Enabled bool `json:"enabled,omitempty"` - TimeZone string `json:"timezone,omitempty"` - - Tasks []struct { - Time string `json:"time,omitempty"` - Cmd []string `json:"cmd,omitempty"` - } `json:"tasks,omitempty"` - } `json:"cron,omitempty"` - - 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"` - } - - AppButtons 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"` - } `json:"app_buttons,omitempty"` - - Apps []struct { - FullText string `json:"full_text,omitempty"` - Name string `json:"name,omitempty"` - Cmd string `json:"cmd,omitempty"` - Args []string `json:"args,omitempty"` - Instance string `json:"instance,omitempty"` - 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"` -} - -// 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 ( @@ -844,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( @@ -942,10 +957,10 @@ func ReadConf(defaultConfig []byte) (*MyConfig, error) { } } - // 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 + // 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 } @@ -1034,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 } @@ -1169,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 } @@ -1216,16 +1231,16 @@ func ReadConf(defaultConfig []byte) (*MyConfig, error) { } } - // Check status file at least once per 3 seconds + // 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 == "" { @@ -1317,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") @@ -1326,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") @@ -1343,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 } @@ -1540,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 @@ -1550,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 @@ -1690,7 +1705,7 @@ 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 @@ -1700,7 +1715,7 @@ func ReadConf(defaultConfig []byte) (*MyConfig, error) { ) } - // sampleConfig.CmdRun.Args can be empty + // sampleConfig.CmdRun.Args can be empty. if sampleConfig.CmdRun.Color == "" { sampleConfig.CmdRun.Color = sampleConfig.Color @@ -1830,7 +1845,7 @@ 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 } @@ -2023,8 +2038,8 @@ func ReadConf(defaultConfig []byte) (*MyConfig, error) { 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 == "" { sampleConfig.Apps[num].FullText = fmt.Sprintf(" %d ", num) } diff --git a/internal/lib/cputemp.go b/internal/lib/cputemp.go index 3bc6d22..a3a2dc3 100644 --- a/internal/lib/cputemp.go +++ b/internal/lib/cputemp.go @@ -41,6 +41,7 @@ func (c *MyConfig) UpdateCPUTemperature() { if err != nil { log.Printf("Unable to read from %s: %s", filename, err) + err = file.Close() if err != nil { diff --git a/internal/lib/cron.go b/internal/lib/cron.go index 0943814..0aae297 100644 --- a/internal/lib/cron.go +++ b/internal/lib/cron.go @@ -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() { diff --git a/internal/lib/i3.go b/internal/lib/i3.go index 51ea202..a0c62d5 100644 --- a/internal/lib/i3.go +++ b/internal/lib/i3.go @@ -105,9 +105,9 @@ func (c *MyConfig) I3EventParser(e *i3.WindowEvent) { // interfaceToUint превращает данный интерфейс в Uint64. // Если может, конечно :) . -func interfaceToUint64(iface interface{}) uint64 { - // А теперь мы начинаем дурдом, нам надо превратить ёбанный interface{} в []string - // Поскольку interface{} может быть чем угодно, перестрахуемся +func interfaceToUint64(iface any) uint64 { + // А теперь мы начинаем дурдом, нам надо превратить ёбанный any в []string. + // Поскольку any может быть чем угодно, перестрахуемся. if reflect.TypeOf(iface).Kind() == reflect.Uint64 { return reflect.ValueOf(iface).Uint() } diff --git a/internal/lib/pulseaudio.go b/internal/lib/pulseaudio.go index c8cd801..1b28a6c 100644 --- a/internal/lib/pulseaudio.go +++ b/internal/lib/pulseaudio.go @@ -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 { diff --git a/internal/lib/runcommand.go b/internal/lib/runcommand.go index 6548386..e90e7dc 100644 --- a/internal/lib/runcommand.go +++ b/internal/lib/runcommand.go @@ -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 diff --git a/internal/lib/spawn.go b/internal/lib/spawn.go index 3ae17b2..b9f2eee 100644 --- a/internal/lib/spawn.go +++ b/internal/lib/spawn.go @@ -59,7 +59,7 @@ func (c *MyConfig) CleanZombies() { } } -// 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 ( diff --git a/internal/lib/stdin.go b/internal/lib/stdin.go index f6b69ec..76d7fea 100644 --- a/internal/lib/stdin.go +++ b/internal/lib/stdin.go @@ -116,6 +116,7 @@ func (c *MyConfig) ParseStdin() { break } + case app.Name != "" && e.Name == app.Name: prg := append([]string{}, app.Cmd) prg = append(prg, app.Args...) diff --git a/internal/lib/vpn.go b/internal/lib/vpn.go index 9a41d04..36a0ac3 100644 --- a/internal/lib/vpn.go +++ b/internal/lib/vpn.go @@ -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(`⍋`, c.Vpn.UpColor) + b.WriteString("⍋") } } else { if c.Vpn.DownColor == "" { - vpnCheck = `⍒` + b.WriteRune('⍒') } else { - vpnCheck = fmt.Sprintf(`⍒`, c.Vpn.DownColor) + b.WriteString("⍒") } } + vpnCheck = b.String() + b.Reset() + if c.Vpn.TCPCheck.Enabled { if c.VPNTCPCheck() { if c.Vpn.UpColor == "" { - tcpCheck = `✔` + b.WriteRune('✔') } else { - tcpCheck = fmt.Sprintf(`✔`, c.Vpn.UpColor) + b.WriteString("✔") } } else { if c.Vpn.DownColor == "" { - tcpCheck = `✘` + b.WriteRune('✘') } else { - tcpCheck = fmt.Sprintf(`✘`, c.Vpn.DownColor) + b.WriteString("✘") } } - 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),