Updates for gathering storm

This commit is contained in:
Ezri Brimhall 2024-11-07 13:38:53 -07:00
parent 06b1f4fb40
commit a279fc4923
15 changed files with 958 additions and 249 deletions

View File

@ -63,6 +63,3 @@ dynamic_padding = true
dynamic_title = true
opacity = 0.8
title = "Terminal"
[general]
working_directory = "/home/ezri"

View File

@ -12,6 +12,76 @@
(include "./windows.yuck")
(defwindow leftbar
:monitor 1
:geometry (geometry :width "100%"
:height "36px"
:anchor "top center")
:exclusive true
:focusable false
:stacking "fg"
(centerbox :orientation "h"
:class "bar root"
(tycho-leftbar--left)
(tycho-leftbar--center)
(tycho-leftbar--right)))
(defwindow centerbar
:monitor 0
:geometry (geometry :width "100%"
:height "26px"
:anchor "top center")
:exclusive true
:focusable false
:stacking "fg"
(centerbox :orientation "h"
:class "bar root"
(tycho-centerbar--left)
(tycho-centerbar--center)
(tycho-centerbar--right)))
(defwindow rightbar
:monitor 2
:geometry (geometry :width "100%"
:height "36px"
:anchor "top center")
:exclusive true
:focusable false
:stacking "fg"
(centerbox :orientation "h"
:class "bar root"
(tycho-rightbar--left)
(tycho-rightbar--center)
(tycho-rightbar--right)))
(defwindow sidebar
:monitor 1
:geometry (geometry :width "200px"
:height "100%"
:anchor "left center")
:exclusive true
:focusable false
:stacking "fg"
(tycho-sidebar))
(defwindow network-status
:monitor 0
:geometry (geometry :width "200px"
:height "0px"
:x "300px"
:y "0px"
:anchor "top right")
:exclusive false
:focusable false
:stacking "overlay"
(box :orientation "v"
:class "bar root bg outline"
:visible {network--show-details}
(network-detail)))
(defwindow builtinbar
:monitor 0
:geometry (geometry :width "100%"

View File

@ -1,77 +1,347 @@
;; -*-lisp-*-
(deflisten network--data
`~/.config/eww/scripts/network.py`)
`~/.config/eww/scripts/network.py`)
(defwidget network--wlan [device]
(defvar network--show-details false)
(defwidget network--interface
[device]
(box :orientation "v"
:halign "center"
:space-evenly false
:spacing 0
(label :class "offline"
:visible {!device.online}
:text "offline")
(label :visible {device.online}
:class "special"
:text "${device.addresses[0].address}/${device.addresses[0].prefixlen}")))
(defwidget network-big--online
[]
(box :orientation "h"
:halign "start"
:valign "center"
:space-evenly false
:spacing 10
(label :class "offline"
:visible {network--data["network"][device]["offline"]}
:text "offline")
(label :visible {network--data["network"][device]["connecting"]}
:class "highlight"
:text "connecting...")
(label :visible {network--data["network"][device]["online"] && !network--data.network[device].connecting}
:class "special"
:text "${network--data['wifi']['ssid']}")
(label :visible {!network--data.connection.internet && network--data.network[device].online}
:class "highlight"
:text "- no internet"
)))
(label :class "medium green nebula"
:visible {network--data.online}
:text "online")
(label :class "medium offline nebula"
:visible {network--data.offline}
:text "offline")
(label :class "medium highlight nebula"
:visible {network--data.configuring}
:text "configuring")))
(defwidget network--lan [device]
(defwidget network-big--lan
[device]
(label :visible {network--data
[device]
.online}
:class ""
:text "${network--data.interfaces[device].addresses[0].address}/${network--data.interfaces[device].addresses[0].prefixlen}"))
(defwidget network--wlan
[device]
(box :orientation "h"
:halign "start"
:space-evenly false
:spacing 0
(label :class "offline"
:visible {network--data["network"][device]["offline"]}
:text "offline")
(label :visible {network--data["network"][device]["connecting"]}
:class "highlight"
:text "connecting...")
(label :visible {network--data["network"][device]["online"] && !network--data.network[device].connecting}
:class "special"
:text "${network--data['network'][device]['ip4_addr']}/${network--data['network'][device]['ip4_prefix']}")))
:visible {network--data
["network"]
[device]
["offline"]
}
:text "offline")
(label :visible {network--data
["network"]
[device]
["connecting"]
}
:class "highlight"
:text "connecting...")
(label :visible {network--data
["network"]
[device]
["online"]
}
:class "special"
:text "${network--data['wifi']['ssid']}")))
(defwidget network--proxy-vpn [device ?required]
(defwidget network--lan
[device]
(box :orientation "h"
:halign "start"
:space-evenly false
:spacing 0
(label :class "offline"
:visible {!device.online}
:text "offline")
(label :visible {device.online}
:class {network--data.last_update.unix < clock--data.unix - 30 ? "highlight" : "special"}
:text "${device.addresses[0].address}/${device.addresses[0].prefixlen}")))
(defwidget network--secure
[]
(box :orientation "h"
:halign "start"
:space-evenly false
:spacing 0
:visible {network--data.connection.internet && (network--data["network"][device]["exists"] || required)}
(label :class "highlight"
:text "- insecure"
:visible {! network--data["network"][device]["exists"]})
:text "- insecure"
:visible {!
network--data.secure })
(label :class "green"
:text "- secured"
:visible {network--data["network"][device]["exists"]})))
:text "- secured via ${network--data.secure_msg}"
:visible {network--data.secure})))
(defwidget vpn-network []
(defwidget vpn-network
[]
(box :orientation "v"
:halign "start"
:space-evenly false
:spacing 0
:visible {network--data
!=
''}
(label :class "highlight"
:text "offline"
:visible {!network--data.connection.ezrinet})
:text "offline"
:visible {!
network--data.interfaces.ezrinet.online })
(label :class "green"
:text "connected"
:visible {network--data.connection.ezrinet})
:text "connected"
:visible {network--data.interfaces.ezrinet.online})
"personal network"))
(defwidget network []
(defwidget network
[]
(button :onclick "eww update network--show-details=${!network--show-details}"
(box :orientation "v"
:halign "start"
:space-evenly false
:spacing 0
:visible {network--data != ''}
(box :orientation "h"
:halign "center"
:space-evenly false
:spacing 10
(network--lan :device {network--data.default_interface}))
"communications")))
(defwidget network--public-ip
[]
(centerbox :orientation "h"
:halign "start"
:width 200
(box :halign "start"
"public ip:")
""
(box :halign "end"
:spacing 0
:space-evenly false
(label :class "highlight"
:text "offline"
:visible {!network--data.online})
(label :class "highlight"
:text "no response"
:visible {network--data.online && !network--data.have_public_ip})
(label :class "special"
:text {network--data.public_ip.ip}
:visible {network--data.online && network--data.have_public_ip}))))
(defwidget network--default-route
[]
(centerbox :orientation "h"
:halign "start"
:width 200
(box :halign "start"
"route on:")
""
(box :halign "end"
:spacing 0
:space-evenly false
(label :class "highlight"
:text "offline"
:visible {!network--data.online})
(label :class "highlight"
:text "no route"
:visible {network--data.online && !network--data.have_default_route})
(label :class "special"
:text {network--data.default_route}
:visible {network--data.online && network--data.have_default_route}))))
(defwidget network--gateway
[]
(centerbox :orientation "h"
:halign "start"
:width 200
(box :halign "start"
"gateway:")
""
(box :halign "end"
:spacing 0
:space-evenly false
(label :class "highlight"
:text "no response"
:visible {!network--data.have_gateway})
(label :class "special"
:text {network--data.gateway}
:visible {network--data.have_gateway}))))
(defwidget network--status-summary
[]
(centerbox :orientation "h"
:halign "start"
:width 200
(box :halign "start"
"status:")
""
(box :halign "end"
:spacing 0
:space-evenly false
(label :class "highlight"
:text "offline"
:visible {!network--data.online})
(label :class "special"
:text "online"
:visible {network--data.online && !network--data.secure})
(label :class "green"
:text {network--data.secure_msg == "usu" ? "vpn online" : "secure"}
:visible {network--data.online && network--data.secure}))))
(defwidget network-detail
[]
(box :orientation "v"
:halign "start"
:space-evenly false
:spacing 0
(box :orientation "h"
:halign "center"
:space-evenly false
:spacing 10
(network--wlan :device "wlan0")
(network--proxy-vpn :device "wg-mullvad" :required {!network--data.trusted}))
"communications"))
(network--status-summary)
(network--public-ip)
(network--default-route)
(network--gateway)
(centerbox :orientation "h"
:halign "start"
:width 200
(box :halign "start"
"last update:")
""
(box :halign "end"
:spacing 0
:space-evenly false
(label :class {network--data.last_update.unix < clock--data.unix - 30 ? "highlight" : "special"}
:text "${network--data.last_update.month}-${network--data.last_update.day} ${network--data.last_update.hour}:${network--data.last_update.minute}:${network--data.last_update.second}")))
))
(defwidget network-sidebar-details []
(box :orientation "v"
:halign "start"
:class "module"
:space-evenly false
:spacing 5
:width 200
(box :orientation "h"
:halign "center"
:class "nebula"
:spacing 10
:space-evenly false
(label :class "medium special"
:text "Comms"))
(box :orientation "h"
:halign "center"
:class "nebula"
:spacing 10
:space-evenly false
(label :class "nebula green"
:text "Online"
:visible {network--data.online})
(label :class "nebula highlight"
:text "Offline"
:visible {!network--data.online}))
(centerbox :orientation "h"
:halign "start"
:spacing 10
:width 200
:space-evenly false
(box :halign "start"
:class "nebula"
"Route On:")
""
(box :halign "end"
(label :text "No Route"
:class "highlight"
:visible {network--data.online && !network--data.have_default_route})
(label :text "${network--data.default_route}"
:class "special"
:visible {network--data.online && network--data.have_default_route})))
(centerbox :orientation "h"
:halign "start"
:spacing 10
:width 200
:space-evenly false
(box :halign "start"
:valign "start"
:class "nebula"
"Address:")
""
(box :halign "end"
:orientation "v"
(label :text "${network--data.default_interface.addresses[0].address}"
:class "special")
(label :text "/${network--data.default_interface.addresses[0].prefixlen}"
:halign "end"
:class "special")))
(centerbox :orientation "h"
:halign "start"
:spacing 10
:width 200
:space-evenly false
(box :halign "start"
:class "nebula"
"Public IP:")
""
(box :halign "end"
(label :text "Offline"
:class "highlight"
:visible {!network--data.have_public_ip})
(label :text {network--data.public_ip.ip}
:class "special"
:visible {network--data.have_public_ip})))
(centerbox :orientation "h"
:halign "start"
:spacing 10
:width 200
:space-evenly false
(box :halign "start"
:class "nebula"
"Gateway:")
""
(box :halign "end"
(label :text "Error"
:class "highlight nebula"
:visible {!network--data.have_gateway})
(label :text {network--data.gateway}
:class "special"
:visible {network--data.have_gateway})))
(centerbox :orientation "h"
:halign "start"
:class "nebula"
:spacing 10
:width 200
:space-evenly false
(box :halign "start"
"VPN:")
""
(box :halign "end"
(label :text "Offline"
:class "highlight"
:visible {!network--data.interfaces.ezrinet.online})
(label :text "Online"
:class "green"
:visible {network--data.interfaces.ezrinet.online})))
))

