initial commit of new dotfiles repo

This commit is contained in:
Ezri Brimhall 2024-03-06 16:35:10 -07:00
commit fb4d968caf
Signed by: ezri
GPG Key ID: D4EE46AFBD899DB5
91 changed files with 7931 additions and 0 deletions

View File

@ -0,0 +1,66 @@
working_directory = "/home/ezri"
[bell]
animation = "EaseOutSine"
color = "0x9a7c9d"
duration = 200
[colors]
draw_bold_text_with_bright_colors = false
[colors.bright]
black = "0x3f3242"
blue = "0x7587a6"
cyan = "0xafc4db"
green = "0x8f9d6a"
magenta = "0x9b859d"
red = "0xcf6a4c"
white = "0xffffff"
yellow = "0xf9ee98"
[colors.normal]
black = "0x2d272f"
blue = "0x7587a6"
cyan = "0xafc4db"
green = "0x8f9d6a"
magenta = "0x9b859d"
red = "0xcf6a4c"
white = "0xa7a7a7"
yellow = "0xf9ee98"
[colors.primary]
background = "0x1e1e1e"
foreground = "0x9a7c9d"
[cursor.style]
blinking = "Always"
shape = "underline"
[debug]
highlight_damage = false
render_timer = false
[font]
size = 9
[font.bold]
family = "JetBrainsMono Nerd Font"
style = "Bold"
[font.bold_italic]
family = "JetBrainsMono Nerd Font"
style = "Semibold Italic"
[font.italic]
family = "JetBrainsMono Nerd Font"
style = "Italic"
[font.normal]
family = "JetBrainsMono Nerd Font"
style = "Regular"
[window]
dynamic_padding = true
dynamic_title = true
opacity = 0.98
title = "Terminal"

View File

@ -0,0 +1,92 @@
colors:
# Default colors
primary:
# background: '0x1b191b'
# foreground: '0x9a7c9d'
background: '0x1e1e1e'
foreground: '0x9a7c9d'
# Normal colors
normal:
black: '0x2d272f'
red: '0xcf6a4c'
green: '0x8f9d6a'
yellow: '0xf9ee98'
blue: '0x7587a6'
magenta: '0x9b859d'
cyan: '0xafc4db'
white: '0xa7a7a7'
# Bright colors
bright:
black: '0x3f3242'
red: '0xcf6a4c'
green: '0x8f9d6a'
yellow: '0xf9ee98'
blue: '0x7587a6'
magenta: '0x9b859d'
cyan: '0xafc4db'
white: '0xffffff'
# normal:
# black: '0x453f45'
# red: '0xd27377'
# green: '0x7e9d7c'
# yellow: '0xd2c377'
# blue: '0x7587a6'
# magenta: '0xae96b0'
# cyan: '0xb0c4c2'
# white: '0xd6cad7'
# bright:
# black: '0x453f45'
# red: '0xd27377'
# green: '0x7e9d7c'
# yellow: '0xd2c377'
# blue: '0x7587a6'
# magenta: '0xae96b0'
# cyan: '0xb0c4c2'
# white: '0xd6cad7'
cursor:
style:
blinking: Always
shape: underline
font:
size: 9
normal:
family: JetBrainsMono Nerd Font
style: Regular
bold:
family: JetBrainsMono Nerd Font
style: Bold
italic:
family: JetBrainsMono Nerd Font
style: Italic
bold_italic:
family: JetBrainsMono Nerd Font
style: Semibold Italic
window:
title: Terminal
dynamic_title: true
opacity: 0.98
dynamic_padding: true
bell:
animation: EaseOutSine
duration: 200
color: '0x9a7c9d'
working_directory: /home/ezri
draw_bold_text_with_bright_colors: false
debug:
render_timer: false
highlight_damage: false

84
.config/dunst/dunstrc Normal file
View File

@ -0,0 +1,84 @@
# -*-conf-unix-*-
[global]
# Settings
monitor = 0
follow = none
# Window Geometry / Appearance
width = 300
origin = top-center
offset = 0x-36
height = 150
indicate_hidden = yes
shrink = no
transparency = 0
notification_height = 0
separator_height = 1
padding = 5
horizontal_padding = 5
frame_width = 1
background = "#1e1e1e"
separator_color = frame
corner_radius = 0
title = Notification
class = Dunst
sort = yes
# Text Apperanace
font = JetBrainsMono 9,Nebula 9
line_height = 0
markup = full
#format = "<b>%a: %s</b>\n───────────────\n%b <i>%p</i>"
format = "<span font-family='Nebula' font-size='11pt'>%a</span>\n<span font-family='JetBrainsMono' font-size='9pt'>%s</span>\n\n<span font-family='JetBrainsMono' font-size='8pt'>%b</span>"
alignment = center
vertical_alignment = top
show_age_threshold = 120
word_wrap = yes
ellipsize = middle
ignore_newline = no
stack_duplicates = true
hide_duplicate_count = false
show_indicators = yes
# Icons
icon_position = off
# History
sticky_history = yes
history_length = 20
# Misc
dmenu = /usr/bin/rofi -dmenu -p dunst:
browser = /usr/bin/firefox --new-tab
always_run_script = true
startup_notification = true
verbosity = mesg
ignore_dbusclose = false
# Mouse
mouse_left_click = do_action, close_current
mouse_middle_click = none
mouse_right_click = none
[urgency_low]
background = "#1e1e1e"
#background = "#3B4252"
foreground = "#9a7c9d"
frame_color = "#3f3242"
timeout = 10
[urgency_normal]
background = "#1e1e1e"
foreground = "#9b859d"
frame_color = "#815986"
timeout = 60
[urgency_critical]
background = "#1e1e1e"
foreground = "#cf6a4c"
frame_color = "#cf6a4c"
timeout = 0

View File

@ -0,0 +1 @@
eww-modules

13
.config/eww/colors.scss Normal file
View File

@ -0,0 +1,13 @@
$wallpaper: #1e1e1e;
$foreground: #9a7c9d;
$bg0: #2d272f;
$bg1: #3f3242;
$red: #cf6a4c;
$green: #8f9d6a;
$yellow: #f9ee98;
$blue: #7587a6;
$magenta: #9b859d;
$cyan: #afc4db;
$white: #a7a7a7;

98
.config/eww/eww.scss Normal file
View File

@ -0,0 +1,98 @@
@import "colors";
* {
all: unset;
}
.root {
color: $foreground;
font-family: "JetBrains Mono";
font-size: 8.5pt;
background-color: rgba(0, 0, 0, 0);
// Probably needs to change
&.bar {
margin: 10px;
margin-bottom: 0px;
}
&.side {
margin: 10px;
margin-right: 0px;
}
&.bg {
background-color: $bg0;
padding: 10px;
}
}
.nebula {
font-family: "Nebula";
font-size: 1.2em;
&.big,
.big {
font-size: 2em;
}
&.medium,
.medium {
font-size: 1.6em;
&.small {
font-size: 1.4em;
}
}
}
.icon {
font-family: "Font Awesome 5 Free Solid";
}
.highlight {
color: $red;
}
.offline {
color: $bg1;
}
.special {
color: $blue;
}
.green {
color: $green;
}
.big {
font-size: 12pt;
}
// sway module
.sway--ws {
color: $bg1;
&.sway--active {
color: $foreground;
}
&.sway--visible {
color: $blue;
}
&.sway--focused {
.fill {
background-color: $foreground;
}
}
}
// clock module
.clock--time {
font-size: 20pt;
}
.clock--date {
font-size: 9pt;
}

170
.config/eww/eww.yuck Normal file
View File

@ -0,0 +1,170 @@
;; Include modules
(include "./modules/workspaces/workspaces.yuck")
(include "./modules/clock/clock.yuck")
(include "./modules/system/system.yuck")
(include "./modules/network/network.yuck")
(include "./modules/volume/volume.yuck")
(include "./modules/aggietime/aggietime.yuck")
(include "./modules/weather/weather.yuck")
(include "./modules/timer/timer.yuck")
(include "./modules/mpris/mpris.yuck")
;; Windows
(defwidget leftbar--left
[]
(box :orientation "h"
:halign "start"
:space-evenly false
:spacing 20
:class "leftbox"
(clock)
(network)
(vpn-network)
(aggietime-shift)))
(defwidget leftbar--center
[]
(box :orientation "h"
:halign "center"
:space-evenly false
:spacing 0
:class "centerbox"
(system-name)))
(defwidget leftbar--right
[]
(box :orientation "h"
:halign "end"
:space-evenly false
:spacing 20
:class "rightbox"
(sway-workspace :group "left")
(sway-workspaces :group "left")))
(defwidget rightbar--left
[]
(box :orientation "h"
:halign "start"
:space-evenly false
:spacing 20
:class "leftbox"
(sway-workspaces :group "right")
(sway-workspace :group "right")))
(defwidget rightbar--hypr-left
[]
(box :orientation "h"
:halign "start"
:space-evenly false
:spacing 20
:class "leftbox"
(hypr-workspaces :group "main")
(hypr-workspace :group "main")))
(defwidget rightbar--center
[]
(box :orientation "h"
:halign "center"
:space-evenly false
:spacing 0
:class "centerbox"
(system-name)))
(defwidget rightbar--right
[]
(box :orientation "h"
:halign "end"
:space-evenly false
:spacing 20
:class "leftbox"
(mpris)
(system-memory)
(system-cpu-avg)
(clock)))
(defwidget sidebar
[]
(box :orientation "v"
:valign "start"
:space-evenly false
:spacing 0
:class "bar root"
(clock)))
(defwindow leftbar
:monitor 0
:geometry (geometry :width "100%"
:height "36px"
:anchor "top center"):exclusive
true
:focusable false
:stacking "fg"
(centerbox :orientation "h"
:class "bar root"
(leftbar--left)
(leftbar--center)
(leftbar--right)))
(defwindow rightbar
:monitor 1
:geometry (geometry :width "100%"
:height "26px"
:anchor "top center"):exclusive
true
:focusable false
:stacking "fg"
(centerbox :orientation "h"
:class "bar root"
(rightbar--left)
(rightbar--center)
(rightbar--right)))
(defwindow network-status
:monitor 0
:geometry (geometry :width "200px"
:height "0px"
:x "80px"
:y "0px"
:anchor "top left")
:exclusive false
:focusable false
:stacking "overlay"
(box :orientation "v"
:class "bar root bg"
:visible {network--show-details}
(network-detail)))
(defwindow lock-overlay-1
:monitor 1
:geometry (geometry :width "50%"
:height "50%"
:anchor "center"):exclusive
false
:focusable false
:stacking "overlay"
"testing")
(defwindow hypr-mainbar
:monitor 0
:geometry (geometry :width "100%"
:height "36px"
:anchor "top center"):exclusive
true
:focusable false
:stacking "overlay"
(centerbox :orientation "h"
:class "bar root"
(rightbar--hypr-left)
(rightbar--center)
(rightbar--right)))
(defwindow sidebar
:monitor 0
:geometry (geometry :width "210px"
:height "1044px"
:anchor "left bottom"):exclusive
true
:focusable false
:stacking "fg"
(sidebar))

128
.config/eww/eww.yuck~ Normal file
View File

@ -0,0 +1,128 @@
;; Include modules
(include "./modules/workspaces/workspaces.yuck")
(include "./modules/clock/clock.yuck")
(include "./modules/system/system.yuck")
(include "./modules/network/network.yuck")
(include "./modules/volume/volume.yuck")
;; Windows
(defwidget leftbar--left []
(box :orientation "h"
:halign "start"
:space-evenly false
:spacing 20
:class "leftbox"
(clock)
(network)
(vpn-network)))
(defwidget leftbar--center []
(box :orientation "h"
:halign "center"
:space-evenly false
:spacing 0
:class "centerbox"
))
(defwidget leftbar--right []
(box :orientation "h"
:halign "end"
:space-evenly false
:spacing 20
:class "rightbox"
(sway-workspace :group "left")
(sway-workspaces :group "left")))
(defwidget rightbar--left []
(box :orientation "h"
:halign "start"
:space-evenly false
:spacing 20
:class "leftbox"
(sway-workspaces :group "right")
(sway-workspace :group "right")))
(defwidget rightbar--hypr-left []
(box :orientation "h"
:halign "start"
:space-evenly false
:spacing 20
:class "leftbox"
(hypr-workspaces :group "main")
(hypr-workspace :group "main")))
(defwidget rightbar--center []
(box :orientation "h"
:halign "center"
:space-evenly false
:spacing 0
:class "centerbox"
))
(defwidget rightbar--right []
(box :orientation "h"
:halign "end"
:space-evenly false
:spacing 20
:class "leftbox"
(system-memory)
(system-cpu-avg)
(clock)))
(defwidget sidebar []
(box :orientation "v"
:valign "start"
:space-evenly false
:spacing 0
:class "bar root"
(clock)))
(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"
(leftbar--left)
(leftbar--center)
(leftbar--right)))
(defwindow rightbar
:monitor 0
:geometry (geometry :width "100%"
:height "26px"
:anchor "top center")
:exclusive true
:focusable false
:stacking "fg"
(centerbox :orientation "h" :class "bar root"
(rightbar--left)
(rightbar--center)
(rightbar--right)))
(defwindow hypr-mainbar
:monitor 0
:geometry (geometry :width "100%"
:height "36px"
:anchor "top center")
:exclusive true
:focusable false
:stacking "overlay"
(centerbox :orientation "h" :class "bar root"
(rightbar--hypr-left)
(rightbar--center)
(rightbar--right)))
(defwindow sidebar
:monitor 1
:geometry (geometry :width "210px"
:height "1044px"
:anchor "left bottom")
:exclusive true
:focusable false
:stacking "fg"
(sidebar))

View File

@ -0,0 +1,25 @@
#!/bin/bash
shift_data=$(aggietimed -s /run/user/1000/aggietimed.sock --action current-shift 2>&1)
if [[ ${shift_data} == "null" ]]; then
echo '{"active": false, "err": false}'
exit
fi
now=$(date +%s)
start=$(date --date=$(echo $shift_data | jq '.start' -r) +%s)
delta=$(( now - start ))
fallback=$(date --date="" +%s)
if [[ $start == $fallback ]]; then
echo '{"active": false, "err": true}'
exit
fi
hours=$(( delta / 3600 ))
minutes=$( printf "%02d" $(( (delta - (hours * 3600)) / 60 )))
seconds=$( printf "%02d" $(( delta - (hours * 3600) - (minutes * 60) )))
echo "{\"active\": true, \"hours\": \"$hours\", \"minutes\": \"$minutes\", \"seconds\": \"$seconds\", \"err\": false}"

View File

@ -0,0 +1,18 @@
(defpoll aggietime--data :interval "10s"
`~/.config/eww/modules/aggietime/aggietime.sh`)
(defwidget aggietime-shift []
(box :class "module text"
:spacing 0
:orientation "v"
:visible {aggietime--data != ''}
(label :class "highlight"
:text "AggieTimeD Not Running"
:visible {aggietime--data.err})
(label :class "special"
:visible {aggietime--data.active && !aggietime--data.err}
:text "${aggietime--data.hours}:${aggietime--data.minutes}")
(label :class "highlight"
:text "not clocked in"
:visible {!aggietime--data.active && !aggietime--data.err})
"current shift"))

View File

@ -0,0 +1,11 @@
(defwidget left-angle []
(image :path "/home/ezri/.config/eww.new/modules/angles/left.png"
:width 150
:height 36))
(defwidget right-angle []
(image :path "/home/ezri/.config/eww.new/modules/angles/right.png"
:width 150
:height 36))

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -0,0 +1,10 @@
(defpoll clock--data :interval "500ms"
`date +'{"hour": "%H", "minute": "%M", "second": "%S", "year": "%Y", "day": "%d", "month": "%m", "dow": "%A", "month_name": "%B", "unix": %s}'`)
(defwidget clock []
(box :class "module text"
:spacing 0
:orientation "v"
(label :class "special"
:text "${clock--data.hour}:${clock--data.minute}:${clock--data.second}")
(label :text "${clock--data.year}-${clock--data.month}-${clock--data.day}")))

View File

@ -0,0 +1,148 @@
#!/usr/bin/env python3
import gi
import os
import sys
import json
import time
import requests
try:
gi.require_version("Playerctl", "2.0")
except:
sys.exit(1)
from gi.repository import Playerctl, GLib
title_maxlen = 30
title_end_at = ["(", "-"]
artist_maxlen = 30
album_maxlen = 30
# Split on these characters, take the first part, and strip whitespace
# from the result. This can be used to remove subtitles (like " - Remastered" or " (feat. Artist)").
album_end_at = ["(", "-"]
class Status:
def __init__(self):
self.running = False
self.playing = False
self.title = None
self.artist = None
self.album = None
self.album_artist = None
self.album_art = None
def _dict_dump(self):
return {
"running": self.running,
"playing": self.playing,
"title": self.title,
"artist": self.artist,
"album": self.album,
"album_artist": self.album_artist,
"album_art": self.album_art,
}
def __str__(self):
return json.dumps(self._dict_dump())
class StatusDisplay:
def __init__(self):
self._player = None
self.last_album_art = None
def show(self):
self._init_player()
main = GLib.MainLoop()
main.run()
def _get_status(self, playing=None):
if self._player:
status = Status()
status.running = self._player.props.playback_status != 2
if playing == None:
status.playing = self._player.props.playback_status == 0
else:
status.playing = playing
status.title = self._player.get_title() or ""
status.artist = self._player.get_artist() or ""
status.album = self._player.get_album() or ""
album_art = (
dict(self._player.get_property("metadata")).get("mpris:artUrl") or ""
)
if album_art != self.last_album_art:
# Need to download the new album art
self.last_album_art = album_art
if album_art.startswith("file://"):
album_art = album_art[7:]
if os.path.exists(album_art):
status.album_art = album_art
else:
try:
r = requests.get(album_art, timeout=1)
# Write album art to tmp file
if r.status_code == 200:
with open("/tmp/album_art", "wb") as f:
f.write(r.content)
status.album_art = "/tmp/album_art"
except:
pass
for end in title_end_at:
if end in status.title:
status.title = status.title.split(end)[0].strip()
if len(status.title) > title_maxlen:
status.title = status.title[: title_maxlen - 1] + ""
if len(status.artist) > artist_maxlen:
status.artist = status.artist[: artist_maxlen - 1] + ""
for end in album_end_at:
if end in status.album:
status.album = status.album.split(end)[0].strip()
if len(status.album) > album_maxlen:
status.album = status.album[: album_maxlen - 1] + ""
return status
else:
return Status()
def _print_status(self, status):
print(status, flush=True)
def _init_player(self):
success = False
while not success:
try:
self._player = Playerctl.Player()
self._player.connect("metadata", self._on_update)
self._player.connect("play", self._on_play)
self._player.connect("pause", self._on_pause)
self._player.connect("exit", self._on_exit)
self._print_status(self._get_status())
success = True
except Exception as e:
# print(e, flush=True, file=sys.stderr)
self._print_status(Status())
time.sleep(2)
def _on_update(self, *args):
self._print_status(self._get_status())
def _on_play(self, *args):
self._print_status(self._get_status(playing=True))
def _on_pause(self, *args):
self._print_status(self._get_status(playing=False))
def _on_exit(self, player):
del self._player
self._player = None
self._init_player()
StatusDisplay().show()

View File

@ -0,0 +1,28 @@
(deflisten mpris--data :initial "{}"
`~/.config/eww/modules/mpris/mpris.py`)
(defwidget mpris
[]
(box :class "module text"
:spacing 0
:orientation "v"
(label :class {mpris--data.playing ? "special" : "offline"}
:visible {mpris--data.running}
:text "${mpris--data.title} by ${mpris--data.artist}")
(label :class "offline"
:visible {!mpris--data.running}
:text "player offline")
(label :visible {mpris--data.running}
:text "now playing from ${mpris--data.album}")
(label :visible {!mpris--data.running}
:text "player offline")))
(defwidget mpris-miniplayer []
(box :class "miniplayer"
:orientation "v"
:spacing 10
(image :path {mpris--data.album_art}
:image-width 100
:image-height 100)
(label)))

View File

