Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
burik666 committed Feb 4, 2018
1 parent b03ca7f commit d9b3aef
Show file tree
Hide file tree
Showing 14 changed files with 1,830 additions and 0 deletions.
674 changes: 674 additions & 0 deletions LICENSE

Large diffs are not rendered by default.

309 changes: 309 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,309 @@
# YaGoStatus
Yet Another i3status replacement written in Go.

## Installation

go get github.com/burik666/yagostatus
cp $GOPATH/src/github.com/burik666/yagostatus/yagostatus.yml ~/.config/i3/yagostatus.yml

Get the absolute path to the yagostatus binary:

$ echo $GOPATH/bin/yagostatus
/home/burik/go/bin/yagostatus


Replace `status_command` to `/home/burik/go/bin/yagostatus` in your i3 config file (`$GOPATH` in `status_command` is empty).

### Troubleshooting
Yagostatus outputs error messages in stderr, you can log them by redirecting stderr to a file.

`status_command /home/burik//go/bin/yagostatus 2> /tmp/yagostatus.log`

## Configuration

Yagostatus uses a configuration file in the yaml format.

Example:
```yml
widgets:
- widget: static
blocks: >
[
{
"full_text": "YaGoStatus",
"color": "#2e9ef4"
}
]
events:
- button: 1
command: xdg-open https://github.com/burik666/yagostatus/

- widget: wrapper
command: /usr/bin/i3status

- widget: clock
format: Jan _2 Mon 15:04:05 # https://golang.org/pkg/time/#Time.Format
template: >
{
"color": "#ffffff",
"separator": true,
"separator_block_width": 20
}
```
## Widgets
### Common parameters
- `widget` - Widget name.
- `template` - The template that is applied to the output of the widget.
- `events` - List of commands to be executed on user actions.
* `button` - X11 button ID (0 for any, 1 to 3 for left/middle/right mouse button. 4/5 for mouse wheel up/down. Default: `0`).
* `command` - Command to execute (via `sh -c`).
Сlick_event json will be written to stdin.
Also env variables are available: `$I3_NAME`, `$I3_INSTANCE`, `$I3_BUTTON`, `$I3_X`, `$I3_Y`.
* `output` - If `true` widget text will be replaced with the command output (default: `false`).
* `name` - Filter by `name` for widgets with multiple blocks (default: empty).
* `instance` - Filter by `instance` for widgets with multiple blocks (default: empty).

Example:
```yml
- widget: static
blocks: >
[
{
"full_text": "Firefox",
"name": "ff"
},
{
"full_text": "Chrome",
"name": "ch"
}
]
template: >
{
"color": "#0000ff"
}
events:
- button: 1
command: /usr/bin/firefox
name: ff
- button: 1
command: /usr/bin/chrome
name: ch
```


### Widget `clock`

The clock widget returns the current time in the specified format.