View File

@ -1,81 +1,306 @@
#!/usr/bin/env python3
import subprocess
import trparse
from subprocess import run, PIPE, DEVNULL
import json
from time import sleep
import sys
import os
import re
from time import sleep, time as now
from ipaddress import (
IPv4Address as IPAddress,
IPv4Network as IPNetwork,
IPv4Interface as IPInterface,
AddressValueError,
)
from netifaces import interfaces, ifaddresses, AF_INET, AF_LINK, gateways
import dbus
from datetime import datetime
TRUSTED_NETWORKS = ['gayer people']
def wifi():
ssid_cmd = subprocess.run(['iwgetid', '-r'], capture_output = True)
if ssid_cmd.returncode != 0:
return {"connected": False, "ssid": None}
ssid = ssid_cmd.stdout.decode('utf-8').strip()
ssid = ssid if len(ssid) <= 15 else f"{ssid[:14]}…"
return {"connected": True, "ssid": ssid}
# These are networks that are considered secure. All traffic being routed
# through one of these networks is being encrypted and routed through an
# anonymizing service.
SECURE_FIRSTHOP_NETWORKS = {
"home": IPNetwork("10.242.0.0/16"), # Personal network
"mullvad": IPNetwork("10.64.0.1/32"), # Mullvad VPN
"usu": IPNetwork("129.123.8.126/32"), # USU VPN
}
def netdev(device: str):
ip_cmd = subprocess.run(['ip', '-j', 'addr', 'show', device], capture_output = True)
if ip_cmd.returncode != 0:
return {"exists": False}
ip_data = json.loads(ip_cmd.stdout.decode('utf-8'))[0]
online = ip_data["operstate"] == "UP"
ip4_addr = ""
ip4_prefix_length = 24
addr4_info = list(filter(lambda addr: addr.get("family") == "inet", ip_data["addr_info"]))
if len(addr4_info) >= 1:
ip4_addr = addr4_info[0]["local"]
ip4_prefix_length = addr4_info[0]["prefixlen"]
connecting = ip_data["operstate"] != "DOWN" and (ip4_addr == "" or not online)
# Interfaces that we should check
DEFAULT_INTERFACES_TO_WATCH = ["lan", "ezrinet"]
# Interfaces that we should use when determining if we are online
DEFAULT_INTERFACES_TO_COUNT = ["lan"]
# Overrides for IP addresses to ping to determine if an interface is
# online This is useful for interfaces that don't have or report a
# gateway, but we still want to check if they're online, such as the
# ezrinet interface.
INTERFACE_PING_OVERRIDES = {"ezrinet": IPAddress("10.242.3.1")}
INTERFACES_TO_WATCH = os.environ.get(
"NETWORK_INTERFACES_TO_WATCH", ",".join(DEFAULT_INTERFACES_TO_WATCH)
).split(",")
INTERFACES_TO_COUNT = os.environ.get(
"NETWORK_INTERFACES_TO_COUNT", ",".join(DEFAULT_INTERFACES_TO_COUNT)
).split(",")
for key, value in os.environ.items():
if key[: len("NETWORK_PING_OVERRIDE_")] == "NETWORK_PING_OVERRIDE_":
INTERFACE_PING_OVERRIDES[key[len("NETWORK_PING_OVERRIDE_") :]] = IPAddress(
value
)
class Interface:
name: str
mac: str
addresses: list[IPInterface]
gateway: IPAddress | None
@property
def online(self):
# If we have no addresses, we're not online
if len(self.addresses) == 0:
return False
# If we have an override, ping that
if self.name in INTERFACE_PING_OVERRIDES:
return ping(INTERFACE_PING_OVERRIDES[self.name])
# If we have no gateway, this interface is likely not intended
# to route beyond the local network, so we'll assume it's
# online, at least for whatever it's used for.
if self.gateway is None:
return True
return ping(self.gateway)
def asdict(self):
return {
"name": self.name,
"mac": self.mac,
"addresses": [
{
"address": str(addr.ip),
"netmask": str(addr.netmask),
"network": str(addr.network),
"prefixlen": addr._prefixlen,
}
for addr in self.addresses
],
"online": self.online,
}
def get_first_hop() -> IPAddress | None:
"""Get the first network hop."""
# Use ping to get the first hop
cmd = ["/usr/bin/ping", "-c1", "-W0.3", "-t1", "1.1.1.1"]
result = run(cmd, stdout=PIPE, stderr=PIPE)
try:
ip = IPAddress(result.stdout.decode("utf-8").split("\n")[1].split()[1])
except (IndexError, AddressValueError):
# If we can't parse the output, return None
return None
return ip
def validate_first_hop_is_secure(first_hop: IPAddress):
"""Check if the first hop is in a secure network."""
for name, network in SECURE_FIRSTHOP_NETWORKS.items():
if first_hop in network:
return name
def get_gateways():
"""Get gateways on each interface."""
gw = gateways().get(AF_INET, [])
result = {}
for iface in INTERFACES_TO_WATCH:
for gateway in gw:
if gateway[1] == iface:
result[iface] = gateway[0]
return result
def interface_status(interface: str, gw):
"""Get the status of an interface."""
try:
addrs = ifaddresses(interface)
except:
addrs = {}
result = Interface()
result.name = interface
result.gateway = gw.get(interface, None)
if AF_LINK in addrs:
result.mac = addrs[AF_LINK][0]["addr"]
else:
result.mac = None
if AF_INET in addrs:
result.addresses = [
IPInterface(f'{addr["addr"]}/{addr["netmask"]}')
for addr in addrs.get(AF_INET, [])
]
else:
result.addresses = []
return result
def ping(host: IPAddress) -> bool:
cmd = ["/usr/bin/ping", "-c1", "-w1", str(host)]
result = run(cmd, stdout=DEVNULL, stderr=DEVNULL)
return result.returncode == 0
def get_public_ip():
"""Get the public IP address."""
cmd = ["/usr/bin/curl", "-s", "https://ipinfo.io"]
result = run(cmd, stdout=PIPE, stderr=PIPE)
try:
data = json.loads(result.stdout.decode("utf-8"))
except (IndexError, ValueError):
return None
try:
# If the IP address is invalid, don't return anything
IPAddress(data["ip"])
except (AddressValueError, KeyError):
if data.get("status", None) == 429:
# We're rate limited, so return something indicating that
return {"rate_limited": True}
return None
return data
def get_default_route():
"""Get the default route."""
cmd = ["/usr/bin/ip", "route", "show", "default"]
result = run(cmd, stdout=PIPE, stderr=PIPE)
try:
# Get first line (might have multiple gateway routes)
line = result.stdout.decode("utf-8").split("\n")[0]
# Get the gateway link (following "dev")
link = re.search(r"dev\s+(\S+)", line).group(1)
# We already know the gateway IP based on our firsthop check earlier, and that's more reliable since it will respect any routing rules
except (IndexError, AttributeError):
return None
return link
def format_time(time: datetime) -> dict[str, str | int]:
"""Format a datetime object for display."""
return {
"exists": True,
"online": online,
"connecting": connecting,
"offline": not online and not connecting,
"ip4_addr": ip4_addr,
"ip4_prefix": ip4_prefix_length
"hour": f"{time.hour:02}",
"minute": f"{time.minute:02}",
"second": f"{time.second:02}",
"year": f"{time.year:04}",
"month": f"{time.month:02}",
"day": f"{time.day:02}",
"unix": int(time.timestamp()),
}
def trusted(ssid: str | None):
# Don't throw up an "INSECURE" alert when offline
if not ssid:
return True
return ssid in TRUSTED_NETWORKS
def ping(host: str):
ping_cmd = subprocess.Popen(['/usr/bin/ping', '-c1', '-W2', host], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
return ping_cmd
# system_bus = dbus.SystemBus()
# networkd = system_bus.get_object(
# "org.freedesktop.network1", "/org/freedesktop/network1"
# )
# manager = dbus.Interface(networkd, "org.freedesktop.network1.Manager")
counter = 0
ezrinet_last = False
internet_last = False
ezrinet_ping = None
internet_ping = None
# def get_dbus_interfaces():
# for iface in INTERFACES_TO_WATCH:
# dbus_object = system_bus.get_object(
# "org.freedesktop.network1", manager.GetLinkByName(iface)
# )
# dbus_interface = dbus.Interface(dbus_object, "org.freedesktop.network1.Link")
# yield dbus_interface
runtime_dir = os.environ.get("XDG_RUNTIME_DIR", "/tmp")
def load_last_data(var_name: str):
try:
if os.path.exists(f"{runtime_dir}/{var_name}.json"):
with open(f"{runtime_dir}/{var_name}.json", "r") as f:
return json.load(f), os.path.getmtime(f"{runtime_dir}/{var_name}.json")
except:
pass
return None, None
def store_last_data(var_name: str, data):
with open(f"{runtime_dir}/{var_name}.json", "w") as f:
json.dump(data, f)
last_default_route = load_last_data("default_route")[0]
last_ip_data, last_request = load_last_data("ip_data")
try:
last_first_hop = IPAddress(load_last_data("first_hop")[0])
except:
last_first_hop = None
while True:
if counter == 0:
ezrinet_ping = ping('10.242.3.1')
internet_ping = ping('1.1.1.1')
if ezrinet_ping.poll() is not None:
ezrinet_last = ezrinet_ping.returncode == 0
if internet_ping.poll() is not None:
internet_last = internet_ping.returncode == 0
wifi_data = wifi()
result = {
"wifi": wifi_data,
"network": {
"wlan0": netdev("wlan0"),
"ezrinet": netdev("ezrinet"),
"wg-mullvad": netdev("mullvad"),
},
"connection": {
"ezrinet": ezrinet_last,
"internet": internet_last
},
"trusted": trusted(wifi_data.get("ssid", None))
}
print(json.dumps(result), flush=True)
counter += 1
# Send pings every 10 seconds
counter %= 3
sleep(1)
try:
online = ping("1.1.1.1")
except:
online = False
hop = get_first_hop()
gw = get_gateways()
default_route = get_default_route()
# public IP shouldn't change often, so only check every 2 hours or
# if the default route or first hop changes
if (
default_route != last_default_route
or last_ip_data is None
or last_request is None
or now() - last_request > (2 * 60 * 60)
or (hop != last_first_hop and hop is not None)
):
print("refreshing public IP", file=sys.stderr, flush=True)
public_ip_data = get_public_ip()
if public_ip_data is None:
print("failed to get public IP", file=sys.stderr, flush=True)
elif public_ip_data.get("rate_limited", False):
last_ip_data = public_ip_data
public_ip_data = None
else:
last_ip_data = public_ip_data
# Write the public IP data to a file
store_last_data("ip_data", public_ip_data)
last_default_route = default_route
store_last_data("default_route", default_route)
last_request = now()
last_first_hop = hop
store_last_data("first_hop", str(hop))
else:
public_ip_data = last_ip_data
if hop is not None:
secure_msg = validate_first_hop_is_secure(hop)
secure = secure_msg is not None
else:
# If we can't reach the router, assume insecure
secure = False
iface_data = [interface_status(iface, gw) for iface in INTERFACES_TO_WATCH]
iface_dict = {iface.name: iface.asdict() for iface in iface_data}
default_route_iface_data = interface_status(default_route, gw)
print(
json.dumps(
{
"online": online,
"secure": secure,
"interfaces": iface_dict,
"public_ip": public_ip_data or {},
"have_public_ip": public_ip_data is not None and "ip" in public_ip_data,
"default_route": default_route,
"default_interface": default_route_iface_data.asdict(),
"have_default_route": default_route is not None,
"gateway": str(hop),
"have_gateway": hop is not None,
"last_update": format_time(datetime.now()),
}
),
flush=True,
)
sleep(5)

View File

@ -38,20 +38,20 @@ column_meters_0=Hostname Blank Tasks LoadAverage Uptime Clock
column_meter_modes_0=2 2 2 2 2 2
column_meters_1=AllCPUs2 Blank MemorySwap
column_meter_modes_1=1 2 1
tree_view=1
sort_key=0
tree_sort_key=0
sort_direction=1
tree_sort_direction=1
tree_view=0
sort_key=46
tree_sort_key=46
sort_direction=-1
tree_sort_direction=-1
tree_view_always_by_pid=0
all_branches_collapsed=0
screen:Main=PID USER PRIORITY NICE M_VIRT M_RESIDENT M_SHARE STATE PERCENT_CPU PERCENT_MEM TIME Command
.sort_key=PID
.tree_sort_key=PID
.sort_key=PERCENT_CPU
.tree_sort_key=PERCENT_CPU
.tree_view_always_by_pid=0
.tree_view=1
.sort_direction=1
.tree_sort_direction=1
.tree_view=0
.sort_direction=-1
.tree_sort_direction=-1
.all_branches_collapsed=0
screen:I/O=PID USER IO_PRIORITY IO_RATE IO_READ_RATE IO_WRITE_RATE PERCENT_SWAP_DELAY PERCENT_IO_DELAY Command
.sort_key=IO_RATE

View File

@ -199,6 +199,9 @@ for_window [floating] border normal 1
## Thunderbird New.* windows should float
for_window [app_id="thunderbird" title="(New|Write)"] floating enable
## Bitwarden extension windows should float by default
for_window [app_id="firefox" title="Extension: \(Bitwarden Password Manager\)"] floating enable
### ###
# Application Keybinds #
### ###

View File

@ -1,3 +0,0 @@
#-*-conf-space-*-
exec_always gsettings set org.gnome.desktop.interface text-scaling-factor 1.25

View File

@ -20,30 +20,3 @@ workspace {
10 output $display
}
## Workspace Switching Keybinds
bindsym {
$mod+1 exec swaymsg workspace 1
$mod+2 exec swaymsg workspace 2
$mod+3 exec swaymsg workspace 3
$mod+4 exec swaymsg workspace 4
$mod+5 exec swaymsg workspace 5
$mod+6 exec swaymsg workspace 6
$mod+7 exec swaymsg workspace 7
$mod+8 exec swaymsg workspace 8
$mod+9 exec swaymsg workspace 9
$mod+0 exec swaymsg workspace 10
}
## Window Reassignment Keybinds
bindsym {
$mod+Shift+1 exec swaymsg move container to workspace 1
$mod+Shift+2 exec swaymsg move container to workspace 2
$mod+Shift+3 exec swaymsg move container to workspace 3
$mod+Shift+4 exec swaymsg move container to workspace 4
$mod+Shift+5 exec swaymsg move container to workspace 5
$mod+Shift+6 exec swaymsg move container to workspace 6
$mod+Shift+7 exec swaymsg move container to workspace 7
$mod+Shift+8 exec swaymsg move container to workspace 8
$mod+Shift+9 exec swaymsg move container to workspace 9
$mod+Shift+0 exec swaymsg move container to workspace 10
}

View File

@ -1,76 +1,249 @@
{
"default_context": "personal",
"display_ordering": ["builtin"],
"display_layout": {
"builtin": "eDP-1"
},
"default_context": "personal-portable",
"workspaces": [
{
"index": 1,
"name": "console",
"exec": "console",
"program_name": "console"
},
{
"index": 2,
"name": "code",
"exec": "emacsclient",
"args": ["-nc"],
"program_name": "emacsclient"
},
{
"index": 3,
"name": "documentation",
"exec": "firefox",
"args": ["--new-window"],
"environ": {},
"program_name": "firefox"
},
{
"index": 4,
"name": "project",
"exec": "firefox",
"args": ["--new-window"],
"program_name": "firefox"
},
{
"index": 5,
"name": "discord",
"exec": "discord",
"program_name": "discord"
},
{
"index": 6,
"name": "console",
"exec": "console",
"program_name": "console"
},
{
"index": 7,
"name": "code",
"exec": "emacsclient",
"args": ["-nc"],
"program_name": "emacsclient"
},
{
"index": 8,
"name": "internet",
"exec": "firefox",
"args": ["--new-window"],
"program_name": "firefox"
},
{
"index": 9,
"name": "project",
"exec": "firefox-developer-edition",
"args": ["-start-debugger-server", "--new-window"],
"program_name": "firefox-developer-edition"
},
{
"index": 10,
"name": "server management",
"exec": "virt-manager",
"program_name": "virt-manager",
"systemd": false
},
{
"index": 11,
"name": "password management",
"exec": "bitwarden-desktop",
"program_name": "bitwarden"
},
{
"index": 12,
"name": "video",
"exec": "jellyfinmediaplayer",
"program_name": "jellyfinmediaplayer"
},
{
"index": 13,
"name": "edex-ui",
"exec": "edex-ui",
"program_name": "edex-ui"
},
{
"index": 14,
"name": "mail",
"exec": "thunderbird",
"program_name": "thunderbird",
"environ": {
"MOZ_ENABLE_WAYLAND": "1"
}
},
{
"index": 15,
"name": "config",
"exec": "console",
"program_name": "console"
},
{
"index": 16,
"name": "console",
"exec": "console",
"program_name": "console"
},
{
"index": 17,
"name": "code",
"exec": "emacsclient",
"args": ["-nc"],
"program_name": "emacsclient"
},
{
"index": 18,
"name": "music",
"exec": "feishin",
"program_name": "feishin"
},
{
"index": 19,
"name": "project",
"exec": "firefox",
"args": ["--new-window"],
"program_name": "firefox"
},
{
"index": 20,
"name": "slack",
"exec": "slack",
"program_name": "slack",
"args": [
"--enable-features=UseOzonePlatform",
"--ozone-platform=wayland",
"--enable-gpu-rasterization"
],
"memory_profile": {
"high": "800M",
"max": "1.2G"
}
},
{
"index": 21,
"name": "ferrets",
"exec": "firefox",
"args": ["--new-window", "https://www.twitch.tv/ferretsoftware"],
"program_name": "firefox"
}
],
"contexts": {
"personal": {
"builtin": [
"docked": {
"primary": "center",
"outputs": [
{
"index": 1,
"name": "terminal",
"exec": "console",
"program_name": "console"
"names": ["eDP-1"],
"group": "builtin",
"position": [0, 600],
"eww_windows": ["builtinbar"],
"mode": "2560x1600@165Hz scale 1.5 color_profile icc /usr/share/color/icc/colord/BOE_CQ_______NE160QDM_NZ6.icm"
},
{
"index": 2,
"name": "code",
"exec": "emacsclient",
"args": ["-nc"],
"program_name": "emacsclient"
"make": "Acer Technologies",
"model": "XV271U M3",
"serial": "1322131231233",
"group": "left",
"position": [1707, 0],
"mode": "2560x1440@120Hz",
"eww_windows": ["leftbar", "sidebar"]
},
{
"index": 3,
"name": "internet",
"exec": "firefox",
"args": ["--new-window"],
"program_name": "firefox"
"make": "Dell Inc.",
"model": "DELL U3818DW",
"serial": "97F8P9350W0L",
"group": "center",
"position": [4267, 0],
"mode": "3840x1600",
"eww_windows": ["centerbar"]
},
{
"index": 4,
"name": "project",
"exec": "firefox",
"args": ["--new-window"],
"program_name": "firefox"
},
{
"index": 5,
"name": "servers",
"exec": "virt-manager",
"program_name": "virt-manager"
},
{
"index": 6,
"name": "steam",
"exec": "steam",
"program_name": "steam"
},
{
"index": 7,
"name": "media",
"exec": "jellyfinmediaplayer",
"program_name": "jellyfinmediaplayer"
},
{
"index": 8,
"name": "real-time comms",
"exec": "discord",
"program_name": "discord"
},
{
"index": 9,
"name": "messages",
"exec": "thunderbird",
"program_name": "thunderbird"
},
{
"index": 10,
"name": "config",
"exec": "pavucontrol",
"program_name": "pavucontrol"
"make": "Acer Technologies",
"model": "XV271U M3",
"serial": "1431038964205",
"group": "right",
"position": [8107, 0],
"mode": "2560x1440@120Hz",
"eww_windows": ["rightbar"]
}
]
],
"groups": {
"builtin": {
"workspaces": [21],
"reverse": false
},
"left": {
"workspaces": [1, 2, 3, 4, 5],
"reverse": true
},
"center": {
"workspaces": [6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
"reverse": false
},
"right": {
"workspaces": [16, 17, 18, 19, 20],
"reverse": false
}
}
},
"work-portable": {
"primary": "builtin",
"outputs": [
{
"names": ["eDP-1"],
"group": "builtin",
"position": [0, 0],
"eww_windows": ["builtinbar"],
"mode": "2560x1600@165Hz scale 1.25 color_profile icc /usr/share/color/icc/colord/BOE_CQ_______NE160QDM_NZ6.icm"
}
],
"groups": {
"builtin": {
"workspaces": [6, 7, 8, 9, 10, 11, 18, 20, 14, 15],
"reverse": false
}
}
},
"personal-portable": {
"primary": "builtin",
"outputs": [
{
"names": ["eDP-1"],
"group": "builtin",
"position": [0, 0],
"eww_windows": ["builtinbar"],
"mode": "2560x1600@165Hz scale 1.25 color_profile icc /usr/share/color/icc/colord/BOE_CQ_______NE160QDM_NZ6.icm"
}
],
"groups": {
"builtin": {
"workspaces": [6, 7, 8, 9, 10, 11, 18, 5, 14, 15],
"reverse": false
}
}
}
}
}

View File

@ -13,8 +13,8 @@ Restart=on-failure
Slice=session.slice
MemoryAccounting=yes
# Tide eats memory like crazy, so lets put it on a diet.
MemoryHigh=3G
MemoryMax=5G
MemoryHigh=8G
MemoryMax=10G
[Install]
WantedBy=graphical-session.target

View File

@ -3,8 +3,8 @@ Description=eww status bars
PartOf=sway-session.target
[Service]
Type=forking
ExecStart=eww daemon
Type=simple
ExecStart=eww daemon --no-daemonize
ExecReload=eww reload
ExecStop=eww kill
ExecStopPost=sleep 1

View File

@ -7,7 +7,7 @@ alias userctl="\systemctl --user"
alias ujournalctl="\journalctl --user"
alias reconf="source $HOME/.zshrc"
alias reconf="exec $SHELL"
alias cp="cp -i --reflink=auto"
alias mv="mv -i"

View File

@ -11,7 +11,7 @@ PATH_wincmake=/opt/msvcmake/bin:/opt/msvc/bin/x64
cdpath=(~ ~/src)
export PATH=.:$PATH_asdf:$PATH_node:$PATH_pyenv:$PATH_java:$PATH_user:$PATH_system
export PATH=.:$PATH_node:$PATH_pyenv:$PATH_java:$PATH_user:$PATH_system
# Function to run a command with only the "safe" system PATH element
function safeexec {

View File

@ -1,2 +0,0 @@
# source $HOME/.local/lib/asdf/asdf.sh
# source $HOME/.local/lib/asdf/completions/asdf.bash

View File

@ -513,26 +513,29 @@ Indent using tabs, render with tab-width of 2.
:config
(setq company-idle-delay 0.3))
#+END_SRC
** LSP Mode
** LSP
#+BEGIN_SRC emacs-lisp
(use-package lsp-mode
:ensure t
:init
;; set prefix for lsp-command-keymap (few alternatives - "C-l", "C-c l")
(setq lsp-keymap-prefix "C-c l")
:hook ((python-mode . lsp) ;; pip install python-lsp-server pyls-black pyls-isort pyls-mypy
(elixir-mode . lsp)
(rust-mode . lsp)
(java-mode . lsp)
(php-mode . lsp)
(typescript-mode . lsp) ;; npm install -g typescript typescript-language-server
(lsp-mode . lsp-enable-which-key-integration))
:config (lsp-register-custom-settings
'(("pyls.plugins.pyls_mypy.enabled" t t)
("pyls.plugins.pyls_mypy.live_mode" nil t)
("pyls.plugins.pyls_black.enabled" t t)
("pyls.plugins.pyls_isort.enabled" t t)))
:commands lsp)
;; (use-package lsp-mode
;; :ensure t
;; :init
;; ;; set prefix for lsp-command-keymap (few alternatives - "C-l", "C-c l")
;; (setq lsp-keymap-prefix "C-c l")
;; :hook ((python-mode . lsp) ;; pip install python-lsp-server pyls-black pyls-isort pyls-mypy
;; (elixir-mode . lsp)
;; (rust-mode . lsp)
;; (java-mode . lsp)
;; (php-mode . lsp)
;; (typescript-mode . lsp) ;; npm install -g typescript typescript-language-server
;; )
;; :config (lsp-register-custom-settings
;; '(("pyls.plugins.pyls_mypy.enabled" t t)
;; ("pyls.plugins.pyls_mypy.live_mode" nil t)
;; ("pyls.plugins.pyls_black.enabled" t t)
;; ("pyls.plugins.pyls_isort.enabled" t t)))
;; :commands lsp)
(use-package eglot
:ensure t)
#+END_SRC
** Languages
@ -570,11 +573,11 @@ After installing the ~rust-analyzer~ program, the following can be used:
(add-to-list 'auto-mode-alist '("\\.tsx\\'" . tsx-ts-mode))
(add-hook 'tsx-ts-mode-hook #'lsp)
(add-hook 'tsx-ts-mode-hook #'setup-tide-mode)
;; (add-hook 'tsx-ts-mode-hook #'eglot)
;; (add-hook 'tsx-ts-mode-hook #'setup-tide-mode)
(add-hook 'typescript-ts-mode-hook #'lsp)
(add-hook 'typescript-ts-mode-hook #'setup-tide-mode)
;; (add-hook 'typescript-ts-mode-hook #'eglot)
;; (add-hook 'typescript-ts-mode-hook #'setup-tide-mode)
#+END_SRC
**** TIDE
#+BEGIN_SRC emacs-lisp