@ -0,0 +1,86 @@
#!/usr/bin/env python3
import subprocess
import json
import sys
from time import sleep
TRUSTED_NETWORKS = ["honnouji", "honnouji_2.4"]
def wifi():
try:
ssid_cmd = subprocess.run(["iwgetid", "-r"], capture_output=True)
if ssid_cmd.returncode != 0:
return {"connected": False, "ssid": None}
return {"connected": True, "ssid": ssid_cmd.stdout.decode("utf-8").strip()}
except:
return {"connected": False, "ssid": None}
def netdev(device: str):
ip_cmd = subprocess.run(["ip", "-j", "addr", "show", device], capture_output=True)
if ip_cmd.returncode != 0:
sys.stderr.write(ip_cmd.stdout.decode("utf-8"))
return {
"exists": False,
"online": False,
"connecting": False,
"offline": True,
"ip4_addr": None,
"ip4_prefix": None,
}
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)
return {
"exists": True,
"online": online,
"connecting": connecting,
"offline": not online and not connecting,
"ip4_addr": ip4_addr,
"ip4_prefix": ip4_prefix_length,
}
def trusted(ssid: str | None):
# Don't throw up an "INSECURE" alert when offline
if not ssid:
return True
return ssid in TRUSTED_NETWORKS
while True:
lan = netdev("lan")
wlan = netdev("wlan0")
vpn = netdev("ezrinet")
mullvad = netdev("wg-mullvad")
wifi_data = wifi()
# VPNs are routed over physical interfaces, so don't check them for online status
online = lan["online"] or wlan["online"]
configuring = (lan["connecting"] and not wlan["online"]) or (
wlan["connecting"] and not lan["online"]
)
result = {
"online": online,
"configuring": configuring,
"offline": not online and not configuring,
"network": {
"lan": lan,
"wlan": wlan,
"vpn": vpn,
"mullvad": mullvad,
},
"wifi": wifi_data,
"trusted": True,
}
print(json.dumps(result), flush=True)
sleep(1)

View File

@ -0,0 +1,249 @@
(deflisten network--data
`~/.config/eww/modules/network/new_network.py`)
(defvar network--show-details false)
(defwidget network-big
[]
(box :orientation "h"
:halign "start"
:valign "center"
:space-evenly false
:spacing 10
(label :class "big nebula"
:text "comms:")
(network--interface :device "lan")
(network--interface :device "ezrinet")
(network--secure)
(network--vpn)))
(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 "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-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"]
}
:class "special"
:text "${network--data['wifi']['ssid']}")))
(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
(label :class "highlight"
:text "- insecure"
:visible {!
network--data.secure })
(label :class "green"
:text "- secured via ${network--data.secure_msg}"
:visible {network--data.secure})))
(defwidget vpn-network
[]
(box :orientation "v"
:halign "start"
:space-evenly false
:spacing 0
:visible {network--data
!=
''}
(label :class "highlight"
:text "offline"
:visible {!
network--data.interfaces.ezrinet.online })
(label :class "green"
:text "connected"
:visible {network--data.interfaces.ezrinet.online})
"personal 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
(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}")))
))

View File

@ -0,0 +1,287 @@
#!/usr/bin/env python3
import trparse
from subprocess import run, PIPE, DEVNULL
import json
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
# 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
}
# 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 {
"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()),
}
# system_bus = dbus.SystemBus()
# networkd = system_bus.get_object(
# "org.freedesktop.network1", "/org/freedesktop/network1"
# )
# manager = dbus.Interface(networkd, "org.freedesktop.network1.Manager")
# 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
last_default_route = None
last_ip_data = None
last_request = None
last_first_hop = None
while True:
start = now()
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 30 minutes 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 > 1800
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
last_default_route = default_route
last_request = now()
last_first_hop = 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,
)
end = now()
delta = end - start
if delta > 5:
print("Warning: took longer than 5 seconds to run", file=sys.stderr, flush=True)
else:
sleep(5 - delta)

View File

@ -0,0 +1,84 @@
#!/usr/bin/env python3
from time import sleep
import json
import psutil
import subprocess
import os
from dotenv import dotenv_values
def cpu():
util = psutil.cpu_percent(percpu=False)
per_core = psutil.cpu_percent(percpu=True)
return {
"avg_display": f"{int(util):2}",
"avg": util,
"cores": [{"value": core, "display": f"{int(core):2}"} for core in per_core],
"cores_display": "".join([f"{int(core):3}" for core in per_core]),
"core_count": len(per_core),
}
def sensor(chip: str):
return {
temp.label: temp.current for temp in psutil.sensors_temperatures().get(chip)
}
def memory():
mem = psutil.virtual_memory()
return {
"total": mem.total,
"available": mem.available,
"percent": mem.percent,
"used": mem.used,
"free": mem.free,
"active": mem.active,
"inactive": mem.inactive,
"buffers": mem.buffers,
"cached": mem.cached,
"shared": mem.shared,
"slab": mem.slab,
}
def swap():
swap = psutil.swap_memory()
return {
"total": swap.total,
"used": swap.used,
"free": swap.free,
"percent": swap.percent,
}
def reboot():
running = os.uname().release
version_proc = subprocess.run(["pacman", "-Q", "linux"], capture_output=True)
installed = version_proc.stdout.strip().decode("utf-8").split(" ")[1]
return running != installed
sensor_list = ["coretemp"]
counter = 60
machine_info = dotenv_values("/etc/machine-info")
while True:
# Refresh machine info every minute, in case it changes
if counter == 0:
machine_info = dotenv_values("/etc/machine-info")
counter = 60
result = {
"cpu": cpu(),
"sensors": {chip: sensor(chip) for chip in sensor_list},
"memory": memory(),
"swap": swap(),
"reboot": reboot(),
"hostname": machine_info.get("PRETTY_HOSTNAME"),
}
print(json.dumps(result), flush=True)
counter -= 1
sleep(1)

View File

@ -0,0 +1,59 @@
(deflisten system--data :initial "{}"
`~/.config/eww/modules/system/system.py`)
(defwidget system-battery [battery]
(box :orientation "v"
:halign "start"
:class "module text"
:space-evenly false
:spacing 0
(label :class {EWW_BATTERY[battery].status == 'Charging' || EWW_BATTERY[battery].status == 'Full' ? 'green' : EWW_BATTERY[battery].capacity <= 25 ? 'highlight' : 'special'}
:text "${EWW_BATTERY[battery].capacity}%")
(label :text "${EWW_BATTERY[battery].status == 'Charging' || EWW_BATTERY[battery].status == 'Full' ? 'external' : 'internal'} power")))
(defwidget system-name []
(label :halign "center"
:valign "center"
:class "module text big nebula"
:text {system--data.hostname}))
(defwidget system-cpu-avg []
(box :orientation "v"
:halign "start"
:class "module text"
:space-evenly false
:spacing 0
(label :class {system--data.cpu.avg > 90 ? 'highlight' : 'special'}
:text "${system--data.cpu.avg_display}%")
(label :text "cpu utilization")))
(defwidget system--cpu-core [core]
(label :class {core.value > 90 ? "highlight" : "special"}
:text "${core.display}%"))
(defwidget system-cpu-percore []
(box :orientation "v"
:halign "start"
:class "module text"
:space-evenly false
;; (box :orientation "h"
;; :halign "center"
;; :space-evenly false
;; (for core in {system--data.cpu.cores}
;; (system--cpu-core :core core)))
(label :class "special"
:text {system--data.cpu.cores_display})
(label :text "per-core cpu utilization")
))
(defwidget system-memory []
(box :orientation "v"
:halign "start"
:class "module text"
:space-evenly false
(label :class {system--data.memory.percent > 85 ? "highlight" : "special"}
:text "${round(system--data.memory.used / 1024 / 1024 / 1024, 2)} / ${round(system--data.memory.total / 1024 / 1024 / 1024, 2)} GiB")
(label :text "system memory")))

View File

@ -0,0 +1,56 @@
#!/usr/bin/env python3
# This script prints the time remaining for the current timer
# as stored in the file ~/.timer as a binary unix timestamp.
import time
import datetime
# Get the time stored in the file ~/.timer
try:
with open("/home/ezri/.timer", "br") as f:
timer = f.read()
except FileNotFoundError:
print("It's Time!", flush=True)
exit()
# Convert the binary unix timestamp to a datetime object
timer = datetime.datetime.fromtimestamp(int.from_bytes(timer, "big"))
while True:
# Get the current time
now = datetime.datetime.now()
# Calculate the time remaining
remaining = timer - now
# If the timer has already expired, delete the file and exit
if remaining.total_seconds() <= 0:
import os
os.remove("/home/ezri/.timer")
print("Timer expired.")
# Print the time remaining in the format "D days, HH:MM:SS"
if remaining.days == 0:
print(
"{} hours {:02d}:{:02d}".format(
remaining.seconds // 3600,
remaining.seconds % 3600 // 60,
remaining.seconds % 60,
),
flush=True,
)
else:
print(
"{} days, {:02d}:{:02d}:{:02d}".format(
remaining.days,
remaining.seconds // 3600,
remaining.seconds % 3600 // 60,
remaining.seconds % 60,
),
flush=True,
)
# Wait half a second before printing the time again
time.sleep(1)

View File

@ -0,0 +1,11 @@
(deflisten timer--text :initial 'loading...'
`~/.config/eww/modules/timer/timer.py`)
(defwidget timer []
(box :class "module text"
:spacing 0
:orientation "v"
(label :class "special"
:text {timer--text})
(label :text "baldur's gate 3")))

View File

@ -0,0 +1,50 @@
#!/usr/bin/env python3
import asyncio
import signal
from contextlib import suppress
import pulsectl_asyncio
import json
import sys
import os
async def get_values(pulse):
sink = None
try:
sink = await pulse.get_sink_by_name("@DEFAULT_SINK@")
source = await pulse.get_source_by_name("@DEFAULT_SOURCE@")
except:
# reload the script in the event of an exception
os.execv(sys.argv[0], sys.argv)
sink_result = {
"mute": sink.mute == 1,
"volume": f"{int(sink.volume.value_flat * 100):2}"
}
source_result = {
"mute": source.mute == 1,
"volume": f"{int(source.volume.value_flat * 100):2}"
}
result = {
"output": sink_result,
"input": source_result
}
print(json.dumps(result), flush=True)
return result
async def listen():
async with pulsectl_asyncio.PulseAsync("volume-monitor") as pulse:
await get_values(pulse)
async for _ in pulse.subscribe_events('all'):
await get_values(pulse)
async def main():
listen_task = asyncio.create_task(listen())
for sig in (signal.SIGTERM, signal.SIGHUP, signal.SIGINT):
loop.add_signal_handler(sig, listen_task.cancel)
with suppress(asyncio.CancelledError):
await listen_task
loop = asyncio.get_event_loop()
loop.run_until_complete(main())

View File

@ -0,0 +1,28 @@
(deflisten volume--data
`~/.config/eww/modules/volume/volume.py`)
(defwidget volume-h []
(box :orientation "h"
:halign "start"
:class "module ${volume--data['mute'] ? 'offline' : ''}"
:space-evenly false
:spacing 0
(label :visible {!volume--data["mute"]} :text "")
(label :visible { volume--data["mute"]} :text "")
(label :text " ${volume--data['volume']}")))
(defwidget audio []
(box :orientation "v"
:halign "center"
:class "module text"
:space-evenly false
:spacing 0
(box :orientation "h"
:halign "center"
:space-evenly false
:spacing 15
(label :class {volume--data.output.mute ? "offline" : "special"}
:text "${volume--data.output.volume}%")
(label :class {volume--data.input.mute ? "offline" : "special"}
:text "${volume--data.input.volume}%"))
"audio system"))

View File

@ -0,0 +1,17 @@
;; -*- lisp -*-
;; This is NOT lisp. It is "yuck", a lisp-like language that is used
;; to configure eww. It is a subset of lisp, with some extra features
;; that make it more suitable for configuration.
(defpoll weather--data :interval "30m"
`curl wttr.in/84321?format=j1 | jq -c `)
(defwidget weather
[]
(box :class "module text"
:spacing 0
:orientation "v"
(label :class "special"
:text "${weather--data.current_condition[0].weatherDesc[0].value} ${weather--data.current_condition[0].temp_F}°F")
(label :text "current weather")))

View File

@ -0,0 +1,213 @@
#!/usr/bin/env python3
import asyncio
import json
import os
import sys
WorkspaceTree = dict[str, dict[str, list['Workspace']]]
WorkspaceList = dict[str, 'Workspace']
socketdir = f"/tmp/hypr/{os.environ['HYPRLAND_INSTANCE_SIGNATURE']}"
socket1 = f"{socketdir}/.socket.sock"
socket2 = f"{socketdir}/.socket2.sock"
listened_events = ['workspace', 'movewindow', 'createworkspace', 'destroyworkspace']
class Workspace:
index: str = None
name: str = None
exec_cmd: str = None
group: str = None
active: bool = False
visible: bool = False
focused: bool = False
alerted: bool = False
def __init__(self, dictionary: dict[str, str | int], group: str):
self.index = str(dictionary.get('index'))
self.name = dictionary.get('name')
self.exec_cmd = dictionary.get('exec')
self.group = group
self.active = dictionary.get('active', False)
self.visible = dictionary.get('visible', False)
self.focused = dictionary.get('focused', False)
self.alerted = dictionary.get('alerted', False)
def update_state(self, state_update, monitor_dict):
self.active = True
self.visible = monitor_dict[state_update['monitor']]['activeWorkspace']['name'] == state_update['name']
self.focused = self.visible and monitor_dict[state_update['monitor']]['focused']
self.alerted = False
def deactivate(self):
self.active = False
self.visible = False
self.focused = False
self.alerted = False
@classmethod
def parse_file(cls: type, filename: str) -> tuple[WorkspaceTree, WorkspaceList]:
result = {}
initial: dict = None
with open(filename, 'r') as file:
initial = json.load(file)
workspaces: WorkspaceList = {}
def find_workspace(workspace: dict[str, str|int], group: str) -> 'Workspace':
index = str(workspace.get('index'))
if index in workspaces:
return workspaces[index]
else:
workspaces[index] = cls(workspace, group)
return workspaces[index]
result = {
context: {
group: [
find_workspace(workspace, group) for workspace in workspaces
] for group, workspaces in groups.items()
} for context, groups in initial.items()
}
return result, workspaces
@staticmethod
def full_dictify(tree: WorkspaceTree):
return {
context: {
group: [
workspace.dictify() for workspace in workspaces
] for group, workspaces in groups.items()
} for context, groups in tree.items()
}
def dictify(self):
return {
'index': self.index,
'name': self.name,
'exec': self.exec_cmd,
'active': self.active,
'visible': self.visible,
'focused': self.focused,
'alerted': self.alerted
}
workspace_tree, workspace_list = Workspace.parse_file(f"{os.environ['HOME']}/.config/hypr/workspaces.json")
data = {
"ws": {},
"current": {},
"context": "personal",
"visible": {},
}
def write_data():
global data
print(json.dumps(data), flush=True)
async def get_workspace_data():
request = b"[[BATCH]] j/workspaces; j/monitors"
reader = None
writer = None
data = None
try:
reader, writer = await asyncio.open_unix_connection(socket1)
writer.write(request)
await writer.drain()
data = await reader.read()
finally:
if writer is not None:
writer.close()
if data is None:
return;
workspace_data = None
monitor_data = None
try:
workspace_data, monitor_data = data.decode().split("}][{")
workspace_data += "}]"
monitor_data = "[{" + monitor_data
except ValueError:
print("Error unpacking response", file=sys.stderr)
return
return [json.loads(workspace_data), json.loads(monitor_data)]
async def update_workspaces():
global workspace_tree, workspace_list, data
workspaces, monitors = await get_workspace_data()
ws_hypr_dict = { ws["name"]: ws for ws in workspaces }
monitor_dict = { monitor["name"]: monitor for monitor in monitors }
touched = []
for index, ws_data in ws_hypr_dict.items():
# Update data for all active workspaces
ws_state = workspace_list.get(index)
if ws_state is None:
# If the workspace isn't configured, note it and handle gracefully
print(f"Warning: found unconfigured workspace {index}", file=sys.stderr, flush=True)
if monitor_dict[ws_data['monitor']]['activeWorkspace']['name'] == ws_data['name']:
data['current'] = {
'index': index,
'name': 'undefined',
'exec': 'alacritty',
'active': True,
'visible': True,
'focused': True,
'alerted': False
}
else:
# Otherwise, 'touch' it and update status data
touched.append(index)
ws_state.update_state(ws_data, monitor_dict)
if ws_state.focused:
data['current'] = ws_state.dictify()
if ws_state.visible:
data['visible'][ws_state.group] = ws_state.dictify()
inactives = [
v for k, v in workspace_list.items() if v.active and k not in touched
]
for workspace in inactives:
workspace.deactivate()
# Create an 'unknown' workspace object for each group that doesn't yet have a listed visible workspace
for group in workspace_tree[data['context'] or 'personal'].keys():
if group not in data['visible']:
data['visible'][group] = {
'index': 'U',
'name': 'undefined',
'exec': 'alacritty',
'active': True,
'visible': True,
'focused': False,
'alerted': False
}
data['ws'] = Workspace.full_dictify(workspace_tree)
write_data()
async def main():
reader, writer = await asyncio.open_unix_connection(socket2)
await update_workspaces()
while True:
event = (await reader.readline()).decode()
eventType, eventData = event.split(">>")
if eventType in listened_events:
await update_workspaces()
asyncio.run(main())

View File

@ -0,0 +1,184 @@
#!/usr/bin/env python3
import asyncio
import json
import os
import sys
from i3ipc.aio import Connection
from i3ipc import Event
from typing import List, Dict, Any, Union, Tuple
WorkspaceTree = Dict[str, Dict[str, List['Workspace']]]
WorkspaceList = Dict[str, 'Workspace']
class Workspace:
index: str = None
name: str = None
exec_cmd: str = None
group: str = None
active: bool = False
visible: bool = False
focused: bool = False
alerted: bool = False
def __init__(self, dictionary: Dict[str, Union[str, int]], group: str):
self.index = str(dictionary.get('index'))
self.name = dictionary.get('name')
self.exec_cmd = dictionary.get('exec')
self.group = group
self.active = dictionary.get('active', False)
self.visible = dictionary.get('visible', False)
self.focused = dictionary.get('focused', False)
self.alerted = dictionary.get('alerted', False)
def update_state(self, state_update: Any):
self.active = True
self.visible = state_update.visible
self.focused = state_update.focused
self.alerted = state_update.urgent
def deactivate(self):
self.active = False
self.visible = False
self.focused = False
self.alerted = False
@classmethod
def parse_file(cls: type, filename: str) -> Tuple[WorkspaceTree, WorkspaceList]:
result = {}
initial: dict = None
with open(filename, 'r') as file:
initial = json.load(file)
workspaces: WorkspaceList = {}
def find_workspace(workspace: Dict[str, Union[str, int]], group: str) -> 'Workspace':
index = str(workspace.get('index'))
if index in workspaces:
return workspaces[index]
else:
workspaces[index] = cls(workspace, group)
return workspaces[index]
result = {
context: {
group: [
find_workspace(workspace, group) for workspace in workspaces
] for group, workspaces in groups.items()
} for context, groups in initial.items()
}
return result, workspaces
@staticmethod
def full_dictify(tree: WorkspaceTree):
return {
context: {
group: [
workspace.dictify() for workspace in workspaces
] for group, workspaces in groups.items()
} for context, groups in tree.items()
}
def dictify(self):
return {
'index': self.index,
'name': self.name,
'exec': self.exec_cmd,
'active': self.active,
'visible': self.visible,
'focused': self.focused,
'alerted': self.alerted
}
workspace_tree, workspace_list = Workspace.parse_file(f"{os.environ['HOME']}/.config/sway/workspaces.json")
data = {
"ws": {},
"mode": "default",
"current": {},
"context": "work",
"visible": {},
}
def write_data():
global data
print(json.dumps(data), flush=True)
async def workspace_event(self: Connection, _):
global workspace_tree, workspace_list, data
ws_sway_dict = { ws.name: ws for ws in await self.get_workspaces()}
touched = []
for index, ws_data in ws_sway_dict.items():
# Update data for all active workspaces
ws_state = workspace_list.get(index)
if ws_state is None:
# If the workspace isn't configured, note it and handle gracefully
print(f"Warning: found unconfigured workspace {index}", file=sys.stderr, flush=True)
if ws_data.focused:
data['current'] = {
'index': index,
'name': 'undefined',
'exec': 'alacritty',
'active': True,
'visible': True,
'focused': True,
'alerted': False
}
else:
# Otherwise, 'touch' it and update the status data
touched.append(index)
ws_state.update_state(ws_data)
if ws_state.focused:
data['current'] = ws_state.dictify()
if ws_state.visible:
data['visible'][ws_state.group] = ws_state.dictify()
# 'Deactivate' any untouched workspaces
inactives = [
v for k, v in workspace_list.items() if v.active and k not in touched
]
for workspace in inactives:
workspace.deactivate()
# Create an 'unknown' workspace object for each group that doesn't yet have a listed visible workspace
for group in workspace_tree[data['context'] or 'personal'].keys():
if group not in data['visible']:
data['visible'][group] = {
'index': 'U',
'name': 'undefined',
'exec': 'alacritty',
'active': True,
'visible': True,
'focused': False,
'alerted': False
}
data['ws'] = Workspace.full_dictify(workspace_tree)
write_data()
async def mode_event(self: Connection, event):
global data
data['mode'] = event.change
write_data()
async def main():
sway = await Connection(auto_reconnect = True).connect()
sway.on(Event.WORKSPACE, workspace_event)
sway.on(Event.MODE, mode_event)
await workspace_event(sway, None)
await sway.main()
asyncio.run(main())

