Compare commits
25 commits
91ca8e12a4
...
92d1eea678
Author | SHA1 | Date | |
---|---|---|---|
92d1eea678 | |||
7f4bf7bb0f | |||
e6a72669ba | |||
8010714091 | |||
528cbb6200 | |||
ff21191f2d | |||
69918d3dfe | |||
9570461b13 | |||
bd5b314cf1 | |||
6f5f255b66 | |||
669707f14a | |||
e018c8f985 | |||
3074f55973 | |||
1ff912edff | |||
079c5d9526 | |||
ae102073b8 | |||
c341c9242a | |||
d0142a966b | |||
f17a160450 | |||
ae35c221fe | |||
deb43144aa | |||
0c03850eb5 | |||
c2b14eb8ef | |||
83171db72e | |||
1a478fca9e |
75 changed files with 1072 additions and 1633 deletions
70
README.MD
70
README.MD
|
@ -1,70 +0,0 @@
|
|||
# A selection of information output tools for dmenu
|
||||
|
||||
These are a selection of independant tools for displaying various information
|
||||
about system status in dmenu. Some of them i.e. `volurrme` have options (up, down, mute...)
|
||||
which are selectable options in dmenu.
|
||||
|
||||
## Tools
|
||||
- `pingclurrk` performs a single `ping` to a server and returns the response time
|
||||
- `batturry` shows the current battery level
|
||||
- `brightnurrs` shows the current backlight level and gives options to adjust it
|
||||
- `volurrme` shows the current volume level and gives options to adjust and manage it
|
||||
- `calendurr` shows the date
|
||||
- `furrytime` shows the fuzzytime clock
|
||||
- `wirelurrs` shows the state of the wireless network interface. SSID connected to and signal level.
|
||||
- `netwurrk` shows the status and/or the ip address of the network interface card
|
||||
- `temperaturr` shows the current CPU temperature
|
||||
- `noteurr` a simple one liner note taking tool, displaying notes in `dmenu`/`rofi`
|
||||
- `calculaturr` a calculator, utilising `qalculate` - inspired by [@fedops](https://codeberg.org/fedops/scripts)
|
||||
- `emurrji` an emoji picker
|
||||
- `remmina_choosurr` reads the files in your remmina config directory and allows you to connect to and edit them
|
||||
- `translaturr` utilises libretranslate (you'll need and API key or your own instance) to translate test. Prefix the text with `en>de`, `de>en`, `en>fr`, etc. as you need. Must be compiled with `-d:ssl`
|
||||
- `clipurr` clipboard manager
|
||||
- `passwuurd` a passmenu clone, that works in rofi too
|
||||
- `cmd_wrappurr` a basic tool to run other `dmenu` related tools with uniform styling.
|
||||
- For example: `dmenu_run`, `clipmenu`, `passmenu` etc.
|
||||
|
||||
### Why do all the tools have "urr" in them?
|
||||
This is something I was inspired to do after writing `clipurr`… "purr", like a cat... see?
|
||||
So I thought I'd rename everything else to conform to this amazing naming convention… cool eh‽
|
||||
|
||||
|
||||
## How to compile
|
||||
There are some configuration variables explicit to me, you'll need to change them for you for them to be useful I imagine.
|
||||
Configuration variables are compile - there are no config files or runtime parameters
|
||||
|
||||
Each tool is compiled separately, for example:
|
||||
```sh
|
||||
nimble install
|
||||
or
|
||||
nim c pingclurrk
|
||||
```
|
||||
|
||||
and then run with
|
||||
```sh
|
||||
./pingclurrk
|
||||
or
|
||||
./pingclurrk rofi
|
||||
```
|
||||
|
||||
## How to use
|
||||
Personally, I have these bound to key combinations in i3 and sway.
|
||||
In fact, I have a seperate `bindsym` mode in which all these
|
||||
tools are accessible i.e. `$mod+i` to get to "info" mode then `p` to show pingclock.
|
||||
It's completely up to you how to run them, they're just simple CLI tools.
|
||||
|
||||
### You can also set the volume and brightness levels by typing a numeric figure into the dmenu/rofi input box
|
||||
|
||||
## Dependencies
|
||||
- `dmenu` or `rofi`
|
||||
- `yad` for calendar
|
||||
- basically any tool that's used to gather the information.
|
||||
- "tools" for audio etc. (`pamixer`, `ncpamixer`, etc.) can be set in the source
|
||||
|
||||
## Full disclosure
|
||||
I'm aware my code is messy.
|
||||
I'm aware my code is mostly undocumented.
|
||||
But hopefully these things are simple enough to work out.
|
||||
|
||||
|
||||
<a href="https://notnull.click/users/paul" rel="me">Fediverse</a>
|
|
@ -1,13 +0,0 @@
|
|||
# Package
|
||||
|
||||
version = "0.1.0"
|
||||
author = "Paul Wilde"
|
||||
description = "Clipboard manager for X11 or Wayland"
|
||||
license = "MIT"
|
||||
srcDir = "src"
|
||||
bin = @["clipurr"]
|
||||
|
||||
|
||||
# Dependencies
|
||||
|
||||
requires "nim >= 1.6.6"
|
|
@ -1,184 +0,0 @@
|
|||
import ../../globurrl
|
||||
import std/[strutils,os,db_sqlite,osproc]
|
||||
|
||||
const CLIP_DB = WM_TOOLS_DIR & "clipurr_cache.sqlite"
|
||||
const KEEP_ITEMS = 15
|
||||
|
||||
proc openDBConn(): DBConn
|
||||
|
||||
proc addClip(str: var string)
|
||||
|
||||
proc killOldRunningProcesses() =
|
||||
let x = execCmdEx("killall wl-paste clipnotify")
|
||||
echo x
|
||||
|
||||
|
||||
proc runDaemon() =
|
||||
echo "Starting Daemon..."
|
||||
if wayland:
|
||||
echo "Using Wl-paste"
|
||||
let cwd = getAppDir()
|
||||
let outp = execProcess("wl-paste -n -w " & cwd & "/clipurr set")
|
||||
else:
|
||||
var run = true
|
||||
while run:
|
||||
# TODO;
|
||||
# Check if WM is running otherwise the TTY will be spammed with "Using Clipnotify" text
|
||||
if XisRunning():
|
||||
echo "Using Clipnotify"
|
||||
let outp = execCmdEx("clipnotify")
|
||||
if outp.exitcode == 0:
|
||||
var content = getCurrentClipboardContent()
|
||||
addClip(content)
|
||||
|
||||
echo "Exiting Daemon..."
|
||||
|
||||
proc openDBConn(): DBConn =
|
||||
let db: DBconn = open(CLIP_DB,"","","")
|
||||
try:
|
||||
db.exec(sql"""create table if not exists
|
||||
clip_items (
|
||||
timestamp DATETIME NOT NULL,
|
||||
clip NVARCHAR(500) NOT NULL
|
||||
)
|
||||
""")
|
||||
except:
|
||||
echo getCurrentExceptionMsg()
|
||||
return db
|
||||
|
||||
proc clearHistory() =
|
||||
let db = openDBConn()
|
||||
|
||||
try:
|
||||
db.exec(sql"drop table if exists clip_items")
|
||||
except:
|
||||
echo getCurrentExceptionMsg()
|
||||
|
||||
proc maintainDB() =
|
||||
return # order by and offset doesn't work unless certain sqlite compile time options set
|
||||
# will create a different way to do this
|
||||
try:
|
||||
let db = openDBConn()
|
||||
defer: db.close()
|
||||
db.exec(sql"""BEGIN""")
|
||||
db.exec(sql"delete from clip_items order by timestamp desc offset ?", KEEP_ITEMS)
|
||||
db.exec(sql"""COMMIT""")
|
||||
except:
|
||||
echo "Error cleaning DB : " & getCurrentExceptionMsg()
|
||||
|
||||
proc escapeClip(str: string): string =
|
||||
var clip = str
|
||||
clip = clip.replace("`","\\`")
|
||||
clip = clip.replace("\\n`","\\\\n`")
|
||||
clip = clip.replace("\x0A","\\x0A")
|
||||
clip = escape(clip)
|
||||
echo "CLIP : ", clip
|
||||
return strip(clip)
|
||||
|
||||
proc unescapeClip(str: string): string =
|
||||
var clip = str
|
||||
try:
|
||||
clip = unescape(clip)
|
||||
if contains(clip,"\\x0A"):
|
||||
echo "NEWLINE FOUND"
|
||||
let idx = find(clip, "\\x0A") - 1
|
||||
clip = clip[0 .. idx] & " ... more ..."
|
||||
except:
|
||||
echo getCurrentExceptionMsg()
|
||||
|
||||
return strip(clip)
|
||||
|
||||
proc readClipFile(): seq[string] =
|
||||
var clips: seq[string] = @[]
|
||||
# let db = openDBConn()
|
||||
try:
|
||||
let db = openDBConn()
|
||||
defer: db.close()
|
||||
for row in db.fastRows(sql"select distinct(clip) from clip_items order by timestamp desc LIMIT ?", KEEP_ITEMS):
|
||||
var str = unescapeClip(row[0])
|
||||
clips.add(str)
|
||||
except:
|
||||
echo "Error Reading Clip File : " & getCurrentExceptionMsg()
|
||||
return clips
|
||||
|
||||
proc addClip(str: var string) =
|
||||
if str == "":
|
||||
return
|
||||
elif str[0] == '\x89':
|
||||
var t = str[1..3]
|
||||
echo "Is a ", $t, " file , not storing"
|
||||
str = "[" & t & " Image] (not stored)"
|
||||
try:
|
||||
str = escapeClip(str)
|
||||
echo "clipboard content : ", str
|
||||
let db = openDBConn()
|
||||
defer: db.close()
|
||||
db.exec(sql"""BEGIN""")
|
||||
db.exec(sql"""insert into clip_items (timestamp, clip)
|
||||
values (CURRENT_TIMESTAMP, ?)
|
||||
""", str)
|
||||
db.exec(sql"""COMMIT""")
|
||||
except:
|
||||
echo getCurrentExceptionMsg()
|
||||
return
|
||||
|
||||
proc getFullClipboardContent(str: string): string =
|
||||
var full = ""
|
||||
try:
|
||||
let db = openDBConn()
|
||||
defer: db.close()
|
||||
let text = "\"" & replace(str," ... more ...", "%") & "\""
|
||||
let stmt = """
|
||||
select clip
|
||||
from clip_items
|
||||
where clip like ?
|
||||
order by timestamp desc
|
||||
LIMIT 1"""
|
||||
var prep = db.prepare(stmt)
|
||||
prep.bindParams(text)
|
||||
let res = db.getAllRows(prep)
|
||||
for r in res:
|
||||
# may need to switch to a getRow or getValue method here as this is messy
|
||||
full = unescape(r[0])
|
||||
full = replace(full, "\\x0A","\x0A")
|
||||
break
|
||||
finalize(prep)
|
||||
except:
|
||||
echo "Error Reading Clip File : " & getCurrentExceptionMsg()
|
||||
|
||||
|
||||
return full
|
||||
|
||||
proc showClips() =
|
||||
let clips = readClipFile()
|
||||
let info = newInfo("Clipurr")
|
||||
let option = outputData(info, clips)
|
||||
if option != "":
|
||||
if contains(option, "... more ..."):
|
||||
let full = getFullClipboardContent(option)
|
||||
copyToClipboard(full)
|
||||
else:
|
||||
copyToClipboard(option)
|
||||
return
|
||||
|
||||
proc main() =
|
||||
for idx, arg in args:
|
||||
if arg == "daemon":
|
||||
killOldRunningProcesses()
|
||||
runDaemon()
|
||||
return
|
||||
if arg == "set":
|
||||
var content = getCurrentClipboardContent()
|
||||
addClip(content)
|
||||
return
|
||||
if arg == "clear":
|
||||
clearHistory()
|
||||
return
|
||||
showClips()
|
||||
return
|
||||
|
||||
block start:
|
||||
if isMainModule:
|
||||
main()
|
||||
|
||||
maintainDB()
|
|
@ -1,13 +0,0 @@
|
|||
# Package
|
||||
|
||||
version = "0.1.0"
|
||||
author = "Paul Wilde"
|
||||
description = "Displays open windows in i3 workspaces"
|
||||
license = "MIT"
|
||||
srcDir = "src"
|
||||
bin = @["i3_wurrkspaces"]
|
||||
|
||||
|
||||
# Dependencies
|
||||
|
||||
requires "nim >= 1.6.6"
|
|
@ -1,173 +0,0 @@
|
|||
import ../../globurrl
|
||||
import std/[osproc,json,strutils]
|
||||
|
||||
const I3_WORKSPACES = "i3-msg -t get_workspaces"
|
||||
const SWAY_WORKSPACES = "swaymsg -t get_workspaces"
|
||||
let WORKSPACES = if wayland: SWAY_WORKSPACES else: I3_WORKSPACES
|
||||
const I3_TREE = "i3-msg -t get_tree"
|
||||
const SWAY_TREE = "swaymsg -t get_tree"
|
||||
let TREE = if wayland: SWAY_TREE else: I3_TREE
|
||||
const VISIBLE = "#"
|
||||
const URGENT = "!"
|
||||
const FOCUSED = "%"
|
||||
|
||||
type
|
||||
Workspace = object
|
||||
num: int
|
||||
name: string
|
||||
focused: bool
|
||||
visible: bool
|
||||
output: string
|
||||
urgent: bool
|
||||
display_string: string
|
||||
apps: seq[string]
|
||||
applications: seq[Application]
|
||||
application: Application
|
||||
Application = object
|
||||
title: string
|
||||
class: string
|
||||
focused: bool
|
||||
urgent: bool
|
||||
|
||||
var my_workspaces: seq[Workspace]
|
||||
var current_workspace: int = 0
|
||||
|
||||
proc showWorkspaces()
|
||||
|
||||
proc buildString(ws: Workspace): string =
|
||||
var str = $ws.num & " |"
|
||||
# if ws.urgent or ws.application.urgent:
|
||||
if ws.application.urgent:
|
||||
str &= URGENT
|
||||
else:
|
||||
str &= " "
|
||||
if ws.focused or ws.application.focused:
|
||||
current_workspace = ws.num
|
||||
str &= FOCUSED
|
||||
# elif ws.visible:
|
||||
# str &= VISIBLE
|
||||
else:
|
||||
str &= " "
|
||||
str &= "| " & ws.output & " | "
|
||||
if ws.application.class != "":
|
||||
str &= ws.application.class & " " & ws.application.title & " | "
|
||||
else:
|
||||
str = ""
|
||||
# for app in ws.applications:
|
||||
# str &= app.class & " " & app.title & " | "
|
||||
return str
|
||||
|
||||
proc findWorkspace(workspace: string): Workspace =
|
||||
for ws in my_workspaces:
|
||||
if workspace == ws.display_string:
|
||||
return ws
|
||||
|
||||
proc switchWorkspace(workspace: string) =
|
||||
if workspace.contains("%"):
|
||||
return
|
||||
let ws = findWorkspace(workspace)
|
||||
if ws.num == current_workspace:
|
||||
return
|
||||
if wayland:
|
||||
let cmd = "swaymsg workspace " & $ws.num
|
||||
discard execCmd(cmd)
|
||||
else:
|
||||
let cmd = "i3-msg workspace " & $ws.num
|
||||
discard execCmd(cmd)
|
||||
showWorkspaces()
|
||||
|
||||
proc getApplication(node: JsonNode, ws: Workspace = Workspace()): Application =
|
||||
var app = Application()
|
||||
let window = node["window_properties"]
|
||||
app.title = window["title"].getStr()
|
||||
app.class = window["class"].getStr()
|
||||
app.focused = node["focused"].getBool()
|
||||
app.urgent = node["urgent"].getBool()
|
||||
#echo ws.num
|
||||
#echo app.title & " " & app.class
|
||||
return app
|
||||
|
||||
proc newWorkspace(node: JsonNode): Workspace =
|
||||
return Workspace(
|
||||
num: node["num"].getInt(),
|
||||
name: node["name"].getStr(),
|
||||
focused: node["focused"].getBool(),
|
||||
#visible: w["visible"].getBool(),
|
||||
urgent: node["urgent"].getBool(),
|
||||
output: node["output"].getStr(),
|
||||
)
|
||||
|
||||
proc findWorkspacesTree(node: JsonNode, parent: Workspace = Workspace()) =
|
||||
for channel in node["nodes"].getElems():
|
||||
### move this into for loop if want separate entry per window
|
||||
var ws: Workspace = Workspace()
|
||||
if parent.num > 0:
|
||||
ws = parent
|
||||
elif node{"type"}.getStr() == "workspace":
|
||||
if node["output"].getStr() == "__i3":
|
||||
return
|
||||
ws = newWorkspace(node)
|
||||
echo ws
|
||||
###
|
||||
echo channel
|
||||
if channel{"window_properties"} != nil:
|
||||
#or (wayland and `something that is the same as window_properties'):
|
||||
let app = getApplication(channel,ws)
|
||||
echo app
|
||||
if ws.name != "":
|
||||
#if app.focused:
|
||||
# ws.focused = true
|
||||
ws.applications.add(app)
|
||||
ws.application = app
|
||||
elif ws.num > 0 and len(channel{"nodes"}) > 0:
|
||||
findWorkspacesTree(channel,ws)
|
||||
else:
|
||||
findWorkspacesTree(channel)
|
||||
### move this into for loop if want separate entry per window
|
||||
if ws.name != "":
|
||||
ws.display_string = ws.buildString()
|
||||
if ws.display_string != "":
|
||||
my_workspaces.add(ws)
|
||||
###
|
||||
return
|
||||
|
||||
proc getTree() =
|
||||
let cur_workspaces = execCmdEx(TREE)
|
||||
if cur_workspaces.output != "":
|
||||
let root = parseJson(cur_workspaces.output)
|
||||
findWorkspacesTree(root)
|
||||
return
|
||||
|
||||
proc getWorkspaces(): seq[Workspace] =
|
||||
let cur_workspaces = execCmdEx(WORKSPACES)
|
||||
if cur_workspaces.output != "":
|
||||
let ws = parseJson(cur_workspaces.output)
|
||||
for w in ws:
|
||||
var space = Workspace(
|
||||
num: w["num"].getInt(),
|
||||
name: w["name"].getStr(),
|
||||
focused: w["focused"].getBool(),
|
||||
visible: w["visible"].getBool(),
|
||||
urgent: w["urgent"].getBool(),
|
||||
output: w["output"].getStr()
|
||||
)
|
||||
space.display_string = buildString(space)
|
||||
my_workspaces.add(space)
|
||||
return my_workspaces
|
||||
|
||||
proc showWorkspaces() =
|
||||
my_workspaces = @[]
|
||||
getTree()
|
||||
var info = newInfo("Wurrkspaces")
|
||||
var args: seq[string] = @[]
|
||||
for ws in my_workspaces:
|
||||
args.add(ws.display_string)
|
||||
let output = outputData(info,args)
|
||||
if output in args:
|
||||
switchWorkspace(output)
|
||||
|
||||
proc main() =
|
||||
showWorkspaces()
|
||||
|
||||
if isMainModule:
|
||||
main()
|
|
@ -1,13 +0,0 @@
|
|||
# Package
|
||||
|
||||
version = "0.1.0"
|
||||
author = "Paul Wilde"
|
||||
description = "Shows battery percentage using dmenu"
|
||||
license = "MIT"
|
||||
srcDir = "src"
|
||||
bin = @["batturry"]
|
||||
|
||||
|
||||
# Dependencies
|
||||
|
||||
requires "nim >= 1.6.6"
|
|
@ -1,13 +0,0 @@
|
|||
# Package
|
||||
|
||||
version = "0.1.0"
|
||||
author = "Paul Wilde"
|
||||
description = "Shows and controls laptop brightness"
|
||||
license = "MIT"
|
||||
srcDir = "src"
|
||||
bin = @["brightnurrs"]
|
||||
|
||||
|
||||
# Dependencies
|
||||
|
||||
requires "nim >= 1.6.6"
|
|
@ -1,116 +0,0 @@
|
|||
import ../../globurrl
|
||||
import std/[os,strutils,osproc,math]
|
||||
|
||||
const backlight = "intel_backlight"
|
||||
const default_bg = yellow
|
||||
const default_fg = black
|
||||
const BACKLIGHT_CMD = "xbacklight"
|
||||
const UP_X = BACKLIGHT_CMD & " -inc %v" # %v is amount by
|
||||
const DOWN_X = BACKLIGHT_CMD & " -dec %v" # %v is amount by
|
||||
const SET_X = BACKLIGHT_CMD & " -set %v" # %v is amount by
|
||||
const BACKLIGHT_CMD_WL = "brightnessctl"
|
||||
const UP_WL = BACKLIGHT_CMD_WL & " set %v%+"
|
||||
const DOWN_WL = BACKLIGHT_CMD_WL & " set %v%-"
|
||||
const SET_WL = BACKLIGHT_CMD_WL & " set %v%"
|
||||
var CMD = BACKLIGHT_CMD
|
||||
var UP = UP_X
|
||||
var DOWN = DOWN_X
|
||||
var SET = SET_X
|
||||
const default_value = "5"
|
||||
|
||||
proc getLimit(): int =
|
||||
try:
|
||||
let back_l = readFile("/sys/class/backlight/" & backlight & "/max_brightness")
|
||||
return parseInt(strip(back_l))
|
||||
except:
|
||||
echo "Error getting backlight max : ", getCurrentExceptionMsg()
|
||||
return -1
|
||||
|
||||
let limit = getLimit()
|
||||
|
||||
proc getDesign(pcnt: float): string =
|
||||
var icon = "🌑"
|
||||
case pcnt:
|
||||
of 85..100:
|
||||
icon = "🌕"
|
||||
of 75..85:
|
||||
icon = "🌖"
|
||||
of 50..75:
|
||||
icon = "🌗"
|
||||
of 35..50:
|
||||
icon = "🌘"
|
||||
else:
|
||||
icon = "🌑"
|
||||
let percent = toInt(round(pcnt,0))
|
||||
let text = icon & " " & $percent & "%"
|
||||
return text
|
||||
|
||||
proc brightnessUp() =
|
||||
let cmd = replace(UP,"%v",default_value)
|
||||
discard execCmd(cmd)
|
||||
proc brightnessDown() =
|
||||
let cmd = replace(DOWN,"%v",default_value)
|
||||
discard execCmd(cmd)
|
||||
|
||||
proc getBrightness*(run_once: bool = false) =
|
||||
var last_pcnt: float = 0
|
||||
while true:
|
||||
let current = parseInt(strip(readFile("/sys/class/backlight/" & backlight & "/actual_brightness")))
|
||||
let pcnt = (current/limit)*100
|
||||
if pcnt != last_pcnt:
|
||||
let text = getDesign(pcnt)
|
||||
var data = newInfo("Brightnurrs")
|
||||
data.full_text = text
|
||||
data.selected_bg = default_fg
|
||||
data.selected_fg = default_bg
|
||||
# i3bar stuff
|
||||
data.border = default_fg
|
||||
let args = @["up", "down"]
|
||||
let option = outputData(data,args)
|
||||
if option in args:
|
||||
case option:
|
||||
of "up":
|
||||
brightnessUp()
|
||||
getBrightness(true)
|
||||
of "down":
|
||||
brightnessDown()
|
||||
getBrightness(true)
|
||||
else:
|
||||
try:
|
||||
let i = parseInt(option)
|
||||
let cmd = replace(SET,"%v",$i)
|
||||
discard execCmd(cmd)
|
||||
getBrightness(true)
|
||||
except:
|
||||
echo getCurrentExceptionMsg()
|
||||
|
||||
if run_once:
|
||||
break
|
||||
if stoploop:
|
||||
break
|
||||
last_pcnt = pcnt
|
||||
sleep(1000)
|
||||
|
||||
proc main() =
|
||||
if limit == -1:
|
||||
switchTwmMode()
|
||||
return
|
||||
getBrightness()
|
||||
|
||||
if isMainModule:
|
||||
block start:
|
||||
if wayland:
|
||||
CMD = BACKLIGHT_CMD_WL
|
||||
UP = UP_WL
|
||||
DOWN = DOWN_WL
|
||||
SET = SET_WL
|
||||
for arg in args:
|
||||
case arg:
|
||||
of "up":
|
||||
brightnessUp()
|
||||
break start
|
||||
of "down":
|
||||
brightnessDown()
|
||||
break start
|
||||
|
||||
main()
|
|
@ -1,13 +0,0 @@
|
|||
# Package
|
||||
|
||||
version = "0.1.0"
|
||||
author = "Paul Wilde"
|
||||
description = "A simple dmenu calculator"
|
||||
license = "MIT"
|
||||
srcDir = "src"
|
||||
bin = @["calculaturr"]
|
||||
|
||||
|
||||
# Dependencies
|
||||
|
||||
requires "nim >= 1.6.6"
|
|
@ -1,13 +0,0 @@
|
|||
# Package
|
||||
|
||||
version = "0.1.0"
|
||||
author = "Paul Wilde"
|
||||
description = "Displays the date in dmenu"
|
||||
license = "MIT"
|
||||
srcDir = "src"
|
||||
bin = @["calendurr"]
|
||||
|
||||
|
||||
# Dependencies
|
||||
|
||||
requires "nim >= 1.6.6"
|
|
@ -1,13 +0,0 @@
|
|||
# Package
|
||||
|
||||
version = "0.1.0"
|
||||
author = "Paul Wilde"
|
||||
description = "A Command wrapper thing - i.e. run clipmenu/passmenu into dmenu with styling, sucks really"
|
||||
license = "MIT"
|
||||
srcDir = "src"
|
||||
bin = @["cmd_wrappurr"]
|
||||
|
||||
|
||||
# Dependencies
|
||||
|
||||
requires "nim >= 1.6.6"
|
|
@ -1,22 +0,0 @@
|
|||
import ../../globurrl
|
||||
import std/[strutils,osproc]
|
||||
|
||||
# Basically just a wrapper to style passmenu nicely
|
||||
proc main() =
|
||||
var info = newInfo(capitalizeAscii(run_command))
|
||||
let cmd = genMenuCmd(info)
|
||||
discard execCmd(cmd)
|
||||
return
|
||||
|
||||
if isMainModule:
|
||||
globurrl.wrappurr = true
|
||||
for idx, arg in args:
|
||||
case arg:
|
||||
of "-r", "--run":
|
||||
run_command = args[idx + 1]
|
||||
break
|
||||
else:
|
||||
echo "No command given, please run again with `[-r|--run] __cmd__`"
|
||||
|
||||
if run_command != "":
|
||||
main()
|
|
@ -1,26 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
build () {
|
||||
dir="$1"
|
||||
i="$2"
|
||||
cd "./$dir" || exit
|
||||
f=$(echo "$dir" | sed 's/\.\///')
|
||||
nimble install -y
|
||||
if [[ $i == "install" ]]; then
|
||||
cp -v "$f" "$HOME/.local/bin/$f"
|
||||
fi
|
||||
cd ../
|
||||
}
|
||||
|
||||
if [[ $2 != "" ]]; then
|
||||
build "$2" "$1"
|
||||
exit
|
||||
fi
|
||||
for dir in ./*; do
|
||||
if [ -d "$dir" ]; then
|
||||
if [[ "$dir" == "./" ]]; then
|
||||
continue
|
||||
fi
|
||||
build "$dir" "$1"
|
||||
fi
|
||||
done
|
|
@ -1,13 +0,0 @@
|
|||
# Package
|
||||
|
||||
version = "0.1.0"
|
||||
author = "Paul Wilde"
|
||||
description = "An emoji picker for dmenu/rofi"
|
||||
license = "MIT"
|
||||
srcDir = "src"
|
||||
bin = @["emurrji"]
|
||||
|
||||
|
||||
# Dependencies
|
||||
|
||||
requires "nim >= 1.6.6"
|
|
@ -1,13 +0,0 @@
|
|||
# Package
|
||||
|
||||
version = "0.1.0"
|
||||
author = "Paul Wilde"
|
||||
description = "Displays the fuzzy time in dmenu"
|
||||
license = "MIT"
|
||||
srcDir = "src"
|
||||
bin = @["furrytime"]
|
||||
|
||||
|
||||
# Dependencies
|
||||
|
||||
requires "nim >= 1.6.6"
|
278
globurrl.nim
278
globurrl.nim
|
@ -1,278 +0,0 @@
|
|||
import std/[os,osproc,strutils,json,rdstdin,marshal]
|
||||
|
||||
type
|
||||
Info* = object
|
||||
title*: string
|
||||
selected_fg*: string
|
||||
selected_bg*: string
|
||||
unselected_fg*: string
|
||||
unselected_bg*: string
|
||||
full_text*: string
|
||||
# next few are for i3bar use
|
||||
border*: string
|
||||
background*: string
|
||||
color*: string
|
||||
html_text*: string
|
||||
short_text*: string
|
||||
args*: seq[string]
|
||||
Menu = object
|
||||
command: string
|
||||
bottom: string
|
||||
grab_kb: string
|
||||
i_case: string
|
||||
lines_shown: string
|
||||
monitor: string
|
||||
prompt: string
|
||||
font: string
|
||||
norm_bg: string
|
||||
norm_fg: string
|
||||
sel_bg: string
|
||||
sel_fg: string
|
||||
extra_cmd: string
|
||||
Tool* = enum
|
||||
ROFI = "rofi", DMENU = "dmenu"
|
||||
|
||||
const WM_TOOLS_DIR* = getHomeDir() & ".wm_tools/"
|
||||
const WM_TOOLS_SYNC_DIR = getHomeDir() & "/Nextcloud/.wm_tools_sync/"
|
||||
const background* = "#000000"
|
||||
const backgroundalt* = "#bb222222"
|
||||
const backgroundalt2* = "#bb333333"
|
||||
const foreground* = "#dfdfdf"
|
||||
const foregroundalt* = "#777"
|
||||
const foregroundalt2* = "#ccc"
|
||||
const black* = "#000000"
|
||||
const white* = "#FFFFFF"
|
||||
const yellow* = "#ffb52a"
|
||||
const red* = "#e60053"
|
||||
const purple* = "#9f78e1"
|
||||
const blue* = "#0a6cf5"
|
||||
const lightblue* = "#7296EF"
|
||||
const lighterblue* = "#B5DDF7"
|
||||
const green* = "#4b9901"
|
||||
const lightgreen* = "#00ff00"
|
||||
const grey* = "#dfdfdf"
|
||||
const darkgrey* = "#444"
|
||||
const primary* = yellow
|
||||
const secondary* = red
|
||||
const alert* = "#bd2c40"
|
||||
const font = "Hermit-12"
|
||||
const MAX_LINES = 20
|
||||
var loop* = false
|
||||
var stoploop* = true
|
||||
var tool* = ROFI
|
||||
var wrappurr* = false
|
||||
var run_command* = ""
|
||||
var wayland* = false
|
||||
|
||||
proc newInfo*(str: string = "Info"): Info =
|
||||
var title = str
|
||||
if tool == ROFI:
|
||||
title = title & " : "
|
||||
return Info(
|
||||
title: title,
|
||||
selected_fg: black,
|
||||
selected_bg: white,
|
||||
unselected_fg: white,
|
||||
unselected_bg: black,
|
||||
# next few are for i3bar use
|
||||
border: white,
|
||||
background: black,
|
||||
color: foreground,
|
||||
)
|
||||
|
||||
proc newMenuConfig(cmd: Tool = ROFI): Menu =
|
||||
var run = $cmd
|
||||
var menu = Menu()
|
||||
menu.command = run
|
||||
if cmd == ROFI:
|
||||
menu.command &= " -dmenu"
|
||||
menu.prompt = "-p"
|
||||
menu.i_case = "-i"
|
||||
menu.lines_shown = "-l"
|
||||
return menu
|
||||
|
||||
proc newRofiConfig(cmd: Tool = ROFI): Menu =
|
||||
var run = cmd
|
||||
var menu = newMenuConfig(run)
|
||||
#menu.extra_cmd = "-markup-rows" #-kb-row-select \"Tab\" -kb-row-tab \"\""
|
||||
return menu
|
||||
|
||||
proc newDmenuConfig(cmd: Tool = DMENU): Menu =
|
||||
var run = cmd
|
||||
var menu = newMenuConfig(run)
|
||||
menu.bottom = "-b"
|
||||
menu.grabkb = "-f"
|
||||
menu.monitor = "-m"
|
||||
menu.font = "-fn"
|
||||
menu.norm_bg = "-nb"
|
||||
menu.norm_fg = "-nf"
|
||||
menu.sel_bg = "-sb"
|
||||
menu.sel_fg = "-sf"
|
||||
return menu
|
||||
|
||||
proc newMenu(): Menu =
|
||||
#if wrappurr:
|
||||
# return newDmenuConfig(run_command)
|
||||
case tool:
|
||||
of ROFI:
|
||||
return newRofiConfig()
|
||||
of DMENU:
|
||||
return newDmenuConfig()
|
||||
return newMenuConfig()
|
||||
|
||||
proc debugLog*(str: string) =
|
||||
let f = open("/tmp/debug.txt",fmAppend)
|
||||
defer: f.close()
|
||||
f.writeLine(str)
|
||||
|
||||
proc checkWayland() =
|
||||
if getEnv("XDG_SESSION_TYPE") == "wayland":
|
||||
wayland = true
|
||||
|
||||
proc XisRunning*(): bool =
|
||||
if getEnv("XAUTHORITY") != "":
|
||||
echo "X IS RUNNING"
|
||||
echo getEnv("XAUTHORITY")
|
||||
return true
|
||||
return false
|
||||
|
||||
proc clearInput*(count: int = 1) =
|
||||
for x in countup(1, count):
|
||||
discard readLineFromStdin("")
|
||||
|
||||
proc getArguments*(): seq[string] =
|
||||
let args = commandLineParams()
|
||||
return args
|
||||
|
||||
proc stripQuotes*(str: string): string =
|
||||
return replace(str,"\"",""")
|
||||
|
||||
proc quote*(str: string): string =
|
||||
var text = str
|
||||
# May need to put some further work to escape some special chars here
|
||||
text = stripQuotes(text)
|
||||
|
||||
# Put leading and ending quote marks in
|
||||
return " \"" & text & "\" "
|
||||
# ^ Add a spaces ^ so the previous flag isn't touching
|
||||
|
||||
|
||||
proc markup(str: string): string =
|
||||
var text = str
|
||||
|
||||
return text
|
||||
|
||||
proc genMenuCmd*(data: Info, opts: varargs[string], rofi: bool = false): string =
|
||||
# Build dmenu/rofi command
|
||||
var cmd = ""
|
||||
var x_lines = len(opts) + 1
|
||||
# if the text is empty, we don't want to create a menu item of it
|
||||
if data.full_text != "":
|
||||
let text = markup(data.full_text)
|
||||
cmd &= text & "\n"
|
||||
else:
|
||||
x_lines -= 1
|
||||
for opt in opts:
|
||||
let text = markup(opt)
|
||||
cmd = cmd & text & "\n"
|
||||
cmd.removeSuffix("\n")
|
||||
|
||||
if x_lines > MAX_LINES:
|
||||
x_lines = MAX_LINES
|
||||
|
||||
cmd = "echo -e" & quote(cmd) & " | "
|
||||
|
||||
var menu = newMenu()
|
||||
cmd = cmd & menu.command & " "
|
||||
cmd = cmd & menu.extra_cmd & " "
|
||||
cmd = cmd & menu.i_case & " "
|
||||
cmd = cmd & menu.lines_shown & " " & $x_lines & " "
|
||||
cmd = cmd & menu.prompt & quote(data.title)
|
||||
cmd = cmd & menu.norm_bg & quote(data.unselected_bg)
|
||||
cmd = cmd & menu.norm_fg & quote(data.unselected_fg)
|
||||
cmd = cmd & menu.sel_bg & quote(data.selected_bg)
|
||||
cmd = cmd & menu.sel_fg & quote(data.selected_fg)
|
||||
cmd = cmd & menu.font & quote(font)
|
||||
echo cmd
|
||||
return cmd
|
||||
|
||||
|
||||
|
||||
proc runMenu*(data: Info, opts: varargs[string], dmenu: bool = false): string =
|
||||
let cmd = genMenuCmd(data, opts, dmenu)
|
||||
#echo cmd
|
||||
#
|
||||
# Run command and get output
|
||||
var output = execCmdEx(cmd)
|
||||
output.output.stripLineEnd()
|
||||
return output.output
|
||||
|
||||
proc copyToClipboard*(str: string) =
|
||||
if wayland:
|
||||
discard execCmd("wl-copy " & str)
|
||||
else:
|
||||
discard execCmd("echo -n " & quote(str) & " | xclip -selection clipboard")
|
||||
|
||||
proc getCurrentClipboardContent*(): string =
|
||||
var str = ""
|
||||
if wayland:
|
||||
let cur = execCmdEx("wl-paste")
|
||||
if cur.exitcode == 0:
|
||||
str = cur[0]
|
||||
else:
|
||||
echo cur
|
||||
else:
|
||||
let cur = execCmdEx("xsel -o -b")
|
||||
if cur.exitcode == 0:
|
||||
str = cur[0]
|
||||
else:
|
||||
echo cur
|
||||
return strip(str)
|
||||
|
||||
proc outputData*(data: Info, args: varargs[string]): string {.discardable.} =
|
||||
var output = ""
|
||||
if tool == DMENU:
|
||||
output = runMenu(data,args, dmenu = true)
|
||||
elif loop:
|
||||
# mainly for i3bar/i3blocks compatible output
|
||||
var j_data = data
|
||||
if j_data.html_text != "":
|
||||
j_data.full_text = j_data.html_text
|
||||
echo $$j_data
|
||||
else:
|
||||
# if all else fails, use dmenu (default)
|
||||
output = runMenu(data,args)
|
||||
return output
|
||||
|
||||
proc getSyncDir*(): string =
|
||||
if existsOrCreateDir(WM_TOOLS_SYNC_DIR):
|
||||
echo "Sync Dir already exists"
|
||||
return WM_TOOLS_SYNC_DIR
|
||||
return WM_TOOLS_SYNC_DIR
|
||||
|
||||
proc checkCacheDir() =
|
||||
if not dirExists(WM_TOOLS_DIR):
|
||||
createDir(WM_TOOLS_DIR)
|
||||
|
||||
# At Start up:
|
||||
checkCacheDir()
|
||||
|
||||
|
||||
let args* = getArguments()
|
||||
for idx, arg in args:
|
||||
case arg:
|
||||
of "noloop":
|
||||
stoploop = true
|
||||
of "i3bar":
|
||||
# I've kind of changed from using an i3bar to using #nobar so i3bar
|
||||
# isn't really supported any more but this is here for backwards compatibility
|
||||
loop = true
|
||||
stoploop = false
|
||||
of "dmenu":
|
||||
stoploop = true
|
||||
tool = DMENU
|
||||
of "rofi":
|
||||
stoploop = true
|
||||
tool = ROFI
|
||||
|
||||
|
4
install.sh
Executable file
4
install.sh
Executable file
|
@ -0,0 +1,4 @@
|
|||
#!/bin/bash
|
||||
|
||||
nimble install -y
|
||||
cp -v "wmtools" "$HOME/.local/bin/wmtools"
|
|
@ -1,13 +0,0 @@
|
|||
# Package
|
||||
|
||||
version = "0.1.0"
|
||||
author = "Paul Wilde"
|
||||
description = "Display NIC IP address and link to manage NICs"
|
||||
license = "GPL-3.0-or-later"
|
||||
srcDir = "src"
|
||||
bin = @["netwurrk"]
|
||||
|
||||
|
||||
# Dependencies
|
||||
|
||||
requires "nim >= 1.6.6"
|
|
@ -1,13 +0,0 @@
|
|||
# Package
|
||||
|
||||
version = "0.1.0"
|
||||
author = "Paul Wilde"
|
||||
description = "A new awesome nimble package"
|
||||
license = "MIT"
|
||||
srcDir = "src"
|
||||
bin = @["passwurrd"]
|
||||
|
||||
|
||||
# Dependencies
|
||||
|
||||
requires "nim >= 1.6.6"
|
|
@ -1,13 +0,0 @@
|
|||
# Package
|
||||
|
||||
version = "0.1.0"
|
||||
author = "Paul Wilde"
|
||||
description = "A ping clock - display current ping time"
|
||||
license = "GPL-3.0-or-later"
|
||||
srcDir = "src"
|
||||
bin = @["pingclurrk"]
|
||||
|
||||
|
||||
# Dependencies
|
||||
|
||||
requires "nim >= 1.6.6"
|
|
@ -1,4 +0,0 @@
|
|||
{
|
||||
"version": 1,
|
||||
"reverseDeps": {}
|
||||
}
|
|
@ -1,13 +0,0 @@
|
|||
# Package
|
||||
|
||||
version = "0.1.0"
|
||||
author = "Paul Wilde"
|
||||
description = "A new awesome nimble package"
|
||||
license = "AGPL-3.0-or-later"
|
||||
srcDir = "src"
|
||||
bin = @["pw_generaturr"]
|
||||
|
||||
|
||||
# Dependencies
|
||||
|
||||
requires "nim >= 2.0.0"
|
|
@ -1,65 +0,0 @@
|
|||
|
||||
#import ../../globurrl
|
||||
|
||||
import httpclient
|
||||
import json
|
||||
import strutils
|
||||
import random
|
||||
import parseopt
|
||||
import os
|
||||
|
||||
var length = 4
|
||||
var number = 10
|
||||
var word_len = 5
|
||||
|
||||
proc getNumber(size: int = 4): string =
|
||||
var num = ""
|
||||
for _ in countup(1,size):
|
||||
randomize()
|
||||
let roll = rand(0..9)
|
||||
num &= $roll
|
||||
return num
|
||||
|
||||
proc parsePw(body: string) =
|
||||
let j = body.parseJson
|
||||
for pass in j.getElems:
|
||||
var p = pass.getStr.capitalizeAscii
|
||||
p &= getNumber(length)
|
||||
echo p
|
||||
|
||||
proc getPW() =
|
||||
var c = newHttpClient()
|
||||
try:
|
||||
let url = "https://random-word-api.herokuapp.com/word?number=" & $number & "&length=" & $word_len
|
||||
echo url
|
||||
let resp = c.get(url)
|
||||
if resp.status == $Http200:
|
||||
parsePw(resp.body)
|
||||
|
||||
except:
|
||||
echo getCurrentExceptionMsg()
|
||||
|
||||
proc parseArgs() =
|
||||
var p = initOptParser(commandLineParams())
|
||||
while true:
|
||||
p.next()
|
||||
case p.kind
|
||||
of cmdEnd: break
|
||||
of cmdShortOption, cmdLongOption:
|
||||
if p.val == "":
|
||||
#echo "Option: ", p.key
|
||||
discard
|
||||
else:
|
||||
#echo "Option and value: ", p.key, ", ", p.val
|
||||
case p.key
|
||||
of "length":
|
||||
word_len = parseInt(p.val)
|
||||
of "number":
|
||||
number = parseInt(p.val)
|
||||
of cmdArgument:
|
||||
#echo "Argument: ", p.key
|
||||
discard
|
||||
|
||||
if isMainModule:
|
||||
parseArgs()
|
||||
getPW()
|
|
@ -1,14 +0,0 @@
|
|||
# Package
|
||||
|
||||
version = "0.1.0"
|
||||
author = "Paul Wilde"
|
||||
description = "A Remmina client tool and opener"
|
||||
license = "GPL-3.0-or-later"
|
||||
srcDir = "src"
|
||||
bin = @["remmina_choosurr"]
|
||||
|
||||
|
||||
# Dependencies
|
||||
|
||||
requires "nim >= 1.6.6"
|
||||
requires "configparser >= 0.1.0"
|
|
@ -1,13 +0,0 @@
|
|||
# Package
|
||||
|
||||
version = "0.1.0"
|
||||
author = "Paul Wilde"
|
||||
description = "A screenshot client, works on both X11 and Wayland"
|
||||
license = "GPL-3.0-or-later"
|
||||
srcDir = "src"
|
||||
bin = @["screenshurrt"]
|
||||
|
||||
|
||||
# Dependencies
|
||||
|
||||
requires "nim >= 1.6.6"
|
11
src/common.nim
Normal file
11
src/common.nim
Normal file
|
@ -0,0 +1,11 @@
|
|||
import model/config
|
||||
import model/tool
|
||||
import model/info
|
||||
|
||||
export config
|
||||
export tool
|
||||
export info
|
||||
|
||||
var myConfig* = newConfig()
|
||||
|
||||
|
22
src/common/colours.nim
Normal file
22
src/common/colours.nim
Normal file
|
@ -0,0 +1,22 @@
|
|||
|
||||
const background* = "#000000"
|
||||
const backgroundalt* = "#bb222222"
|
||||
const backgroundalt2* = "#bb333333"
|
||||
const foreground* = "#dfdfdf"
|
||||
const foregroundalt* = "#777"
|
||||
const foregroundalt2* = "#ccc"
|
||||
const black* = "#000000"
|
||||
const white* = "#FFFFFF"
|
||||
const yellow* = "#ffb52a"
|
||||
const red* = "#e60053"
|
||||
const purple* = "#9f78e1"
|
||||
const blue* = "#0a6cf5"
|
||||
const lightblue* = "#7296EF"
|
||||
const lighterblue* = "#B5DDF7"
|
||||
const green* = "#4b9901"
|
||||
const lightgreen* = "#00ff00"
|
||||
const grey* = "#dfdfdf"
|
||||
const darkgrey* = "#444"
|
||||
const primary* = yellow
|
||||
const secondary* = red
|
||||
const alert* = "#bd2c40"
|
55
src/dispatcher.nim
Normal file
55
src/dispatcher.nim
Normal file
|
@ -0,0 +1,55 @@
|
|||
|
||||
import common
|
||||
import util/furrytime
|
||||
import util/pingclock
|
||||
import util/batturry
|
||||
import util/volurrme
|
||||
import util/netwurrk
|
||||
import util/wirelurrs
|
||||
import util/emurrji
|
||||
import util/calendurr
|
||||
import util/remminurr
|
||||
import util/passwurrd
|
||||
import util/pw_generaturr
|
||||
import util/temperaturr
|
||||
import util/screenshurrt
|
||||
import util/calculaturr
|
||||
import util/brightnurrs
|
||||
import util/tideurrl
|
||||
|
||||
proc dispatch*(cfg: Config) =
|
||||
case cfg.run
|
||||
of FurryTime:
|
||||
furrytime.go()
|
||||
of PingClock:
|
||||
pingclock.go()
|
||||
of Batturry:
|
||||
batturry.go()
|
||||
of Volurrme:
|
||||
volurrme.go()
|
||||
of Netwurrk:
|
||||
netwurrk.go()
|
||||
of Wirelurrs:
|
||||
wirelurrs.go()
|
||||
of Emurrji:
|
||||
emurrji.go()
|
||||
of Calendurr:
|
||||
calendurr.go()
|
||||
of Remminurr:
|
||||
remminurr.go()
|
||||
of Passwurrd:
|
||||
passwurrd.go()
|
||||
of PasswurrdGeneraturr:
|
||||
pw_generaturr.go()
|
||||
of Temperaturr:
|
||||
temperaturr.go()
|
||||
of Screenshurrt:
|
||||
screenshurrt.go()
|
||||
of Calculaturr:
|
||||
calculaturr.go()
|
||||
of Brightnurrs:
|
||||
brightnurrs.go()
|
||||
of Tideurrl:
|
||||
tideurrl.go()
|
||||
else:
|
||||
echo "No valid run command given"
|
6
src/model/brightness.nim
Normal file
6
src/model/brightness.nim
Normal file
|
@ -0,0 +1,6 @@
|
|||
|
||||
type
|
||||
BrightnessArg* = enum
|
||||
None,
|
||||
BrightUp,
|
||||
BrightDown
|
49
src/model/config.nim
Normal file
49
src/model/config.nim
Normal file
|
@ -0,0 +1,49 @@
|
|||
import os
|
||||
import parsetoml
|
||||
|
||||
import tool
|
||||
import screenshot
|
||||
|
||||
type
|
||||
Config* = ref object
|
||||
exec*: string
|
||||
run*: Tool
|
||||
max_lines*: int
|
||||
prepend*: bool
|
||||
screenshot_tool*: ScreenshotTool
|
||||
|
||||
let config_dir* = getHomeDir() & ".config/wm_tools/"
|
||||
let config_file* = config_dir & "config.toml"
|
||||
|
||||
proc `$`(c: Config): string =
|
||||
var str = "exec = \"" & c.exec & "\"\n"
|
||||
str &= "prepend = " & $c.prepend & "\n"
|
||||
str &= "screenshot_tool = \"" & $c.screenshot_tool & "\"\n"
|
||||
str &= "max_lines = " & $c.max_lines
|
||||
str &= "\n"
|
||||
return str
|
||||
|
||||
proc newConfig*(): Config =
|
||||
var cfg = Config()
|
||||
cfg.exec = "rofi -dmenu"
|
||||
cfg.prepend = true
|
||||
cfg.screenshot_tool = Maim
|
||||
cfg.max_lines = 20
|
||||
|
||||
discard existsOrCreateDir(config_dir)
|
||||
if not fileExists(config_file):
|
||||
writeFile(config_file,$cfg)
|
||||
else:
|
||||
let content = readFile(config_file)
|
||||
try:
|
||||
let toml = parseString(content)
|
||||
if toml.hasKey("exec"):
|
||||
cfg.exec = toml["exec"].getStr
|
||||
if toml.hasKey("max_lines"):
|
||||
cfg.max_lines = toml["max_lines"].getInt
|
||||
if toml.hasKey("screenshot_tool"):
|
||||
cfg.screenshot_tool = toml["screenshot_tool"].getStr.toScreenshotTool
|
||||
except:
|
||||
echo "Error with Config File:"
|
||||
echo getCurrentExceptionMsg()
|
||||
return cfg
|
11
src/model/info.nim
Normal file
11
src/model/info.nim
Normal file
|
@ -0,0 +1,11 @@
|
|||
type
|
||||
Info* = object
|
||||
title*: string
|
||||
full_text*: string
|
||||
html_text*: string
|
||||
short_text*: string
|
||||
args*: seq[string]
|
||||
|
||||
proc newInfo*(str: string = "Info"): Info =
|
||||
var title = str
|
||||
return Info(title: title)
|
14
src/model/pwgen.nim
Normal file
14
src/model/pwgen.nim
Normal file
|
@ -0,0 +1,14 @@
|
|||
|
||||
type
|
||||
PWGen* = object
|
||||
to_terminal*: bool
|
||||
word_len*: int
|
||||
digits*: int
|
||||
number*: int
|
||||
|
||||
proc newPWGen*(): PWGen =
|
||||
var pw = PWGen()
|
||||
pw.word_len = 5
|
||||
pw.digits = 4
|
||||
pw.number = 10
|
||||
return pw
|
72
src/model/screenshot.nim
Normal file
72
src/model/screenshot.nim
Normal file
|
@ -0,0 +1,72 @@
|
|||
|
||||
import sequtils
|
||||
import strutils
|
||||
|
||||
type
|
||||
Screenshot* = object
|
||||
size*: ScreenshotSize
|
||||
tool*: ScreenshotTool
|
||||
ScreenshotSize* = enum
|
||||
None = ""
|
||||
Region = "region",
|
||||
Full = "fullscreen",
|
||||
Window = "window"
|
||||
ScreenshotTool* = enum
|
||||
None = ""
|
||||
Maim = "maim"
|
||||
|
||||
proc newScreenshot*(): Screenshot =
|
||||
var ss = Screenshot()
|
||||
ss.tool = Maim
|
||||
ss.size = None
|
||||
return ss
|
||||
|
||||
proc toScreenshotSize*(str: string): ScreenshotSize =
|
||||
case str
|
||||
of "region": return Region
|
||||
of "fullscreen": return Full
|
||||
of "window": return Window
|
||||
else: return None
|
||||
|
||||
proc isScreenshotSize*(str: string): bool =
|
||||
return str.toScreenshotSize != None
|
||||
|
||||
proc ScreenshotSizes*(): seq[string] =
|
||||
var sizes: seq[string] = @[]
|
||||
for item in ScreenshotSize.toSeq:
|
||||
if item != None:
|
||||
sizes.add($item)
|
||||
return sizes
|
||||
|
||||
proc toScreenshotTool*(str: string): ScreenshotTool =
|
||||
case str
|
||||
of "maim": return Maim
|
||||
else: return None
|
||||
|
||||
proc isScreenshotTool*(str: string): bool =
|
||||
return str.toScreenshotTool != None
|
||||
|
||||
proc command*(tool: ScreenshotTool): string =
|
||||
case tool
|
||||
of Maim: return "maim -u %s --format png %f"
|
||||
else: return ""
|
||||
|
||||
proc activeWindowCommand*(tool: ScreenshotTool): string =
|
||||
var cmd = tool.command()
|
||||
# where %s is an extra flag or process, i.e. xdotool for getting active window
|
||||
case tool
|
||||
of Maim:
|
||||
cmd = cmd.replace("%s","-i $(xdotool getactivewindow)")
|
||||
else: return cmd
|
||||
return cmd
|
||||
|
||||
proc regionCommand*(tool: ScreenshotTool): string =
|
||||
var cmd = tool.command()
|
||||
case tool
|
||||
of Maim:
|
||||
cmd = cmd.replace("%s","-s")
|
||||
else: return cmd
|
||||
return cmd
|
||||
|
||||
const CLIPBOARD_CMD* = "xclip -selection clipboard -t image/png"
|
||||
|
22
src/model/tides.nim
Normal file
22
src/model/tides.nim
Normal file
|
@ -0,0 +1,22 @@
|
|||
import times
|
||||
|
||||
const TIDE_URL* = "https://www.tidetimes.org.uk/%LOC-tide-times"
|
||||
const DEFAULT_LOC* = "exmouth-dock"
|
||||
|
||||
type
|
||||
Tide* = ref object
|
||||
state*: string
|
||||
time*: string
|
||||
height*: string
|
||||
tomorrow*: bool
|
||||
TideList* = ref object
|
||||
tides*: seq[Tide]
|
||||
url*: string
|
||||
last_updated*: DateTime
|
||||
location*: string
|
||||
|
||||
proc newTideList*(): TideList =
|
||||
var tl = TideList()
|
||||
tl.url = TIDE_URL
|
||||
tl.location = DEFAULT_LOC
|
||||
return tl
|
20
src/model/tool.nim
Normal file
20
src/model/tool.nim
Normal file
|
@ -0,0 +1,20 @@
|
|||
|
||||
type
|
||||
Tool* = enum
|
||||
None,
|
||||
FurryTime,
|
||||
PingClock,
|
||||
Batturry,
|
||||
Volurrme,
|
||||
Netwurrk,
|
||||
Wirelurrs,
|
||||
Emurrji,
|
||||
Calendurr,
|
||||
Remminurr,
|
||||
Passwurrd,
|
||||
PasswurrdGeneraturr,
|
||||
Temperaturr,
|
||||
Screenshurrt,
|
||||
Calculaturr,
|
||||
Brightnurrs,
|
||||
Tideurrl
|
4
src/model/volume.nim
Normal file
4
src/model/volume.nim
Normal file
|
@ -0,0 +1,4 @@
|
|||
|
||||
type
|
||||
VolArg* = enum
|
||||
None, VolUp, VolDown, VolMute
|
63
src/output.nim
Normal file
63
src/output.nim
Normal file
|
@ -0,0 +1,63 @@
|
|||
import osproc
|
||||
import strutils
|
||||
|
||||
import common
|
||||
|
||||
proc stripQuotes(str: string): string =
|
||||
var text = replace(str,"\"",""")
|
||||
return text
|
||||
|
||||
proc quote*(str: string): string =
|
||||
var text = str
|
||||
# May need to put some further work to escape some special chars here
|
||||
text = stripQuotes(text)
|
||||
|
||||
# Put leading and ending quote marks in
|
||||
return " \"" & text & "\" "
|
||||
# ^ Add a spaces ^ so the previous flag isn't touching
|
||||
|
||||
proc markup(str: string): string =
|
||||
# Placeholder proc for future use
|
||||
var text = stripQuotes(str)
|
||||
return text
|
||||
|
||||
proc copyToClipboard*(str: string): bool {.discardable.} =
|
||||
let ok = execCmd("echo -n " & quote(str) & " | xclip -selection clipboard")
|
||||
return ok == 0
|
||||
|
||||
proc genMenuCmd(data: Info, opts: varargs[string]): string =
|
||||
var cmd = ""
|
||||
var x_lines = len(opts) + 1
|
||||
# if the text is empty, we don't want to create a menu item of it
|
||||
if data.full_text != "":
|
||||
let text = markup data.full_text
|
||||
cmd &= text & "\n"
|
||||
else:
|
||||
x_lines -= 1
|
||||
for opt in opts:
|
||||
let text = markup opt
|
||||
cmd &= text & "\n"
|
||||
|
||||
cmd.removeSuffix("\n")
|
||||
|
||||
if x_lines > myConfig.max_lines: x_lines = myConfig.max_lines
|
||||
|
||||
if myConfig.prepend:
|
||||
cmd = "echo -e" & quote(cmd) & "| "
|
||||
cmd &= myConfig.exec
|
||||
cmd &= " -i" # set case insensitive
|
||||
cmd &= " -p" & quote(data.title)
|
||||
cmd &= "-l " & $x_lines
|
||||
echo "Sending command:\n" & cmd
|
||||
return cmd
|
||||
|
||||
proc runExec(data: Info, opts: varargs[string]): string =
|
||||
let cmd = genMenuCmd(data, opts)
|
||||
var output = execCmdEx(cmd)
|
||||
echo "Output:\n" & $output
|
||||
output.output.stripLineEnd()
|
||||
return output.output
|
||||
|
||||
proc outputData*(data: Info, args: varargs[string,`$`]): string {.discardable.} =
|
||||
var output = runExec(data,args)
|
||||
return output
|
179
src/parser.nim
Normal file
179
src/parser.nim
Normal file
|
@ -0,0 +1,179 @@
|
|||
import os
|
||||
|
||||
import argparse
|
||||
|
||||
import common
|
||||
import model/pwgen
|
||||
import model/volume
|
||||
import model/brightness
|
||||
import model/screenshot
|
||||
import model/tides
|
||||
|
||||
proc parseArgs*() =
|
||||
let params = commandLineParams()
|
||||
var p = newParser:
|
||||
help("WMTools : a set of tools to output option to your program of choice i.e. Rofi")
|
||||
arg("input",help="the tool to run, i.e. furrytime, pingclock, volurrme, etc.")
|
||||
arg("others", nargs = -1)
|
||||
try:
|
||||
var opts = p.parse(params)
|
||||
case opts.input
|
||||
of "furrytime", "fuzzytime", "time":
|
||||
myConfig.run = FurryTime
|
||||
of "pingclock", "pingclurrk", "ping":
|
||||
myConfig.run = PingClock
|
||||
of "batturry", "battery", "bat":
|
||||
myConfig.run = Batturry
|
||||
of "volurrme", "volume", "vol":
|
||||
myConfig.run = Volurrme
|
||||
of "netwurrk", "network", "net":
|
||||
myConfig.run = Netwurrk
|
||||
of "wirelurrs", "wireless", "wifi":
|
||||
myConfig.run = Wirelurrs
|
||||
of "emurrji", "emoji":
|
||||
myConfig.run = Emurrji
|
||||
of "calendurr", "calender", "cal":
|
||||
myConfig.run = Calendurr
|
||||
of "remminurr", "remmina", "rdp", "rem":
|
||||
myConfig.run = Remminurr
|
||||
of "passwurrd", "password", "pw":
|
||||
myConfig.run = Passwurrd
|
||||
of "passwurrdgeneraturr", "passwordgenerator", "pwgen":
|
||||
myConfig.run = PasswurrdGeneraturr
|
||||
of "temperaturr", "temperature", "temp":
|
||||
myConfig.run = Temperaturr
|
||||
of "screenshurrt", "screenshot", "screeny":
|
||||
myConfig.run = Screenshurrt
|
||||
of "calculaturr", "calculator", "calc":
|
||||
myConfig.run = Calculaturr
|
||||
of "brightnurrs", "brightness", "bright":
|
||||
myConfig.run = Brightnurrs
|
||||
of "tideurrl", "tides":
|
||||
myConfig.run = Tideurrl
|
||||
else:
|
||||
echo p.help
|
||||
quit(1)
|
||||
except ShortCircuit as err:
|
||||
if err.flag == "argparse_help":
|
||||
echo err.help
|
||||
quit(1)
|
||||
except UsageError:
|
||||
stderr.writeLine getCurrentExceptionMsg()
|
||||
quit(1)
|
||||
|
||||
proc parseVolArgs*(): VolArg =
|
||||
var arg: VolArg
|
||||
let params = commandLineParams()
|
||||
var p = newParser:
|
||||
help("Args for volurrme")
|
||||
arg("volurrme",help="can only ever be 'volurrme' as you won't have gotten this far otherwise")
|
||||
arg("adjust",help="up, down, or mute",default=some(""))
|
||||
try:
|
||||
var opts = p.parse(params)
|
||||
case opts.adjust
|
||||
of "volup", "up":
|
||||
arg = VolUp
|
||||
of "voldown", "down":
|
||||
arg = VolDown
|
||||
of "mute","volmute":
|
||||
arg = VolMute
|
||||
except ShortCircuit as err:
|
||||
if err.flag == "argparse_help":
|
||||
echo err.help
|
||||
quit(1)
|
||||
except UsageError:
|
||||
stderr.writeLine getCurrentExceptionMsg()
|
||||
quit(1)
|
||||
return arg
|
||||
|
||||
proc parseBrightnessArgs*(): BrightnessArg =
|
||||
var arg: BrightnessArg
|
||||
let params = commandLineParams()
|
||||
var p = newParser:
|
||||
help("Args for volurrme")
|
||||
arg("brightnurrs",help="can only ever be 'brightnurrs' as you won't have gotten this far otherwise")
|
||||
arg("adjust",help="up, down, or mute",default=some(""))
|
||||
try:
|
||||
var opts = p.parse(params)
|
||||
case opts.adjust
|
||||
of "up":
|
||||
arg = BrightUp
|
||||
of "down":
|
||||
arg = BrightDown
|
||||
except ShortCircuit as err:
|
||||
if err.flag == "argparse_help":
|
||||
echo err.help
|
||||
quit(1)
|
||||
except UsageError:
|
||||
stderr.writeLine getCurrentExceptionMsg()
|
||||
quit(1)
|
||||
return arg
|
||||
|
||||
proc parsePWGenArgs*(): PWGen =
|
||||
var gen = newPWGen()
|
||||
let params = commandLineParams()
|
||||
var p = newParser:
|
||||
help("Args for pw_generaturr")
|
||||
arg("pwgen",help="can only ever be 'pwgen' as you won't have gotten this far otherwise")
|
||||
flag("-o","--output",help="outputs to terminal instead of something else")
|
||||
option("-l","--length",help="Length of the word part of the password")
|
||||
option("-d","--digits",help="Length of the number part of the password",default=some(""))
|
||||
option("-n","--number",help="Number of passwords to return")
|
||||
try:
|
||||
var opts = p.parse(params)
|
||||
if opts.length != "":
|
||||
gen.word_len = parseInt(opts.length)
|
||||
if opts.digits != "":
|
||||
gen.digits = parseInt(opts.digits)
|
||||
if opts.number != "":
|
||||
gen.number = parseInt(opts.number)
|
||||
gen.to_terminal = not opts.output
|
||||
except ShortCircuit as err:
|
||||
if err.flag == "argparse_help":
|
||||
echo err.help
|
||||
quit(1)
|
||||
except UsageError:
|
||||
stderr.writeLine getCurrentExceptionMsg()
|
||||
quit(1)
|
||||
return gen
|
||||
|
||||
proc parseScreenshotArgs*(): Screenshot =
|
||||
var ss = newScreenshot()
|
||||
ss.tool = myConfig.screenshot_tool
|
||||
let params = commandLineParams()
|
||||
var p = newParser:
|
||||
help("Args for screenshurrt")
|
||||
arg("screenshurrt",help="can only ever be 'screenshurrt' as you won't have gotten this far otherwise")
|
||||
option("-s","--size",help="size/region i.e. region, fullscreen or window")
|
||||
try:
|
||||
var opts = p.parse(params)
|
||||
if opts.size != "":
|
||||
ss.size = opts.size.toScreenshotSize()
|
||||
except ShortCircuit as err:
|
||||
if err.flag == "argparse_help":
|
||||
echo err.help
|
||||
quit(1)
|
||||
except UsageError:
|
||||
stderr.writeLine getCurrentExceptionMsg()
|
||||
quit(1)
|
||||
return ss
|
||||
|
||||
proc parseTideurrlArgs*(): TideList =
|
||||
var t = newTideList()
|
||||
let params = commandLineParams()
|
||||
var p = newParser:
|
||||
help("Args for tideurrl")
|
||||
arg("tideurrl",help="can only ever be 'tideurrl' as you won't have gotten this far otherwise")
|
||||
option("-l","--loc",help="location name")
|
||||
try:
|
||||
var opts = p.parse(params)
|
||||
if opts.loc != "":
|
||||
t.location = opts.loc
|
||||
except ShortCircuit as err:
|
||||
if err.flag == "argparse_help":
|
||||
echo err.help
|
||||
quit(1)
|
||||
except UsageError:
|
||||
stderr.writeLine getCurrentExceptionMsg()
|
||||
quit(1)
|
||||
return t
|
|
@ -1,5 +1,8 @@
|
|||
import ../../globurrl
|
||||
import std/[strutils,os]
|
||||
import strutils
|
||||
|
||||
import ../common
|
||||
import ../common/colours
|
||||
import ../output
|
||||
|
||||
const battery = "BAT0"
|
||||
const ok_fg = lightgreen
|
||||
|
@ -43,7 +46,7 @@ proc getCharge(): int =
|
|||
echo "Error getting battery level : " & getCurrentExceptionMsg()
|
||||
return charge
|
||||
|
||||
proc getDesign(charge: int, state: bool): (string, string, string, string, string) =
|
||||
proc getDesign(charge: int, state: bool): string =
|
||||
var icon = " "
|
||||
var icon_colour = ok_fg
|
||||
var col = default_fg
|
||||
|
@ -81,46 +84,25 @@ proc getDesign(charge: int, state: bool): (string, string, string, string, strin
|
|||
icon = "x "
|
||||
|
||||
let main_text = icon & " " & $charge & "%"
|
||||
# This next line is here for i3bar purposes
|
||||
let html_text = "<span foreground=\"" & icon_colour & "\">" & icon & "</span>" & $charge & "%"
|
||||
|
||||
return (html_text,main_text, col, bg, border)
|
||||
return main_text
|
||||
|
||||
proc getOutput(charge: int, state: bool): Info =
|
||||
let (html_text,main_text,col,bg_col,highlight_col) = get_design(charge, state)
|
||||
let main_text = get_design(charge, state)
|
||||
var data = newInfo("Batturry")
|
||||
# TODO check if html text works with rofi
|
||||
data.full_text = main_text
|
||||
data.selected_bg = highlight_col
|
||||
data.selected_fg = col # may just want `black` here
|
||||
# i3bar stuff
|
||||
data.html_text = html_text
|
||||
data.color = col
|
||||
data.border = highlight_col
|
||||
data.background = bg_col
|
||||
return data
|
||||
|
||||
|
||||
proc getBatteryInfo() =
|
||||
var last_charge = -1
|
||||
var last_state = false
|
||||
while true:
|
||||
let charge = getCharge()
|
||||
let state = isCharging()
|
||||
if charge != last_charge or state != last_state:
|
||||
let data = getoutput(charge, state)
|
||||
outputData(data)
|
||||
last_charge = charge
|
||||
last_state = state
|
||||
if stoploop:
|
||||
break
|
||||
sleep(1000)
|
||||
let charge = getCharge()
|
||||
let state = isCharging()
|
||||
let data = getoutput(charge, state)
|
||||
outputData(data)
|
||||
|
||||
proc main() =
|
||||
proc go*() =
|
||||
if batteryExists():
|
||||
getBatteryInfo()
|
||||
else:
|
||||
switchTwmMode()
|
||||
|
||||
if isMainModule:
|
||||
main()
|
||||
|
98
src/util/brightnurrs.nim
Normal file
98
src/util/brightnurrs.nim
Normal file
|
@ -0,0 +1,98 @@
|
|||
import os
|
||||
import strutils
|
||||
import osproc
|
||||
import math
|
||||
|
||||
import ../common
|
||||
import ../parser
|
||||
import ../model/brightness
|
||||
import ../output
|
||||
|
||||
#const backlight = "intel_backlight"
|
||||
const BACKLIGHT_CMD = "xbacklight"
|
||||
const UP = BACKLIGHT_CMD & " -inc %v" # %v is amount by
|
||||
const DOWN = BACKLIGHT_CMD & " -dec %v" # %v is amount by
|
||||
const SET = BACKLIGHT_CMD & " -set %v" # %v is amount by
|
||||
const default_value = "5"
|
||||
|
||||
proc getBacklight(): string =
|
||||
for dir in walkDir("/sys/class/backlight"):
|
||||
echo dir.path
|
||||
var bl = dir.path.replace("/sys/class/backlight/","")
|
||||
echo bl
|
||||
return bl
|
||||
|
||||
proc getLimit(backlight: string): int =
|
||||
try:
|
||||
if backlight != "":
|
||||
let back_l = readFile("/sys/class/backlight/" & backlight & "/max_brightness")
|
||||
return parseInt(strip(back_l))
|
||||
except:
|
||||
echo "Error getting backlight max : ", getCurrentExceptionMsg()
|
||||
return -1
|
||||
|
||||
|
||||
proc getDesign(pcnt: float): string =
|
||||
var icon = "🌑"
|
||||
case pcnt:
|
||||
of 85..100:
|
||||
icon = "🌕"
|
||||
of 75..85:
|
||||
icon = "🌖"
|
||||
of 50..75:
|
||||
icon = "🌗"
|
||||
of 35..50:
|
||||
icon = "🌘"
|
||||
else:
|
||||
icon = "🌑"
|
||||
let percent = toInt(round(pcnt,0))
|
||||
let text = icon & " " & $percent & "%"
|
||||
return text
|
||||
|
||||
proc brightnessUp() =
|
||||
let cmd = replace(UP,"%v",default_value)
|
||||
discard execCmd(cmd)
|
||||
proc brightnessDown() =
|
||||
let cmd = replace(DOWN,"%v",default_value)
|
||||
discard execCmd(cmd)
|
||||
|
||||
proc getBrightness*(backlight: string) =
|
||||
var data = newInfo("Brightnurrs")
|
||||
if backlight == "":
|
||||
data.full_text = "No Backlight Found"
|
||||
discard outputData(data)
|
||||
quit(1)
|
||||
let limit = getLimit(backlight)
|
||||
let current = parseInt(strip(readFile("/sys/class/backlight/" & backlight & "/actual_brightness")))
|
||||
let pcnt = (current/limit)*100
|
||||
let text = getDesign(pcnt)
|
||||
data.full_text = text
|
||||
let args = @["up", "down"]
|
||||
let option = outputData(data,args)
|
||||
if option in args:
|
||||
case option:
|
||||
of "up":
|
||||
brightnessUp()
|
||||
backlight.getBrightness()
|
||||
of "down":
|
||||
brightnessDown()
|
||||
backlight.getBrightness()
|
||||
else:
|
||||
try:
|
||||
let i = parseInt(option)
|
||||
let cmd = replace(SET,"%v",$i)
|
||||
discard execCmd(cmd)
|
||||
backlight.getBrightness()
|
||||
except:
|
||||
echo getCurrentExceptionMsg()
|
||||
|
||||
proc go*() =
|
||||
let backlight = getBacklight()
|
||||
let barg = parseBrightnessArgs()
|
||||
case barg:
|
||||
of BrightUp:
|
||||
brightnessUp()
|
||||
of BrightDown:
|
||||
brightnessDown()
|
||||
else:
|
||||
backlight.getBrightness()
|
|
@ -1,9 +1,14 @@
|
|||
import ../../globurrl
|
||||
import std/[osproc,strutils,sequtils]
|
||||
import osproc
|
||||
import strutils
|
||||
import sequtils
|
||||
|
||||
import ../common
|
||||
import ../output
|
||||
|
||||
# using qalc as it has a lot of nice inbuilt features
|
||||
# may be nice to make it totally non-dependant on other things though
|
||||
|
||||
const exitSeq = @["---","exit"]
|
||||
proc doCalculation(calc: string) =
|
||||
var info = newInfo("Calculaturr")
|
||||
let ans_cmd_terse = "echo \"" & calc & "\" | qalc +u8 -terse -color=never | awk '!/^>/ && !/^$/ {gsub(/^[ \\t]+|[ \\t]+$/, \"\", $0); print}'"
|
||||
|
@ -14,17 +19,16 @@ proc doCalculation(calc: string) =
|
|||
ans_terse.output.stripLineEnd()
|
||||
let answers = @[strip(ans_full.output),
|
||||
strip(ans_terse.output)]
|
||||
let args = concat(answers,@["exit"])
|
||||
let args = concat(answers,exitSeq)
|
||||
var cmd = outputData(info, args)
|
||||
cmd.stripLineEnd()
|
||||
if cmd in answers:
|
||||
copyToClipboard(cmd)
|
||||
elif cmd == "exit" or cmd == "":
|
||||
elif cmd in exitSeq or cmd == "":
|
||||
return
|
||||
else:
|
||||
doCalculation(cmd)
|
||||
|
||||
proc main() =
|
||||
proc go*() =
|
||||
var info = newInfo("Calculaturr")
|
||||
let args = @["exit"]
|
||||
let cmd = outputData(info, args)
|
||||
|
@ -32,5 +36,3 @@ proc main() =
|
|||
doCalculation(cmd)
|
||||
return
|
||||
|
||||
if isMainModule:
|
||||
main()
|
|
@ -1,8 +1,10 @@
|
|||
import ../../globurrl
|
||||
import std/[times,osproc,re]
|
||||
import times
|
||||
import osproc
|
||||
import re
|
||||
|
||||
import ../common
|
||||
import ../output
|
||||
|
||||
const default_bg = blue
|
||||
const default_fg = white
|
||||
const default_format = "yyyy-MM-dd"
|
||||
const cal_pos_x = "20"
|
||||
const cal_pos_y = "20"
|
||||
|
@ -10,9 +12,6 @@ const cal_pos_y = "20"
|
|||
proc getObject(date: string): Info =
|
||||
var data = newInfo("Calendurr")
|
||||
data.full_text = date
|
||||
data.border = default_bg
|
||||
data.selected_bg = default_bg
|
||||
data.selected_fg = default_fg
|
||||
return data
|
||||
|
||||
proc newCalendar(): string =
|
||||
|
@ -24,13 +23,7 @@ proc newCalendar(): string =
|
|||
"""
|
||||
return c
|
||||
|
||||
proc openCalendar*(input: i3barInput) =
|
||||
var c = newCalendar()
|
||||
c = replace(c,re"%pos_x", $(input.x - 111))
|
||||
c = replace(c,re"%pos_y", $input.y)
|
||||
discard execCmd(c)
|
||||
|
||||
proc dmenuCalendar() =
|
||||
proc openCalendar() =
|
||||
var c = newCalendar()
|
||||
c = replace(c,re"%pos_x", cal_pos_x)
|
||||
c = replace(c,re"%pos_y", cal_pos_y)
|
||||
|
@ -41,12 +34,9 @@ proc getDate*() =
|
|||
let data = getObject(date_today)
|
||||
let output = outputData(data)
|
||||
if output == date_today:
|
||||
dmenuCalendar()
|
||||
openCalendar()
|
||||
|
||||
proc main() =
|
||||
proc go*() =
|
||||
getDate()
|
||||
|
||||
|
||||
if isMainModule:
|
||||
main()
|
||||
|
|
@ -1,8 +1,10 @@
|
|||
import ../../globurrl
|
||||
import lib/emurrjilist
|
||||
import std/[re]
|
||||
import ../lib/emurrjilist
|
||||
import ../common
|
||||
import ../output
|
||||
|
||||
proc main() =
|
||||
import re
|
||||
|
||||
proc go*() =
|
||||
var info = newInfo("Emurrji")
|
||||
var args = getEmoji()
|
||||
args.add("exit")
|
||||
|
@ -16,5 +18,3 @@ proc main() =
|
|||
copyToClipboard(emoji)
|
||||
return
|
||||
|
||||
if isMainModule:
|
||||
main()
|
|
@ -1,28 +1,7 @@
|
|||
import ../../globurrl
|
||||
import std/[times]
|
||||
import times
|
||||
|
||||
const default_bg = lightblue
|
||||
const default_fg = black
|
||||
|
||||
proc getHour(hr: int): string
|
||||
proc getMinute(min: int): string
|
||||
|
||||
proc getFuzzyTime(): string =
|
||||
let tm = now()
|
||||
var hr = tm.hour()
|
||||
let min = tm.minute()
|
||||
var link = "past"
|
||||
if min > 32 :
|
||||
link = "to"
|
||||
case hr:
|
||||
of 23:
|
||||
hr = 0
|
||||
else:
|
||||
hr = hr + 1
|
||||
if min >= 58 or min <= 02:
|
||||
return getHour(hr) & " " & getMinute(min)
|
||||
else:
|
||||
return getMinute(min) & " " & link & " " & getHour(hr)
|
||||
import ../model/info
|
||||
import ../output
|
||||
|
||||
proc getHour(hr: int): string =
|
||||
case hr:
|
||||
|
@ -56,7 +35,7 @@ proc getHour(hr: int): string =
|
|||
proc getMinute(min: int): string =
|
||||
case min:
|
||||
of 58,59,0,1,2:
|
||||
return "o'clock"
|
||||
return "oclock"
|
||||
of 3,4,5,6,7,53,54,55,56,57:
|
||||
return "five"
|
||||
of 8,9,10,11,12,48,49,50,51,52:
|
||||
|
@ -72,14 +51,26 @@ proc getMinute(min: int): string =
|
|||
else:
|
||||
return "error"
|
||||
|
||||
proc getFuzzyTime(): string =
|
||||
let tm = now()
|
||||
var hr = tm.hour()
|
||||
let min = tm.minute()
|
||||
var link = "past"
|
||||
if min > 32 :
|
||||
link = "to"
|
||||
case hr:
|
||||
of 23:
|
||||
hr = 0
|
||||
else:
|
||||
hr = hr + 1
|
||||
if min >= 58 or min <= 02:
|
||||
return getHour(hr) & " " & getMinute(min)
|
||||
else:
|
||||
return getMinute(min) & " " & link & " " & getHour(hr)
|
||||
|
||||
proc getObject(time: string): Info =
|
||||
var data = newInfo("Furry Time")
|
||||
data.full_text = time
|
||||
data.selected_bg = default_bg
|
||||
data.selected_fg = default_fg
|
||||
#i3bar stuff
|
||||
data.color = default_fg
|
||||
data.border = default_fg
|
||||
return data
|
||||
|
||||
proc show(time: string, next_fuzzy: bool = false) =
|
||||
|
@ -94,10 +85,7 @@ proc show(time: string, next_fuzzy: bool = false) =
|
|||
let t = now().format("HH:mm:ss")
|
||||
show(t, true)
|
||||
|
||||
|
||||
proc main() =
|
||||
proc go*() =
|
||||
let time = getFuzzyTime()
|
||||
show(time)
|
||||
|
||||
if isMainModule:
|
||||
main()
|
|
@ -1,10 +1,12 @@
|
|||
import ../../globurrl
|
||||
import std/[os,osproc,strutils,sequtils]
|
||||
import os
|
||||
import osproc
|
||||
import strutils
|
||||
import sequtils
|
||||
|
||||
import ../common
|
||||
import ../output
|
||||
|
||||
const default_fg = black
|
||||
const default_bg = purple
|
||||
const mng_cmd = "alacritty -e nmtui-connect"
|
||||
const nics: seq[string] = @["wlan0","bridge0", "enp3s0","wlp2s0","enp0s20f0u3"]
|
||||
|
||||
proc getIP(nic: string): string =
|
||||
let cmd = "ifconfig " & nic & " | grep inet | awk -F\" \" '{print $2}' | head -1 | awk '{print $1}'"
|
||||
|
@ -29,10 +31,6 @@ proc getConnState(nic: string): (string, string) =
|
|||
|
||||
proc getObject(): Info =
|
||||
var data = newInfo("Netwurrk")
|
||||
data.selected_bg = default_bg
|
||||
data.selected_fg = default_fg
|
||||
# i3bar stuff
|
||||
data.border = default_bg
|
||||
return data
|
||||
|
||||
proc getNetInfo*(my_nics: seq[string]) =
|
||||
|
@ -59,8 +57,6 @@ proc getNics*(): seq[string] =
|
|||
return my_nics
|
||||
return @["no-nic"]
|
||||
|
||||
proc main() =
|
||||
proc go*() =
|
||||
getNetInfo(getNics())
|
||||
|
||||
if isMainModule:
|
||||
main()
|
|
@ -1,5 +1,10 @@
|
|||
import ../../globurrl.nim
|
||||
import std/[os,osproc,re,strutils]
|
||||
import os
|
||||
import osproc
|
||||
import re
|
||||
import strutils
|
||||
|
||||
import ../common
|
||||
import ../output
|
||||
|
||||
const pw_store = getHomeDir() & ".password-store/"
|
||||
var passwords: seq[string] = @[]
|
||||
|
@ -20,12 +25,9 @@ proc getPasswords(): seq[string] =
|
|||
proc passwordToClipboard(password: string) =
|
||||
discard execCmd("pass show -c " & password)
|
||||
|
||||
proc main() =
|
||||
proc go*() =
|
||||
var info = newInfo("Passwurrd")
|
||||
var pws = getPasswords()
|
||||
let output = outputData(info,pws)
|
||||
if output in passwords:
|
||||
passwordToClipboard(output)
|
||||
|
||||
when isMainModule:
|
||||
main()
|
|
@ -1,15 +1,11 @@
|
|||
import ../../globurrl
|
||||
import std/[osproc, re, strutils]
|
||||
import osproc
|
||||
import re
|
||||
import strutils
|
||||
|
||||
import ../common
|
||||
import ../output
|
||||
|
||||
const host: string = "9.9.9.9"
|
||||
const default_bg = blue
|
||||
const default_fg = white
|
||||
const medium_bg = alert
|
||||
const medium_fg = black
|
||||
const alert_bg = alert
|
||||
const alert_fg = black
|
||||
const warning_bg = red
|
||||
const warning_fg = white
|
||||
|
||||
let ping_re = re(r"time=[0-9.]+")
|
||||
const ping_cmd: string = "ping -4 -c 1 " & host
|
||||
|
@ -47,39 +43,13 @@ proc getObject(ping: float): Info =
|
|||
var data = newInfo("Ping Clurrk")
|
||||
data.full_text = text
|
||||
# i3bar stuff
|
||||
data.color = default_fg
|
||||
data.border = default_bg
|
||||
data.background = black
|
||||
data.selected_bg = default_bg
|
||||
data.selected_fg = default_fg
|
||||
case state:
|
||||
of 1:
|
||||
data.selected_bg = medium_bg
|
||||
data.selected_fg = medium_fg
|
||||
# i3bar stuff
|
||||
data.color = medium_bg
|
||||
of 2:
|
||||
data.selected_bg = alert_bg
|
||||
data.selected_fg = alert_fg
|
||||
# i3bar stuff
|
||||
data.color = alert_bg
|
||||
of 9:
|
||||
data.selected_bg = warning_bg
|
||||
data.selected_fg = warning_fg
|
||||
# i3bar stuff
|
||||
data.color = warning_bg
|
||||
else:
|
||||
#default options already set
|
||||
let ok = true
|
||||
return data
|
||||
|
||||
|
||||
proc main() =
|
||||
proc go*() =
|
||||
let ping = get_ping()
|
||||
let data = getObject(ping)
|
||||
let output = outputData(data)
|
||||
if output == data.full_text:
|
||||
main()
|
||||
go()
|
||||
|
||||
if isMainModule:
|
||||
main()
|
65
src/util/pw_generaturr.nim
Normal file
65
src/util/pw_generaturr.nim
Normal file
|
@ -0,0 +1,65 @@
|
|||
|
||||
import httpclient
|
||||
import json
|
||||
import strutils
|
||||
import random
|
||||
|
||||
import ../parser
|
||||
import ../model/pwgen
|
||||
import ../common
|
||||
import ../output
|
||||
|
||||
var passwords: seq[string]
|
||||
proc getNumber(size: int = 4): string =
|
||||
var num = ""
|
||||
for _ in countup(1,size):
|
||||
randomize()
|
||||
let roll = rand(0..9)
|
||||
num &= $roll
|
||||
return num
|
||||
|
||||
proc parsePasswords(body: string, digits: int) =
|
||||
passwords = @[]
|
||||
let j = body.parseJson
|
||||
for pass in j.getElems:
|
||||
var p = pass.getStr.capitalizeAscii
|
||||
p &= getNumber(digits)
|
||||
passwords.add(p)
|
||||
|
||||
proc getPasswords(pwgen: PWGen) =
|
||||
var c = newHttpClient()
|
||||
try:
|
||||
let url = "https://random-word-api.herokuapp.com/word?number=" & $pwgen.number & "&length=" & $pwgen.word_len
|
||||
let resp = c.get(url)
|
||||
if resp.status == $Http200:
|
||||
parsePasswords(resp.body, pwgen.digits)
|
||||
except:
|
||||
stderr.writeLine getCurrentExceptionMsg()
|
||||
|
||||
proc getOutput(): Info =
|
||||
var data = newInfo("PW Generaturr")
|
||||
data.full_text = "Refresh"
|
||||
return data
|
||||
|
||||
proc goOutput(args: PWGen) =
|
||||
let data = getoutput()
|
||||
let selected = outputData(data,passwords)
|
||||
if selected in passwords:
|
||||
copyToClipboard(selected)
|
||||
elif selected == "Refresh":
|
||||
getPasswords(args)
|
||||
goOutput(args)
|
||||
|
||||
proc go*() =
|
||||
echo "Getting passwords..."
|
||||
let args = parsePWGenArgs()
|
||||
getPasswords(args)
|
||||
if args.to_terminal:
|
||||
for pw in passwords:
|
||||
echo pw
|
||||
else:
|
||||
echo "Outputting to app"
|
||||
goOutput(args)
|
||||
|
||||
if isMainModule:
|
||||
go()
|
|
@ -1,20 +1,18 @@
|
|||
import ../../globurrl
|
||||
import std/[os,osproc,tables,algorithm]
|
||||
import os
|
||||
import osproc
|
||||
import tables
|
||||
import algorithm
|
||||
|
||||
import configparser
|
||||
|
||||
import ../common
|
||||
import ../output
|
||||
|
||||
const REMMINA_DIR = getHomeDir() & ".local/share/remmina"
|
||||
const SWITCH_WS = false
|
||||
const REMMINA_WS = "4"
|
||||
|
||||
var sessions = initTable[string,string]()
|
||||
var names: seq[string] = @[]
|
||||
|
||||
proc main()
|
||||
|
||||
proc switchWorkspace() =
|
||||
if SWITCH_WS and REMMINA_WS != "":
|
||||
discard execCmd("i3-msg workspace number " & REMMINA_WS)
|
||||
|
||||
proc getRemminaFiles(): seq[string] =
|
||||
if len(names) < 1:
|
||||
for file in walkFiles(REMMINA_DIR & "/*.remmina"):
|
||||
|
@ -38,6 +36,8 @@ proc startRemmina(conn: string) =
|
|||
let session = sessions[conn]
|
||||
discard execCmd("remmina -c " & quote(session))
|
||||
|
||||
proc go*() # adding as need to refer back to it in selectRemmina
|
||||
|
||||
proc selectRemmina(conn: string) =
|
||||
var info = newInfo("Remmina Choosurr : " & conn)
|
||||
let args = @["connect", "edit", "back"]
|
||||
|
@ -51,11 +51,9 @@ proc selectRemmina(conn: string) =
|
|||
editRemmina(conn)
|
||||
#switchWorkspace()
|
||||
of "back":
|
||||
main()
|
||||
go()
|
||||
|
||||
|
||||
|
||||
proc main() =
|
||||
proc go*() =
|
||||
var info = newInfo("Remmina Choosurr")
|
||||
var args: seq[string] = getRemminaFiles()
|
||||
args.add("new")
|
||||
|
@ -68,7 +66,3 @@ proc main() =
|
|||
elif output in names:
|
||||
selectRemmina(output)
|
||||
return
|
||||
return
|
||||
|
||||
if isMainModule:
|
||||
main()
|
|
@ -1,23 +1,21 @@
|
|||
import ../../globurrl
|
||||
import std/[times,os,osproc,strutils,sequtils]
|
||||
import times
|
||||
import os
|
||||
import osproc
|
||||
import strutils
|
||||
import sequtils
|
||||
|
||||
import ../common
|
||||
import ../output
|
||||
import ../parser
|
||||
import ../model/screenshot
|
||||
|
||||
var screenshot_type = ""
|
||||
const TYPES = @["region", "fullscreen", "window"]
|
||||
const DATE_FORMAT = "yyyyMMdd-hhmmss"
|
||||
const FILENAME = "Screenshot-%d.png"
|
||||
const TEMP_DIR = "/tmp/"
|
||||
const SCREENSHOT_CMD = "maim -u %s --format png %f"
|
||||
var RUN_CMD = SCREENSHOT_CMD
|
||||
let DATE_STR = now().format(DATE_FORMAT)
|
||||
# where %s is an extra flag or process, i.e. xdotool for getting active window
|
||||
const ACTIVE_WINDOW_CMD = "-i $(xdotool getactivewindow)"
|
||||
const REGION_FLAG = "-s"
|
||||
var REGION_CMD = REGION_FLAG
|
||||
const CLIPBOARD_CMD = "xclip -selection clipboard -t image/png"
|
||||
var CLIP_CMD = CLIPBOARD_CMD
|
||||
|
||||
proc saveToClipboard(filename: string) =
|
||||
let cmd = "cat " & filename & " | " & CLIP_CMD
|
||||
let cmd = "cat " & filename & " | " & CLIPBOARD_CMD
|
||||
let status = execCmd(cmd)
|
||||
if status == 0 and fileExists(filename):
|
||||
removeFile(filename)
|
||||
|
@ -54,42 +52,44 @@ proc showScreenshotSaveSel(filename: string) =
|
|||
openFile(filename)
|
||||
return
|
||||
|
||||
proc showScreenshotTypeSel() =
|
||||
proc showScreenshotSizeSel(): ScreenshotSize =
|
||||
let info = newInfo("Screenshurrt type")
|
||||
let args = concat(TYPES,@["---","exit"])
|
||||
let args = concat(ScreenshotSizes(),@["---","exit"])
|
||||
let choice = outputData(info,args)
|
||||
if choice in TYPES:
|
||||
screenshot_type = choice
|
||||
if choice.isScreenshotSize():
|
||||
return choice.toScreenshotSize()
|
||||
elif choice == "---":
|
||||
showScreenshotTypeSel()
|
||||
return showScreenshotSizeSel()
|
||||
elif choice == "exit":
|
||||
return
|
||||
return
|
||||
quit(0)
|
||||
else:
|
||||
quit(0)
|
||||
|
||||
proc takeScreenshot() =
|
||||
proc takeScreenshot(ss: Screenshot) =
|
||||
let filename = TEMP_DIR & FILENAME.replace("%d",DATE_STR)
|
||||
var cmd = RUN_CMD.replace("%f",filename)
|
||||
case screenshot_type:
|
||||
of "window":
|
||||
cmd = cmd.replace("%s",ACTIVE_WINDOW_CMD)
|
||||
of "region":
|
||||
cmd = cmd.replace("%s",REGION_CMD)
|
||||
var cmd = ss.tool.command
|
||||
case ss.size:
|
||||
of Window:
|
||||
cmd = ss.tool.activeWindowCommand()
|
||||
of Region:
|
||||
cmd = ss.tool.regionCommand()
|
||||
else: #fullscreen
|
||||
cmd = cmd.replace("%s","")
|
||||
# sleep for a bit otherwise the screen shot grabs dmenu as well
|
||||
# sleep for a bit otherwise the screen shot could grabs dmenu as well
|
||||
sleep(1*500)
|
||||
|
||||
cmd = cmd.replace("%f",filename)
|
||||
echo "Running command:\n" & cmd
|
||||
let status = execCmd(cmd)
|
||||
if status == 0:
|
||||
showScreenshotSaveSel(filename)
|
||||
return
|
||||
|
||||
proc go*() =
|
||||
var ss = parseScreenshotArgs()
|
||||
if ss.size == None:
|
||||
ss.size = showScreenshotSizeSel()
|
||||
if ss.size != None:
|
||||
ss.takeScreenshot()
|
||||
|
||||
if isMainModule:
|
||||
for arg in args:
|
||||
if arg in TYPES:
|
||||
screenshot_type = arg
|
||||
break
|
||||
if screenshot_type == "":
|
||||
showScreenshotTypeSel()
|
||||
if screenshot_type != "":
|
||||
takeScreenshot()
|
||||
go()
|
54
src/util/temperaturr.nim
Normal file
54
src/util/temperaturr.nim
Normal file
|
@ -0,0 +1,54 @@
|
|||
import os
|
||||
import re
|
||||
import math
|
||||
import strutils
|
||||
|
||||
import ../common
|
||||
import ../output
|
||||
|
||||
proc getThermalZones(): seq[string] =
|
||||
var zones: seq[string] = @[]
|
||||
let dirname_re = re("thermal_zone[\\d]+")
|
||||
let enabled_re = re("enabled")
|
||||
for file in walkDir("/sys/class/thermal/"):
|
||||
if file.path.contains(dirname_re):
|
||||
let state = readFile(file.path & "/mode")
|
||||
if state.contains(enabled_re):
|
||||
zones.add(file.path)
|
||||
return zones
|
||||
|
||||
proc getTemp(zone: string): int =
|
||||
let temp = strip(readFile(zone & "/temp"))
|
||||
return parseInt(temp)
|
||||
|
||||
proc getAverageTemp(zones: seq[string]): float =
|
||||
var temps: int = 0
|
||||
for zone in zones:
|
||||
let temp = getTemp(zone)
|
||||
temps += temp
|
||||
let avgtemp = ceil((temps / len(zones))/1000)
|
||||
return round(avgtemp,2)
|
||||
|
||||
proc getObject(temp: float): Info =
|
||||
var icon = ""
|
||||
case temp:
|
||||
of 40..59:
|
||||
icon = ""
|
||||
of 60.. 200:
|
||||
icon = ""
|
||||
else:
|
||||
icon = ""
|
||||
let main_text = icon & " " & $temp & "°C"
|
||||
var data = newInfo("Temperaturr")
|
||||
data.full_text = main_text
|
||||
return data
|
||||
|
||||
proc go*() =
|
||||
let zones = getThermalZones()
|
||||
let temp = getAverageTemp(zones)
|
||||
let data = getObject(temp)
|
||||
let option = outputData(data)
|
||||
if option == data.full_text:
|
||||
# Refresh
|
||||
go()
|
||||
|
110
src/util/tideurrl.nim
Normal file
110
src/util/tideurrl.nim
Normal file
|
@ -0,0 +1,110 @@
|
|||
#curl https://www.tidetimes.org.uk/exmouth-dock-tide-times-20190101 | grep -E -o ">((High|Low)|([0-9]+:[0-9]+)|([0-9]+\.[0-9]+m))"
|
||||
|
||||
import re
|
||||
import httpclient
|
||||
import times
|
||||
import osproc
|
||||
import sequtils
|
||||
|
||||
import ../common
|
||||
import ../parser
|
||||
import ../output
|
||||
import ../model/tides
|
||||
|
||||
const icon: string = "🌊 "
|
||||
|
||||
proc sortTides(tides: seq[Tide], is_tomorrow: bool = false): seq[Tide] =
|
||||
let timenow = now()
|
||||
var reltides: seq[Tide]
|
||||
for tide in tides:
|
||||
if timenow.format("HH:MM") <= tide.time and not is_tomorrow:
|
||||
reltides.add(tide)
|
||||
elif is_tomorrow:
|
||||
reltides.add(tide)
|
||||
return reltides
|
||||
|
||||
|
||||
proc getTideData(mytides: TideList, get_tomorrow: bool = false): seq[Tide] =
|
||||
var tides: seq[Tide]
|
||||
let fnd = re">((High|Low)|([0-9]+:[0-9]+)|([0-9]+\.[0-9]+m))"
|
||||
var client = newHttpClient(timeout = 10000)
|
||||
var link = replace(mytides.url,re"\%LOC",mytides.location)
|
||||
if get_tomorrow:
|
||||
let tomdate = now() + initTimeInterval(days = 1)
|
||||
link &= "-" & tomdate.format("yyyyMMdd")
|
||||
try:
|
||||
# Remember to compile with -d:ssl else this won't work
|
||||
let resp = client.request(link)
|
||||
if resp.status != $Http200 or resp.body == "":
|
||||
var data = newInfo("Tideurrl")
|
||||
data.full_text = "Error Response: " & resp.status & ":\nBody:" & resp.body
|
||||
discard outputData(data)
|
||||
return @[]
|
||||
let data = resp.body
|
||||
let times = findAll(data,fnd)
|
||||
var tide: Tide
|
||||
var column = 0
|
||||
for idx,time in times:
|
||||
if idx == 12:
|
||||
break
|
||||
let l = len(time) - 1
|
||||
if time == ">High" or time == ">Low":
|
||||
tide = Tide()
|
||||
tide.state = time[1..l]
|
||||
column = 1
|
||||
continue
|
||||
elif column == 1:
|
||||
tide.time = time[1..l]
|
||||
column = 2
|
||||
continue
|
||||
elif column == 2:
|
||||
tide.height = time[1..l]
|
||||
tides.add(tide)
|
||||
column = 0
|
||||
continue
|
||||
except:
|
||||
var data = newInfo("Tideurrl")
|
||||
data.full_text = "Unable to get Tide Data : " & getCurrentExceptionMsg()
|
||||
discard outputData(data)
|
||||
return tides
|
||||
|
||||
proc getDesign(tl: TideList): Info =
|
||||
var my_tides: seq[string] = @[]
|
||||
my_tides.add(tl.location)
|
||||
let tides = tl.tides
|
||||
for tide in tides:
|
||||
let str = icon & tide.state[0] & " " & tide.time & " " & tide.height
|
||||
my_tides.add(str)
|
||||
var data = newInfo("Tideurrl")
|
||||
data.args = my_tides
|
||||
return data
|
||||
|
||||
proc getTides*(mytides: var TideList, get_tomorrow: bool = false) =
|
||||
mytides.tides = mytides.getTideData(get_tomorrow)
|
||||
mytides.tides = sortTides(mytides.tides, get_tomorrow)
|
||||
if len(mytides.tides) == 0:
|
||||
return
|
||||
let data = getDesign(mytides)
|
||||
var opt_tomorrow = "tomorrow"
|
||||
if get_tomorrow:
|
||||
opt_tomorrow = "back"
|
||||
let args = concat(data.args,@["---",opt_tomorrow])
|
||||
let output = outputData(data,args)
|
||||
if output == "tomorrow":
|
||||
getTides(mytides,true)
|
||||
elif output == "back":
|
||||
getTides(mytides)
|
||||
elif output == "---" or output == "":
|
||||
return
|
||||
elif output in args:
|
||||
let url = replace(mytides.url,re"\%LOC",mytides.location)
|
||||
discard execCmd("xdg-open " & url)
|
||||
else:
|
||||
mytides.location = output
|
||||
getTides(mytides)
|
||||
|
||||
|
||||
proc go*() =
|
||||
var mytides = parseTideurrlArgs()
|
||||
getTides(mytides)
|
||||
|
|
@ -1,5 +1,12 @@
|
|||
import ../../globurrl
|
||||
import std/[os,strutils,sequtils,osproc]
|
||||
import os
|
||||
import strutils
|
||||
import sequtils
|
||||
import osproc
|
||||
|
||||
import ../common
|
||||
import ../output
|
||||
import ../parser
|
||||
import ../model/volume
|
||||
|
||||
const audio_tools = @["ncpamixer", "pavucontrol"]
|
||||
const vol_cmd = "pamixer"
|
||||
|
@ -10,11 +17,14 @@ const vol_mute = vol_cmd & " -t"
|
|||
const vol_default_by = "5"
|
||||
const vol_get = vol_cmd & " --get-volume"
|
||||
const vol_get_mute = vol_cmd & " --get-mute"
|
||||
const default_bg = green
|
||||
const default_fg = black
|
||||
|
||||
|
||||
proc getCurrentVolume(): string {.gcsafe.}
|
||||
proc getCurrentVolume(): string =
|
||||
let mute = execCmdEx(vol_get_mute)
|
||||
if strip(mute.output) == "true":
|
||||
return "muted"
|
||||
let vol = execCmdEx(vol_get)
|
||||
return vol.output
|
||||
|
||||
proc checkVolume(volume: string): string =
|
||||
var vol = volume
|
||||
|
@ -24,11 +34,11 @@ proc checkVolume(volume: string): string =
|
|||
vol = checkVolume(vol)
|
||||
return vol
|
||||
|
||||
proc getDesign(volume: string): (string,string) =
|
||||
proc getDesign(volume: string): string =
|
||||
let vol = checkVolume(volume)
|
||||
var icon = " "
|
||||
if vol == "muted":
|
||||
return (icon & "muted", icon & "muted")
|
||||
return icon & "muted"
|
||||
let pcnt = parseInt(strip(vol))
|
||||
case pcnt:
|
||||
of 85..100:
|
||||
|
@ -42,15 +52,7 @@ proc getDesign(volume: string): (string,string) =
|
|||
else:
|
||||
icon = " "
|
||||
let main_text = icon & $pcnt & "%"
|
||||
let text = "<span size=\"x-large\">" & icon & "</span>" & $pcnt & "%"
|
||||
return (text, main_text)
|
||||
|
||||
proc getCurrentVolume(): string =
|
||||
let mute = execCmdEx(vol_get_mute)
|
||||
if strip(mute.output) == "true":
|
||||
return "muted"
|
||||
let vol = execCmdEx(vol_get)
|
||||
return vol.output
|
||||
return main_text
|
||||
|
||||
proc volumeUp() =
|
||||
let cmd = replace(vol_up, "%v", vol_default_by)
|
||||
|
@ -63,18 +65,11 @@ proc volumeDown() =
|
|||
proc volumeMute() =
|
||||
discard execCmd(vol_mute)
|
||||
|
||||
proc getVolume*(run_once: bool = false) =
|
||||
proc getVolume*() =
|
||||
let vol = getCurrentVolume()
|
||||
let (text, main_text) = getDesign(vol)
|
||||
let main_text = getDesign(vol)
|
||||
var data = newInfo("Volurrme")
|
||||
data.full_text = main_text
|
||||
data.selected_bg = default_bg
|
||||
data.selected_fg = default_fg
|
||||
# i3bar stuff
|
||||
data.html_text = text
|
||||
data.color = foreground
|
||||
data.border = green
|
||||
data.background = black
|
||||
let args = concat(@["up", "down", "mute", "---", "exit", "---"],audio_tools)
|
||||
let option = outputData(data,args)
|
||||
if option == "":
|
||||
|
@ -101,26 +96,20 @@ proc getVolume*(run_once: bool = false) =
|
|||
try:
|
||||
let vol = parseInt(option)
|
||||
let cmd = replace(vol_set, "%v", $vol)
|
||||
let x = execCmd(cmd)
|
||||
discard execCmd(cmd)
|
||||
getVolume()
|
||||
except:
|
||||
echo getCurrentExceptionMsg()
|
||||
getVolume()
|
||||
|
||||
proc main() =
|
||||
getVolume()
|
||||
|
||||
if isMainModule:
|
||||
block start:
|
||||
for arg in args:
|
||||
case arg:
|
||||
of "up":
|
||||
volumeUp()
|
||||
break start
|
||||
of "down":
|
||||
volumeDown()
|
||||
break start
|
||||
of "mute":
|
||||
volumeMute()
|
||||
break start
|
||||
main()
|
||||
proc go*() =
|
||||
let arg = parseVolArgs()
|
||||
case arg
|
||||
of VolUp:
|
||||
volumeUp()
|
||||
of VolDown:
|
||||
volumeDown()
|
||||
of VolMute:
|
||||
volumeMute()
|
||||
else:
|
||||
getVolume()
|
|
@ -1,9 +1,11 @@
|
|||
import ../../globurrl
|
||||
import std/[os,osproc,strutils,sequtils]
|
||||
import os
|
||||
import osproc
|
||||
import strutils
|
||||
import sequtils
|
||||
|
||||
import ../common
|
||||
import ../output
|
||||
|
||||
const default_bg = purple
|
||||
const default_fg = white
|
||||
const wlan_nics: seq[string] = @["wlan0"]
|
||||
const get_ssid_cmd = "iwgetid -r"
|
||||
const mng_cmd = "alacritty -e nmtui-connect"
|
||||
|
||||
|
@ -28,9 +30,6 @@ proc getWifi(nic: string): (string, string) =
|
|||
|
||||
proc getObject(): Info =
|
||||
var data = newInfo("Wirelurrs")
|
||||
data.border = purple
|
||||
data.selected_bg = default_bg
|
||||
data.selected_fg = default_fg
|
||||
return data
|
||||
|
||||
proc getWifiInfo*(nics: seq[string]) =
|
||||
|
@ -41,6 +40,8 @@ proc getWifiInfo*(nics: seq[string]) =
|
|||
let data = getObject()
|
||||
let args = concat(lst,@["---", "manage","exit"])
|
||||
let output = outputData(data, args)
|
||||
if output in lst:
|
||||
discard execCmd(mng_cmd)
|
||||
case output:
|
||||
of "manage":
|
||||
discard execCmd(mng_cmd)
|
||||
|
@ -49,16 +50,20 @@ proc getWifiInfo*(nics: seq[string]) =
|
|||
of "---":
|
||||
return
|
||||
|
||||
proc main() =
|
||||
proc getWiFiNICs(): seq[string] =
|
||||
var my_nics: seq[string] = @[]
|
||||
for nic in wlan_nics:
|
||||
if dirExists("/sys/class/net/" & nic):
|
||||
for path in walkDir("/sys/class/net/"):
|
||||
if dirExists(path.path & "/wireless"):
|
||||
let nic = path.path.replace("/sys/class/net/","")
|
||||
my_nics.add(nic)
|
||||
return my_nics
|
||||
|
||||
proc go*() =
|
||||
let my_nics = getWiFiNICs()
|
||||
if len(my_nics) > 0:
|
||||
getWifiInfo(my_nics)
|
||||
else:
|
||||
switchTwmMode()
|
||||
echo "No WLAN"
|
||||
var data = getObject()
|
||||
data.full_text = "No WLAN"
|
||||
discard outputData(data)
|
||||
|
||||
if isMainModule:
|
||||
main()
|
11
src/wmtools.nim
Normal file
11
src/wmtools.nim
Normal file
|
@ -0,0 +1,11 @@
|
|||
# This is just an example to get you started. A typical binary package
|
||||
# uses this file as the main entry point of the application.
|
||||
#
|
||||
|
||||
import common
|
||||
import parser
|
||||
import dispatcher
|
||||
|
||||
when isMainModule:
|
||||
parseArgs()
|
||||
dispatch myConfig
|
|
@ -1,72 +0,0 @@
|
|||
import ../../globurrl
|
||||
import std/[os,re,math,strutils]
|
||||
|
||||
const default_bg = green
|
||||
const default_fg = black
|
||||
const alert_bg = yellow
|
||||
const alert_fg = black
|
||||
const warning_bg = red
|
||||
const warning_fg = black
|
||||
|
||||
proc getThermalZones(): seq[string] =
|
||||
var zones: seq[string] = @[]
|
||||
let dirname = re("thermal_zone[\\d]+")
|
||||
for file in walkDir("/sys/class/thermal/"):
|
||||
if contains(file.path,dirname):
|
||||
let state = readFile(file.path & "/mode")
|
||||
if contains(state,re"enabled"):
|
||||
zones.add(file.path)
|
||||
return zones
|
||||
|
||||
proc getTemp(zone: string): int =
|
||||
let temp = strip(readFile(zone & "/temp"))
|
||||
return parseInt(temp)
|
||||
|
||||
proc getAverageTemp(zones: seq[string]): int =
|
||||
var temps: int = 0
|
||||
for zone in zones:
|
||||
let temp = getTemp(zone)
|
||||
temps += temp
|
||||
let avgtemp = ceil((temps / len(zones))/1000)
|
||||
return toInt(round(avgtemp,0))
|
||||
|
||||
proc getObject(temp: int): Info =
|
||||
var icon = ""
|
||||
var bg_col = default_bg
|
||||
var fg_col = default_fg
|
||||
case temp:
|
||||
of 40..59:
|
||||
bg_col = alert_bg
|
||||
fg_col = alert_fg
|
||||
icon = ""
|
||||
of 60.. 200:
|
||||
bg_col = warning_bg
|
||||
fg_col = warning_fg
|
||||
icon = ""
|
||||
else:
|
||||
bg_col = default_bg
|
||||
fg_col = default_fg
|
||||
icon = ""
|
||||
let text = "<span foreground='" & bg_col & "'>" & icon & "</span> " & $temp & "°C"
|
||||
let main_text = icon & " " & $temp & "°C"
|
||||
var data = newInfo("Temperaturr")
|
||||
data.full_text = main_text
|
||||
data.selected_bg = bg_col
|
||||
data.selected_fg = fg_col
|
||||
# i3bar stuff
|
||||
data.html_text = text
|
||||
data.color = bg_col
|
||||
data.border = bg_col
|
||||
return data
|
||||
|
||||
proc main() =
|
||||
let zones = getThermalZones()
|
||||
let temp = getAverageTemp(zones)
|
||||
let data = getObject(temp)
|
||||
let option = outputData(data)
|
||||
if option == data.full_text:
|
||||
# Refresh
|
||||
main()
|
||||
|
||||
if isMainModule:
|
||||
main()
|
|
@ -1,13 +0,0 @@
|
|||
# Package
|
||||
|
||||
version = "0.1.0"
|
||||
author = "Paul Wilde"
|
||||
description = "Display temp in dmenu"
|
||||
license = "GPL-3.0-or-later"
|
||||
srcDir = "src"
|
||||
bin = @["temperaturr"]
|
||||
|
||||
|
||||
# Dependencies
|
||||
|
||||
requires "nim >= 1.6.6"
|
|
@ -1,106 +0,0 @@
|
|||
#curl https://www.tidetimes.org.uk/exmouth-dock-tide-times-20190101 | grep -E -o ">((High|Low)|([0-9]+:[0-9]+)|([0-9]+\.[0-9]+m))"
|
||||
import ../../globurrl
|
||||
import std/[re,httpclient,times,osproc,sequtils]
|
||||
|
||||
# TODO:
|
||||
# Pass location in as variable
|
||||
|
||||
const url* = "https://www.tidetimes.org.uk/%LOC-tide-times"
|
||||
const loc* = "exmouth-dock"
|
||||
const icon: string = "🌊 "
|
||||
|
||||
type
|
||||
Tide = ref object
|
||||
State: string
|
||||
Time: string
|
||||
Height: string
|
||||
Tomorrow: bool
|
||||
TideList = ref object
|
||||
Tides: seq[Tide]
|
||||
LastUpdated: DateTime
|
||||
|
||||
proc sortTides(tides: seq[Tide], is_tomorrow: bool = false): seq[Tide] =
|
||||
let timenow = now()
|
||||
var reltides: seq[Tide]
|
||||
for tide in tides:
|
||||
if timenow.format("HH:MM") <= tide.Time and not is_tomorrow:
|
||||
reltides.add(tide)
|
||||
elif is_tomorrow:
|
||||
reltides.add(tide)
|
||||
return reltides
|
||||
|
||||
|
||||
proc getTideData(get_tomorrow: bool = false): seq[Tide] =
|
||||
var tides: seq[Tide]
|
||||
let fnd = re">((High|Low)|([0-9]+:[0-9]+)|([0-9]+\.[0-9]+m))"
|
||||
var client = newHttpClient()
|
||||
var link = replace(url,re"\%LOC",loc)
|
||||
if get_tomorrow:
|
||||
let tomdate = now() + initTimeInterval(days = 1)
|
||||
link &= "-" & tomdate.format("yyyyMMdd")
|
||||
try:
|
||||
# Remember to compile with -d:ssl else this won't work
|
||||
let data = client.getContent(link)
|
||||
let times = findAll(data,fnd)
|
||||
var tide: Tide
|
||||
var column = 0
|
||||
for idx,time in times:
|
||||
if idx == 12:
|
||||
break
|
||||
let l = len(time) - 1
|
||||
if time == ">High" or time == ">Low":
|
||||
tide = Tide()
|
||||
tide.State = time[1..l]
|
||||
column = 1
|
||||
continue
|
||||
elif column == 1:
|
||||
tide.Time = time[1..l]
|
||||
column = 2
|
||||
continue
|
||||
elif column == 2:
|
||||
tide.Height = time[1..l]
|
||||
tides.add(tide)
|
||||
column = 0
|
||||
continue
|
||||
except:
|
||||
echo "Unable to get Tide Data : " & getCurrentExceptionMsg()
|
||||
return tides
|
||||
|
||||
proc getDesign(tides: seq[Tide]): Info =
|
||||
var my_tides: seq[string] = @[]
|
||||
for tide in tides:
|
||||
let str = icon & tide.State[0] & " " & tide.Time & " " & tide.Height
|
||||
my_tides.add(str)
|
||||
var data = newInfo("Tideurrl")
|
||||
data.border = black
|
||||
data.args = my_tides
|
||||
return data
|
||||
|
||||
proc getTides*(get_tomorrow: bool = false) =
|
||||
var mytides = TideList()
|
||||
mytides.Tides = getTideData(get_tomorrow)
|
||||
mytides.Tides = sortTides(mytides.Tides, get_tomorrow)
|
||||
if len(mytides.Tides) == 0:
|
||||
getTides(true)
|
||||
return
|
||||
let data = getDesign(mytides.Tides)
|
||||
var opt_tomorrow = "tomorrow"
|
||||
if get_tomorrow:
|
||||
opt_tomorrow = "back"
|
||||
let args = concat(data.args,@["---",opt_tomorrow])
|
||||
let output = outputData(data,args)
|
||||
if output == "tomorrow":
|
||||
getTides(true)
|
||||
elif output == "back":
|
||||
getTides()
|
||||
elif output == "---":
|
||||
return
|
||||
elif output in args:
|
||||
let url = replace(url,re"\%LOC",loc)
|
||||
discard execCmd("xdg-open " & url)
|
||||
|
||||
proc main() =
|
||||
getTides()
|
||||
|
||||
if isMainModule:
|
||||
main()
|
|
@ -1,13 +0,0 @@
|
|||
# Package
|
||||
|
||||
version = "0.1.0"
|
||||
author = "Paul Wilde"
|
||||
description = "Display local tides in dmenu"
|
||||
license = "GPL-3.0-or-later"
|
||||
srcDir = "src"
|
||||
bin = @["tideurrl"]
|
||||
|
||||
|
||||
# Dependencies
|
||||
|
||||
requires "nim >= 1.6.6"
|
|
@ -1 +0,0 @@
|
|||
-d:ssl
|
|
@ -1,13 +0,0 @@
|
|||
# Package
|
||||
|
||||
version = "0.1.0"
|
||||
author = "Paul Wilde"
|
||||
description = "Display and control volume with dmenu"
|
||||
license = "GPL-3.0-or-later"
|
||||
srcDir = "src"
|
||||
bin = @["volurrme"]
|
||||
|
||||
|
||||
# Dependencies
|
||||
|
||||
requires "nim >= 1.6.6"
|
|
@ -1,13 +0,0 @@
|
|||
# Package
|
||||
|
||||
version = "0.1.0"
|
||||
author = "Paul Wilde"
|
||||
description = "Display and control WLAN state with dmenu"
|
||||
license = "GPL-3.0-or-later"
|
||||
srcDir = "src"
|
||||
bin = @["wirelurrs"]
|
||||
|
||||
|
||||
# Dependencies
|
||||
|
||||
requires "nim >= 1.6.6"
|
16
wm_tools.nimble
Normal file
16
wm_tools.nimble
Normal file
|
@ -0,0 +1,16 @@
|
|||
# Package
|
||||
|
||||
version = "2.0.1"
|
||||
author = "Paul Wilde"
|
||||
description = "A set of informational tools"
|
||||
license = "AGPL-3.0-or-later"
|
||||
srcDir = "src"
|
||||
bin = @["wmtools"]
|
||||
|
||||
|
||||
# Dependencies
|
||||
|
||||
requires "nim >= 2.0.0"
|
||||
requires "parsetoml >= 0.7.1"
|
||||
requires "argparse"
|
||||
requires "configparser"
|
Loading…
Reference in a new issue