- `format` - Time format (https://golang.org/pkg/time/#Time.Format).
- `interval` - Clock update interval in seconds (default: `1`).


### Widget `exec`

This widget runs the command at the specified interval.

- `command` - Command to execute (via `sh -c`).
- `interval` - Update interval in seconds (set 0 to run once at start).
- `events_update` - Update widget if an event occurred (default: `false`).


### Widget `wrapper`

The wrapper widget starts the command and proxy received blocks (and click_events).
See: https://i3wm.org/docs/i3bar-protocol.html

- `command` - Command to execute.


### Widget `static`

The static widget renders the blocks. Useful for labels and buttons.

- `blocks` - JSON List of i3bar blocks.


### Widget `http`

The http widget starts http server and accept HTTP or Websocket requests.

- `listen` - Address and port for binding (example: `localhost:9900`).
- `path` - Path for receiving requests (example: `/mystatus/`).
Must be unique for multiple widgets with same `listen`.

For example, you can update the widget with the following command:

curl http://localhost:9900/mystatus/ -d '[{"full_text": "hello"}, {"full_text": "world"}]'

Send an empty array to clear:

curl http://localhost:9900/mystatus/ -d '[]'


## Examples

### Volume control
```yml
- widget: exec
command: |
res=($(amixer get Master|grep -Eo '\[[0-9]+%\] \[(on|off)\]'|head -n1|tr -d "[]"))
color="#ffffff"
if [ "${res[1]}" = "off" ]; then
color="#ff0000"
fi
echo -e '[{"full_text": "<span font_family=\"Symbola\">\xF0\x9F\x94\x8A</span> '${res[0]}'", "color": "'$color'"}]'
interval: 0
events_update: true
events:
- button: 1
command: amixer -q set Master toggle
- button: 4
command: amixer -q set Master 3%+
- button: 5
command: amixer -q set Master 3%-
template: >
{
"markup": "pango",
"separator": true,
"separator_block_width": 20
}
```

### Weather

To get access to weather API you need an APIID.
See https://openweathermap.org/appid for details.

Requires [jq](https://stedolan.github.com/jq/) for json parsing.

```yml
- widget: static
blocks: >
[
{
"full_text": "Weather:",
"color": "#2e9ef4",
"separator": false
}
]
- widget: exec
command: curl -s 'http://api.openweathermap.org/data/2.5/weather?q=London,uk&units=metric&appid=<APPID>'|jq .main.temp
interval: 300
template: >
{
"separator": true,
"separator_block_width": 20
}
```

### Conky

```yml
- widget: wrapper
command: /usr/bin/conky -c /home/burik/.config/i3/conky.conf
```
Specify the full path to `conky.conf`.

**conky.conf** (conky 1.10 or higher):
```lua
conky.config = {
out_to_x = false,
own_window = false,
out_to_console = true,
background = false,
max_text_width = 0,
-- Update interval in seconds
update_interval = 1.0,
-- This is the number of times Conky will update before quitting.
-- Set to zero to run forever.
total_run_times = 0,
-- Shortens units to a single character (kiB->k, GiB->G, etc.). Default is off.
-- short_units yes
-- Add spaces to keep things from moving about? This only affects certain objects.
-- use_spacer should have an argument of left, right, or none
use_spacer = 'left',
-- Force UTF8? note that UTF8 support required XFT
override_utf8_locale = false,
-- number of cpu samples to average
-- set to 1 to disable averaging
cpu_avg_samples = 3,
net_avg_samples = 3,
diskio_avg_samples = 3,
format_human_readable = true,
lua_load = '~/.config/i3/conky.lua',
};
conky.text = [[
[
{ "full_text": "CPU:", "color": "\#2e9ef4", "separator": false },
{ ${lua_parse cpu cpu1} , "min_width": "100%", "align": "right", "separator": false },
{ ${lua_parse cpu cpu2} , "min_width": "100%", "align": "right", "separator": false },
{ ${lua_parse cpu cpu3} , "min_width": "100%", "align": "right", "separator": false },
{ ${lua_parse cpu cpu4} , "min_width": "100%", "align": "right", "separator": true, "separator_block_width":20 },
{ "full_text": "RAM:", "color": "\#2e9ef4", "separator": false },
{ "full_text": "${mem} / ${memeasyfree}", "color": ${if_match ${memperc}<80}"\#ffffff"${else}"\#ff0000"${endif}, "separator": true, "separator_block_width":20 },
{ "full_text": "sda:", "color": "\#2e9ef4", "separator": false },
{ "full_text": "▼ ${diskio_read sda} ▲ ${diskio_write sda}", "color": "\#ffffff", "separator": true, "separator_block_width":20 },
{ "full_text": "eth0:", "color": "\#2e9ef4", "separator": false },
{ "full_text": "▼ ${downspeed eth0} ▲ ${upspeed eth0}", "color": "\#ffffff", "separator": true, "separator_block_width":20 }
]
]];
```


**conky.lua**:
```lua
function gradient_red(min, max, val)
local min = tonumber(min)
local max = tonumber(max)
local val = tonumber(val)
if (val > max) then val = max end
if (val < min) then val = min end
local v = val - min
local d = (max - min) * 0.5
local red, green
if (v <= d) then
red = math.floor((255 * v) / d + 0.5)
green = 255
else
red = 255
green = math.floor(255 - (255 * (v-d)) / (max - min - d) + 0.5)
end
return string.format("%02x%02x00", red, green)
end
function conky_cpu (cpun)
local val = tonumber(conky_parse("${cpu " .. cpun .. "}"))
if val == nil then val = 0 end
return "\"full_text\": \"" .. val .. "%\", \"color\": \"\\#" .. gradient_red(0, 100, val) .. "\""
end
```

## License

YaGoStatus is licensed under the GNU GPLv3 License.

76 changes: 76 additions & 0 deletions config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package main

import (
"encoding/json"
"errors"
"github.com/burik666/yagostatus/ygs"
"gopkg.in/yaml.v2"
"io/ioutil"
)

type tmpConfig struct {
Widgets []map[string]interface{} `yaml:"widgets"`
}

type Config struct {
Widgets []ConfigWidget
}

type ConfigWidgetEvent struct {
Command string `yaml:"command"`
Button uint8 `yaml:"button"`
Name string `yaml:"name,omitempty"`
Instance string `yaml:"instance,omitempty"`
Output bool `yaml:"output,omitempty"`
}

type ConfigWidget struct {
Name string
Params map[string]interface{}
Template ygs.I3BarBlock
Events []ConfigWidgetEvent
}

func loadConfig(filename string) (*Config, error) {
data, err := ioutil.ReadFile(filename)
if err != nil {
return nil, err
}

var t tmpConfig
if err := yaml.Unmarshal(data, &t); err != nil {
return nil, err
}

config := Config{}

for _, v := range t.Widgets {
widget := ConfigWidget{}

var ok bool
widget.Name, ok = v["widget"].(string)
if !ok {
return nil, errors.New("Missing widget name.")
}
delete(v, "widget")

tpl, ok := v["template"]
if ok {
if err := json.Unmarshal([]byte(tpl.(string)), &widget.Template); err != nil {
return nil, err
}
delete(v, "template")
}

events, ok := v["events"]
if ok {
ymlevents, _ := yaml.Marshal(events)
yaml.Unmarshal(ymlevents, &widget.Events)
delete(v, "events")
}

widget.Params = v
config.Widgets = append(config.Widgets, widget)
}
return &config, nil
}
Loading

0 comments on commit d9b3aef

Please sign in to comment.