View File

@ -0,0 +1,77 @@
(deflisten sway--data :initial '{"mode": "default"}'
`~/.config/eww/modules/workspaces/sway.py`)
(defvar hypr--data '{}')
(defwidget sway--workspace [ws]
(button :onclick "swaymsg workspace ${ws['index']}"
(circular-progress
:class 'indicator-circle sway--ws ${ws.active ? "sway--active" : ""} ${ws.visible ? "sway--visible" : ""} ${ws.focused ? "sway--focused" : ""} ${ws.alerted ? "sway--alerted" : ""}'
:value 100
:start-at 0
:clockwise true
:width 16
:thickness 1
(box :class 'fill' ))))
(defwidget hypr--workspace [ws]
(button :onclick "hyprmsg dispatch workspace ${ws['index']}"
(circular-progress
:class 'indicator-circle sway--ws ${ws.active ? "sway--active" : ""} ${ws.visible ? "sway--visible" : ""} ${ws.focused ? "sway--focused": ""}'
:value 100
:start-at 0
:clockwise true
:width 15
:thickness 1
(box :class 'fill' :visible {ws.focused}))))
(defwidget sway-mode []
(box :orientation "v"
:halign "center"
:space-evenly false
:spacing 0
:class "module text"
:visible {sway--data != '' && sway--data.mode != "default"}
(label :class "special"
:text "${hypr--data.mode}")
"sway mode"))
(defwidget sway-workspace [group]
(box :orientation "v"
:halign "center"
:valign "center"
:space-evenly false
:spacing 0
:class 'module text'
(label :class '${sway--data.visible[group].focused ? "special" : "offline"} nebula medium small'
:text '${sway--data.visible[group].name}')))
; (label :text "current workspace")))
(defwidget hypr-workspace [group]
(box :orientation "v"
:halign "center"
:space-evenly false
:spacing 0
:class 'module text'
(label :class '${hypr--data.visible[group].focused ? "special" : "offline"}'
:text '${hypr--data.visible[group].name}')
(label :text "current workspace")))
(defwidget sway-workspaces [group]
(box :orientation "h"
:halign "start"
:visible {sway--data != ''}
:space-evenly false
:spacing 5
:class "sway--root"
(for workspace in {sway--data.ws[sway--data.context ?: "personal"][group]}
(sway--workspace :ws workspace))))
(defwidget hypr-workspaces [group]
(box :orientation "h"
:halign "start"
:space-evenly false
:spacing 5
:class "sway--root"
(for workspace in {hypr--data.ws[hypr--data.context ?: "personal"][group]}
(hypr--workspace :ws workspace))))

63
.config/htop/htoprc Normal file
View File

@ -0,0 +1,63 @@
# Beware! This file is rewritten by htop when settings are changed in the interface.
# The parser is also very primitive, and not human-friendly.
htop_version=3.3.0
config_reader_min_version=3
fields=0 48 17 18 38 39 40 2 46 47 49 1
hide_kernel_threads=1
hide_userland_threads=1
hide_running_in_container=0
shadow_other_users=0
show_thread_names=0
show_program_path=1
highlight_base_name=0
highlight_deleted_exe=1
shadow_distribution_path_prefix=0
highlight_megabytes=1
highlight_threads=1
highlight_changes=0
highlight_changes_delay_secs=5
find_comm_in_cmdline=1
strip_exe_from_cmdline=1
show_merged_command=0
header_margin=1
screen_tabs=1
detailed_cpu_time=0
cpu_count_from_one=0
show_cpu_usage=1
show_cpu_frequency=0
show_cpu_temperature=1
degree_fahrenheit=0
update_process_names=0
account_guest_in_cpu_meter=0
color_scheme=0
enable_mouse=1
delay=15
hide_function_bar=0
header_layout=two_33_67
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=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=PERCENT_CPU
.tree_sort_key=PERCENT_CPU
.tree_view_always_by_pid=0
.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
.tree_sort_key=PID
.tree_view_always_by_pid=0
.tree_view=0
.sort_direction=-1
.tree_sort_direction=1
.all_branches_collapsed=0

19
.config/sway/config Normal file
View File

