2022-05-04 17:17:02 +02:00
|
|
|
import std/[os,osproc,strutils,json,rdstdin,marshal]
|
2022-02-06 21:10:06 +01:00
|
|
|
|
|
|
|
type
|
2022-04-28 21:58:40 +02:00
|
|
|
Info* = object
|
2022-04-28 13:50:07 +02:00
|
|
|
title*: string
|
2022-05-04 17:17:02 +02:00
|
|
|
selected_fg*: string
|
|
|
|
selected_bg*: string
|
|
|
|
unselected_fg*: string
|
|
|
|
unselected_bg*: string
|
2022-02-06 21:10:06 +01:00
|
|
|
full_text*: string
|
2022-05-04 17:17:02 +02:00
|
|
|
# next few are for i3bar use
|
2022-02-06 21:10:06 +01:00
|
|
|
border*: string
|
2022-02-12 16:19:43 +01:00
|
|
|
background*: string
|
2022-05-04 17:17:02 +02:00
|
|
|
color*: string
|
|
|
|
html_text*: string
|
|
|
|
short_text*: string
|
2022-05-24 22:11:16 +02:00
|
|
|
args*: seq[string]
|
2022-07-05 14:00:40 +02:00
|
|
|
Menu = object
|
2022-05-06 12:12:13 +02:00
|
|
|
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
|
2022-07-05 14:00:40 +02:00
|
|
|
extra_cmd: string
|
2022-02-06 23:07:32 +01:00
|
|
|
i3BarInput* = object
|
|
|
|
button*: int
|
2022-02-12 16:19:43 +01:00
|
|
|
x*: int
|
|
|
|
y*: int
|
2022-02-06 23:07:32 +01:00
|
|
|
|
2022-07-05 14:00:40 +02:00
|
|
|
const font = "Hermit-8"
|
2022-02-06 21:10:06 +01:00
|
|
|
const background* = "#000000"
|
|
|
|
const backgroundalt* = "#bb222222"
|
|
|
|
const backgroundalt2* = "#bb333333"
|
|
|
|
const foreground* = "#dfdfdf"
|
|
|
|
const foregroundalt* = "#777"
|
|
|
|
const foregroundalt2* = "#ccc"
|
2022-02-12 16:19:43 +01:00
|
|
|
const black* = "#000000"
|
2022-02-27 15:57:40 +01:00
|
|
|
const white* = "#FFFFFF"
|
2022-02-06 21:10:06 +01:00
|
|
|
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"
|
2022-05-06 12:12:13 +02:00
|
|
|
const MAX_LINES = 20
|
2022-05-04 17:17:02 +02:00
|
|
|
var loop* = false
|
|
|
|
var stoploop* = true
|
2022-07-05 14:00:40 +02:00
|
|
|
var dmenu* = false
|
|
|
|
var rofi* = true
|
2022-05-06 13:07:22 +02:00
|
|
|
var passmenu* = false
|
|
|
|
var command_wrapper* = false
|
|
|
|
var run_command* = ""
|
2022-02-06 21:10:06 +01:00
|
|
|
|
2022-05-10 21:47:15 +02:00
|
|
|
proc newInfo*(str: string = "Info"): Info =
|
|
|
|
var title = str
|
|
|
|
if rofi:
|
|
|
|
title = title & " : "
|
2022-04-28 21:58:40 +02:00
|
|
|
return Info(
|
2022-05-04 17:17:02 +02:00
|
|
|
title: title,
|
|
|
|
selected_fg: black,
|
|
|
|
selected_bg: white,
|
|
|
|
unselected_fg: white,
|
|
|
|
unselected_bg: black,
|
|
|
|
# next few are for i3bar use
|
2022-02-27 15:57:40 +01:00
|
|
|
border: white,
|
2022-05-04 17:17:02 +02:00
|
|
|
background: black,
|
|
|
|
color: foreground,
|
2022-02-27 15:57:40 +01:00
|
|
|
)
|
2022-05-06 12:12:13 +02:00
|
|
|
|
2022-07-05 14:00:40 +02:00
|
|
|
proc newMenuConfig(cmd: string = "rofi -dmenu"): Menu =
|
|
|
|
var menu = Menu()
|
|
|
|
menu.command = cmd
|
|
|
|
menu.prompt = "-p"
|
|
|
|
menu.i_case = "-i"
|
|
|
|
menu.lines_shown = "-l"
|
|
|
|
return menu
|
|
|
|
|
|
|
|
proc newRofiConfig(): Menu =
|
|
|
|
var menu = newMenuConfig()
|
|
|
|
menu.extra_cmd = "-markup-rows -kb-row-select \"Tab\" -kb-row-tab \"\""
|
|
|
|
return menu
|
|
|
|
|
|
|
|
proc newDmenuConfig(cmd: string = "dmenu"): Menu =
|
|
|
|
var menu = newMenuConfig("dmenu")
|
2022-07-05 14:50:25 +02:00
|
|
|
menu.command = cmd
|
2022-07-05 14:00:40 +02:00
|
|
|
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 =
|
2022-07-05 14:50:25 +02:00
|
|
|
if passmenu:
|
|
|
|
return newDmenuConfig("passmenu")
|
|
|
|
elif command_wrapper:
|
|
|
|
return newDmenuConfig(run_command)
|
|
|
|
elif rofi:
|
2022-05-06 12:12:13 +02:00
|
|
|
return newRofiConfig()
|
2022-07-05 14:50:25 +02:00
|
|
|
elif dmenu:
|
2022-07-05 14:00:40 +02:00
|
|
|
return newDmenuConfig()
|
|
|
|
return newMenuConfig()
|
2022-05-06 12:12:13 +02:00
|
|
|
|
2022-02-06 23:07:32 +01:00
|
|
|
proc debugLog*(str: string) =
|
|
|
|
let f = open("/tmp/debug.txt",fmAppend)
|
|
|
|
defer: f.close()
|
|
|
|
f.writeLine(str)
|
|
|
|
|
2022-05-04 17:27:50 +02:00
|
|
|
proc switchTwmMode*(mode: string = "default") =
|
2022-05-04 17:17:02 +02:00
|
|
|
# I intend to add support for more twm as time goes on (I switch around a lot)
|
|
|
|
# Switch out of an i3 bindsym mode if set
|
2022-05-04 17:27:50 +02:00
|
|
|
discard execCmd("i3-msg mode \"" & mode & "\"")
|
2022-05-04 17:17:02 +02:00
|
|
|
|
2022-02-06 23:07:32 +01:00
|
|
|
proc parseInput*(): i3BarInput =
|
|
|
|
let input = readLineFromStdin("")
|
|
|
|
try:
|
|
|
|
let jsonNode = parseJson(input)
|
|
|
|
let i3input = to(jsonNode, i3BarInput)
|
|
|
|
return i3input
|
|
|
|
except:
|
|
|
|
return i3BarInput()
|
2022-04-28 13:34:09 +02:00
|
|
|
|
2022-02-12 14:20:21 +01:00
|
|
|
proc clearInput*(count: int = 1) =
|
2022-02-12 16:19:43 +01:00
|
|
|
for x in countup(1, count):
|
2022-02-12 14:20:21 +01:00
|
|
|
discard readLineFromStdin("")
|
2022-02-06 23:07:32 +01:00
|
|
|
|
2022-02-06 21:10:06 +01:00
|
|
|
proc getArguments*(): seq[string] =
|
|
|
|
let args = commandLineParams()
|
|
|
|
return args
|
2022-05-06 12:12:13 +02:00
|
|
|
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
|
2022-07-05 14:00:40 +02:00
|
|
|
#
|
|
|
|
proc markup(str: string): string =
|
|
|
|
var text = str
|
|
|
|
|
|
|
|
return text
|
2022-05-06 12:12:13 +02:00
|
|
|
|
2022-07-05 14:00:40 +02:00
|
|
|
proc genMenuCmd*(data: Info, opts: varargs[string], rofi: bool = false): string =
|
2022-05-04 17:17:02 +02:00
|
|
|
# Build dmenu/rofi command
|
2022-05-06 12:12:13 +02:00
|
|
|
var cmd = ""
|
2022-05-04 17:17:02 +02:00
|
|
|
# if the text is empty, we don't want to create a menu item of it
|
2022-05-06 12:12:13 +02:00
|
|
|
if data.full_text != "":
|
2022-07-05 14:00:40 +02:00
|
|
|
let text = markup(data.full_text)
|
|
|
|
cmd &= text & "\n"
|
2022-04-28 16:52:45 +02:00
|
|
|
for opt in opts:
|
2022-07-05 14:00:40 +02:00
|
|
|
let text = markup(opt)
|
|
|
|
cmd = cmd & text & "\n"
|
2022-04-28 21:58:40 +02:00
|
|
|
cmd.removeSuffix("\n")
|
2022-05-06 12:12:13 +02:00
|
|
|
|
|
|
|
cmd = "echo -e" & quote(cmd) & " | "
|
|
|
|
|
2022-07-05 14:00:40 +02:00
|
|
|
var menu = newMenu()
|
|
|
|
cmd = cmd & menu.command & " "
|
|
|
|
cmd = cmd & menu.extra_cmd & " "
|
|
|
|
cmd = cmd & menu.i_case & " "
|
|
|
|
cmd = cmd & menu.lines_shown & " " & $MAX_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
|
2022-05-06 13:07:22 +02:00
|
|
|
return cmd
|
2022-05-06 12:12:13 +02:00
|
|
|
|
2022-05-06 13:07:22 +02:00
|
|
|
|
|
|
|
|
2022-07-05 14:00:40 +02:00
|
|
|
proc runMenu*(data: Info, opts: varargs[string], rofi: bool = false): string =
|
|
|
|
let cmd = genMenuCmd(data, opts, rofi)
|
2022-05-06 12:12:13 +02:00
|
|
|
#echo cmd
|
|
|
|
#
|
2022-05-04 17:17:02 +02:00
|
|
|
# Run command and get output
|
2022-05-09 21:12:05 +02:00
|
|
|
var output = execCmdEx(cmd)
|
|
|
|
output.output.stripLineEnd()
|
|
|
|
return output.output
|
2022-04-28 16:52:45 +02:00
|
|
|
|
2022-05-09 22:08:54 +02:00
|
|
|
proc copyToClipboard*(str: string) =
|
|
|
|
discard execCmd("echo -n " & quote(str) & " | xclip -selection clipboard")
|
2022-05-14 16:44:20 +02:00
|
|
|
|
2022-05-04 17:17:02 +02:00
|
|
|
proc outputData*(data: Info, args: varargs[string]): string {.discardable.} =
|
2022-04-28 16:52:45 +02:00
|
|
|
var output = ""
|
2022-05-04 17:17:02 +02:00
|
|
|
if rofi:
|
2022-07-05 14:00:40 +02:00
|
|
|
output = runMenu(data,args, rofi = true)
|
2022-05-04 17:17:02 +02:00
|
|
|
elif loop:
|
|
|
|
# mainly for i3bar/i3blocks compatible output
|
2022-04-28 16:52:45 +02:00
|
|
|
var j_data = data
|
|
|
|
if j_data.html_text != "":
|
|
|
|
j_data.full_text = j_data.html_text
|
|
|
|
echo $$j_data
|
2022-05-04 17:17:02 +02:00
|
|
|
else:
|
|
|
|
# if all else fails, use dmenu (default)
|
2022-07-05 14:00:40 +02:00
|
|
|
output = runMenu(data,args)
|
2022-04-28 16:52:45 +02:00
|
|
|
return output
|
|
|
|
|
2022-05-04 17:27:03 +02:00
|
|
|
|
|
|
|
|
|
|
|
# At Start up:
|
|
|
|
|
|
|
|
# Switch bindsym mode back to default as it could be being used.
|
|
|
|
switchTwmMode()
|
|
|
|
|
2022-05-06 13:07:22 +02:00
|
|
|
let args* = getArguments()
|
|
|
|
for idx, arg in args:
|
2022-05-04 17:17:02 +02:00
|
|
|
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
|
|
|
|
dmenu = true
|
|
|
|
of "rofi":
|
|
|
|
stoploop = true
|
|
|
|
rofi = true
|
2022-05-06 13:07:22 +02:00
|
|
|
of ["pass","passmenu"]:
|
|
|
|
passmenu = true
|
|
|
|
break
|
2022-04-28 13:50:07 +02:00
|
|
|
|
|
|
|
|