@ -0,0 +1,19 @@
### ###
# Tycho Station Sway Config #
### ###
# This config file is modular. Set variables here, then use them in
# drop-in config files located in ~/.config/sway/config.d/
set $mod Mod4
set $alt Mod1
set $colors.primary '#815986'
set $colors.background '#2d272f'
### ###
# HERE BE DRAGONS #
### ###
# Do not edit anything below these comments. You have been warned.
include ~/.config/sway/config.d/*.conf

View File

@ -0,0 +1,9 @@
### ###
# Controls for Sway #
### ###
# This file includes "meta" controls, that is, keybinds
# for sway itself.
bindsym $mod+Shift+r reload
bindsym $mod+Shift+e exit

View File

@ -0,0 +1,88 @@
### ###
# Display Settings #
### ###
set $leftdisplay 'Hewlett Packard HP Z24n CN47090537'
set $centerdisplay 'Hewlett Packard HP Z24n CN4709053L'
output {
$leftdisplay pos 0 0 mode 1920x1200
$centerdisplay pos 1920 0 mode 1920x1200
# * bg '/home/ezri/2023-09-28T14:06:22,599070355-06:00.png' center '#1e1e1e'
* bg '#1e1e1e' solid_color
}
mode "output-switching" {
bindsym 1 mode output-1
bindsym 2 mode output-2
# bindsym 3 mode output-3
}
mode "output-1" {
## Focus output
bindsym Return exec swaymsg focus output $leftdisplay && swaymsg mode default
## Focus workspace on another output
bindsym 1 exec swaymsg workspace 1 && swaymsg mode default
bindsym 2 exec swaymsg workspace 2 && swaymsg mode default
bindsym 3 exec swaymsg workspace 3 && swaymsg mode default
bindsym 4 exec swaymsg workspace 4 && swaymsg mode default
bindsym 5 exec swaymsg workspace 5 && swaymsg mode default
bindsym 6 exec swaymsg workspace 6 && swaymsg mode default
bindsym 7 exec swaymsg workspace 7 && swaymsg mode default
bindsym 8 exec swaymsg workspace 8 && swaymsg mode default
bindsym 9 exec swaymsg workspace 9 && swaymsg mode default
bindsym 0 exec swaymsg workspace 10 && swaymsg mode default
## Move container to focused workspace on other output
bindsym Shift+Return exec swaymsg move container to output $leftdisplay && swaymsg mode default
## Move container to workspace on another output
bindsym Shift+1 exec swaymsg move container to workspace 1 && swaymsg mode default
bindsym Shift+2 exec swaymsg move container to workspace 2 && swaymsg mode default
bindsym Shift+3 exec swaymsg move container to workspace 3 && swaymsg mode default
bindsym Shift+4 exec swaymsg move container to workspace 4 && swaymsg mode default
bindsym Shift+5 exec swaymsg move container to workspace 5 && swaymsg mode default
bindsym Shift+6 exec swaymsg move container to workspace 6 && swaymsg mode default
bindsym Shift+7 exec swaymsg move container to workspace 7 && swaymsg mode default
bindsym Shift+8 exec swaymsg move container to workspace 8 && swaymsg mode default
bindsym Shift+9 exec swaymsg move container to workspace 9 && swaymsg mode default
bindsym Shift+0 exec swaymsg move container to workspace 10 && swaymsg mode default
}
mode "output-2" {
## Focus output
bindsym Return exec swaymsg focus output $centerdisplay && swaymsg mode default
## Focus workspace on another output
bindsym 1 exec swaymsg workspace 11 && swaymsg mode default
bindsym 2 exec swaymsg workspace 12 && swaymsg mode default
bindsym 3 exec swaymsg workspace 13 && swaymsg mode default
bindsym 4 exec swaymsg workspace 14 && swaymsg mode default
bindsym 5 exec swaymsg workspace 15 && swaymsg mode default
bindsym 6 exec swaymsg workspace 16 && swaymsg mode default
bindsym 7 exec swaymsg workspace 17 && swaymsg mode default
bindsym 8 exec swaymsg workspace 18 && swaymsg mode default
bindsym 9 exec swaymsg workspace 19 && swaymsg mode default
bindsym 0 exec swaymsg workspace 20 && swaymsg mode default
## Move container to focused workspace on other output
bindsym Shift+Return exec swaymsg move container to output $centerdisplay && swaymsg mode default
## Move container to workspace on another output
bindsym Shift+1 exec swaymsg move container to workspace 11 && swaymsg mode default
bindsym Shift+2 exec swaymsg move container to workspace 12 && swaymsg mode default
bindsym Shift+3 exec swaymsg move container to workspace 13 && swaymsg mode default
bindsym Shift+4 exec swaymsg move container to workspace 14 && swaymsg mode default
bindsym Shift+5 exec swaymsg move container to workspace 15 && swaymsg mode default
bindsym Shift+6 exec swaymsg move container to workspace 16 && swaymsg mode default
bindsym Shift+7 exec swaymsg move container to workspace 17 && swaymsg mode default
bindsym Shift+8 exec swaymsg move container to workspace 18 && swaymsg mode default
bindsym Shift+9 exec swaymsg move container to workspace 19 && swaymsg mode default
bindsym Shift+0 exec swaymsg move container to workspace 10 && swaymsg mode default
}
bindsym $mod+O mode output-switching

View File

@ -0,0 +1,66 @@
### ###
# Workspaces #
### ###
# This section defines the workspaces and creates keybinds to switch
# between them. It relies on an `i3-sensible-workspaces' command
# which prints the name of the workspace to target when given a
# workspace index
## Define Workspaces
workspace {
# Left monitor workspaces
1 output $leftdisplay
2 output $leftdisplay
3 output $leftdisplay
4 output $leftdisplay
5 output $leftdisplay
6 output $leftdisplay
7 output $leftdisplay
8 output $leftdisplay
9 output $leftdisplay
10 output $leftdisplay
# Right monitor workspaces
11 output $centerdisplay
12 output $centerdisplay
13 output $centerdisplay
14 output $centerdisplay
15 output $centerdisplay
16 output $centerdisplay
17 output $centerdisplay
18 output $centerdisplay
19 output $centerdisplay
20 output $centerdisplay
}
## Workspace Switching Keybinds
bindsym {
$mod+1 exec swaymsg workspace $(i3-sensible-workspaces 1 )
$mod+2 exec swaymsg workspace $(i3-sensible-workspaces 2 )
$mod+3 exec swaymsg workspace $(i3-sensible-workspaces 3 )
$mod+4 exec swaymsg workspace $(i3-sensible-workspaces 4 )
$mod+5 exec swaymsg workspace $(i3-sensible-workspaces 5 )
$mod+6 exec swaymsg workspace $(i3-sensible-workspaces 6 )
$mod+7 exec swaymsg workspace $(i3-sensible-workspaces 7 )
$mod+8 exec swaymsg workspace $(i3-sensible-workspaces 8 )
$mod+9 exec swaymsg workspace $(i3-sensible-workspaces 9 )
$mod+0 exec swaymsg workspace $(i3-sensible-workspaces 10)
}
## Window Reassignment Keybinds
bindsym {
$mod+Shift+1 exec swaymsg move container to workspace $(i3-sensible-workspaces 1 )
$mod+Shift+2 exec swaymsg move container to workspace $(i3-sensible-workspaces 2 )
$mod+Shift+3 exec swaymsg move container to workspace $(i3-sensible-workspaces 3 )
$mod+Shift+4 exec swaymsg move container to workspace $(i3-sensible-workspaces 4 )
$mod+Shift+5 exec swaymsg move container to workspace $(i3-sensible-workspaces 5 )
$mod+Shift+6 exec swaymsg move container to workspace $(i3-sensible-workspaces 6 )
$mod+Shift+7 exec swaymsg move container to workspace $(i3-sensible-workspaces 7 )
$mod+Shift+8 exec swaymsg move container to workspace $(i3-sensible-workspaces 8 )
$mod+Shift+9 exec swaymsg move container to workspace $(i3-sensible-workspaces 9 )
$mod+Shift+0 exec swaymsg move container to workspace $(i3-sensible-workspaces 10)
}

View File

@ -0,0 +1,71 @@
### ###
# Window Management #
### ###
# This file contains settings and keybinds related to window
# management
## Allow dragging of floating windows whilst holding $mod
floating_modifier $mod
## Define a window resizing mode
mode "resize" {
bindsym {
Left resize shrink width 10 px or 1 ppt
Right resize grow width 10 px or 1 ppt
Up resize shrink height 10 px or 1 ppt
Down resize grow height 10 px or 1 ppt
Return mode "default"
Escape mode "default"
$mod+r mode "default"
}
}
bindsym $mod+r mode "resize"
## Moving windows
bindsym {
$mod+Shift+b move left
$mod+Shift+f move right
$mod+Shift+p move up
$mod+Shift+n move down
$mod+Shift+Left move left
$mod+Shift+Right move right
$mod+Shift+Up move up
$mod+Shift+Down move down
}
## Shifting focus
bindsym {
$mod+b focus left
$mod+f focus right
$mod+p focus up
$mod+n focus down
$mod+Left focus left
$mod+Right focus right
$mod+Up focus up
$mod+Down focus down
$mod+a focus parent
$mod+space focus mode_toggle
}
## Creating and rearranging containers
bindsym {
# Create new split-view containers
$mod+h split h
$mod+v split v
# Rearrange focused container
$mod+e layout toggle split
$mod+t layout tabbed
$mod+s layout stacking
# Toggle floating of focused container
$mod+Shift+space floating toggle
}
## Close focused window
bindsym $mod+Shift+q kill

View File

@ -0,0 +1,36 @@
### ###
# Style configuration #
### ###
## Window-manager Font
font pango:JetBrainsMono Nerd Font 8
## One-pixel borders around windows
default_border pixel 1
set $colorprimary '#815986'
set $colorbackground '#2d272f'
set $colorwallpaper '#1e1e1e'
## Colors (define these in the main config file
client.focused $colorprimary $colorbackground $colorprimary $colorprimary $colorprimary
client.focused_inactive $colorbackground $colorbackground $colorprimary $colorbackground $colorbackground
client.unfocused $colorwallpaper $colorwallpaper $colorprimary $colorbackground $colorbackground
## Window gaps
gaps inner 10
## GTK theme
exec_always gsettings set org.gnome.desktop.interface {
gtk-theme 'Nordic-darker'
icon-theme 'ePapirus-dark'
font-name 'Source Sans Pro:12'
text-scaling-factor 1
}
for_window [app_id="Alacritty"] {
border normal 1
client.focused $colorprimary $colorbackground $colorprimary $colorprimary $colorprimary
client.focused_inactive $colorbackground $colorbackground $colorprimary $colorbackground $colorbackground
client.unfocusd $colorbackground $colorwallpaper $colorprimary $colorbackground $colorbackground
}

View File

@ -0,0 +1,51 @@
### ###
# Desktop QoL Features #
### ###
# This file includes common desktop features such as application
# launching keybinds, alongside quality-of-life things such as media
# controls.
## Application 'sensible' launcher.
# Relies on an `i3-sensible-launcher' script, intended to launch
# specific programs based on environment data, such as the current
# workspace.
bindsym $mod+Return exec i3-sensible-launcher
## Terminal launch override
# Quick keybind to launch a terminal on any workspace, ignoring the
# normal default.
bindsym $mod+Shift+Return exec alacritty msg create-window || alacritty
## Program menu
bindsym $mod+d exec wofi --show drun
## Media controls
# Relies on the `playerctl' command, will not function without it.
# Security note: these keybinds will function while screen is locked
bindsym --locked {
XF86AudioPlay exec playerctl play-pause
XF86AudioNext exec playerctl next
XF86AudioPrev exec playerctl previous
Ctrl+F7 exec playerctl previous
Ctrl+F8 exec playerctl play-pause
Ctrl+F9 exec playerctl next
}
## Screen locking
# This depends on a running screen-locking agent (ideally `swayidle')
bindsym $mod+l exec loginctl lock-session
## Notification management
# This depends on the `dunst' notification daemon
bindsym $mod+Ctrl+Space exec swaync-client --hide-latest
bindsym Ctrl+Shift+Space exec swaync-client -t
## Screenshotting
bindsym {
Shift+Print exec grimshot copy window && notify-send -a 'Screenshot' -u low 'Screenshot taken' 'An image of the focused window has been copied to clipboard'
Ctrl+Print exec grimshot copy area && notify-send -a 'Screenshot' -u low 'Screenshot taken' 'An image of the selected area has been copied to clipboard'
Print exec grimshot copy screen && notify-send -a 'Screenshot' -u low 'Screenshot taken' 'An image of the entire screen has been copied to clipboard'
Mod1+Print exec grimshot copy output && notify-send -a 'Screenshot' -u low 'Screenshot taken' 'An image of the focused display has been copied to clipboard'
}

View File

@ -0,0 +1,21 @@
### ###
# Input Configuration #
### ###
# Includes configuration for input devices (keyboards, mice,
# trackpads, etc.)
## Keyboard settings
# Enables numlock, makes capslock into a compose key, and loads custom
# keymap
input * {
xkb_numlock enabled
xkb_options compose:caps
xkb_file ~/.config/sway/keymap.xkb
}
## Touchpad settings
# Enables tap-to-click
input type:touchpad {
tap enabled
}

View File

@ -0,0 +1,14 @@
### ###
# Service Management #
### ###
# This file interacts with SystemD to activate services
## Import activation environment
exec_always XDG_CURRENT_DESKTOP=sway {
systemctl --user import-environment DISPLAY WAYLAND_DISPLAY SWAYSOCK XDG_CURRENT_DESKTOP PATH ASDF_DATA_DIR
dbus-update-activation-environment DISPLAY WAYLAND_DISPLAY SWAYSOCK XDG_CURRENT_DESKTOP PATH ASDF_DATA_DIR
}
## Start the session target
exec_always systemctl --user start sway-session.target

19
.config/sway/config.new Normal file
View File

@ -0,0 +1,19 @@
### ###
# Tycho Station Sway Config #
### ###
# This config file is modular. Set variables here, then use them in
# drop-in config files located in ~/.config/sway/config.d/
set $mod Mod4
set $alt Mod1
set $leftdisplay DP-1
set $rightdisplay DP-2
### ###
# HERE BE DRAGONS #
### ###
# Do not edit anything below these comments. You have been warned.
include ~/.config/sway/config.d/*.conf

264
.config/sway/config.old Normal file
View File

@ -0,0 +1,264 @@
#### ####
## Tycho Station sway Config File ##
#### ####
### ###
# Display settings #
### ###
# This section controls how connected displays are treated
# Set monitor vars
set $leftdisplay DP-1
set $rightdisplay DP-2
output {
$leftdisplay pos 0 0 mode 1920x1200
$rightdisplay pos 1920 0 mode 1920x1200
* bg '#1e1e1e' solid_color
}
### ###
# Window Manager settings #
### ###
# This section controls how the window manager functions. It does
# not include keybinds that are not directly related to the window
# manager's window management functions.
set $mod Mod4
set $alt Mod1
# Set font
font pango:Source Code Pro 8
# Reload configuration
bindsym $mod+Shift+r reload
# Exit
bindsym $mod+Shift+e exit
### ###
# Window Management Settings #
### ###
# This section controls window behavior and management keybinds.
# It also includes the resize mode.
# Set keybinds to switch workspaces
bindsym $mod+1 exec swaymsg workspace $(i3-sensible-workspaces 1 )
bindsym $mod+2 exec swaymsg workspace $(i3-sensible-workspaces 2 )
bindsym $mod+3 exec swaymsg workspace $(i3-sensible-workspaces 3 )
bindsym $mod+4 exec swaymsg workspace $(i3-sensible-workspaces 4 )
bindsym $mod+5 exec swaymsg workspace $(i3-sensible-workspaces 5 )
bindsym $mod+6 exec swaymsg workspace $(i3-sensible-workspaces 6 )
bindsym $mod+7 exec swaymsg workspace $(i3-sensible-workspaces 7 )
bindsym $mod+8 exec swaymsg workspace $(i3-sensible-workspaces 8 )
bindsym $mod+9 exec swaymsg workspace $(i3-sensible-workspaces 9 )
bindsym $mod+0 exec swaymsg workspace $(i3-sensible-workspaces 10)
# Set keybinds to move windows between workspaces
bindsym $mod+Shift+1 exec swaymsg move container to workspace $(i3-sensible-workspaces 1 )
bindsym $mod+Shift+2 exec swaymsg move container to workspace $(i3-sensible-workspaces 2 )
bindsym $mod+Shift+3 exec swaymsg move container to workspace $(i3-sensible-workspaces 3 )
bindsym $mod+Shift+4 exec swaymsg move container to workspace $(i3-sensible-workspaces 4 )
bindsym $mod+Shift+5 exec swaymsg move container to workspace $(i3-sensible-workspaces 5 )
bindsym $mod+Shift+6 exec swaymsg move container to workspace $(i3-sensible-workspaces 6 )
bindsym $mod+Shift+7 exec swaymsg move container to workspace $(i3-sensible-workspaces 7 )
bindsym $mod+Shift+8 exec swaymsg move container to workspace $(i3-sensible-workspaces 8 )
bindsym $mod+Shift+9 exec swaymsg move container to workspace $(i3-sensible-workspaces 9 )
bindsym $mod+Shift+0 exec swaymsg move container to workspace $(i3-sensible-workspaces 10)
# Bind workspaces to monitors
workspace 1 output $leftdisplay
workspace 2 output $leftdisplay
workspace 3 output $leftdisplay
workspace 4 output $leftdisplay
workspace 5 output $leftdisplay
workspace 6 output $leftdisplay
workspace 7 output $leftdisplay
workspace 8 output $leftdisplay
workspace 9 output $leftdisplay
workspace 10 output $leftdisplay
workspace 11 output $rightdisplay
workspace 12 output $rightdisplay
workspace 13 output $rightdisplay
workspace 14 output $rightdisplay
workspace 15 output $rightdisplay
workspace 16 output $rightdisplay
workspace 17 output $rightdisplay
workspace 18 output $rightdisplay
workspace 19 output $rightdisplay
workspace 20 output $rightdisplay
# Allow dragging of floating windows whilst holding $mod
floating_modifier $mod
# Resize mode
mode "resize" {
bindsym Left resize shrink width 10 px or 1 ppt
bindsym Down resize grow height 10 px or 1 ppt
bindsym Up resize shrink height 10 px or 1 ppt
bindsym f resize grow width 10 px or 1 ppt
# Exit resize mode
bindsym Return mode "default"
bindsym Escape mode "default"
bindsym $mod+r mode "default"
}
bindsym $mod+r mode "resize"
bindsym {
# Move windows
$mod+Shift+b move left
$mod+Shift+f move right
$mod+Shift+p move up
$mod+Shift+n move down
$mod+Shift+Left move left
$mod+Shift+Right move right
$mod+Shift+Up move up
$mod+Shift+Down move down
# Shift focus
$mod+b focus left
$mod+f focus right
$mod+p focus up
$mod+n focus down
$mod+a focus parent
# Splits
$mod+h split h
$mod+v split v
# Fullscreen
$mod+$alt+f fullscreen toggle
# Floating
$mod+Shift+space floating toggle
$mod+space focus mode_toggle
# Close window
$mod+Shift+q kill
# Change window arrangement
$mod+e layout toggle split
$mod+t layout tabbed
$mod+s layout stacking
}
### ###
# Appearance #
### ###
default_border pixel 1
# Colors
set $blue #5E81AC
set $orange #D08770
set $grey #2E3440
set $wallpaper #242933
set $primary '#815986'
set $background '#2d272f'
set $wallpaper '#242933'
client.focused $primary $background $primary $primary $primary
client.focused_inactive $primary $background $primary $background $background
client.unfocused $background $background $primary $background $background
# client.focused $blue $grey $blue $blue $blue
# client.focused_inactive $grey $grey $blue $blue $grey
# client.unfocused $grey $grey $blue $blue $grey
# client.urgent $orange $wallpaper $orange $orange $orange
# Gaps
gaps inner 10
# Themes
set $gnome-schema org.gnome.desktop.interface
exec_always {
gsettings set $gnome-schema gtk-theme 'Nordic-darker'
gsettings set $gnome-schema icon-theme 'ePapirus-Dark'
gsettings set $gnome-schema font-name 'Source Sans Pro:12'
gsettings set $gnome-schema text-scaling-factor 1
}
### ###
# Desktop Features #
### ###
# This section includes basic desktop features, such as
# the ability to launch programs and functional media keys
# Sensible launcher (launches program based on workspace)
bindsym $mod+Return exec i3-sensible-launcher
# Terminal launch override
bindsym $mod+Shift+Return exec alacritty
# Program menu
bindsym $mod+d exec wofi --show drun
# Media keys
bindsym --locked {
XF86AudioPlay exec playerctl play-pause
XF86AudioNext exec playerctl next
XF86AudioPrev exec playerctl previous
}
# Volume keys (disabled)
# bindsym --locked {
# XF86AudioRaiseVolume exec pactl set-sink-volume @DEFAULT_SINK@ +1%
# XF86AudioLowerVolume exec pactl set-sink-volume @DEFAULT_SINK@ -1%
# XF86AudioMute exec pactl set-sink-mute @DEFAULT_SINK@ toggle
# }
# Backlight
bindsym --locked {
XF86MonBrightnessUp exec light -A 5
XF86MonBrightnessDown exec light -U 5
}
# Lock screen
bindsym $mod+l exec loginctl lock-session
bindsym $mod+Shift+l exec aggietimed -s /run/user/1000/aggietimed.sock --action clock-out && loginctl lock-session
# Notification management
bindsym $mod+Ctrl+Space exec dunstctl close
# Screenshot bindings
bindsym {
Shift+Print exec grimshot copy area
Ctrl+Print exec grimshot copy window
Print exec grimshot copy screen
Mod1+Print exec grimshot copy output
}
# Start daemons
#include /etc/sway/config.d/50-systemd-user.conf
exec_always env ASDF_DATA_DIR=/home/ezri/.local/share/asdf-vm XDG_CURRENT_DESKTOP=sway {
systemctl --user import-environment DISPLAY WAYLAND_DISPLAY SWAYSOCK XDG_CURRENT_DESKTOP PATH ASDF_DATA_DIR
dbus-update-activation-environment --systemd DISPLAY WAYLAND_DISPLAY SWAYSOCK XDG_CURRENT_DESKTOP PATH ASDF_DATA_DIR
}
exec_always /usr/bin/systemctl --user start sway-session.target
# Start status bars
exec systemd-cat -t eww -p info --stderr-priority=notice eww daemon; sleep 1; eww open-many leftbar rightbar
# Keyboard settings
input * {
xkb_numlock enabled
xkb_options compose:caps
xkb_file ~/.config/sway/keymap.xkb
}
input type:touchpad {
tap enabled
}

260
.config/sway/config~ Normal file
View File

@ -0,0 +1,260 @@
#### ####
## Triskelion sway Config File ##
#### ####
### ###
# Display settings #
### ###
# This section controls how connected displays are treated
# Set monitor vars
set $leftdisplay DP-1
set $rightdisplay DP-2
output {
$leftdisplay pos 0 0 mode 1920x1080
$rightdisplay pos 1920 0 mode 1920x1080
* bg '#1e1e1e' solid_color
}
### ###
# Window Manager settings #
### ###
# This section controls how the window manager functions. It does
# not include keybinds that are not directly related to the window
# manager's window management functions.
set $mod Mod4
set $alt Mod1
# Set font
font pango:Source Code Pro 8
# Reload configuration
bindsym $mod+Shift+r reload
# Exit
bindsym $mod+Shift+e exit
### ###
# Window Management Settings #
### ###
# This section controls window behavior and management keybinds.
# It also includes the resize mode.
# Set keybinds to switch workspaces
bindsym $mod+1 exec swaymsg workspace $(i3-sensible-workspaces 1 )
bindsym $mod+2 exec swaymsg workspace $(i3-sensible-workspaces 2 )
bindsym $mod+3 exec swaymsg workspace $(i3-sensible-workspaces 3 )
bindsym $mod+4 exec swaymsg workspace $(i3-sensible-workspaces 4 )
bindsym $mod+5 exec swaymsg workspace $(i3-sensible-workspaces 5 )
bindsym $mod+6 exec swaymsg workspace $(i3-sensible-workspaces 6 )
bindsym $mod+7 exec swaymsg workspace $(i3-sensible-workspaces 7 )
bindsym $mod+8 exec swaymsg workspace $(i3-sensible-workspaces 8 )
bindsym $mod+9 exec swaymsg workspace $(i3-sensible-workspaces 9 )
bindsym $mod+0 exec swaymsg workspace $(i3-sensible-workspaces 10)
# Set keybinds to move windows between workspaces
bindsym $mod+Shift+1 exec swaymsg move container to workspace $(i3-sensible-workspaces 1 )
bindsym $mod+Shift+2 exec swaymsg move container to workspace $(i3-sensible-workspaces 2 )
bindsym $mod+Shift+3 exec swaymsg move container to workspace $(i3-sensible-workspaces 3 )
bindsym $mod+Shift+4 exec swaymsg move container to workspace $(i3-sensible-workspaces 4 )
bindsym $mod+Shift+5 exec swaymsg move container to workspace $(i3-sensible-workspaces 5 )
bindsym $mod+Shift+6 exec swaymsg move container to workspace $(i3-sensible-workspaces 6 )
bindsym $mod+Shift+7 exec swaymsg move container to workspace $(i3-sensible-workspaces 7 )
bindsym $mod+Shift+8 exec swaymsg move container to workspace $(i3-sensible-workspaces 8 )
bindsym $mod+Shift+9 exec swaymsg move container to workspace $(i3-sensible-workspaces 9 )
bindsym $mod+Shift+0 exec swaymsg move container to workspace $(i3-sensible-workspaces 10)
# Bind workspaces to monitors
workspace 1 output $leftdisplay
workspace 2 output $leftdisplay
workspace 3 output $leftdisplay
workspace 4 output $leftdisplay
workspace 5 output $leftdisplay
workspace 6 output $leftdisplay
workspace 7 output $leftdisplay
workspace 8 output $leftdisplay
workspace 9 output $leftdisplay
workspace 10 output $leftdisplay
workspace 11 output $rightdisplay
workspace 12 output $rightdisplay
workspace 13 output $rightdisplay
workspace 14 output $rightdisplay
workspace 15 output $rightdisplay
workspace 16 output $rightdisplay
workspace 17 output $rightdisplay
workspace 18 output $rightdisplay
workspace 19 output $rightdisplay
workspace 20 output $rightdisplay
# Allow dragging of floating windows whilst holding $mod
floating_modifier $mod
# Resize mode
mode "resize" {
bindsym Left resize shrink width 10 px or 1 ppt
bindsym Down resize grow height 10 px or 1 ppt
bindsym Up resize shrink height 10 px or 1 ppt
bindsym f resize grow width 10 px or 1 ppt
# Exit resize mode
bindsym Return mode "default"
bindsym Escape mode "default"
bindsym $mod+r mode "default"
}
bindsym $mod+r mode "resize"
bindsym {
# Move windows
$mod+Shift+b move left
$mod+Shift+f move right
$mod+Shift+p move up
$mod+Shift+n move down
$mod+Shift+Left move left
$mod+Shift+Right move right
$mod+Shift+Up move up
$mod+Shift+Down move down
# Shift focus
$mod+b focus left
$mod+f focus right
$mod+p focus up
$mod+n focus down
$mod+a focus parent
# Splits
$mod+h split h
$mod+v split v
# Fullscreen
$mod+$alt+f fullscreen toggle
# Floating
$mod+Shift+space floating toggle
$mod+space focus mode_toggle
# Close window
$mod+Shift+q kill
# Change window arrangement
$mod+e layout toggle split
$mod+t layout tabbed
$mod+s layout stacking
}
### ###
# Appearance #
### ###
default_border pixel 1
# Colors
set $blue #5E81AC
set $orange #D08770
set $grey #2E3440
set $wallpaper #242933
set $primary '#815986'
set $background '#2d272f'
set $wallpaper '#242933'
client.focused $primary $background $primary $primary $primary
client.focused_inactive $primary $background $primary $background $background
client.unfocused $background $background $primary $background $background
# client.focused $blue $grey $blue $blue $blue
# client.focused_inactive $grey $grey $blue $blue $grey
# client.unfocused $grey $grey $blue $blue $grey
# client.urgent $orange $wallpaper $orange $orange $orange
# Gaps
gaps inner 10
# Themes
set $gnome-schema org.gnome.desktop.interface
exec_always {
gsettings set $gnome-schema gtk-theme 'Nordic-darker'
gsettings set $gnome-schema icon-theme 'ePapirus-Dark'
gsettings set $gnome-schema font-name 'Source Sans Pro:12'
gsettings set $gnome-schema text-scaling-factor 1
}
### ###
# Desktop Features #
### ###
# This section includes basic desktop features, such as
# the ability to launch programs and functional media keys
# Sensible launcher (launches program based on workspace)
bindsym $mod+Return exec i3-sensible-launcher
# Terminal launch override
bindsym $mod+Shift+Return exec alacritty
# Program menu
bindsym $mod+d exec wofi --show drun
# Media keys
bindsym --locked {
XF86AudioPlay exec playerctl play-pause
XF86AudioNext exec playerctl next
XF86AudioPrev exec playerctl previous
}
# Volume keys
bindsym --locked {
XF86AudioRaiseVolume exec pactl set-sink-volume @DEFAULT_SINK@ +1%
XF86AudioLowerVolume exec pactl set-sink-volume @DEFAULT_SINK@ -1%
XF86AudioMute exec pactl set-sink-mute @DEFAULT_SINK@ toggle
}
# Backlight
bindsym --locked {
XF86MonBrightnessUp exec light -A 5
XF86MonBrightnessDown exec light -U 5
}
# Lock screen
bindsym $mod+l exec loginctl lock-session
# Notification management
bindsym $mod+Ctrl+Space exec dunstctl close
# Screenshot bindings
bindsym {
Shift+Print exec grimshot copy area
Ctrl+Print exec grimshot copy window
Print exec grimshot copy screen
Mod1+Print exec grimshot copy output
}
# Start daemons
#include /etc/sway/config.d/50-systemd-user.conf
exec env XDG_CURRENT_DESKTOP=sway systemctl --user import-environment DISPLAY WAYLAND_DISPLAY SWAYSOCK XDG_CURRENT_DESKTOP PATH
exec env XDG_CURRENT_DESKTOP=sway hash dbus-update-activation-environment 2>/dev/null && \
env XDG_CURRENT_DESKTOP=sway dbus-update-activation-environment --systemd DISPLAY WAYLAND_DISPLAY SWAYSOCK XDG_CURRENT_DESKTOP PATH
exec_always /usr/bin/systemctl --user start sway-session.target
# Start status bars
exec eww open-many leftbar rightbar
# Keyboard settings
input * {
xkb_numlock enabled
xkb_options compose:caps
xkb_file ~/.config/sway/keymap.xkb
}
input type:touchpad {
tap enabled
}

1565
.config/sway/keymap.xkb Normal file

File diff suppressed because it is too large Load Diff

9
.config/sway/swayidle Normal file
View File

@ -0,0 +1,9 @@
# -*-conf-*-
timeout 30 'if pgrep swaylock; then swaymsg "output * power off"; pkill -SIGSTOP electron; pkill -SIGSTOP slack; fi' resume 'if pgrep swaylock; then swaymsg "output * power on"; pkill -SIGCONT electron; pkill -SIGCONT slack; fi'
timeout 300 'if pgrep swaylock; then lock-keyring; fi'
lock ~/.local/bin/screenlock
before-sleep 'loginctl lock-session'
unlock 'pkill -USR1 swaylock'
idlehint 300

View File

@ -0,0 +1,137 @@
{
"work": {
"left": [
{
"index": 10,
"name": "config",
"exec": "pavucontrol",
"program_name": "pavucontrol"
},
{
"index": 9,
"name": "messages",
"exec": "alacritty",
"program_name": "console"
},
{
"index": 8,
"name": "slack",
"exec": "slack -s",
"program_name": "slack",
"memory_profile": {
"high": "800M",
"max": "1.2G"
}
},
{
"index": 7,
"name": "music",
"exec": "spotify",
"program_name": "spotify"
},
{
"index": 6,
"name": "documents",
"exec": "console",
"program_name": "console"
},
{
"index": 5,
"name": "images",
"exec": "console",
"program_name": "console"
},
{
"index": 4,
"name": "project",
"exec": "firefox --new-window",
"void_output": true,
"program_name": "firefox"
},
{
"index": 3,
"name": "internet",
"exec": "firefox --new-window",
"void_output": true,
"program_name": "firefox"
},
{
"index": 2,
"name": "code",
"exec": "emacsclient -nc",
"program_name": "emacsclient"
},
{
"index": 1,
"name": "console",
"exec": "console",
"program_name": "console"
}
],
"right": [
{
"index": 11,
"name": "console",
"exec": "console",
"program_name": "console"
},
{
"index": 12,
"name": "code",
"exec": "code",
"program_name": "vscode"
},
{
"index": 13,
"name": "internet",
"exec": "firefox --new-window",
"void_output": true,
"program_name": "firefox"
},
{
"index": 14,
"name": "project",
"exec": "firefox --new-window",
"void_output": true,
"program_name": "firefox"
},
{
"index": 15,
"name": "server management",
"exec": "virt-manager",
"program_name": "virt-manager",
"systemd": false
},
{
"index": 16,
"name": "password management",
"exec": "bitwarden-desktop",
"program_name": "bitwarden"
},
{
"index": 17,
"name": "video",
"exec": "jellyfinmediaplayer",
"program_name": "jellyfinmediaplayer"
},
{
"index": 18,
"name": "discord",
"exec": "discord",
"program_name": "discord"
},
{
"index": 19,
"name": "matrix",
"exec": "element-desktop",
"program_name": "element"
},
{
"index": 20,
"name": "vpn control",
"exec": "gpclient",
"program_name": "gpclient"
}
]
}
}

View File

@ -0,0 +1,85 @@
{
"$schema": "/etc/xdg/swaync/configSchema.json",
"positionX": "center",
"positionY": "top",
"layer": "overlay",
"control-center-layer": "top",
"layer-shell": true,
"cssPriority": "user",
"control-center-margin-top": 0,
"control-center-margin-bottom": 0,
"control-center-margin-right": 0,
"control-center-margin-left": 0,
"notification-2fa-action": true,
"notification-inline-replies": false,
"notification-icon-size": 64,
"notification-body-image-height": 100,
"notification-body-image-width": 200,
"timeout": 10,
"timeout-low": 5,
"timeout-critical": 0,
"fit-to-screen": true,
"relative-timestamps": true,
"control-center-width": 500,
"control-center-height": 600,
"notification-window-width": 500,
"keyboard-shortcuts": true,
"image-visibility": "when-available",
"transition-time": 200,
"hide-on-clear": false,
"hide-on-action": true,
"script-fail-notify": true,
"scripts": {
"example-script": {
"exec": "echo 'Do something...'",
"urgency": "Normal"
},
"example-action-script": {
"exec": "echo 'Do something actionable!'",
"urgency": "Normal",
"run-on": "action"
}
},
"notification-visibility": {
"example-name": {
"state": "muted",
"urgency": "Low",
"app-name": "Spotify"
}
},
"widgets": ["inhibitors", "title", "dnd", "notifications"],
"widget-config": {
"inhibitors": {
"text": "Inhibitors",
"button-text": "Clear All",
"clear-all-button": true
},
"title": {
"text": "Notifications",
"clear-all-button": true,
"button-text": "Clear All"
},
"dnd": {
"text": "Do Not Disturb"
},
"label": {
"max-lines": 5,
"text": "Label Text"
},
"mpris": {
"image-size": 96,
"image-radius": 12
},
"buttons-grid": {
"actions": [
{
"label": "直",
"type": "toggle",
"active": true,
"command": "sh -c '[[ $SWAYNC_TOGGLE_STATE == true ]] && nmcli radio wifi on || nmcli radio wifi off'",
"update_command": "sh -c '[[ $(nmcli radio wifi) == \"enabled\" ]] && echo true || echo false'"
}
]
}
}
}

659
.config/swaync/style.css Normal file
View File

@ -0,0 +1,659 @@
@define-color cc-bg rgba(30, 30, 30, 0.8);
@define-color noti-border-color #815986;
@define-color noti-border-color-low #3f3242;
@define-color noti-border-color-critical #cf6a4c;
@define-color noti-bg rgba(30, 30, 30, 0.8);
@define-color noti-bg-opaque #1e1e1e;
@define-color noti-bg-darker #1a1a1a;
@define-color noti-bg-hover rgba(32, 32, 32, 0.8);
@define-color noti-bg-hover-opaque #202020;
@define-color noti-bg-focus rgba(40, 40, 40, 0.8);
@define-color noti-close-bg rgba(255, 255, 255, 0.1);
@define-color noti-close-bg-hover rgba(255, 255, 255, 0.15);
@define-color text-color #9b859d;
@define-color text-color-low #9a7c9d;
@define-color text-color-critical #cf6a4c;
@define-color text-color-disabled rgb(150, 150, 150);
@define-color bg-selected rgb(0, 128, 255);
.notification-row {
outline: none;
border-radius: 0px;
}
.notification-row:focus,
.notification-row:hover {
background: @noti-bg-focus;
border-radius: 0px;
}
.notification-row .notification-background {
padding: 6px 12px;
border-radius: 0px;
}
.notification-row .notification-background .close-button {
/* The notification Close Button */
background: @noti-close-bg;
color: @text-color;
text-shadow: none;
padding: 0;
margin-top: 5px;
margin-right: 5px;
box-shadow: none;
border: none;
min-width: 24px;
min-height: 24px;
}
.notification-row .notification-background .close-button:hover {
box-shadow: none;
background: @noti-close-bg-hover;
transition: background 0.15s ease-in-out;
border: none;
}
.notification-row .notification-background .notification {
/* The actual notification */
border: 1px solid @noti-border-color;
padding: 0;
transition: background 0.15s ease-in-out;
background: @noti-bg;
border-radius: 0px;
}
.notification-row .notification-background .notification.low {
/* Low Priority Notification */
border-color: @noti-border-color-low;
}
.notification-row .notification-background .notification.normal {
/* Normal Priority Notification */
}
.notification-row .notification-background .notification.critical {
/* Critical Priority Notification */
border-color: @noti-border-color-critical;
}
.notification-row .notification-background .notification .notification-action,
.notification-row
.notification-background
.notification
.notification-default-action {
padding: 4px;
margin: 0;
box-shadow: none;
background: transparent;
border: none;
color: @text-color;
transition: background 0.15s ease-in-out;
}
.notification-row
.notification-background
.notification
.notification-action:hover,
.notification-row
.notification-background
.notification
.notification-default-action:hover {
-gtk-icon-effect: none;
background: @noti-bg-hover;
}
.notification-row
.notification-background
.notification
.notification-default-action {
/* The large action that also displays the notification summary and body */
}
.notification-row
.notification-background
.notification
.notification-default-action:not(:only-child) {
/* When alternative actions are visible */
border-bottom-left-radius: 0px;
border-bottom-right-radius: 0px;
}
.notification-row
.notification-background
.notification
.notification-default-action
.notification-content {
background: transparent;
padding: 4px;
}
.notification-row
.notification-background
.notification
.notification-default-action
.notification-content
.image {
/* Notification Primary Image */
-gtk-icon-effect: none;
/* Size in px */
margin: 4px;
}
.notification-row
.notification-background
.notification
.notification-default-action
.notification-content
.app-icon {
/* Notification app icon (only visible when the primary image is set) */
-gtk-icon-effect: none;
-gtk-icon-shadow: 0 1px 4px black;
margin: 6px;
}
.notification-row
.notification-background
.notification
.notification-default-action
.notification-content
.text-box
.summary {
/* Notification summary/title */
font-size: 16px;
font-weight: bold;
background: transparent;
color: @text-color;
text-shadow: none;
}
.notification-row
.notification-background
.notification.low
.notification-default-action
.notification-content
.text-box
.summary {
/* Low Priority Notification summary/title */
color: @text-color-low;
}
.notification-row
.notification-background
.notification.critical
.notification-default-action
.notification-content
.text-box
.summary {
/* Critical Priority Notification summary/title */
color: @text-color-critical;
}
.notification-row
.notification-background
.notification
.notification-default-action
.notification-content
.text-box
.time {
/* Notification time-ago */
font-size: 16px;
font-weight: bold;
background: transparent;
color: @text-color;
text-shadow: none;
margin-right: 30px;
}
.notification-row
.notification-background
.notification
.notification-default-action
.notification-content
.text-box
.body {
/* Notification body */
font-size: 15px;
font-weight: normal;
background: transparent;
color: @text-color;
text-shadow: none;
}
.notification-row
.notification-background
.notification.low
.notification-default-action
.notification-content
.text-box
.body {
/* Low Priority Notification body */
color: @text-color-low;
}
.notification-row
.notification-background
.notification.critical
.notification-default-action
.notification-content
.text-box
.body {
/* Critical Priority Notification body */
color: @text-color-critical;
}
.notification-row
.notification-background
.notification
.notification-default-action
.notification-content
progressbar {
/* The optional notification progress bar */
margin-top: 4px;
}
.notification-row
.notification-background
.notification
.notification-default-action
.notification-content
.body-image {
/* The "extra" optional bottom notification image */
margin-top: 4px;
background-color: white;
-gtk-icon-effect: none;
}
.notification-row
.notification-background
.notification
.notification-default-action
.notification-content
.inline-reply {
/* The inline reply section */
margin-top: 4px;
}
.notification-row
.notification-background
.notification
.notification-default-action
.notification-content
.inline-reply
.inline-reply-entry {
background: @noti-bg-darker;
color: @text-color;
caret-color: @text-color;
border: 1px solid @noti-border-color;
}
.notification-row
.notification-background
.notification
.notification-default-action
.notification-content
.inline-reply
.inline-reply-button {
margin-left: 4px;
background: @noti-bg;
border: 1px solid @noti-border-color;
color: @text-color;
}
.notification-row
.notification-background
.notification
.notification-default-action
.notification-content
.inline-reply
.inline-reply-button:disabled {
background: initial;
color: @text-color-disabled;
border: 1px solid @noti-border-color;
border-color: transparent;
}
.notification-row
.notification-background
.notification
.notification-default-action
.notification-content
.inline-reply
.inline-reply-button:hover {
background: @noti-bg-hover;
}
.notification-row .notification-background .notification .notification-action {
/* The alternative actions below the default action */
border-top: 1px solid @noti-border-color;
border-right: 1px solid @noti-border-color;
}
.notification-row
.notification-background
.notification
.notification-action:first-child {
/* add bottom border radius to eliminate clipping */
}
.notification-row
.notification-background
.notification
.notification-action:last-child {
border-right: none;
}
.notification-group {
/* Styling only for Grouped Notifications */
}
.notification-group.low {
/* Low Priority Group */
}
.notification-group.normal {
/* Low Priority Group */
}
.notification-group.critical {
/* Low Priority Group */
}
.notification-group .notification-group-buttons,
.notification-group .notification-group-headers {
margin: 0 16px;
color: @text-color;
}
.notification-group .notification-group-headers {
/* Notification Group Headers */
}
.notification-group .notification-group-headers .notification-group-icon {
color: @text-color;
}
.notification-group.low .notification-group-headers .notification-group-icon {
/* Low Priority Group Icon */
color: @text-color-low;
}
.notification-group.critical
.notification-group-headers
.notification-group-icon {
/* Critical Priority Group Icon */
color: @text-color-critical;
}
.notification-group .notification-group-headers .notification-group-header {
color: @text-color;
}
.notification-group.low .notification-group-headers .notification-group-header {
/* Low Priority Group Header */
color: @text-color-low;
}
.notification-group.critical
.notification-group-headers
.notification-group-header {
/* Critical Priority Group Header */
color: @text-color-critical;
}
.notification-group .notification-group-buttons {
/* Notification Group Buttons */
}
.notification-group.collapsed .notification-row .notification {
background-color: @noti-bg-opaque;
}
.notification-group.collapsed .notification-row:not(:last-child) {
/* Top notification in stack */
/* Set lower stacked notifications opacity to 0 */
}
.notification-group.collapsed
.notification-row:not(:last-child)
.notification-action,
.notification-group.collapsed
.notification-row:not(:last-child)
.notification-default-action {
opacity: 0;
}
.notification-group.collapsed:hover
.notification-row:not(:only-child)
.notification {
background-color: @noti-bg-hover-opaque;
}
.control-center {
/* The Control Center which contains the old notifications + widgets */
background: @cc-bg;
color: @text-color;
}
.control-center .control-center-list-placeholder {
/* The placeholder when there are no notifications */
opacity: 0.5;
}
.control-center .control-center-list {
/* List of notifications */
background: transparent;
}
.control-center .control-center-list .notification {
}
.control-center .control-center-list .notification .notification-default-action,
.control-center .control-center-list .notification .notification-action {
transition: opacity 400ms ease-in-out, background 0.15s ease-in-out;
}
.control-center
.control-center-list
.notification
.notification-default-action:hover,
.control-center .control-center-list .notification .notification-action:hover {
background-color: @noti-bg-hover;
}
.blank-window {
/* Window behind control center and on all other monitors */
background: transparent;
}
.floating-notifications {
background: transparent;
}
.floating-notifications .notification {
box-shadow: none;
}
/*** Widgets ***/
/* Title widget */
.widget-title {
color: @text-color;
margin: 8px;
font-size: 1.5rem;
}
.widget-title > button {
font-size: initial;
color: @text-color;
text-shadow: none;
background: @noti-bg;
border: 1px solid @noti-border-color;
box-shadow: none;
}
.widget-title > button:hover {
background: @noti-bg-hover;
}
/* DND widget */
.widget-dnd {
color: @text-color;
margin: 8px;
font-size: 1.1rem;
}
.widget-dnd > switch {
font-size: initial;
background: @noti-bg;
border: 1px solid @noti-border-color;
box-shadow: none;
}
.widget-dnd > switch:checked {
background: @bg-selected;
}
.widget-dnd > switch slider {
background: @noti-bg-hover;
}
/* Label widget */
.widget-label {
margin: 8px;
}
.widget-label > label {
font-size: 1.1rem;
}
/* Mpris widget */
@define-color mpris-album-art-overlay rgba(0, 0, 0, 0.55);
@define-color mpris-button-hover rgba(0, 0, 0, 0.50);
.widget-mpris {
/* The parent to all players */
}
.widget-mpris .widget-mpris-player {
padding: 8px;
padding: 16px;
margin: 16px 20px;
background-color: @mpris-album-art-overlay;
box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.75);
}
.widget-mpris .widget-mpris-player button:hover {
/* The media player buttons (play, pause, next, etc...) */
background: @noti-bg-hover;
}
.widget-mpris .widget-mpris-player .widget-mpris-album-art {
box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.75);
}
.widget-mpris .widget-mpris-player .widget-mpris-title {
font-weight: bold;
font-size: 1.25rem;
}
.widget-mpris .widget-mpris-player .widget-mpris-subtitle {
font-size: 1.1rem;
}
.widget-mpris .widget-mpris-player > box > button {
/* Change player control buttons */
}
.widget-mpris .widget-mpris-player > box > button:hover {
background-color: @mpris-button-hover;
}
.widget-mpris > box > button {
/* Change player side buttons */
}
.widget-mpris > box > button:disabled {
/* Change player side buttons insensitive */
}
/* Buttons widget */
.widget-buttons-grid {
padding: 8px;
margin: 8px;
background-color: @noti-bg;
}
.widget-buttons-grid > flowbox > flowboxchild > button {
background: @noti-bg;
}
.widget-buttons-grid > flowbox > flowboxchild > button.toggle:checked {
/* style given to the active toggle button */
}
/* Menubar widget */
.widget-menubar > box > .menu-button-bar > button {
border: none;
background: transparent;
}
/* .AnyName { Name defined in config after #
background-color: @noti-bg;
padding: 8px;
margin: 8px;
}
.AnyName>button {
background: transparent;
border: none;
}
.AnyName>button:hover {
background-color: @noti-bg-hover;
} */
.topbar-buttons > button {
/* Name defined in config after # */
border: none;
background: transparent;
}
/* Volume widget */
.widget-volume {
background-color: @noti-bg;
padding: 8px;
margin: 8px;
}
.widget-volume > box > button {
background: transparent;
border: none;
}
.per-app-volume {
background-color: @noti-bg-alt;
padding: 4px 8px 8px 8px;
margin: 0px 8px 8px 8px;
}
/* Backlight widget */
.widget-backlight {
background-color: @noti-bg;
padding: 8px;
margin: 8px;
}
/* Inhibitors widget */
.widget-inhibitors {
margin: 8px;
font-size: 1.5rem;
}
.widget-inhibitors > button {
font-size: initial;
color: @text-color;
text-shadow: none;
background: @noti-bg;
border: 1px solid @noti-border-color;
box-shadow: none;
}
.widget-inhibitors > button:hover {
background: @noti-bg-hover;
}

View File

@ -0,0 +1,651 @@
@define-color cc-bg rgba(30, 30, 30, 0.8);
@define-color noti-border-color #815986;
@define-color noti-border-color-low #3f3242;
@define-color noti-border-color-critical #cf6a4c;
@define-color noti-bg rgba(30, 30, 30, 0.8);
@define-color noti-bg-opaque #1e1e1e;
@define-color noti-bg-darker #1a1a1a;
@define-color noti-bg-hover rgba(32, 32, 32, 0.8);
@define-color noti-bg-hover-opaque #202020;
@define-color noti-bg-focus rgba(40, 40, 40, 0.8);
@define-color noti-close-bg rgba(255, 255, 255, 0.1);
@define-color noti-close-bg-hover rgba(255, 255, 255, 0.15);
@define-color text-color #9b859d;
@define-color text-color-low #9a7c9d;
@define-color text-color-critical #cf6a4c;
@define-color text-color-disabled rgb(150, 150, 150);
@define-color bg-selected rgb(0, 128, 255);
.notification-row {
outline: none;
}
.notification-row:focus,
.notification-row:hover {
background: @noti-bg-focus;
}
.notification-row .notification-background {
padding: 6px 12px;
}
.notification-row .notification-background .close-button {
/* The notification Close Button */
background: @noti-close-bg;
color: @text-color;
text-shadow: none;
padding: 0;
border-radius: 100%;
margin-top: 5px;
margin-right: 5px;
box-shadow: none;
border: none;
min-width: 24px;
min-height: 24px;
}
.notification-row .notification-background .close-button:hover {
box-shadow: none;
background: @noti-close-bg-hover;
transition: background 0.15s ease-in-out;
border: none;
}
.notification-row .notification-background .notification {
/* The actual notification */
border: 1px solid @noti-border-color;
padding: 0;
transition: background 0.15s ease-in-out;
background: @noti-bg;
}
.notification-row .notification-background .notification.low {
/* Low Priority Notification */
border-color: @noti-border-color-low;
}
.notification-row .notification-background .notification.normal {
/* Normal Priority Notification */
}
.notification-row .notification-background .notification.critical {
/* Critical Priority Notification */
border-color: @noti-border-color-critical;
}
.notification-row .notification-background .notification .notification-action,
.notification-row
.notification-background
.notification
.notification-default-action {
padding: 4px;
margin: 0;
box-shadow: none;
background: transparent;
border: none;
color: @text-color;
transition: background 0.15s ease-in-out;
}
.notification-row
.notification-background
.notification
.notification-action:hover,
.notification-row
.notification-background
.notification
.notification-default-action:hover {
-gtk-icon-effect: none;
background: @noti-bg-hover;
}
.notification-row
.notification-background
.notification
.notification-default-action {
/* The large action that also displays the notification summary and body */
}
.notification-row
.notification-background
.notification
.notification-default-action:not(:only-child) {
/* When alternative actions are visible */
border-bottom-left-radius: 0px;
border-bottom-right-radius: 0px;
}
.notification-row
.notification-background
.notification
.notification-default-action
.notification-content {
background: transparent;
padding: 4px;
}
.notification-row
.notification-background
.notification
.notification-default-action
.notification-content
.image {
/* Notification Primary Image */
-gtk-icon-effect: none;
border-radius: 100px;
/* Size in px */
margin: 4px;
}
.notification-row
.notification-background
.notification
.notification-default-action
.notification-content
.app-icon {
/* Notification app icon (only visible when the primary image is set) */
-gtk-icon-effect: none;
-gtk-icon-shadow: 0 1px 4px black;
margin: 6px;
}
.notification-row
.notification-background
.notification
.notification-default-action
.notification-content
.text-box
.summary {
/* Notification summary/title */
font-size: 16px;
font-weight: bold;
background: transparent;
color: @text-color;
text-shadow: none;
}
.notification-row
.notification-background
.notification.low
.notification-default-action
.notification-content
.text-box
.summary {
/* Low Priority Notification summary/title */
color: @text-color-low;
}
.notification-row
.notification-background
.notification.critical
.notification-default-action
.notification-content
.text-box
.summary {
/* Critical Priority Notification summary/title */
color: @text-color-critical;
}
.notification-row
.notification-background
.notification
.notification-default-action
.notification-content
.text-box
.time {
/* Notification time-ago */
font-size: 16px;
font-weight: bold;
background: transparent;
color: @text-color;
text-shadow: none;
margin-right: 30px;
}
.notification-row
.notification-background
.notification
.notification-default-action
.notification-content
.text-box
.body {
/* Notification body */
font-size: 15px;
font-weight: normal;
background: transparent;
color: @text-color;
text-shadow: none;
}
.notification-row
.notification-background
.notification.low
.notification-default-action
.notification-content
.text-box
.body {
/* Low Priority Notification body */
color: @text-color-low;
}
.notification-row
.notification-background
.notification.critical
.notification-default-action
.notification-content
.text-box
.body {
/* Critical Priority Notification body */
color: @text-color-critical;
}
.notification-row
.notification-background
.notification
.notification-default-action
.notification-content
progressbar {
/* The optional notification progress bar */
margin-top: 4px;
}
.notification-row
.notification-background
.notification
.notification-default-action
.notification-content
.body-image {
/* The "extra" optional bottom notification image */
margin-top: 4px;
background-color: white;
-gtk-icon-effect: none;
}
.notification-row
.notification-background
.notification
.notification-default-action
.notification-content
.inline-reply {
/* The inline reply section */
margin-top: 4px;
}
.notification-row
.notification-background
.notification
.notification-default-action
.notification-content
.inline-reply
.inline-reply-entry {
background: @noti-bg-darker;
color: @text-color;
caret-color: @text-color;
border: 1px solid @noti-border-color;
}
.notification-row
.notification-background
.notification
.notification-default-action
.notification-content
.inline-reply
.inline-reply-button {
margin-left: 4px;
background: @noti-bg;
border: 1px solid @noti-border-color;
color: @text-color;
}
.notification-row
.notification-background
.notification
.notification-default-action
.notification-content
.inline-reply
.inline-reply-button:disabled {
background: initial;
color: @text-color-disabled;
border: 1px solid @noti-border-color;
border-color: transparent;
}
.notification-row
.notification-background
.notification
.notification-default-action
.notification-content
.inline-reply
.inline-reply-button:hover {
background: @noti-bg-hover;
}
.notification-row .notification-background .notification .notification-action {
/* The alternative actions below the default action */
border-top: 1px solid @noti-border-color;
border-radius: 0px;
border-right: 1px solid @noti-border-color;
}
.notification-row
.notification-background
.notification
.notification-action:first-child {
/* add bottom border radius to eliminate clipping */
border-bottom-left-radius: 12px;
}
.notification-row
.notification-background
.notification
.notification-action:last-child {
border-bottom-right-radius: 12px;
border-right: none;
}
.notification-group {
/* Styling only for Grouped Notifications */
}
.notification-group.low {
/* Low Priority Group */
}
.notification-group.normal {
/* Low Priority Group */
}
.notification-group.critical {
/* Low Priority Group */
}
.notification-group .notification-group-buttons,
.notification-group .notification-group-headers {
margin: 0 16px;
color: @text-color;
}
.notification-group .notification-group-headers {
/* Notification Group Headers */
}
.notification-group .notification-group-headers .notification-group-icon {
color: @text-color;
}
.notification-group .notification-group-headers .notification-group-header {
color: @text-color;
}
.notification-group .notification-group-buttons {
/* Notification Group Buttons */
}
.notification-group.collapsed .notification-row .notification {
background-color: @noti-bg-opaque;
}
.notification-group.collapsed .notification-row:not(:last-child) {
/* Top notification in stack */
/* Set lower stacked notifications opacity to 0 */
}
.notification-group.collapsed
.notification-row:not(:last-child)
.notification-action,
.notification-group.collapsed
.notification-row:not(:last-child)
.notification-default-action {
opacity: 0;
}
.notification-group.collapsed:hover
.notification-row:not(:only-child)
.notification {
background-color: @noti-bg-hover-opaque;
}
.control-center {
/* The Control Center which contains the old notifications + widgets */
background: @cc-bg;
color: @text-color;
border-radius: 12px;
}
.control-center .control-center-list-placeholder {
/* The placeholder when there are no notifications */
opacity: 0.5;
}
.control-center .control-center-list {
/* List of notifications */
background: transparent;
}
.control-center .control-center-list .notification {
box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.3), 0 1px 3px 1px rgba(0, 0, 0, 0.7),
0 2px 6px 2px rgba(0, 0, 0, 0.3);
}
.control-center .control-center-list .notification .notification-default-action,
.control-center .control-center-list .notification .notification-action {
transition: opacity 400ms ease-in-out, background 0.15s ease-in-out;
}
.control-center
.control-center-list
.notification
.notification-default-action:hover,
.control-center .control-center-list .notification .notification-action:hover {
background-color: @noti-bg-hover;
}
.blank-window {
/* Window behind control center and on all other monitors */
background: transparent;
}
.floating-notifications {
background: transparent;
}
.floating-notifications .notification {
box-shadow: none;
}
/*** Widgets ***/
/* Title widget */
.widget-title {
color: @text-color;
margin: 8px;
font-size: 1.5rem;
}
.widget-title > button {
font-size: initial;
color: @text-color;
text-shadow: none;
background: @noti-bg;
border: 1px solid @noti-border-color;
box-shadow: none;
border-radius: 12px;
}
.widget-title > button:hover {
background: @noti-bg-hover;
}
/* DND widget */
.widget-dnd {
color: @text-color;
margin: 8px;
font-size: 1.1rem;
}
.widget-dnd > switch {
font-size: initial;
border-radius: 12px;
background: @noti-bg;
border: 1px solid @noti-border-color;
box-shadow: none;
}
.widget-dnd > switch:checked {
background: @bg-selected;
}
.widget-dnd > switch slider {
background: @noti-bg-hover;
border-radius: 12px;
}
/* Label widget */
.widget-label {
margin: 8px;
}
.widget-label > label {
font-size: 1.1rem;
}
/* Mpris widget */
@define-color mpris-album-art-overlay rgba(0, 0, 0, 0.55);
@define-color mpris-button-hover rgba(0, 0, 0, 0.50);
.widget-mpris {
/* The parent to all players */
}
.widget-mpris .widget-mpris-player {
padding: 8px;
padding: 16px;
margin: 16px 20px;
background-color: @mpris-album-art-overlay;
border-radius: 12px;
box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.75);
}
.widget-mpris .widget-mpris-player button:hover {
/* The media player buttons (play, pause, next, etc...) */
background: @noti-bg-hover;
}
.widget-mpris .widget-mpris-player .widget-mpris-album-art {
border-radius: 12px;
box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.75);
}
.widget-mpris .widget-mpris-player .widget-mpris-title {
font-weight: bold;
font-size: 1.25rem;
}
.widget-mpris .widget-mpris-player .widget-mpris-subtitle {
font-size: 1.1rem;
}
.widget-mpris .widget-mpris-player > box > button {
/* Change player control buttons */
}
.widget-mpris .widget-mpris-player > box > button:hover {
background-color: @mpris-button-hover;
}
.widget-mpris > box > button {
/* Change player side buttons */
}
.widget-mpris > box > button:disabled {
/* Change player side buttons insensitive */
}
/* Buttons widget */
.widget-buttons-grid {
padding: 8px;
margin: 8px;
border-radius: 12px;
background-color: @noti-bg;
}
.widget-buttons-grid > flowbox > flowboxchild > button {
background: @noti-bg;
border-radius: 12px;
}
.widget-buttons-grid > flowbox > flowboxchild > button.toggle:checked {
/* style given to the active toggle button */
}
/* Menubar widget */
.widget-menubar > box > .menu-button-bar > button {
border: none;
background: transparent;
}
/* .AnyName { Name defined in config after #
background-color: @noti-bg;
padding: 8px;
margin: 8px;
border-radius: 12px;
}
.AnyName>button {
background: transparent;
border: none;
}
.AnyName>button:hover {
background-color: @noti-bg-hover;
} */
.topbar-buttons > button {
/* Name defined in config after # */
border: none;
background: transparent;
}
/* Volume widget */
.widget-volume {
background-color: @noti-bg;
padding: 8px;
margin: 8px;
border-radius: 12px;
}
.widget-volume > box > button {
background: transparent;
border: none;
}
.per-app-volume {
background-color: @noti-bg-alt;
padding: 4px 8px 8px 8px;
margin: 0px 8px 8px 8px;
border-radius: 12px;
}
/* Backlight widget */
.widget-backlight {
background-color: @noti-bg;
padding: 8px;
margin: 8px;
border-radius: 12px;
}
/* Inhibitors widget */
.widget-inhibitors {
margin: 8px;
font-size: 1.5rem;
}
.widget-inhibitors > button {
font-size: initial;
color: @text-color;
text-shadow: none;
background: @noti-bg;
border: 1px solid @noti-border-color;
box-shadow: none;
border-radius: 12px;
}
.widget-inhibitors > button:hover {
background: @noti-bg-hover;
}

View File

@ -0,0 +1,13 @@
[Unit]
Description=AggieTimeD
[Service]
Type=simple
ExecStartPre=-/usr/bin/rm /run/user/%U/aggietimed.sock
ExecStartPre=/usr/bin/sleep 1
ExecStart=/usr/bin/node /usr/bin/aggietimed -d -s /run/user/%U/aggietimed.sock -p echo
RestartSec=30
Restart=always
[Install]
WantedBy=sway-session.target

View File

@ -0,0 +1,9 @@
[Unit]
Description=Terminal emulator
PartOf=sway-session.target
[Service]
Type=simple
ExecStart=alacritty
Slice=gui.slice

View File

@ -0,0 +1,12 @@
[Unit]
Description = Lock the screen when the last smart card is removed
PartOf = smartcard.target
[Service]
Type=oneshot
RemainAfterExit = yes
ExecStart = swaymsg output '*' dpms on
ExecStop = sh -c "loginctl lock-session; sleep 1; swaymsg output '*' dpms off"
[Install]
WantedBy = smartcard.target

View File

@ -0,0 +1,11 @@
[Unit]
Description=dunst notification daemon
PartOf=sway-session.target
[Service]
Type=simple
ExecStart=dunst
Slice=session.slice
[Install]
WantedBy=sway-session.target

View File

@ -0,0 +1,20 @@
[Unit]
Description=Emacs text editor
Documentation=info:emacs man:emacs(1) https://gnu.org/software/emacs/
PartOf=graphical-session.target
[Service]
Type=forking
ExecStart=/usr/bin/emacs --daemon
ExecStop=/usr/bin/emacsclient --eval "(kill-emacs)"
Environment=SSH_AUTH_SOCK=%t/keyring/ssh
Environment=ASDF_DATA_DIR=/home/ezri/.local/share/asdf-vm
Restart=on-failure
Slice=session.slice
MemoryAccounting=yes
# Tide eats memory like crazy, so lets put it on a diet.
MemoryHigh=3G
MemoryMax=5G
[Install]
WantedBy=graphical-session.target

View File

@ -0,0 +1,20 @@
[Unit]
Description=eww status bars
PartOf=sway-session.target
[Service]
Type=simple
ExecStart=eww daemon --no-daemonize
ExecStartPost=eww open-many leftbar rightbar network-status
ExecReload=eww reload
Slice=session.slice
MemoryAccounting=yes
# Eww is prone to memory leaks, esp. with (for ...), so
# if it ever goes nuts, kill it and restart.
MemoryHigh=150M
MemoryMax=400M
Restart=on-abnormal
RestartSec=5s
[Install]
WantedBy=sway-session.target

View File

@ -0,0 +1,9 @@
[Unit]
Description = GNOME Keyring
[Service]
Type=forking
ExecStart=gnome-keyring-daemon --daemonize
[Install]
WantedBy=default.target

View File

@ -0,0 +1,7 @@
[Unit]
Description=Hyprland compositor session
Documentation=man:systemd.special
BindsTo=graphical-session.target
Wants=graphical-session-pre.target
After=graphical-session-pre.target
Wants=sway-session.target

View File

@ -0,0 +1,9 @@
[Unit]
Description=KDE Connect Daemon
[Service]
Type=simple
ExecStart=/usr/lib/kdeconnectd
[Install]
WantedBy=default.target

View File

@ -0,0 +1,10 @@
[Unit]
Description = PolicyKit authentication agent
BindTo=sway-session.target
[Service]
Type=simple
ExecStart=/usr/bin/lxpolkit
[Install]
WantedBy=sway-session.target

View File

@ -0,0 +1,9 @@
[Unit]
Description = Forwarding bluetooth audio controls to MPRIS players
[Service]
Type = simple
ExecStart = /usr/bin/mpris-proxy
[Install]
WantedBy = graphical@i3.target

View File

@ -0,0 +1,10 @@
[Unit]
Description=Keeping track of media player activity
[Service]
Type=oneshot
ExecStart=/usr/bin/playerctld daemon
RemainAfterExit=yes
[Install]
WantedBy=default.target

View File

@ -0,0 +1,6 @@
[Unit]
Description=Sway compositor session
Documentation=man:systemd.special
BindsTo=graphical-session.target
Wants=graphical-session-pre.target
After=graphical-session-pre.target

View File

@ -0,0 +1,10 @@
[Unit]
Description=Background program for wlroots-based compositors
BindsTo=hypr-session.target
[Service]
Type=simple
ExecStart=swaybg -c "#1e1e1e"
[Install]
WantedBy=hypr-session.target

View File

@ -0,0 +1,11 @@
[Unit]
Description=Sway idle management
PartOf=sway-session.target
[Service]
Type=simple
ExecStart=swayidle -C %h/.config/sway/swayidle
Slice=session.slice
[Install]
WantedBy=sway-session.target

View File

@ -0,0 +1,14 @@
[Unit]
Description=swaync notification daemon
PartOf=sway-session.target
[Service]
Type=dbus
BusName=org.freedesktop.Notifications
ExecStart=swaync
ExecReload=swaync-client -R
ExecReload=swaync-client -rs
Slice=session.slice
[Install]
WantedBy=sway-session.target

View File

@ -0,0 +1,11 @@
[Unit]
Description=testing a thing
After=smartcard.target
Conflicts=smartcard.target
[Service]
Type=oneshot
ExecStart=echo it worked
[Install]
WantedBy=smartcard.target

2
.config/wofi/config Normal file
View File

@ -0,0 +1,2 @@
dynamic_lines=true
layer=overlay

31
.config/wofi/style.css Normal file
View File

@ -0,0 +1,31 @@
* {
all: unset;
}
#outer-box {
background-color: #1e1e1e;
border: 1px solid #815986;
padding: 20px;
}
#scroll {
padding-top: 10px;
}
#entry {
padding: 5px;
}
#entry:selected {
background-color: #2d272f;
}
#text {
color: #9a7c9d;
}
#input {
background-color: #2d272f;
color: #9a7c9d;
padding: 5px;
}

47
.config/yadm/bootstrap Normal file
View File

@ -0,0 +1,47 @@
#!/usr/bin/env zsh
cd $HOME
# Initialize and update submodules
yadm submodule update --init --recursive
yadm submodule foreach git pull
# Load OS information from /etc/os-release
eval $(awk '{print "OS_" $0}' /etc/os-release)
function pyenv_install() {
if [[ ${OS_ID} == "arch" ]]; then
sudo pacman -S --noconfirm pyenv pyenv-virtualenv
elif [[ ${OS_ID} == "ubuntu" ]]; then
sudo apt install -y make build-essential libssl-dev zlib1g-dev libbz2-dev \
libreadline-dev libsqlite3-dev wget curl llvm libncursesw5-dev xz-utils \
tk-dev libxml2-dev libxmlsec1-dev libffi-dev liblzma-dev
curl https://pyenv.run | bash
fi
pyenv install 3.10.13
pyenv virtualenv 3.10.13 personal
pyenv virtualenv 3.10.13 eww-modules
pyenv global personal
pyenv rehash
eval "$(pyenv init -)"
# Install packages for personal python environment
pyenv shell personal
pip install --upgrade pip
if [[ -f $HOME/.config/pip/requirements.txt ]]; then
pip install -r $HOME/.config/pip/requirements.txt
fi
# Install packages for eww-modules
pyenv shell eww-modules
pip install --upgrade pip
if [[ -f $HOME/.config/pip/eww-modules-requirements.txt ]]; then
pip install -r $HOME/.config/pip/eww-modules-requirements.txt
fi
}
# Install pyenv and configure personal and eww-modules python environments
if [[ ! -d $HOME/.pyenv ]]; then
pyenv_install
fi

View File

@ -0,0 +1 @@
stephen@Triskelion.703:1598899691

125
.config/zsh/alias.zsh Normal file
View File

@ -0,0 +1,125 @@
# Simple shell aliasing
alias emacs="TERM=screen-256color emacsclient -t"
alias sumacs="sudo emacs -nw"
alias systemctl="sudo systemctl"
alias userctl="\systemctl --user"
alias ujournalctl="\journalctl --user"
alias reconf="source $HOME/.zshrc"
alias cp="cp -i --reflink=auto"
alias mv="mv -i"
alias rm="rm -i"
alias screenclip="scrot -o >(xclip -sel clip -t image/png)"
alias virsh="\virsh -c qemu:///system"
alias sandbox-virsh="\virsh -c qemu+ssh://sandbox/system"
alias ls='ls --color=tty'
alias ll='ls -lh'
alias la='ls -lAh'
alias l='ls -lh'
alias nuke='echo "Are you sure?"; read -q && rm -rf'
alias sudo='sudo '
alias sign='gpg --sign-with ezri@ezri.dev --detach-sign'
alias verify='gpg --verify'
function didifuckingstutter {
echo $fg[blue]Apologies, Captain. Right away.$fg[default]
# Run the last command as root
last_cmd=$(fc -ln -1)
# if last command was emacs, use TRAMP rather than running as root
if [[ $last_cmd =~ "^emacs .*" ]]; then
cmd="emacsclient -t /sudo::$(echo $last_cmd | cut -d' ' -f2-)"
echo "> $fg[white]$cmd$fg[default]"
$=cmd
else
cmd="sudo $(fc -ln -1)"
echo "> $fg[white]$cmd$fg[default]"
sudo -p "$fg[red]I'll need your authorization:$fg[default] " $last_cmd
fi
}
function pygrep {
success=0
for pid in $(pgrep python); do
if cut -d '' -f2 < /proc/$pid/cmdline | rev | cut -d'/' -f1 | rev | grep "$1.py" &> /dev/null; then
echo $pid
success=1
fi
done
if ! (( success )); then
return 1
fi
}
function create-discord-timestamp {
date --date="$(echo $@)" +'<t:%s:t>' | tee >(tr -d '\n' | cbcopy)
}
function copy-text {
echo -n $@ | cbcopy
}
function cbcopy {
x_args='-sel clip'
if [[ $1 == '--primary' ]] || [[ $1 == '-p' ]]; then
wl_args='--primary'
x_args=''
fi
if [[ -x $(command -v wl-copy) ]]; then
# Prioritize wayland
wl-copy $wl_args
return $?
fi
if [[ -x $(command -v xclip) ]]; then
# Next do Xorg
xclip $x_args
return $?
fi
if [[ -x $(command -v pbcopy) ]]; then
pbcopy
return $?
fi
echo "No known clipboard commands available"
return 1
}
function cbpaste {
x_args='-sel clip'
if [[ $1 == '--primary' ]] || [[ $1 == '-p' ]]; then
wl_args='--primary'
x_args=''
fi
if [[ -x $(command -v wl-copy) ]]; then
# Prioritize wayland
wl-paste $wl_args
return $?
fi
if [[ -x $(command -v xclip) ]]; then
# Next do Xorg
xclip -o $x_args
return $?
fi
if [[ -x $(command -v pbcopy) ]]; then
pbpaste
return $?
fi
echo "No known clipboard commands available" > /dev/stderr
return 1
}
alias aggietimed='aggietimed -s /run/user/1000/aggietimed.sock -pos 190910 --action'
function mkcd {
[[ -e $1 ]] || mkdir -p $1
cd $1
}

30
.config/zsh/alias.zsh~ Normal file
View File

@ -0,0 +1,30 @@
# Simple shell aliasing
alias emacs="TERM=screen-256color emacsclient -t"
alias sumacs="sudo emacs -nw"
alias systemctl="sudo systemctl"
alias userctl="\systemctl --user"
alias reconf="source $HOME/.zshrc"
alias cp="cp --reflink=auto"
alias screenclip="scrot -o >(xclip -sel clip -t image/png)"
alias virsh="\virsh -c qemu:///system"
alias sandbox-virsh="\virsh -c qemu+ssh://sandbox/system"
alias ssh="env TERM=xterm-256color \ssh"
alias ls='ls --color=tty'
alias ll='ls -lh'
alias la='ls -lAh'
alias l='ls -lh'
alias sudo='sudo '
function take {
[[ -e $1 ]] || mkdir -p $1
cd $1
}

2
.config/zsh/dir-hash.zsh Normal file
View File

@ -0,0 +1,2 @@
hash -d cpp=$HOME/Documents/School/FA22/CS3460
hash -d hpc=$HOME/Documents/School/FA22/CS5030

View File

@ -0,0 +1,2 @@
hash -d webdev=$HOME/Documents/School/SP22/CS4610
hash -d gamedev=$HOME/Documents/School/SP22/CS5410

43
.config/zsh/env.zsh Normal file
View File

@ -0,0 +1,43 @@
export ASDF_DATA_DIR=$HOME/.local/share/asdf-vm
PATH_pyenv=$HOME/.pyenv/bin:$HOME/.pyenv/shims:/opt/pyenv/pyenv-virtualenv/shims
PATH_asdf=$ASDF_DATA_DIR/shims:/opt/asdf-vm/bin
PATH_node=$HOME/.opt/npm/bin
PATH_java=/usr/lib/jvm/default/bin
PATH_perl=/usr/bin/vendor_perl:/usr/bin/core_perl
PATH_system=/usr/local/sbin:/usr/local/bin:/usr/bin
PATH_system_nonarch=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
PATH_user=$HOME/.local/bin
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
# Function to run a command with only the "safe" system PATH element
function safeexec {
env PATH=$PATH_system "$@"
}
# Set an alias with a trailing space so that we can run other aliases
# using this function
alias safeexec="safeexec "
# Function to run a command with only the user PATH element, forcing
# the use of user-installed binaries
function userexec {
env PATH=$PATH_user "$@"
}
export LS_COLORS='di=34;40:ln=1;35;1:so=1;33;1:pi=32;1;40:ex=1;32;1:bd=33;1;40:cd=1;33;1;40:su=1;31;1:sg=1;31;1;40:tw=1;35;1;40:ow=1;31;1;40'
export GPG_TTY=$(tty)
gpg-connect-agent updatestartuptty /bye &> /dev/null
export EDITOR="emacsclient -t"
SAVEHIST=10000
HISTSIZE=$SAVEHIST
HISTFILE="${HOME}/.zsh_history"
export PAGER=less
export SUDO_PROMPT="$fg[red]Authorization required: $fg[default]"

14
.config/zsh/env.zsh~ Normal file
View File

@ -0,0 +1,14 @@
export PATH=/usr/local/bin:/usr/bin
enabled_snaps=('discord' 'apple-music-for-linux')
for snap in $enabled_snaps; do
export PATH=/snap/$snap/current/usr/bin:$PATH
done
export PATH=.:$HOME/.local/bin:$PATH
export GPG_TTY=$(tty)
gpg-connect-agent updatestartuptty /bye &> /dev/null
export EDITOR="emacsclient -t"

View File

@ -0,0 +1,24 @@
WORDCHARS='*?$'
# The following lines were added by compinstall
zstyle ':completion:*' completer _expand _complete _ignored _correct
zstyle ':completion:*' file-sort name
zstyle ':completion:*' format '--- Completing %d ---'
zstyle ':completion:*' group-name ''
zstyle ':completion:*' ignore-parents parent pwd
zstyle ':completion:*' insert-unambiguous false
zstyle ':completion:*' list-colors ''
zstyle ':completion:*' list-suffixes true
zstyle ':completion:*' matcher-list '' 'm:{[:lower:]}={[:upper:]}' 'r:|[._-]=** r:|=**' 'l:|=* r:|=*'
zstyle ':completion:*' menu select=1
zstyle ':completion:*' original false
zstyle ':completion:*' preserve-prefix '//[^/]##/'
zstyle ':completion:*' select-prompt %SScrolling active: current selection at %p%s
zstyle ':completion:*' squeeze-slashes true
zstyle ':completion:*' use-compctl true
zstyle :compinstall filename "${HOME}/.config/zsh/compinstall.zsh"
autoload -Uz compaudit compinit
compinit
# End of lines added by compinstall

11
.config/zsh/options.zsh Normal file
View File

@ -0,0 +1,11 @@
# CD to directory when you type it, without having to type cd
setopt auto_cd
# Use directory stack
setopt auto_pushd
# Always resolve symlinks when changing directory
setopt chase_links
# Ignore duplicate commands and commands starting with space
setopt hist_ignore_dups
setopt hist_ignore_space

View File

@ -0,0 +1,152 @@
autoload -Uz vcs_info
pwd="%B%F{blue}%3~%f%b"
# Show active python virtualenv in prompt
precmd_pyenv_info() {
# use nerd fonts for icons
_pyenv_icon=""
# Only update if we've changed directory, since pyenv can be slow
if [[ "$PWD" == "$_pyenv_old_pwd" ]]; then
return
else
_pyenv_old_pwd="$PWD"
fi
_pyenv_version=$(pyenv version-name 2>/dev/null)
if [[ $? -eq 0 ]] && [[ ${_pyenv_version} != "system" ]] && [[ ${_pyenv_version} != "personal" ]]; then
pyenv_info_msg_0_="%F{yellow} ${_pyenv_icon} ${_pyenv_version}%f"
elif [[ ${_pyenv_version} == "system" ]]; then
pyenv_info_msg_0_="%F{red} ${_pyenv_icon} ${_pyenv_version}%f"
else
pyenv_info_msg_0_=""
fi
}
_kernel_pkg=$(pacman -Qqo /usr/lib/modules/$(uname -r)/vmlinuz 2>/dev/null)
precmd_kernel_info() {
# check to see if a kernel update has been installed
# since we need to reboot to use it
# if message has been set, don't check again, since a reboot
# is required to clear the message
if [[ -n ${kernel_info_msg_0_} ]]; then
return
fi
if [[ -z ${_kernel_pkg} ]]; then
# no kernel package found, so we can't check for updates
return
fi
case ${_kernel_pkg} in
"linux")
# mainline kernel
diff <(uname -r | sed 's/-/./;s/\.0\././') <(pacman -Q linux | cut -d' ' -f2) >/dev/null
_ret=$?
;;
"linux-lts")
# lts kernel
diff <(uname -r | sed 's/-lts//') <(pacman -Q linux-lts | cut -d' ' -f2) >/dev/null
_ret=$?
;;
esac
diff <(uname -r | sed 's/-/./;s/\.0\././') <(pacman -Q linux | cut -d' ' -f2) >/dev/null
if [[ $? -eq 1 ]]; then
# kernel update available
kernel_info_msg_0_="%F{red} reboot required %f"
fi
}
precmd_vcs_info() {
vcs_info
}
# Reset precmd_functions, then add our functions. This way, regardless of
# whether this file is sourced multiple times, we don't end up with duplicate
# entries which will slow down the prompt.
precmd_functions=()
precmd_functions+=(precmd_vcs_info precmd_pyenv_info _reset_window_name)
setopt prompt_subst
eval $(awk '{print "OS_" $0}' /etc/os-release)
eval $(awk '{print "MACHINE_" $0}' /etc/machine-info)
eval $(awk '{print "PERSONAL_" $0}' ${HOME}/.personal-info 2>/dev/null)
if [[ -z ${MACHINE_CHASSIS} ]]; then MACHINE_CHASSIS=$(hostnamectl chassis); fi
if [[ ${MACHINE_CHASSIS} != "container" ]]; then
# Only check if a reboot is necessary if we're not in a container
precmd_functions+=(precmd_kernel_info)
fi
hostname=$PERSONAL_HOSTNAME
if [[ -z ${hostname} ]]; then # No personal hostname set
if [[ -n ${MACHINE_PRETTY_HOSTNAME} ]]; then
# Use MACHINE_PRETTY_HOSTNAME if set
hostname=${MACHINE_PRETTY_HOSTNAME}
elif [[ -f /etc/hostname ]]; then
# Fall back to system hostname
hostname=$(</etc/hostname)
else
# Ask the kernel for the hostname
hostname=$(uname -n)
fi
fi
show_os_icon=1
# use nerd fonts for icons
case $OS_ID in
"arch")
show_os_icon=0 # Arch is my default, no need to show icon
;;
"debian")
os_icon=""
;;
"ubuntu")
os_icon=""
;;
*)
show_os_icon=0
;;
esac
prompt="▶"
host="%F{cyan}[ %F{green}${hostname}%(!.%F{red} as root.) %F{cyan}]%f"
localhost="%F{cyan}[ %F{magenta}%B${hostname}%(!.%F{red} as root.)%b %F{cyan}]%f"
serial_host="%F{cyan}[ %F{magenta}${hostname}%(!.%F{red} as root.) %F{cyan}] %F{red}%y%f"
container_host="%F{cyan}[ %F{blue}%B${hostname}%(!.%F{red} as root.)%b %F{cyan}]%f"
returncode="%(?..%F{red}  %?%f)"
prompt_line1='$kernel_info_msg_0_'
prompt_line3=$prompt
# Create conditional prompt line 2
if [[ -v SSH_CLIENT ]]; then
prompt_line2='${host}$pyenv_info_msg_0_ ${pwd}'
elif [[ ${TTY} =~ "tty" ]]; then
prompt_line2='${serial_host}$pyenv_info_msg_0_ ${pwd}'
elif [[ ${MACHINE_CHASSIS} == "container" ]]; then
prompt_line2='${container_host}$pyenv_info_msg_0_ ${pwd}'
else
prompt_line2='${localhost}$pyenv_info_msg_0_ ${pwd}'
fi
# Inject icon if available, with ANSI color code stored in $OS_ANSI_COLOR
if [[ ${show_os_icon} -eq 1 ]]; then
prompt_line2=$'%{\x1b[${OS_ANSI_COLOR}m${os_icon}\x1b[0m%}'" ${prompt_line2}"
fi
if [[ ${TERM} == "dumb" ]]; then
# Dumb terminal needs a dumb prompt, otherwise things like
# emacs TRAMP break
PROMPT='$ '
else
PROMPT="${prompt_line1}
${prompt_line2}
${prompt_line3} "
fi
RPROMPT='$vcs_info_msg_0_$returncode'
zstyle ':vcs_info:git:*' formats '%c %F{magenta} 󰊢 %B%r%%b %F{cyan} %b%f'
zstyle ':vcs_info:git:*' actionformats '%c%F{magenta} 󰊢 %B%r%%b %F{cyan} %b %F{red} %a%f'
zstyle ':vcs_info:git:*' stagedstr "%F{green}%f"
zstyle ':vcs_info:git:*' check-for-staged-changes true
zstyle ':vcs_info:*' enable git

6
.config/zsh/pyenv.zsh Normal file
View File

@ -0,0 +1,6 @@
export PYENV_ROOT="$HOME/.pyenv"
# Remove pyenv alias for shell reloads
unalias pyenv > /dev/null 2>&1
eval "$(pyenv init -)"
alias pyenv="unset _pyenv_old_pwd; pyenv"

43
.config/zsh/ros.zsh Normal file
View File

@ -0,0 +1,43 @@
#
# ROS stuff for ZSH
#
function ros-version {
if [[ $1 == '' ]]; then
if [[ $ROS_DISTRO == '' ]]; then
echo 'Error: no ROS distribution active' >&2
return 1
else
echo ROS Distribution: $ROS_DISTRO
echo ROS Version: $ROS_VERSION
fi
else
source /opt/ros/$1/setup.zsh
fi
}
function ros-load-workspace {
if [[ $1 == '' ]]; then
echo 'Error: No workspace directory given' >&2
return 1
elif [[ ! -d $1 ]]; then
echo 'Error: workspace directory does not exist' >&2
return 2
elif [[ $ROS_VERSION != '2' ]] && ([[ ! -d $1/devel ]] || [[ ! -f $1/devel/setup.zsh ]]); then
echo 'Error: directory is not a ROS workspace' >&2
return 3
elif [[ $ROS_VERSION == '2' ]] && ([[ ! -d $1/install ]] || [[ ! -f $1/install/local_setup.zsh ]]); then
echo 'Error: directory is not a ROS workspace' >&2
return 3
else
if [[ $ROS_VERSION == '2' ]]; then
source $1/install/local_setup.zsh
else
source $1/devel/setup.zsh
fi
ROS_WORKSPACES=$ROS_WORKSPACES:$(readlink -f $1)
fi
}
export ROS_DOMAIN_ID=37

36
.config/zsh/utils.zsh Normal file
View File

@ -0,0 +1,36 @@
# Utility functions
function copylastcmd() {
echo -n $(fc -ln -1) | wl-copy
}
function getkernelpkg() {
if [[ ${OS_ID} == "arch" ]]; then
pacman -Qqo /usr/lib/modules/$(uname -r)/vmlinuz
else
echo "Unsupported OS" >&2
fi
}
if [[ $(hostnamectl chassis) == "container" ]]; then
DEFAULT_WINDOW_NAME="Container Connection: [  $hostname Console ]"
elif [[ -z "${SSH_CONNECTION+x}" ]]; then
DEFAULT_WINDOW_NAME="$hostname Console"
else
DEFAULT_WINDOW_NAME="Remote Connection: [  $hostname Console ]"
fi
function _rename_window() {
echo -ne "\033]0;$@\007"
}
function _reset_window_name() {
_rename_window "$DEFAULT_WINDOW_NAME"
}
function rename_window() {
_rename_window "$@"
DEFAULT_WINDOW_NAME="$@"
}
_rename_window "$DEFAULT_WINDOW_NAME"

2
.config/zsh/zz-asdf.zsh Normal file
View File

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

View File

@ -0,0 +1,8 @@
# This file activates certain plugins which are not a part of oh-my-zsh
source $HOME/.local/lib/zsh/zsh-autosuggestions/zsh-autosuggestions.zsh
source $HOME/.local/lib/zsh/zsh-syntax-highlighting/zsh-syntax-highlighting.zsh
source $HOME/.local/lib/zsh/zsh-history-substring-search/zsh-history-substring-search.zsh
bindkey '^P' history-substring-search-up
bindkey '^N' history-substring-search-down

23
.config/zsh/zz-ssh.zsh Normal file
View File

@ -0,0 +1,23 @@
if [[ $SSH_CLIENT != "" ]]; then
mkfifo "/tmp/ssh_test.$$"
exec 3<> "/tmp/ssh_test.$$"
unlink "/tmp/ssh_test.$$"
ps -o ppid= -p $$ | sed 's/ //g' 1>&3
read -u3 ppid
if ls /tmp | grep ssh- 1> /dev/null 2>&1; then
for dir in /tmp/ssh-*; do
if [[ -e $dir/agent.$ppid ]]; then
export SSH_AUTH_SOCK=$dir/agent.$ppid
fi
done
fi
else
export SSH_AUTH_SOCK=$(gpgconf --list-dirs agent-ssh-socket)
fi

View File

@ -0,0 +1,198 @@
;;; doom-nord-theme.el --- dark variant of Nord -*- lexical-binding: t; no-byte-compile: t; -*-
;;
;; Added: March 8, 2018 (c503ebdacac1)
;; Author: fuxialexander <https://github.com/fuxialexander>
;; Maintainer:
;; Source: https://www.nordtheme.com
;;
;;; Commentary:
;;; Code:
(require 'doom-themes)
;;
;;; Variables
(defgroup doom-personal-theme nil
"Options for the `doom-personal' theme."
:group 'doom-themes)
(defcustom doom-nord-brighter-modeline nil
"If non-nil, more vivid colors will be used to style the mode-line."
:group 'doom-nord-theme
:type 'boolean)
(defcustom doom-nord-brighter-comments nil
"If non-nil, comments will be highlighted in more vivid colors."
:group 'doom-nord-theme
:type 'boolean)
(defcustom doom-nord-comment-bg doom-nord-brighter-comments
"If non-nil, comments will have a subtle, darker background. Enhancing their
legibility."
:group 'doom-nord-theme
:type 'boolean)
(defcustom doom-nord-padded-modeline doom-themes-padded-modeline
"If non-nil, adds a 4px padding to the mode-line. Can be an integer to
determine the exact padding."
:group 'doom-nord-theme
:type '(choice integer boolean))
(eval-and-compile
(defcustom doom-nord-region-highlight t
"Determines the selection highlight style. Can be 'frost, 'snowstorm or t
(default)."
:group 'doom-nord-theme
:type 'symbol))
;;
;;; Theme definition
(def-doom-theme doom-personal
"A dark theme I made myself."
;; name default 256 16
((bg '("#1e1e1e" nil nil ))
(bg-alt '("#2d272f" nil nil ))
(base0 '("#2d272f" "black" "black" ))
(base1 '("#2d272f" "#1e1e1e" "brightblack" ))
(base2 '("#2d272f" "#2e2e2e" "brightblack" ))
(base3 '("#2d272f" "#262626" "brightblack" ))
(base4 '("#3f3242" "#3f3f3f" "brightblack" ))
(base5 '("#3f3242" "#525252" "brightblack" ))
(base6 '("#4C566A" "#6b6b6b" "brightblack" ))
(base7 '("#a7a7a7" "#979797" "brightblack" ))
(base8 '("#a7a7a7" "#dfdfdf" "white" ))
(fg '("#a7a7a7" "#ECECEC" "white" ))
(fg-alt '("#ffffff" "#bfbfbf" "brightwhite" ))
(grey base4)
(red '("#cf6a4c" "#ff6655" "red" )) ;; Nord11
(orange '("#cf6a4c" "#dd8844" "brightred" )) ;; Nord12
(green '("#8f9d6a" "#99bb66" "green" )) ;; Nord14
(teal '("#8f9d6a" "#44b9b1" "brightgreen" )) ;; Nord7
(yellow '("#f9ee98" "#ECBE7B" "yellow" )) ;; Nord13
(blue '("#7587a6" "#51afef" "brightblue" )) ;; Nord9
(dark-blue '("#7587a6" "#2257A0" "blue" )) ;; Nord10
(magenta '("#9b859d" "#c678dd" "magenta" )) ;; Nord15
(violet '("#9b859d" "#a9a1e1" "brightmagenta")) ;; ??
(cyan '("#afc4db" "#46D9FF" "brightcyan" )) ;; Nord8
(dark-cyan '("#afc4db" "#5699AF" "cyan" )) ;; ??
;; face categories -- required for all themes
(highlight blue)
(vertical-bar (doom-darken base1 0.2))
(selection dark-blue)
(builtin blue)
(comments (if doom-nord-brighter-comments dark-cyan (doom-lighten base5 0.2)))
(doc-comments (doom-lighten (if doom-nord-brighter-comments dark-cyan base5) 0.25))
(constants blue)
(functions cyan)
(keywords blue)
(methods cyan)
(operators blue)
(type teal)
(strings green)
(variables base7)
(numbers magenta)
(region (pcase doom-nord-region-highlight
(`frost teal)
(`snowstorm base7)
(_ base4)))
(error red)
(warning yellow)
(success green)
(vc-modified orange)
(vc-added green)
(vc-deleted red)
;; custom categories
(hidden `(,(car bg) "black" "black"))
(-modeline-bright doom-nord-brighter-modeline)
(-modeline-pad
(when doom-nord-padded-modeline
(if (integerp doom-nord-padded-modeline) doom-nord-padded-modeline 4)))
(region-fg
(when (memq doom-nord-region-highlight '(frost snowstorm))
base0))
(modeline-fg nil)
(modeline-fg-alt base6)
(modeline-bg
(if -modeline-bright
(doom-blend bg base5 0.2)
`(,(doom-darken (car bg) 0.1) ,@(cdr base2))))
(modeline-bg-l
(if -modeline-bright
(doom-blend bg base5 0.2)
base1))
(modeline-bg-inactive `(,(doom-darken (car bg) 0.1) ,@(cdr base2)))
(modeline-bg-inactive-l `(,(doom-darken (car bg) 0.025) ,@(cdr base2))))
;;;; Base theme face overrides
((fringe :foreground teal)
((line-number &override) :foreground (doom-lighten 'base5 0.2))
((line-number-current-line &override) :foreground base7)
((font-lock-comment-face &override)
:background (if doom-nord-comment-bg (doom-lighten bg 0.05)))
((tab-line &override) :background modeline-bg :foreground magenta)
((tab-line-tab-inactive &override) :foreground magenta)
(mode-line
:background modeline-bg :foreground modeline-fg
:box (if -modeline-pad `(:line-width ,-modeline-pad :color ,modeline-bg)))
(mode-line-inactive
:background modeline-bg-inactive :foreground modeline-fg-alt
:box (if -modeline-pad `(:line-width ,-modeline-pad :color ,modeline-bg-inactive)))
(mode-line-emphasis :foreground (if -modeline-bright base8 highlight))
((region &override) :foreground region-fg)
;;;; css-mode <built-in> / scss-mode
(css-proprietary-property :foreground orange)
(css-property :foreground green)
(css-selector :foreground magenta)
;;;; doom-modeline
(doom-modeline-bar :background (if -modeline-bright modeline-bg highlight))
(doom-modeline-project-root-dir :foreground base6)
;;;; ediff <built-in>
(ediff-fine-diff-A :background (doom-darken violet 0.4) :weight 'bold)
(ediff-current-diff-A :background (doom-darken base0 0.25))
;;;; elscreen
(elscreen-tab-other-screen-face :background "#353a42" :foreground "#1e2022")
;;;; highlight-symbol
(highlight-symbol-face :background (doom-lighten base4 0.1) :distant-foreground fg-alt)
;;;; highlight-thing
(highlight-thing :background (doom-lighten base4 0.1) :distant-foreground fg-alt)
;;;; ivy
((ivy-current-match &override) :foreground region-fg :weight 'semi-bold)
;;;; markdown-mode
(markdown-markup-face :foreground base5)
(markdown-header-face :inherit 'bold :foreground red)
((markdown-code-face &override) :background (doom-lighten base3 0.05))
;;;; mic-paren
((paren-face-match &override) :foreground bg :background teal :weight 'ultra-bold)
((paren-face-mismatch &override) :foreground base7 :background red :weight 'ultra-bold)
;;;; org <built-in>
(org-hide :foreground hidden)
;;;; solaire-mode
(solaire-mode-line-face
:inherit 'mode-line
:background modeline-bg-l
:box (if -modeline-pad `(:line-width ,-modeline-pad :color ,modeline-bg-l)))
(solaire-mode-line-inactive-face
:inherit 'mode-line-inactive
:background modeline-bg-inactive-l
:box (if -modeline-pad `(:line-width ,-modeline-pad :color ,modeline-bg-inactive-l)))
;;;; vimish-fold
((vimish-fold-overlay &override) :inherit 'font-lock-comment-face :background base3 :weight 'light)
((vimish-fold-fringe &override) :foreground teal))
;;;; Base theme variable overrides-
())
;;; doom-nord-theme.el ends here

546
.emacs.d/settings.org Normal file
View File

@ -0,0 +1,546 @@
#+TITLE: Ezri's Settings
#+AUTHOR: Ezri & Simponic
#+STARTUP: fold
Shamelessly stole this from Simponic, made some limited modifications myself.
Namely to indent style, theme, and line numbers. Also added Github Copilot.
* Packages
** Melpa
#+BEGIN_SRC emacs-lisp
(require 'package)
(add-to-list 'package-archives
'("melpa" . "https://melpa.org/packages/") t)
#+END_SRC
* General emacs
** Tab bar mode
#+BEGIN_SRC emacs-lisp
(defun my-tabbar-buffer-groups () ;; customize to show all normal files in one group
(list (cond ((string-equal "*" (substring (buffer-name) 0 1)) "emacs")
((eq major-mode 'dired-mode) "emacs")
(t "user"))))
(setq tabbar-buffer-groups-function 'my-tabbar-buffer-groups)
(tab-bar-mode)
#+END_SRC
** Indentation
Indent using tabs, render with tab-width of 2.
#+BEGIN_SRC emacs-lisp
(setq default-tab-width 2)
(setq-default tab-width 2)
(setq-default indent-tabs-mode t)
(setq sh-indentation 2)
(smart-tabs-insinuate 'c 'c++ 'java 'javascript 'python)
#+END_SRC
** Line numbers
#+BEGIN_SRC emacs-lisp
(global-display-line-numbers-mode)
#+END_SRC
** Filesystem stuff
#+BEGIN_SRC emacs-lisp
(setq auto-save-default nil)
(setq make-backup-files nil)
(setq create-lockfiles nil)
(global-auto-revert-mode t) ;; Change files on disk as they are updated
#+END_SRC
** UI stuff
#+BEGIN_SRC emacs-lisp
;; (when (window-system)
;; (menu-bar-mode -1)
;; (tool-bar-mode -1)
;; (toggle-scroll-bar -1)
;; (if (display-graphic-p)
;; (funcall (lambda ()
;; (set-fringe-mode '(1 . 1))
;; )))
;; (setq frame-resize-pixelwise t))
(setq inhibit-startup-screen t)
(defun my-frame-config (&optional frame)
(setq frame-resize-pixelwise t)
(if (display-graphic-p)
(set-fringe-mode '(1 . 1)))
(if (not frame) ;; The initial call, run when emacs starts
(funcall (lambda ()
(menu-bar-mode -1)
(tool-bar-mode -1)
(toggle-scroll-bar -1)
)))
;;-----------------------------------------;;
;; reinitialize modes in case of new frame ;;
;;-----------------------------------------;;
(if menu-bar-mode
(menu-bar-mode -1))
(if tool-bar-mode
(tool-bar-mode -1))
(if scroll-bar-mode
(scroll-bar-mode -1)))
(my-frame-config) ;; Run initially so that direct invocations work
(add-hook 'after-make-frame-functions 'my-frame-config)
#+END_SRC
** TUI stuff
#+BEGIN_SRC emacs-lisp
(defun terminal-config (&optional frame)
"Establish settings for teh current terminal."
(if (not frame) ;; The initial call.
(xterm-mouse-mode 1)
(if xterm-mouse-mode
;; Re-initialize the mode in case of a new terminal.
(xterm-mouse-mode 1))))
(terminal-config)
(add-hook 'after-make-frame-functions 'terminal-config)
#+END_SRC
** Custom keymap
#+BEGIN_SRC emacs-lisp
(global-set-key (kbd "C-;") 'comment-or-uncomment-region)
#+END_SRC
** System path (macos)
#+BEGIN_SRC emacs-lisp
;; Use system path on macos - needed for node
(use-package exec-path-from-shell
:ensure t
:init
(when (memq window-system '(mac ns x))
(exec-path-from-shell-initialize)))
#+END_SRC
* Theming
** Highlight current line
#+BEGIN_SRC emacs-lisp
(global-hl-line-mode)
#+END_SRC
** Font
#+BEGIN_SRC emacs-lisp
(add-to-list 'default-frame-alist '(font . "JetBrains Mono-9"))
#+END_SRC
** Doom-themes
#+BEGIN_SRC emacs-lisp
(defun my-theme-config (&optional frame)
(use-package doom-themes
:ensure t
:config
;; Global settings (defaults)
(setq doom-themes-enable-bold t ; if nil, bold is universally disabled
doom-themes-enable-italic t) ; if nil, italics is universally disabled
(load-theme 'doom-personal t)
;; Enable flashing mode-line on errors
(doom-themes-visual-bell-config)
;; Enable custom neotree theme (all-the-icons must be installed!)
(doom-themes-neotree-config)
;; or for treemacs users
(setq doom-themes-treemacs-theme "doom-atom") ; use "doom-colors" for less minimal icon theme
(doom-themes-treemacs-config)
;; Corrects (and improves) org-mode's native fontification.
(doom-themes-org-config)))
(my-theme-config)
(add-hook 'after-make-frame-functions 'my-theme-config)
#+END_SRC
** Doom-modeline
#+BEGIN_SRC emacs-lisp
(defun my-modeline-config (&optional frame)
(use-package doom-modeline
:ensure t
:init (doom-modeline-mode 1)))
(my-modeline-config)
(add-hook 'after-make-frame-functions 'my-modeline-config)
#+END_SRC
** All the icons
#+BEGIN_SRC emacs-lisp
(use-package all-the-icons
:ensure t)
#+END_SRC
* Projectile
#+BEGIN_SRC emacs-lisp
(use-package projectile
:bind ("C-c p" . 'projectile-command-map)
:init (projectile-mode +1) (setq projectile-enable-caching t)
:ensure t)
#+END_SRC
* Swiper, Ivy
#+BEGIN_SRC emacs-lisp
(use-package counsel
:ensure t
:bind
("C-s" . 'swiper-isearch)
("M-x" . 'counsel-M-x)
:init
(setq ivy-use-virtual-buffers t)
(setq enable-recursive-minibuffers t)
(ivy-mode 1))
#+END_SRC
* Neotree
#+BEGIN_SRC emacs-lisp
(use-package neotree
:ensure t
:bind ("C-c j" . 'neotree-toggle)
:init
;; slow rendering
(setq inhibit-compacting-font-caches t)
;; set icons theme
(setq neo-theme (if (display-graphic-p) 'icons 'arrow))
;; Every time when the neotree window is opened, let it find current file and jump to node
(setq neo-smart-open t)
;; When running projectile-switch-project (C-c p p), neotree will change root automatically
(setq projectile-switch-project-action 'neotree-projectile-action)
(setq neo-window-width 35)
;; show hidden files
(setq-default neo-show-hidden-files t))
#+END_SRC
* Custom Mode Bindings
** SystemD unit files
#+BEGIN_SRC emacs-lisp
;; Base systemd unit files
(add-to-list 'auto-mode-alist '("\\.service\\'" . conf-unix-mode))
(add-to-list 'auto-mode-alist '("\\.timer\\'" . conf-unix-mode))
(add-to-list 'auto-mode-alist '("\\.mount\\'" . conf-unix-mode))
(add-to-list 'auto-mode-alist '("\\.automount\\'" . conf-unix-mode))
(add-to-list 'auto-mode-alist '("\\.target\\'" . conf-unix-mode))
(add-to-list 'auto-mode-alist '("\\.path\\'" . conf-unix-mode))
(add-to-list 'auto-mode-alist '("\\.slice\\'" . conf-unix-mode))
(add-to-list 'auto-mode-alist '("\\.socket\\'" . conf-unix-mode))
(add-to-list 'auto-mode-alist '("\\.device\\'" . conf-unix-mode))
;; systemd-networkd
(add-to-list 'auto-mode-alist '("\\.network\\'" . conf-unix-mode))
(add-to-list 'auto-mode-alist '("\\.link\\'" . conf-unix-mode))
(add-to-list 'auto-mode-alist '("\\.netdev\\'" . conf-unix-mode))
#+END_SRC
** elkowar's wacky widgets
#+BEGIN_SRC emacs-lisp
(add-to-list 'auto-mode-alist '("\\.yuck\\'" . conf-unix-mode))
#+END_SRC
* Markdown mode
** Auto Text Wrap
#+BEGIN_SRC emacs-lisp
(add-hook 'markdown-mode-hook (lambda ()
(setq fill-column 85)
(visual-fill-column-mode)
(visual-line-mode)
(display-fill-column-indicator-mode)))
#+END_SRC
* Org mode
** General
#+BEGIN_SRC emacs-lisp
(setq org-startup-indented t)
#+END_SRC
** Auto Text Wrap
#+BEGIN_SRC emacs-lisp
(add-hook 'org-mode-hook (lambda ()
(setq fill-column 85)
(visual-fill-column-mode)
(visual-line-mode)))
#+END_SRC
** Babel
*** Elixir
#+BEGIN_SRC emacs-lisp
(use-package ob-elixir
:ensure t)
#+END_SRC
*** Load Languages
#+BEGIN_SRC emacs-lisp
(org-babel-do-load-languages
'org-babel-load-languages
'((lisp . t)
(elixir . t)
(emacs-lisp . t)
(python . t)))
#+END_SRC
** org-bullets
#+BEGIN_SRC emacs-lisp
(use-package org-bullets
:ensure t
:init
(add-hook 'org-mode-hook (lambda () (org-bullets-mode 1))))
#+END_SRC
** org-appear
#+BEGIN_SRC emacs-lisp
(use-package org-appear
:ensure t
:init
(add-hook 'org-mode-hook 'org-appear-mode))
#+END_SRC
** Presentations
#+BEGIN_SRC emacs-lisp
(use-package org-present
:ensure t
:straight '(org-present
:type git
:host github
:repo "rlister/org-present"))
#+END_SRC
* Development
** Copilot
#+BEGIN_SRC emacs-lisp
;; Load copilot
(add-to-list 'load-path "/home/ezri/.emacs.d/copilot.el")
(require 'copilot)
;; Enable completion
(add-hook 'prog-mode-hook 'copilot-mode)
#+END_SRC
** Git
#+BEGIN_SRC emacs-lisp
(use-package magit :ensure t)
#+END_SRC
** Autocomplete
#+BEGIN_SRC emacs-lisp
(use-package auto-complete :ensure t)
(ac-config-default)
(defun my-tab ()
(interactive)
(or (copilot-accept-completion)
(ac-expand nil)))
(with-eval-after-load 'auto-complete
; diable inline preview
(setq ac-disable-inline t)
; show menu if have only one candidate
(setq ac-candidate-menu-min 0))
(define-key copilot-completion-map (kbd "<tab>") 'copilot-accept-completion)
(define-key copilot-completion-map (kbd "TAB") 'copilot-accept-completion)
#+END_SRC
** Company mode
#+BEGIN_SRC emacs-lisp
(use-package company
:ensure t
:init
(global-company-mode t)
:bind (:map company-active-map
("C-n" . company-select-next)
("C-p" . company-select-previous))
:config
(setq company-idle-delay 0.3))
#+END_SRC
** LSP Mode
#+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)
#+END_SRC
** Languages
*** Common Lisp
**** Formatter! semantic-refactor
#+BEGIN_SRC emacs-lisp
(use-package srefactor
:ensure t
:hook ((before-save .
(lambda ()
(when (eq major-mode 'lisp-mode)
(srefactor-lisp-format-buffer))))))
(require 'srefactor)
(require 'srefactor-lisp)
#+END_SRC
**** Rainbow Parentheses
#+BEGIN_SRC emacs-lisp
(use-package rainbow-delimiters :ensure t)
(add-hook 'lisp-mode-hook #'rainbow-delimiters-mode)
#+END_SRC
**** Slime
#+BEGIN_SRC emacs-lisp
(use-package slime
:ensure t
:init
(setq inferior-lisp-program "sbcl"))
#+END_SRC
**** AC-Slime
#+BEGIN_SRC emacs-lisp
(use-package ac-slime
:ensure t
:straight '(ac-slime
:type git
:host github
:repo "purcell/ac-slime"))
(add-hook 'slime-mode-hook 'set-up-slime-ac)
(add-hook 'slime-repl-mode-hook 'set-up-slime-ac)
(eval-after-load "auto-complete"
'(add-to-list 'ac-modes 'slime-repl-mode))
#+END_SRC
*** Elixir
#+BEGIN_SRC emacs-lisp
(use-package elixir-mode
:ensure t
:hook ((before-save .
(lambda ()
(when (eq major-mode 'elixir-mode)
(elixir-format))))))
#+END_SRC
*** Rust
After installing the ~rust-analyzer~ program, the following can be used:
#+BEGIN_SRC emacs-lisp
(use-package rust-mode
:ensure t)
(setq lsp-rust-server 'rust-analyzer)
#+END_SRC
*** Vue
#+BEGIN_SRC emacs-lisp
(add-hook 'mmm-mode-hook
(lambda ()
(set-face-background 'mmm-default-submode-face nil)))
#+END_SRC
*** Web Stuff
**** typescript-mode
#+BEGIN_SRC emacs-lisp
;; TODO: Update to tree-sitter in Emacs 29
(use-package typescript-mode
:ensure t)
(setq typescript-indent-level 2)
#+END_SRC
**** TIDE
#+BEGIN_SRC emacs-lisp
(defun setup-tide-mode ()
(interactive)
(tide-setup)
(flycheck-mode +1)
(setq flycheck-check-syntax-automatically '(save mode-enabled))
(eldoc-mode +1)
(tide-hl-identifier-mode +1)
;; company is an optional dependency. You have to
;; install it separately via package-install
;; `M-x package-install [ret] company`
(company-mode +1))
(use-package tide
:ensure t
:after (typescript-mode company flycheck)
:hook ((typescript-mode . setup-tide-mode) ;; TODO: Update to tree-sitter in Emacs 29
(js2-mode . setup-tide-mode)))
#+END_SRC
**** Web Mode
#+BEGIN_SRC emacs-lisp
;; web-mode
(setq web-mode-markup-indent-offset 2)
(setq web-mode-code-indent-offset 2)
(setq web-mode-css-indent-offset 2)
(use-package web-mode
:ensure t
:mode (("\\.scss\\'" . web-mode)
("\\.css\\'" . web-mode)
("\\.jsx\\'" . web-mode)
("\\.tsx\\'" . web-mode)
("\\.html\\'" . web-mode))
:commands web-mode)
#+END_SRC
**** Prettier
#+BEGIN_SRC emacs-lisp
(use-package prettier-js
:ensure t)
(add-hook 'js2-mode-hook 'prettier-js-mode)
(add-hook 'typescript-mode 'prettier-js-mode)
(add-hook 'web-mode-hook 'prettier-js-mode)
#+END_SRC
**** Prisma
#+BEGIN_SRC emacs-lisp
(use-package prisma-mode
:ensure t
:straight '(prisma-mode
:type git
:host github
:repo "pimeys/emacs-prisma-mode"))
#+END_SRC
**** Svelte
#+BEGIN_SRC emacs-lisp
(use-package svelte-mode
:ensure t
:straight '(svelte-mode
:type git
:host github
:repo "leafOfTree/svelte-mode"))
#+END_SRC
*** Kotlin
#+BEGIN_SRC emacs-lisp
(use-package kotlin-mode
:ensure t)
#+END_SRC
*** Java
#+BEGIN_SRC emacs-lisp
(use-package lsp-java
:config (add-hook 'java-mode-hook 'lsp)
:ensure t)
#+END_SRC
#+RESULTS:
: t
*** PHP
#+BEGIN_SRC emacs-lisp
(use-package php-mode
:ensure t)
#+END_SRC
#+RESULTS:
** Format All The Buffers
#+BEGIN_SRC emacs-lisp
(use-package format-all
:ensure t)
(add-hook 'prog-mode-hook 'format-all-mode)
(add-hook 'format-all-mode-hook 'format-all-ensure-formatter)
#+END_SRC
#+RESULTS:
| format-all-ensure-formatter |
* Multiple Cursors
#+BEGIN_SRC emacs-lisp
(use-package multiple-cursors
:straight t
:ensure t
:bind (("H-SPC" . set-rectangular-region-anchor)
("C-M-SPC" . set-rectangular-region-anchor)
("C->" . mc/mark-next-like-this)
("C-<" . mc/mark-previous-like-this)
("C-c C->" . mc/mark-all-like-this)
("C-c C-SPC" . mc/edit-lines)
))
#+END_SRC
* Obsidian
#+BEGIN_SRC emacs-lisp
(use-package obsidian
:ensure t
:demand t
:config
(obsidian-specify-path "~/PersonalDocuments/Personal/TTRPG Vault")
(global-obsidian-mode t)
:custom
:bind (:map obsidian-mode-map
("C-c C-o" . obsidian-follow-link-at-point)
("C-c C-b" . obsidian-backlink-jump)
("C-c C-l" . obsidian-insert-wikilink)))
#+END_SRC

9
.gitmodules vendored Normal file
View File

@ -0,0 +1,9 @@
[submodule ".local/lib/zsh/zsh-syntax-highlighting"]
path = .local/lib/zsh/zsh-syntax-highlighting
url = github:zsh-users/zsh-syntax-highlighting
[submodule ".local/lib/zsh/zsh-autosuggestions"]
path = .local/lib/zsh/zsh-autosuggestions
url = github:zsh-users/zsh-autosuggestions
[submodule ".local/lib/zsh/zsh-history-substring-search"]
path = .local/lib/zsh/zsh-history-substring-search
url = github:zsh-users/zsh-history-substring-search

@ -0,0 +1 @@
Subproject commit c3d4e576c9c86eac62884bd47c01f6faed043fc5

@ -0,0 +1 @@
Subproject commit 8dd05bfcc12b0cd1ee9ea64be725b3d9f713cf64

@ -0,0 +1 @@
Subproject commit e0165eaa730dd0fa321a6a6de74f092fe87630b0

2
.ssh/authorized_keys Normal file
View File

@ -0,0 +1,2 @@
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQCxTuUx4k1E+354rh1nyC5totwtIcw4RuyXXixIj0dCmlfACfCijuIYoA+2nCcGrGGDnEPLCR7PwHgJebN1MxQ6T1Vf170k05Zfnlqnd7d0llBmGYEVY1BgBcKIJEfASsOYxSnIlqT0mYCVYGx/el928tLwrWBfp2f2RqTblg6hTFW//1krkrD3X/s+rTX51dP9dOE9U7dIpKaHaxE1IpKziLbL6RnjDdNDK4ZvIRDjQIOcSNJbw3z42pZO/u83SpIB3O3pWckE5WTYcqhyg764gMkcQeWbpGpB+9wvxkbpoDuVUcNkdBYKF3+AF3ELszAMD+TwgFaqbLpy2EivhuC52DC64j+ZcpQC1vozm7JK81+7tZVfZc6VQqwe15BSx1n0rPPaBn98l0t26BUfZEQFFdp6AHjnEAjaJTiKJ4pqdsCJSprolXtGfyY7WVIrLr7hM5JihGftGrb6d08kbs0tSE1VC15fRMZ/XMhucqEF91cLzCNgRhJG55FDlaSHryQHqGDlzeaKZECDm0EwhoMDi2Qfb2d2Jy/BDZvf9mYhiCvLgSNAh3qi5hHXyq5IY7RP3xrs7Cz3e6lSlpYpyfey9fU+tya+RfgwMCB9HWDrCI6wUiwHs2SRuHLtZIZYfFKzkpct/la7voSDWZHv+O0gUyik3CBFJKaL9Ra/fot2Yw== cardno:11 462 306
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDGIejfvH+wJXmUFW1xGlGtKRSRmEb0DwcWH7FvXIQXMFdomZI/imrDbr/Lj0i1o66TsIDc3IgxxLzO+aCDSyr768S0y1/w7ob50NtOcRTOLHqhK2kS2dQGouhDNVG5pnBI1muS0YxuQ1mLRoFteY7BL24wbYttfmRd/dQXbTAzk+WRZw8lCOLMCphLDA4axuWMi116Tbc/x4/i41DHsrXz+Q3qr/+p06DMRc2HcbHQ8WyZoF70iB24WAdWydw+9GU6HNdmHtmPLrmNM007dkKHvZ0r5Z5gbOpqSdEA6+N2EP6KrC/euzDcaCEuBjDj7ro5fzltmLh5TyyTcXlfgNYj7L8ft+2adHsBgVP4Mf9GljZANWFee10G+lubIYKCVDUtKz5smzNZAH6VAd1+q8BLwsWHkxkX9CZELEKprnEbjS9Bw81grhKYDFf+U2qqOGUNIX++rADBeVram8EVIFvz424FXC5IGbaOUoacqbonk9pb4cGiPOzORs4FdroVMplVsll9WC6HpzGpTFDSu9ExJInnjCXjYFGehlB8aNGOE0WMUMc8iuUUkcIpNMv7+kTZFEDRcXqrsX1VbGa0+8hgtlcwiG3VJTbOT/M3m/ioS2ZDctKvwfBfFQpR93+o79nUMvtZC+9fhdb8bfsi/Pp4i8MMpjhhG+lZYhAGotTkfw== cardno:12 241 532