commit fb4d968caf8c6bfb3763b82e8c04356789de8538 Author: Ezri Brimhall Date: Wed Mar 6 16:35:10 2024 -0700 initial commit of new dotfiles repo diff --git a/.config/alacritty/alacritty.toml b/.config/alacritty/alacritty.toml new file mode 100644 index 0000000..58eec09 --- /dev/null +++ b/.config/alacritty/alacritty.toml @@ -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" diff --git a/.config/alacritty/alacritty.yml b/.config/alacritty/alacritty.yml new file mode 100644 index 0000000..acd84db --- /dev/null +++ b/.config/alacritty/alacritty.yml @@ -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 diff --git a/.config/dunst/dunstrc b/.config/dunst/dunstrc new file mode 100644 index 0000000..ebc4e22 --- /dev/null +++ b/.config/dunst/dunstrc @@ -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 = "%a: %s\n───────────────\n%b %p" +format = "%a\n%s\n\n%b" +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 diff --git a/.config/eww/.python-version b/.config/eww/.python-version new file mode 100644 index 0000000..bba70ea --- /dev/null +++ b/.config/eww/.python-version @@ -0,0 +1 @@ +eww-modules diff --git a/.config/eww/colors.scss b/.config/eww/colors.scss new file mode 100644 index 0000000..a62e408 --- /dev/null +++ b/.config/eww/colors.scss @@ -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; diff --git a/.config/eww/eww.scss b/.config/eww/eww.scss new file mode 100644 index 0000000..31507a0 --- /dev/null +++ b/.config/eww/eww.scss @@ -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; +} diff --git a/.config/eww/eww.yuck b/.config/eww/eww.yuck new file mode 100644 index 0000000..a743232 --- /dev/null +++ b/.config/eww/eww.yuck @@ -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)) diff --git a/.config/eww/eww.yuck~ b/.config/eww/eww.yuck~ new file mode 100644 index 0000000..314cec4 --- /dev/null +++ b/.config/eww/eww.yuck~ @@ -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)) diff --git a/.config/eww/modules/aggietime/aggietime.sh b/.config/eww/modules/aggietime/aggietime.sh new file mode 100755 index 0000000..f81cff8 --- /dev/null +++ b/.config/eww/modules/aggietime/aggietime.sh @@ -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}" diff --git a/.config/eww/modules/aggietime/aggietime.yuck b/.config/eww/modules/aggietime/aggietime.yuck new file mode 100644 index 0000000..48e9def --- /dev/null +++ b/.config/eww/modules/aggietime/aggietime.yuck @@ -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")) diff --git a/.config/eww/modules/angles/angles.yuck b/.config/eww/modules/angles/angles.yuck new file mode 100644 index 0000000..c424577 --- /dev/null +++ b/.config/eww/modules/angles/angles.yuck @@ -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)) + + diff --git a/.config/eww/modules/angles/left.png b/.config/eww/modules/angles/left.png new file mode 100644 index 0000000..f79354d Binary files /dev/null and b/.config/eww/modules/angles/left.png differ diff --git a/.config/eww/modules/angles/right.png b/.config/eww/modules/angles/right.png new file mode 100644 index 0000000..10a158d Binary files /dev/null and b/.config/eww/modules/angles/right.png differ diff --git a/.config/eww/modules/clock/clock.yuck b/.config/eww/modules/clock/clock.yuck new file mode 100644 index 0000000..f6df637 --- /dev/null +++ b/.config/eww/modules/clock/clock.yuck @@ -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}"))) diff --git a/.config/eww/modules/mpris/mpris.py b/.config/eww/modules/mpris/mpris.py new file mode 100755 index 0000000..f279563 --- /dev/null +++ b/.config/eww/modules/mpris/mpris.py @@ -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() diff --git a/.config/eww/modules/mpris/mpris.yuck b/.config/eww/modules/mpris/mpris.yuck new file mode 100644 index 0000000..6499257 --- /dev/null +++ b/.config/eww/modules/mpris/mpris.yuck @@ -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))) diff --git a/.config/eww/modules/network/network.py b/.config/eww/modules/network/network.py new file mode 100755 index 0000000..e4ec9ee --- /dev/null +++ b/.config/eww/modules/network/network.py @@ -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) diff --git a/.config/eww/modules/network/network.yuck b/.config/eww/modules/network/network.yuck new file mode 100644 index 0000000..8e9d67e --- /dev/null +++ b/.config/eww/modules/network/network.yuck @@ -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}"))) + )) diff --git a/.config/eww/modules/network/new_network.py b/.config/eww/modules/network/new_network.py new file mode 100755 index 0000000..ae72061 --- /dev/null +++ b/.config/eww/modules/network/new_network.py @@ -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) diff --git a/.config/eww/modules/system/system.py b/.config/eww/modules/system/system.py new file mode 100755 index 0000000..d802661 --- /dev/null +++ b/.config/eww/modules/system/system.py @@ -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) diff --git a/.config/eww/modules/system/system.yuck b/.config/eww/modules/system/system.yuck new file mode 100644 index 0000000..f6b2e4f --- /dev/null +++ b/.config/eww/modules/system/system.yuck @@ -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"))) + + + diff --git a/.config/eww/modules/timer/timer.py b/.config/eww/modules/timer/timer.py new file mode 100755 index 0000000..c45225d --- /dev/null +++ b/.config/eww/modules/timer/timer.py @@ -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) diff --git a/.config/eww/modules/timer/timer.yuck b/.config/eww/modules/timer/timer.yuck new file mode 100644 index 0000000..b6240bc --- /dev/null +++ b/.config/eww/modules/timer/timer.yuck @@ -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"))) + diff --git a/.config/eww/modules/volume/volume.py b/.config/eww/modules/volume/volume.py new file mode 100755 index 0000000..8bc8bd9 --- /dev/null +++ b/.config/eww/modules/volume/volume.py @@ -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()) diff --git a/.config/eww/modules/volume/volume.yuck b/.config/eww/modules/volume/volume.yuck new file mode 100644 index 0000000..31ef72c --- /dev/null +++ b/.config/eww/modules/volume/volume.yuck @@ -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")) diff --git a/.config/eww/modules/weather/weather.yuck b/.config/eww/modules/weather/weather.yuck new file mode 100644 index 0000000..06b4b76 --- /dev/null +++ b/.config/eww/modules/weather/weather.yuck @@ -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"))) diff --git a/.config/eww/modules/workspaces/hyprland.py b/.config/eww/modules/workspaces/hyprland.py new file mode 100755 index 0000000..a332f07 --- /dev/null +++ b/.config/eww/modules/workspaces/hyprland.py @@ -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()) diff --git a/.config/eww/modules/workspaces/sway.py b/.config/eww/modules/workspaces/sway.py new file mode 100755 index 0000000..fd5c4ae --- /dev/null +++ b/.config/eww/modules/workspaces/sway.py @@ -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()) diff --git a/.config/eww/modules/workspaces/workspaces.yuck b/.config/eww/modules/workspaces/workspaces.yuck new file mode 100644 index 0000000..52a9cee --- /dev/null +++ b/.config/eww/modules/workspaces/workspaces.yuck @@ -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)))) diff --git a/.config/htop/htoprc b/.config/htop/htoprc new file mode 100644 index 0000000..e918bed --- /dev/null +++ b/.config/htop/htoprc @@ -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 diff --git a/.config/sway/config b/.config/sway/config new file mode 100644 index 0000000..02c7b87 --- /dev/null +++ b/.config/sway/config @@ -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 diff --git a/.config/sway/config.d/00-meta.conf b/.config/sway/config.d/00-meta.conf new file mode 100644 index 0000000..dec694a --- /dev/null +++ b/.config/sway/config.d/00-meta.conf @@ -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 diff --git a/.config/sway/config.d/10-display-settings.conf b/.config/sway/config.d/10-display-settings.conf new file mode 100644 index 0000000..3c0f74a --- /dev/null +++ b/.config/sway/config.d/10-display-settings.conf @@ -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 + diff --git a/.config/sway/config.d/11-workspaces.conf b/.config/sway/config.d/11-workspaces.conf new file mode 100644 index 0000000..8981802 --- /dev/null +++ b/.config/sway/config.d/11-workspaces.conf @@ -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) +} diff --git a/.config/sway/config.d/12-windows.conf b/.config/sway/config.d/12-windows.conf new file mode 100644 index 0000000..40aae72 --- /dev/null +++ b/.config/sway/config.d/12-windows.conf @@ -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 diff --git a/.config/sway/config.d/20-style.conf b/.config/sway/config.d/20-style.conf new file mode 100644 index 0000000..f35cc45 --- /dev/null +++ b/.config/sway/config.d/20-style.conf @@ -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 +} diff --git a/.config/sway/config.d/30-qol.conf b/.config/sway/config.d/30-qol.conf new file mode 100644 index 0000000..2653e5b --- /dev/null +++ b/.config/sway/config.d/30-qol.conf @@ -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' +} diff --git a/.config/sway/config.d/40-input.conf b/.config/sway/config.d/40-input.conf new file mode 100644 index 0000000..0bbadf8 --- /dev/null +++ b/.config/sway/config.d/40-input.conf @@ -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 +} \ No newline at end of file diff --git a/.config/sway/config.d/90-services.conf b/.config/sway/config.d/90-services.conf new file mode 100644 index 0000000..c09aa42 --- /dev/null +++ b/.config/sway/config.d/90-services.conf @@ -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 diff --git a/.config/sway/config.new b/.config/sway/config.new new file mode 100644 index 0000000..55384d1 --- /dev/null +++ b/.config/sway/config.new @@ -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 diff --git a/.config/sway/config.old b/.config/sway/config.old new file mode 100644 index 0000000..bc6a748 --- /dev/null +++ b/.config/sway/config.old @@ -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 +} diff --git a/.config/sway/config~ b/.config/sway/config~ new file mode 100644 index 0000000..4908ebb --- /dev/null +++ b/.config/sway/config~ @@ -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 +} diff --git a/.config/sway/keymap.xkb b/.config/sway/keymap.xkb new file mode 100644 index 0000000..90aa12f --- /dev/null +++ b/.config/sway/keymap.xkb @@ -0,0 +1,1565 @@ +xkb_keymap { +xkb_keycodes "(unnamed)" { + minimum = 8; + maximum = 255; + = 9; + = 10; + = 11; + = 12; + = 13; + = 14; + = 15; + = 16; + = 17; + = 18; + = 19; + = 20; + = 21; + = 22; + = 23; + = 24; + = 25; + = 26; + = 27; + = 28; + = 29; + = 30; + = 31; + = 32; + = 33; + = 34; + = 35; + = 36; + = 37; + = 38; + = 39; + = 40; + = 41; + = 42; + = 43; + = 44; + = 45; + = 46; + = 47; + = 48; + = 49; + = 50; + = 51; + = 52; + = 53; + = 54; + = 55; + = 56; + = 57; + = 58; + = 59; + = 60; + = 61; + = 62; + = 63; + = 64; + = 65; + = 66; + = 67; + = 68; + = 69; + = 70; + = 71; + = 72; + = 73; + = 74; + = 75; + = 76; + = 77; + = 78; + = 79; + = 80; + = 81; + = 82; + = 83; + = 84; + = 85; + = 86; + = 87; + = 88; + = 89; + = 90; + = 91; + = 92; + = 94; + = 95; + = 96; + = 97; + = 98; + = 99; + = 100; + = 101; + = 102; + = 103; + = 104; + = 105; + = 106; + = 107; + = 108; + = 109; + = 110; + = 111; + = 112; + = 113; + = 114; + = 115; + = 116; + = 117; + = 118; + = 119; + = 120; + = 121; + = 122; + = 123; + = 124; + = 125; + = 126; + = 127; + = 128; + = 129; + = 130; + = 131; + = 132; + = 133; + = 134; + = 135; + = 136; + = 137; + = 138; + = 139; + = 140; + = 141; + = 142; + = 143; + = 144; + = 145; + = 146; + = 147; + = 148; + = 149; + = 150; + = 151; + = 152; + = 153; + = 154; + = 155; + = 156; + = 157; + = 158; + = 159; + = 160; + = 161; + = 162; + = 163; + = 164; + = 165; + = 166; + = 167; + = 168; + = 169; + = 170; + = 171; + = 172; + = 173; + = 174; + = 175; + = 176; + = 177; + = 178; + = 179; + = 180; + = 181; + = 182; + = 183; + = 184; + = 185; + = 186; + = 187; + = 188; + = 189; + = 190; + = 191; + = 192; + = 193; + = 194; + = 195; + = 196; + = 197; + = 198; + = 199; + = 200; + = 201; + = 202; + = 203; + = 204; + = 205; + = 206; + = 207; + = 208; + = 209; + = 210; + = 211; + = 212; + = 213; + = 214; + = 215; + = 216; + = 217; + = 218; + = 219; + = 220; + = 221; + = 222; + = 223; + = 224; + = 225; + = 226; + = 227; + = 228; + = 229; + = 230; + = 231; + = 232; + = 233; + = 234; + = 235; + = 236; + = 237; + = 238; + = 239; + = 240; + = 241; + = 242; + = 243; + = 244; + = 245; + = 246; + = 247; + = 248; + = 249; + = 250; + = 251; + = 252; + = 253; + = 254; + = 255; + indicator 1 = "Charging"; + indicator 2 = "Num Lock"; + indicator 3 = "Scroll Lock"; + indicator 4 = "Compose"; + indicator 5 = "Kana"; + indicator 6 = "Sleep"; + indicator 7 = "Suspend"; + indicator 8 = "Mute"; + indicator 9 = "Misc"; + indicator 10 = "Mail"; + indicator 11 = "Charging"; + indicator 12 = "Shift Lock"; + indicator 13 = "Group 2"; + indicator 14 = "Mouse Keys"; + alias = ; + alias = ; + alias = ; + alias = ; + alias = ; + alias = ; + alias = ; + alias = ; + alias = ; + alias = ; + alias = ; + alias = ; + alias = ; + alias = ; + alias = ; + alias = ; + alias = ; + alias = ; + alias = ; + alias = ; + alias = ; + alias = ; + alias = ; + alias = ; + alias = ; + alias = ; + alias = ; + alias = ; + alias = ; + alias = ; + alias = ; + alias = ; + alias = ; + alias = ; + alias = ; + alias = ; + alias = ; + alias = ; + alias = ; + alias = ; + alias = ; + alias = ; + alias = ; + alias = ; + alias = ; + alias = ; + alias = ; + alias = ; + alias = ; + alias = ; + alias = ; + alias = ; + alias = ; + alias = ; + alias = ; + alias = ; + alias = ; + alias = ; + alias = ; + alias = ; + alias = ; + alias = ; + alias = ; + alias = ; + alias = ; + alias = ; + alias = ; + alias = ; + alias = ; + alias = ; + alias = ; + alias = ; + alias = ; +}; + +xkb_types "(unnamed)" { + + virtual_modifiers NumLock,Alt,LevelThree,LevelFive,Meta,Super,Hyper,ScrollLock; + + type "ONE_LEVEL" { + modifiers= none; + level_name[Level1]= "Any"; + }; + type "TWO_LEVEL" { + modifiers= Shift; + map[Shift]= Level2; + level_name[Level1]= "Base"; + level_name[Level2]= "Shift"; + }; + type "ALPHABETIC" { + modifiers= Shift+Lock; + map[Shift]= Level2; + map[Lock]= Level2; + level_name[Level1]= "Base"; + level_name[Level2]= "Caps"; + }; + type "KEYPAD" { + modifiers= Shift+NumLock; + map[NumLock]= Level2; + level_name[Level1]= "Base"; + level_name[Level2]= "Number"; + }; + type "SHIFT+ALT" { + modifiers= Shift+Alt; + map[Shift+Alt]= Level2; + level_name[Level1]= "Base"; + level_name[Level2]= "Shift+Alt"; + }; + type "PC_SUPER_LEVEL2" { + modifiers= Mod4; + map[Mod4]= Level2; + level_name[Level1]= "Base"; + level_name[Level2]= "Super"; + }; + type "PC_CONTROL_LEVEL2" { + modifiers= Control; + map[Control]= Level2; + level_name[Level1]= "Base"; + level_name[Level2]= "Control"; + }; + type "PC_ALT_LEVEL2" { + modifiers= Alt; + map[Alt]= Level2; + level_name[Level1]= "Base"; + level_name[Level2]= "Alt"; + }; + type "CTRL+ALT" { + modifiers= Shift+Control+Alt+LevelThree; + map[Shift]= Level2; + preserve[Shift]= Shift; + map[LevelThree]= Level3; + map[Shift+LevelThree]= Level4; + preserve[Shift+LevelThree]= Shift; + map[Control+Alt]= Level5; + level_name[Level1]= "Base"; + level_name[Level2]= "Shift"; + level_name[Level3]= "Alt Base"; + level_name[Level4]= "Shift Alt"; + level_name[Level5]= "Ctrl+Alt"; + }; + type "LOCAL_EIGHT_LEVEL" { + modifiers= Shift+Lock+Control+LevelThree; + map[Shift]= Level2; + map[Lock]= Level2; + map[LevelThree]= Level3; + map[Shift+Lock+LevelThree]= Level3; + map[Shift+LevelThree]= Level4; + map[Lock+LevelThree]= Level4; + map[Control]= Level5; + map[Shift+Lock+Control]= Level5; + map[Shift+Control]= Level6; + map[Lock+Control]= Level6; + map[Control+LevelThree]= Level7; + map[Shift+Lock+Control+LevelThree]= Level7; + map[Shift+Control+LevelThree]= Level8; + map[Lock+Control+LevelThree]= Level8; + level_name[Level1]= "Base"; + level_name[Level2]= "Shift"; + level_name[Level3]= "Level3"; + level_name[Level4]= "Shift Level3"; + level_name[Level5]= "Ctrl"; + level_name[Level6]= "Shift Ctrl"; + level_name[Level7]= "Level3 Ctrl"; + level_name[Level8]= "Shift Level3 Ctrl"; + }; + type "THREE_LEVEL" { + modifiers= Shift+LevelThree; + map[Shift]= Level2; + map[LevelThree]= Level3; + map[Shift+LevelThree]= Level3; + level_name[Level1]= "Base"; + level_name[Level2]= "Shift"; + level_name[Level3]= "Level3"; + }; + type "EIGHT_LEVEL" { + modifiers= Shift+LevelThree+LevelFive; + map[Shift]= Level2; + map[LevelThree]= Level3; + map[Shift+LevelThree]= Level4; + map[LevelFive]= Level5; + map[Shift+LevelFive]= Level6; + map[LevelThree+LevelFive]= Level7; + map[Shift+LevelThree+LevelFive]= Level8; + level_name[Level1]= "Base"; + level_name[Level2]= "Shift"; + level_name[Level3]= "Alt Base"; + level_name[Level4]= "Shift Alt"; + level_name[Level5]= "X"; + level_name[Level6]= "X Shift"; + level_name[Level7]= "X Alt Base"; + level_name[Level8]= "X Shift Alt"; + }; + type "EIGHT_LEVEL_ALPHABETIC" { + modifiers= Shift+Lock+LevelThree+LevelFive; + map[Shift]= Level2; + map[Lock]= Level2; + map[LevelThree]= Level3; + map[Shift+LevelThree]= Level4; + map[Lock+LevelThree]= Level4; + map[Shift+Lock+LevelThree]= Level3; + map[LevelFive]= Level5; + map[Shift+LevelFive]= Level6; + map[Lock+LevelFive]= Level6; + map[Shift+Lock+LevelFive]= Level5; + map[LevelThree+LevelFive]= Level7; + map[Shift+LevelThree+LevelFive]= Level8; + map[Lock+LevelThree+LevelFive]= Level8; + map[Shift+Lock+LevelThree+LevelFive]= Level7; + level_name[Level1]= "Base"; + level_name[Level2]= "Shift"; + level_name[Level3]= "Alt Base"; + level_name[Level4]= "Shift Alt"; + level_name[Level5]= "X"; + level_name[Level6]= "X Shift"; + level_name[Level7]= "X Alt Base"; + level_name[Level8]= "X Shift Alt"; + }; + type "EIGHT_LEVEL_SEMIALPHABETIC" { + modifiers= Shift+Lock+LevelThree+LevelFive; + map[Shift]= Level2; + map[Lock]= Level2; + map[LevelThree]= Level3; + map[Shift+LevelThree]= Level4; + map[Lock+LevelThree]= Level3; + preserve[Lock+LevelThree]= Lock; + map[Shift+Lock+LevelThree]= Level4; + preserve[Shift+Lock+LevelThree]= Lock; + map[LevelFive]= Level5; + map[Shift+LevelFive]= Level6; + map[Lock+LevelFive]= Level6; + map[Shift+Lock+LevelFive]= Level5; + map[LevelThree+LevelFive]= Level7; + map[Shift+LevelThree+LevelFive]= Level8; + map[Lock+LevelThree+LevelFive]= Level7; + preserve[Lock+LevelThree+LevelFive]= Lock; + map[Shift+Lock+LevelThree+LevelFive]= Level8; + preserve[Shift+Lock+LevelThree+LevelFive]= Lock; + level_name[Level1]= "Base"; + level_name[Level2]= "Shift"; + level_name[Level3]= "Alt Base"; + level_name[Level4]= "Shift Alt"; + level_name[Level5]= "X"; + level_name[Level6]= "X Shift"; + level_name[Level7]= "X Alt Base"; + level_name[Level8]= "X Shift Alt"; + }; + type "EIGHT_LEVEL_LEVEL_FIVE_LOCK" { + modifiers= Shift+Lock+NumLock+LevelThree+LevelFive; + map[Shift]= Level2; + map[LevelThree]= Level3; + map[Shift+LevelThree]= Level4; + map[LevelFive]= Level5; + map[Shift+LevelFive]= Level6; + preserve[Shift+LevelFive]= Shift; + map[LevelThree+LevelFive]= Level7; + map[Shift+LevelThree+LevelFive]= Level8; + map[NumLock]= Level5; + map[Shift+NumLock]= Level6; + preserve[Shift+NumLock]= Shift; + map[NumLock+LevelThree]= Level7; + map[Shift+NumLock+LevelThree]= Level8; + map[Shift+NumLock+LevelFive]= Level2; + map[NumLock+LevelThree+LevelFive]= Level3; + map[Shift+NumLock+LevelThree+LevelFive]= Level4; + map[Shift+Lock]= Level2; + map[Lock+LevelThree]= Level3; + map[Shift+Lock+LevelThree]= Level4; + map[Lock+LevelFive]= Level5; + map[Shift+Lock+LevelFive]= Level6; + preserve[Shift+Lock+LevelFive]= Shift; + map[Lock+LevelThree+LevelFive]= Level7; + map[Shift+Lock+LevelThree+LevelFive]= Level8; + map[Lock+NumLock]= Level5; + map[Shift+Lock+NumLock]= Level6; + preserve[Shift+Lock+NumLock]= Shift; + map[Lock+NumLock+LevelThree]= Level7; + map[Shift+Lock+NumLock+LevelThree]= Level8; + map[Shift+Lock+NumLock+LevelFive]= Level2; + map[Lock+NumLock+LevelThree+LevelFive]= Level3; + map[Shift+Lock+NumLock+LevelThree+LevelFive]= Level4; + level_name[Level1]= "Base"; + level_name[Level2]= "Shift"; + level_name[Level3]= "Alt Base"; + level_name[Level4]= "Shift Alt"; + level_name[Level5]= "X"; + level_name[Level6]= "X Shift"; + level_name[Level7]= "X Alt Base"; + level_name[Level8]= "X Shift Alt"; + }; + type "EIGHT_LEVEL_ALPHABETIC_LEVEL_FIVE_LOCK" { + modifiers= Shift+Lock+NumLock+LevelThree+LevelFive; + map[Shift]= Level2; + map[LevelThree]= Level3; + map[Shift+LevelThree]= Level4; + map[LevelFive]= Level5; + map[Shift+LevelFive]= Level6; + preserve[Shift+LevelFive]= Shift; + map[LevelThree+LevelFive]= Level7; + map[Shift+LevelThree+LevelFive]= Level8; + map[NumLock]= Level5; + map[Shift+NumLock]= Level6; + preserve[Shift+NumLock]= Shift; + map[NumLock+LevelThree]= Level7; + map[Shift+NumLock+LevelThree]= Level8; + map[Shift+NumLock+LevelFive]= Level2; + map[NumLock+LevelThree+LevelFive]= Level3; + map[Shift+NumLock+LevelThree+LevelFive]= Level4; + map[Lock]= Level2; + map[Lock+LevelThree]= Level3; + map[Shift+Lock+LevelThree]= Level4; + map[Lock+LevelFive]= Level5; + map[Shift+Lock+LevelFive]= Level6; + map[Lock+LevelThree+LevelFive]= Level7; + map[Shift+Lock+LevelThree+LevelFive]= Level8; + map[Lock+NumLock]= Level5; + map[Shift+Lock+NumLock]= Level6; + map[Lock+NumLock+LevelThree]= Level7; + map[Shift+Lock+NumLock+LevelThree]= Level8; + map[Lock+NumLock+LevelFive]= Level2; + map[Lock+NumLock+LevelThree+LevelFive]= Level4; + map[Shift+Lock+NumLock+LevelThree+LevelFive]= Level3; + level_name[Level1]= "Base"; + level_name[Level2]= "Shift"; + level_name[Level3]= "Alt Base"; + level_name[Level4]= "Shift Alt"; + level_name[Level5]= "X"; + level_name[Level6]= "X Shift"; + level_name[Level7]= "X Alt Base"; + level_name[Level8]= "X Shift Alt"; + }; + type "FOUR_LEVEL" { + modifiers= Shift+LevelThree; + map[Shift]= Level2; + map[LevelThree]= Level3; + map[Shift+LevelThree]= Level4; + level_name[Level1]= "Base"; + level_name[Level2]= "Shift"; + level_name[Level3]= "Alt Base"; + level_name[Level4]= "Shift Alt"; + }; + type "FOUR_LEVEL_ALPHABETIC" { + modifiers= Shift+Lock+LevelThree; + map[Shift]= Level2; + map[Lock]= Level2; + map[LevelThree]= Level3; + map[Shift+LevelThree]= Level4; + map[Lock+LevelThree]= Level4; + map[Shift+Lock+LevelThree]= Level3; + level_name[Level1]= "Base"; + level_name[Level2]= "Shift"; + level_name[Level3]= "Alt Base"; + level_name[Level4]= "Shift Alt"; + }; + type "FOUR_LEVEL_SEMIALPHABETIC" { + modifiers= Shift+Lock+LevelThree; + map[Shift]= Level2; + map[Lock]= Level2; + map[LevelThree]= Level3; + map[Shift+LevelThree]= Level4; + map[Lock+LevelThree]= Level3; + preserve[Lock+LevelThree]= Lock; + map[Shift+Lock+LevelThree]= Level4; + preserve[Shift+Lock+LevelThree]= Lock; + level_name[Level1]= "Base"; + level_name[Level2]= "Shift"; + level_name[Level3]= "Alt Base"; + level_name[Level4]= "Shift Alt"; + }; + type "FOUR_LEVEL_MIXED_KEYPAD" { + modifiers= Shift+NumLock+LevelThree; + map[NumLock]= Level2; + map[Shift]= Level2; + map[LevelThree]= Level3; + map[NumLock+LevelThree]= Level3; + map[Shift+LevelThree]= Level4; + map[Shift+NumLock+LevelThree]= Level4; + level_name[Level1]= "Base"; + level_name[Level2]= "Number"; + level_name[Level3]= "Alt Base"; + level_name[Level4]= "Shift Alt"; + }; + type "FOUR_LEVEL_X" { + modifiers= Shift+Control+Alt+LevelThree; + map[LevelThree]= Level2; + map[Shift+LevelThree]= Level3; + map[Control+Alt]= Level4; + level_name[Level1]= "Base"; + level_name[Level2]= "Alt Base"; + level_name[Level3]= "Shift Alt"; + level_name[Level4]= "Ctrl+Alt"; + }; + type "SEPARATE_CAPS_AND_SHIFT_ALPHABETIC" { + modifiers= Shift+Lock+LevelThree; + map[Shift]= Level2; + map[Lock]= Level4; + preserve[Lock]= Lock; + map[LevelThree]= Level3; + map[Shift+LevelThree]= Level4; + map[Lock+LevelThree]= Level3; + preserve[Lock+LevelThree]= Lock; + map[Shift+Lock+LevelThree]= Level3; + level_name[Level1]= "Base"; + level_name[Level2]= "Shift"; + level_name[Level3]= "AltGr Base"; + level_name[Level4]= "Shift AltGr"; + }; + type "FOUR_LEVEL_PLUS_LOCK" { + modifiers= Shift+Lock+LevelThree; + map[Shift]= Level2; + map[LevelThree]= Level3; + map[Shift+LevelThree]= Level4; + map[Lock]= Level5; + map[Shift+Lock]= Level2; + map[Lock+LevelThree]= Level3; + map[Shift+Lock+LevelThree]= Level4; + level_name[Level1]= "Base"; + level_name[Level2]= "Shift"; + level_name[Level3]= "Alt Base"; + level_name[Level4]= "Shift Alt"; + level_name[Level5]= "Lock"; + }; + type "FOUR_LEVEL_KEYPAD" { + modifiers= Shift+NumLock+LevelThree; + map[Shift]= Level2; + map[NumLock]= Level2; + map[LevelThree]= Level3; + map[Shift+LevelThree]= Level4; + map[NumLock+LevelThree]= Level4; + map[Shift+NumLock+LevelThree]= Level3; + level_name[Level1]= "Base"; + level_name[Level2]= "Number"; + level_name[Level3]= "Alt Base"; + level_name[Level4]= "Alt Number"; + }; +}; + +xkb_compatibility "(unnamed)" { + + virtual_modifiers NumLock,Alt,LevelThree,LevelFive,Meta,Super,Hyper,ScrollLock; + + interpret.useModMapMods= AnyLevel; + interpret.repeat= False; + interpret.locking= False; + interpret ISO_Level2_Latch+Exactly(Shift) { + useModMapMods=level1; + action= LatchMods(modifiers=Shift,clearLocks,latchToLock); + }; + interpret Shift_Lock+AnyOf(Shift+Lock) { + action= LockMods(modifiers=Shift); + }; + interpret Num_Lock+AnyOf(all) { + virtualModifier= NumLock; + action= LockMods(modifiers=NumLock); + }; + interpret ISO_Level3_Shift+AnyOf(all) { + virtualModifier= LevelThree; + useModMapMods=level1; + action= SetMods(modifiers=LevelThree,clearLocks); + }; + interpret ISO_Level3_Latch+AnyOf(all) { + virtualModifier= LevelThree; + useModMapMods=level1; + action= LatchMods(modifiers=LevelThree,clearLocks,latchToLock); + }; + interpret ISO_Level3_Lock+AnyOf(all) { + virtualModifier= LevelThree; + useModMapMods=level1; + action= LockMods(modifiers=LevelThree); + }; + interpret Alt_L+AnyOf(all) { + virtualModifier= Alt; + action= SetMods(modifiers=modMapMods,clearLocks); + }; + interpret Alt_R+AnyOf(all) { + virtualModifier= Alt; + action= SetMods(modifiers=modMapMods,clearLocks); + }; + interpret Meta_L+AnyOf(all) { + virtualModifier= Meta; + action= SetMods(modifiers=modMapMods,clearLocks); + }; + interpret Meta_R+AnyOf(all) { + virtualModifier= Meta; + action= SetMods(modifiers=modMapMods,clearLocks); + }; + interpret Super_L+AnyOf(all) { + virtualModifier= Super; + action= SetMods(modifiers=modMapMods,clearLocks); + }; + interpret Super_R+AnyOf(all) { + virtualModifier= Super; + action= SetMods(modifiers=modMapMods,clearLocks); + }; + interpret Hyper_L+AnyOf(all) { + virtualModifier= Hyper; + action= SetMods(modifiers=modMapMods,clearLocks); + }; + interpret Hyper_R+AnyOf(all) { + virtualModifier= Hyper; + action= SetMods(modifiers=modMapMods,clearLocks); + }; + interpret Scroll_Lock+AnyOf(all) { + virtualModifier= ScrollLock; + action= LockMods(modifiers=modMapMods); + }; + interpret ISO_Level5_Shift+AnyOf(all) { + virtualModifier= LevelFive; + useModMapMods=level1; + action= SetMods(modifiers=LevelFive,clearLocks); + }; + interpret ISO_Level5_Latch+AnyOf(all) { + virtualModifier= LevelFive; + useModMapMods=level1; + action= LatchMods(modifiers=LevelFive,clearLocks,latchToLock); + }; + interpret ISO_Level5_Lock+AnyOf(all) { + virtualModifier= LevelFive; + useModMapMods=level1; + action= LockMods(modifiers=LevelFive); + }; + interpret Mode_switch+AnyOfOrNone(all) { + action= SetGroup(group=+1); + }; + interpret ISO_Level3_Shift+AnyOfOrNone(all) { + action= SetMods(modifiers=LevelThree,clearLocks); + }; + interpret ISO_Level3_Latch+AnyOfOrNone(all) { + action= LatchMods(modifiers=LevelThree,clearLocks,latchToLock); + }; + interpret ISO_Level3_Lock+AnyOfOrNone(all) { + action= LockMods(modifiers=LevelThree); + }; + interpret ISO_Group_Latch+AnyOfOrNone(all) { + action= LatchGroup(group=2); + }; + interpret ISO_Next_Group+AnyOfOrNone(all) { + action= LockGroup(group=+1); + }; + interpret ISO_Prev_Group+AnyOfOrNone(all) { + action= LockGroup(group=-1); + }; + interpret ISO_First_Group+AnyOfOrNone(all) { + action= LockGroup(group=1); + }; + interpret ISO_Last_Group+AnyOfOrNone(all) { + action= LockGroup(group=2); + }; + interpret KP_1+AnyOfOrNone(all) { + repeat= True; + action= MovePtr(x=-1,y=+1); + }; + interpret KP_End+AnyOfOrNone(all) { + repeat= True; + action= MovePtr(x=-1,y=+1); + }; + interpret KP_2+AnyOfOrNone(all) { + repeat= True; + action= MovePtr(x=+0,y=+1); + }; + interpret KP_Down+AnyOfOrNone(all) { + repeat= True; + action= MovePtr(x=+0,y=+1); + }; + interpret KP_3+AnyOfOrNone(all) { + repeat= True; + action= MovePtr(x=+1,y=+1); + }; + interpret KP_Next+AnyOfOrNone(all) { + repeat= True; + action= MovePtr(x=+1,y=+1); + }; + interpret KP_4+AnyOfOrNone(all) { + repeat= True; + action= MovePtr(x=-1,y=+0); + }; + interpret KP_Left+AnyOfOrNone(all) { + repeat= True; + action= MovePtr(x=-1,y=+0); + }; + interpret KP_6+AnyOfOrNone(all) { + repeat= True; + action= MovePtr(x=+1,y=+0); + }; + interpret KP_Right+AnyOfOrNone(all) { + repeat= True; + action= MovePtr(x=+1,y=+0); + }; + interpret KP_7+AnyOfOrNone(all) { + repeat= True; + action= MovePtr(x=-1,y=-1); + }; + interpret KP_Home+AnyOfOrNone(all) { + repeat= True; + action= MovePtr(x=-1,y=-1); + }; + interpret KP_8+AnyOfOrNone(all) { + repeat= True; + action= MovePtr(x=+0,y=-1); + }; + interpret KP_Up+AnyOfOrNone(all) { + repeat= True; + action= MovePtr(x=+0,y=-1); + }; + interpret KP_9+AnyOfOrNone(all) { + repeat= True; + action= MovePtr(x=+1,y=-1); + }; + interpret KP_Prior+AnyOfOrNone(all) { + repeat= True; + action= MovePtr(x=+1,y=-1); + }; + interpret KP_5+AnyOfOrNone(all) { + repeat= True; + action= PtrBtn(button=default); + }; + interpret KP_Begin+AnyOfOrNone(all) { + repeat= True; + action= PtrBtn(button=default); + }; + interpret KP_F2+AnyOfOrNone(all) { + repeat= True; + action= SetPtrDflt(affect=button,button=1); + }; + interpret KP_Divide+AnyOfOrNone(all) { + repeat= True; + action= SetPtrDflt(affect=button,button=1); + }; + interpret KP_F3+AnyOfOrNone(all) { + repeat= True; + action= SetPtrDflt(affect=button,button=2); + }; + interpret KP_Multiply+AnyOfOrNone(all) { + repeat= True; + action= SetPtrDflt(affect=button,button=2); + }; + interpret KP_F4+AnyOfOrNone(all) { + repeat= True; + action= SetPtrDflt(affect=button,button=3); + }; + interpret KP_Subtract+AnyOfOrNone(all) { + repeat= True; + action= SetPtrDflt(affect=button,button=3); + }; + interpret KP_Separator+AnyOfOrNone(all) { + repeat= True; + action= PtrBtn(button=default,count=2); + }; + interpret KP_Add+AnyOfOrNone(all) { + repeat= True; + action= PtrBtn(button=default,count=2); + }; + interpret KP_0+AnyOfOrNone(all) { + repeat= True; + action= LockPtrBtn(button=default,affect=lock); + }; + interpret KP_Insert+AnyOfOrNone(all) { + repeat= True; + action= LockPtrBtn(button=default,affect=lock); + }; + interpret KP_Decimal+AnyOfOrNone(all) { + repeat= True; + action= LockPtrBtn(button=default,affect=unlock); + }; + interpret KP_Delete+AnyOfOrNone(all) { + repeat= True; + action= LockPtrBtn(button=default,affect=unlock); + }; + interpret F25+AnyOfOrNone(all) { + repeat= True; + action= SetPtrDflt(affect=button,button=1); + }; + interpret F26+AnyOfOrNone(all) { + repeat= True; + action= SetPtrDflt(affect=button,button=2); + }; + interpret F27+AnyOfOrNone(all) { + repeat= True; + action= MovePtr(x=-1,y=-1); + }; + interpret F29+AnyOfOrNone(all) { + repeat= True; + action= MovePtr(x=+1,y=-1); + }; + interpret F31+AnyOfOrNone(all) { + repeat= True; + action= PtrBtn(button=default); + }; + interpret F33+AnyOfOrNone(all) { + repeat= True; + action= MovePtr(x=-1,y=+1); + }; + interpret F35+AnyOfOrNone(all) { + repeat= True; + action= MovePtr(x=+1,y=+1); + }; + interpret Pointer_Button_Dflt+AnyOfOrNone(all) { + action= PtrBtn(button=default); + }; + interpret Pointer_Button1+AnyOfOrNone(all) { + action= PtrBtn(button=1); + }; + interpret Pointer_Button2+AnyOfOrNone(all) { + action= PtrBtn(button=2); + }; + interpret Pointer_Button3+AnyOfOrNone(all) { + action= PtrBtn(button=3); + }; + interpret Pointer_DblClick_Dflt+AnyOfOrNone(all) { + action= PtrBtn(button=default,count=2); + }; + interpret Pointer_DblClick1+AnyOfOrNone(all) { + action= PtrBtn(button=1,count=2); + }; + interpret Pointer_DblClick2+AnyOfOrNone(all) { + action= PtrBtn(button=2,count=2); + }; + interpret Pointer_DblClick3+AnyOfOrNone(all) { + action= PtrBtn(button=3,count=2); + }; + interpret Pointer_Drag_Dflt+AnyOfOrNone(all) { + action= LockPtrBtn(button=default,affect=both); + }; + interpret Pointer_Drag1+AnyOfOrNone(all) { + action= LockPtrBtn(button=1,affect=both); + }; + interpret Pointer_Drag2+AnyOfOrNone(all) { + action= LockPtrBtn(button=2,affect=both); + }; + interpret Pointer_Drag3+AnyOfOrNone(all) { + action= LockPtrBtn(button=3,affect=both); + }; + interpret Pointer_EnableKeys+AnyOfOrNone(all) { + action= LockControls(controls=MouseKeys); + }; + interpret Pointer_Accelerate+AnyOfOrNone(all) { + action= LockControls(controls=MouseKeysAccel); + }; + interpret Pointer_DfltBtnNext+AnyOfOrNone(all) { + action= SetPtrDflt(affect=button,button=+1); + }; + interpret Pointer_DfltBtnPrev+AnyOfOrNone(all) { + action= SetPtrDflt(affect=button,button=-1); + }; + interpret AccessX_Enable+AnyOfOrNone(all) { + action= LockControls(controls=AccessXKeys); + }; + interpret AccessX_Feedback_Enable+AnyOfOrNone(all) { + action= LockControls(controls=AccessXFeedback); + }; + interpret RepeatKeys_Enable+AnyOfOrNone(all) { + action= LockControls(controls=RepeatKeys); + }; + interpret SlowKeys_Enable+AnyOfOrNone(all) { + action= LockControls(controls=SlowKeys); + }; + interpret BounceKeys_Enable+AnyOfOrNone(all) { + action= LockControls(controls=BounceKeys); + }; + interpret StickyKeys_Enable+AnyOfOrNone(all) { + action= LockControls(controls=StickyKeys); + }; + interpret MouseKeys_Enable+AnyOfOrNone(all) { + action= LockControls(controls=MouseKeys); + }; + interpret MouseKeys_Accel_Enable+AnyOfOrNone(all) { + action= LockControls(controls=MouseKeysAccel); + }; + interpret Overlay1_Enable+AnyOfOrNone(all) { + action= LockControls(controls=none); + }; + interpret Overlay2_Enable+AnyOfOrNone(all) { + action= LockControls(controls=none); + }; + interpret AudibleBell_Enable+AnyOfOrNone(all) { + action= LockControls(controls=AudibleBell); + }; + interpret Terminate_Server+AnyOfOrNone(all) { + action= Terminate(); + }; + interpret Alt_L+AnyOfOrNone(all) { + action= SetMods(modifiers=Alt,clearLocks); + }; + interpret Alt_R+AnyOfOrNone(all) { + action= SetMods(modifiers=Alt,clearLocks); + }; + interpret Meta_L+AnyOfOrNone(all) { + action= SetMods(modifiers=Meta,clearLocks); + }; + interpret Meta_R+AnyOfOrNone(all) { + action= SetMods(modifiers=Meta,clearLocks); + }; + interpret Super_L+AnyOfOrNone(all) { + action= SetMods(modifiers=Super,clearLocks); + }; + interpret Super_R+AnyOfOrNone(all) { + action= SetMods(modifiers=Super,clearLocks); + }; + interpret Hyper_L+AnyOfOrNone(all) { + action= SetMods(modifiers=Hyper,clearLocks); + }; + interpret Hyper_R+AnyOfOrNone(all) { + action= SetMods(modifiers=Hyper,clearLocks); + }; + interpret Shift_L+AnyOfOrNone(all) { + action= SetMods(modifiers=Shift,clearLocks); + }; + interpret XF86Switch_VT_1+AnyOfOrNone(all) { + repeat= True; + action= SwitchScreen(screen=1,!same); + }; + interpret XF86Switch_VT_2+AnyOfOrNone(all) { + repeat= True; + action= SwitchScreen(screen=2,!same); + }; + interpret XF86Switch_VT_3+AnyOfOrNone(all) { + repeat= True; + action= SwitchScreen(screen=3,!same); + }; + interpret XF86Switch_VT_4+AnyOfOrNone(all) { + repeat= True; + action= SwitchScreen(screen=4,!same); + }; + interpret XF86Switch_VT_5+AnyOfOrNone(all) { + repeat= True; + action= SwitchScreen(screen=5,!same); + }; + interpret XF86Switch_VT_6+AnyOfOrNone(all) { + repeat= True; + action= SwitchScreen(screen=6,!same); + }; + interpret XF86Switch_VT_7+AnyOfOrNone(all) { + repeat= True; + action= SwitchScreen(screen=7,!same); + }; + interpret XF86Switch_VT_8+AnyOfOrNone(all) { + repeat= True; + action= SwitchScreen(screen=8,!same); + }; + interpret XF86Switch_VT_9+AnyOfOrNone(all) { + repeat= True; + action= SwitchScreen(screen=9,!same); + }; + interpret XF86Switch_VT_10+AnyOfOrNone(all) { + repeat= True; + action= SwitchScreen(screen=10,!same); + }; + interpret XF86Switch_VT_11+AnyOfOrNone(all) { + repeat= True; + action= SwitchScreen(screen=11,!same); + }; + interpret XF86Switch_VT_12+AnyOfOrNone(all) { + repeat= True; + action= SwitchScreen(screen=12,!same); + }; + interpret XF86LogGrabInfo+AnyOfOrNone(all) { + repeat= True; + action= Private(type=0x86,data[0]=0x50,data[1]=0x72,data[2]=0x47,data[3]=0x72,data[4]=0x62,data[5]=0x73,data[6]=0x00); + }; + interpret XF86LogWindowTree+AnyOfOrNone(all) { + repeat= True; + action= Private(type=0x86,data[0]=0x50,data[1]=0x72,data[2]=0x57,data[3]=0x69,data[4]=0x6e,data[5]=0x73,data[6]=0x00); + }; + interpret XF86Next_VMode+AnyOfOrNone(all) { + repeat= True; + action= Private(type=0x86,data[0]=0x2b,data[1]=0x56,data[2]=0x4d,data[3]=0x6f,data[4]=0x64,data[5]=0x65,data[6]=0x00); + }; + interpret XF86Prev_VMode+AnyOfOrNone(all) { + repeat= True; + action= Private(type=0x86,data[0]=0x2d,data[1]=0x56,data[2]=0x4d,data[3]=0x6f,data[4]=0x64,data[5]=0x65,data[6]=0x00); + }; + interpret ISO_Level5_Shift+AnyOfOrNone(all) { + action= SetMods(modifiers=LevelFive,clearLocks); + }; + interpret ISO_Level5_Latch+AnyOfOrNone(all) { + action= LatchMods(modifiers=LevelFive,clearLocks,latchToLock); + }; + interpret ISO_Level5_Lock+AnyOfOrNone(all) { + action= LockMods(modifiers=LevelFive); + }; + interpret Caps_Lock+AnyOfOrNone(all) { + action= LockMods(modifiers=Lock); + }; + interpret Any+Exactly(Lock) { + action= LockMods(modifiers=Lock); + }; + interpret Any+AnyOf(all) { + action= SetMods(modifiers=modMapMods,clearLocks); + }; + indicator "Caps Lock" { + whichModState= locked; + modifiers= Lock; + }; + indicator "Num Lock" { + whichModState= locked; + modifiers= NumLock; + }; + indicator "Scroll Lock" { + whichModState= locked; + modifiers= ScrollLock; + }; + indicator "Shift Lock" { + whichModState= locked; + modifiers= Shift; + }; + indicator "Group 2" { + groups= 0xfe; + }; + indicator "Mouse Keys" { + controls= mouseKeys; + }; +}; + +xkb_symbols "(unnamed)" { + + name[group1]="English (US)"; + + key { [ Escape ] }; + key { [ 1, exclam ] }; + key { [ 2, at ] }; + key { [ 3, numbersign ] }; + key { [ 4, dollar ] }; + key { [ 5, percent ] }; + key { [ 6, asciicircum ] }; + key { [ 7, ampersand ] }; + key { [ 8, asterisk ] }; + key { [ 9, parenleft ] }; + key { [ 0, parenright ] }; + key { [ minus, underscore ] }; + key { [ equal, plus ] }; + key { [ BackSpace, BackSpace ] }; + key { [ Tab, ISO_Left_Tab ] }; + key { + type= "ALPHABETIC", + symbols[Group1]= [ q, Q ] + }; + key { + type= "ALPHABETIC", + symbols[Group1]= [ w, W ] + }; + key { + type= "ALPHABETIC", + symbols[Group1]= [ e, E ] + }; + key { + type= "ALPHABETIC", + symbols[Group1]= [ r, R ] + }; + key { + type= "ALPHABETIC", + symbols[Group1]= [ t, T ] + }; + key { + type= "ALPHABETIC", + symbols[Group1]= [ y, Y ] + }; + key { + type= "ALPHABETIC", + symbols[Group1]= [ u, U ] + }; + key { + type= "ALPHABETIC", + symbols[Group1]= [ i, I ] + }; + key { + type= "ALPHABETIC", + symbols[Group1]= [ o, O ] + }; + key { + type= "ALPHABETIC", + symbols[Group1]= [ p, P ] + }; + key { [ bracketleft, braceleft ] }; + key { [ bracketright, braceright ] }; + key { [ Return ] }; + key { [ Control_L ] }; + key { + type= "ALPHABETIC", + symbols[Group1]= [ a, A ] + }; + key { + type= "ALPHABETIC", + symbols[Group1]= [ s, S ] + }; + key { + type= "ALPHABETIC", + symbols[Group1]= [ d, D ] + }; + key { + type= "ALPHABETIC", + symbols[Group1]= [ f, F ] + }; + key { + type= "ALPHABETIC", + symbols[Group1]= [ g, G ] + }; + key { + type= "ALPHABETIC", + symbols[Group1]= [ h, H ] + }; + key { + type= "ALPHABETIC", + symbols[Group1]= [ j, J ] + }; + key { + type= "ALPHABETIC", + symbols[Group1]= [ k, K ] + }; + key { + type= "ALPHABETIC", + symbols[Group1]= [ l, L ] + }; + key { [ semicolon, colon ] }; + key { [ apostrophe, quotedbl ] }; + key { [ grave, asciitilde ] }; + key { [ Shift_L ] }; + key { [ backslash, bar ] }; + key { + type= "ALPHABETIC", + symbols[Group1]= [ z, Z ] + }; + key { + type= "ALPHABETIC", + symbols[Group1]= [ x, X ] + }; + key { + type= "ALPHABETIC", + symbols[Group1]= [ c, C ] + }; + key { + type= "ALPHABETIC", + symbols[Group1]= [ v, V ] + }; + key { + type= "ALPHABETIC", + symbols[Group1]= [ b, B ] + }; + key { + type= "ALPHABETIC", + symbols[Group1]= [ n, N ] + }; + key { + type= "ALPHABETIC", + symbols[Group1]= [ m, M ] + }; + key { [ comma, less ] }; + key { [ period, greater ] }; + key { [ slash, question ] }; + key { [ Shift_R ] }; + key { + type= "CTRL+ALT", + symbols[Group1]= [ KP_Multiply, KP_Multiply, KP_Multiply, KP_Multiply, XF86ClearGrab ] + }; + key { [ Alt_L, Meta_L ] }; + key { [ space, underscore ] }; + key { + type= "TWO_LEVEL", + symbols[Group1]= [ Multi_key, Multi_key ] + }; + key { + type= "CTRL+ALT", + symbols[Group1]= [ F1, F1, F1, F1, XF86Switch_VT_1 ] + }; + key { + type= "CTRL+ALT", + symbols[Group1]= [ F2, F2, F2, F2, XF86Switch_VT_2 ] + }; + key { + type= "CTRL+ALT", + symbols[Group1]= [ F3, F3, F3, F3, XF86Switch_VT_3 ] + }; + key { + type= "CTRL+ALT", + symbols[Group1]= [ F4, F4, F4, F4, XF86Switch_VT_4 ] + }; + key { + type= "CTRL+ALT", + symbols[Group1]= [ F5, F5, F5, F5, XF86Switch_VT_5 ] + }; + key { + type= "CTRL+ALT", + symbols[Group1]= [ F6, F6, F6, F6, XF86Switch_VT_6 ] + }; + key { + type= "CTRL+ALT", + symbols[Group1]= [ F7, F7, F7, F7, XF86Switch_VT_7 ] + }; + key { + type= "CTRL+ALT", + symbols[Group1]= [ F8, F8, F8, F8, XF86Switch_VT_8 ] + }; + key { + type= "CTRL+ALT", + symbols[Group1]= [ F9, F9, F9, F9, XF86Switch_VT_9 ] + }; + key { + type= "CTRL+ALT", + symbols[Group1]= [ F10, F10, F10, F10, XF86Switch_VT_10 ] + }; + key { [ Num_Lock ] }; + key { [ Scroll_Lock ] }; + key { [ KP_Home, KP_7 ] }; + key { [ KP_Up, KP_8 ] }; + key { [ KP_Prior, KP_9 ] }; + key { + type= "CTRL+ALT", + symbols[Group1]= [ KP_Subtract, KP_Subtract, KP_Subtract, KP_Subtract, XF86Prev_VMode ] + }; + key { [ KP_Left, KP_4 ] }; + key { [ KP_Begin, KP_5 ] }; + key { [ KP_Right, KP_6 ] }; + key { + type= "CTRL+ALT", + symbols[Group1]= [ KP_Add, KP_Add, KP_Add, KP_Add, XF86Next_VMode ] + }; + key { [ KP_End, KP_1 ] }; + key { [ KP_Down, KP_2 ] }; + key { [ KP_Next, KP_3 ] }; + key { [ KP_Insert, KP_0 ] }; + key { [ KP_Delete, KP_Decimal ] }; + key { [ ISO_Level3_Shift ] }; + key { + type= "FOUR_LEVEL", + symbols[Group1]= [ less, greater, bar, brokenbar ] + }; + key { + type= "CTRL+ALT", + symbols[Group1]= [ F11, F11, F11, F11, XF86Switch_VT_11 ] + }; + key { + type= "CTRL+ALT", + symbols[Group1]= [ F12, F12, F12, F12, XF86Switch_VT_12 ] + }; + key { [ Katakana ] }; + key { [ Hiragana ] }; + key { [ Henkan_Mode ] }; + key { [ Hiragana_Katakana ] }; + key { [ Muhenkan ] }; + key { [ KP_Enter ] }; + key { [ Control_R ] }; + key { + type= "CTRL+ALT", + symbols[Group1]= [ KP_Divide, KP_Divide, KP_Divide, KP_Divide, XF86Ungrab ] + }; + key { + type= "PC_ALT_LEVEL2", + symbols[Group1]= [ Print, Sys_Req ] + }; + key { [ Alt_R, Meta_R ] }; + key { [ Linefeed ] }; + key { [ Home ] }; + key { [ Up ] }; + key { [ Prior ] }; + key { [ Left ] }; + key { [ Right ] }; + key { [ End ] }; + key { [ Down ] }; + key { [ Next ] }; + key { [ Insert ] }; + key { [ Delete ] }; + key { [ XF86AudioMute ] }; + key { [ XF86AudioLowerVolume ] }; + key { [ XF86AudioRaiseVolume ] }; + key { [ XF86PowerOff ] }; + key { [ KP_Equal ] }; + key { [ plusminus ] }; + key { + type= "PC_CONTROL_LEVEL2", + symbols[Group1]= [ Pause, Break ] + }; + key { [ XF86LaunchA ] }; + key { [ KP_Decimal, KP_Decimal ] }; + key { [ Hangul ] }; + key { [ Hangul_Hanja ] }; + key { [ Super_L ] }; + key { [ Super_R ] }; + key { [ Menu ] }; + key { [ Cancel ] }; + key { [ Redo ] }; + key { [ SunProps ] }; + key { [ Undo ] }; + key { [ SunFront ] }; + key { [ XF86Copy ] }; + key { [ XF86Open ] }; + key { [ XF86Paste ] }; + key { [ Find ] }; + key { [ XF86Cut ] }; + key { [ Help ] }; + key { [ XF86MenuKB ] }; + key { [ XF86Calculator ] }; + key { [ XF86Sleep ] }; + key { [ XF86WakeUp ] }; + key { [ XF86Explorer ] }; + key { [ XF86Send ] }; + key { [ XF86Xfer ] }; + key { [ XF86Launch1 ] }; + key { [ XF86Launch2 ] }; + key { [ XF86WWW ] }; + key { [ XF86DOS ] }; + key { [ XF86ScreenSaver ] }; + key { [ XF86RotateWindows ] }; + key { [ XF86TaskPane ] }; + key { [ XF86Mail ] }; + key { [ XF86Favorites ] }; + key { [ XF86MyComputer ] }; + key { [ XF86Back ] }; + key { [ XF86Forward ] }; + key { [ XF86Eject ] }; + key { [ XF86Eject ] }; + key { [ XF86AudioNext ] }; + key { [ XF86AudioPlay, XF86AudioPause ] }; + key { [ XF86AudioPrev ] }; + key { [ XF86AudioStop, XF86Eject ] }; + key { [ XF86AudioRecord ] }; + key { [ XF86AudioRewind ] }; + key { [ XF86Phone ] }; + key { [ XF86Tools ] }; + key { [ XF86HomePage ] }; + key { [ XF86Reload ] }; + key { [ XF86Close ] }; + key { [ XF86ScrollUp ] }; + key { [ XF86ScrollDown ] }; + key { [ parenleft ] }; + key { [ parenright ] }; + key { [ XF86New ] }; + key { [ Redo ] }; + key { [ XF86Tools ] }; + key { [ XF86Launch5 ] }; + key { [ XF86Launch6 ] }; + key { [ XF86Launch7 ] }; + key { [ XF86Launch8 ] }; + key { [ XF86Launch9 ] }; + key { [ XF86AudioMicMute ] }; + key { [ XF86TouchpadToggle ] }; + key { [ XF86TouchpadOn ] }; + key { [ XF86TouchpadOff ] }; + key { [ ISO_Level5_Shift ] }; + key { [ NoSymbol, Alt_L ] }; + key { [ NoSymbol, Meta_L ] }; + key { [ NoSymbol, Super_L ] }; + key { [ NoSymbol, Hyper_L ] }; + key { [ XF86AudioPlay ] }; + key { [ XF86AudioPause ] }; + key { [ XF86Launch3 ] }; + key { [ XF86Launch4 ] }; + key { [ XF86LaunchB ] }; + key { [ XF86Suspend ] }; + key { [ XF86Close ] }; + key { [ XF86AudioPlay ] }; + key { [ XF86AudioForward ] }; + key { [ Print ] }; + key { [ XF86WebCam ] }; + key { [ XF86AudioPreset ] }; + key { [ XF86Mail ] }; + key { [ XF86Messenger ] }; + key { [ XF86Search ] }; + key { [ XF86Go ] }; + key { [ XF86Finance ] }; + key { [ XF86Game ] }; + key { [ XF86Shop ] }; + key { [ Cancel ] }; + key { [ XF86MonBrightnessDown ] }; + key { [ XF86MonBrightnessUp ] }; + key { [ XF86AudioMedia ] }; + key { [ XF86Display ] }; + key { [ XF86KbdLightOnOff ] }; + key { [ XF86KbdBrightnessDown ] }; + key { [ XF86KbdBrightnessUp ] }; + key { [ XF86Send ] }; + key { [ XF86Reply ] }; + key { [ XF86MailForward ] }; + key { [ XF86Save ] }; + key { [ XF86Documents ] }; + key { [ XF86Battery ] }; + key { [ XF86Bluetooth ] }; + key { [ XF86WLAN ] }; + key { [ XF86UWB ] }; + key { [ XF86Next_VMode ] }; + key { [ XF86Prev_VMode ] }; + key { [ XF86MonBrightnessCycle ] }; + key { [ XF86BrightnessAuto ] }; + key { [ XF86DisplayOff ] }; + key { [ XF86WWAN ] }; + key { [ XF86RFKill ] }; + modifier_map Control { }; + modifier_map Shift { }; + modifier_map Shift { }; + modifier_map Mod1 { }; + modifier_map Mod2 { }; + modifier_map Mod5 { }; + modifier_map Control { }; + modifier_map Mod1 { }; + modifier_map Mod4 { }; + modifier_map Mod4 { }; + modifier_map Mod3 { }; + modifier_map Mod1 { }; + modifier_map Mod1 { }; + modifier_map Mod4 { }; + modifier_map Mod4 { }; +}; + +}; diff --git a/.config/sway/swayidle b/.config/sway/swayidle new file mode 100644 index 0000000..715a68c --- /dev/null +++ b/.config/sway/swayidle @@ -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 + diff --git a/.config/sway/workspaces.json b/.config/sway/workspaces.json new file mode 100644 index 0000000..9f9ee5c --- /dev/null +++ b/.config/sway/workspaces.json @@ -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" + } + ] + } +} diff --git a/.config/swaync/config.json b/.config/swaync/config.json new file mode 100644 index 0000000..68aefbd --- /dev/null +++ b/.config/swaync/config.json @@ -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'" + } + ] + } + } +} diff --git a/.config/swaync/style.css b/.config/swaync/style.css new file mode 100644 index 0000000..28d9e8d --- /dev/null +++ b/.config/swaync/style.css @@ -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; +} diff --git a/.config/swaync/style.css.old b/.config/swaync/style.css.old new file mode 100644 index 0000000..acafd9d --- /dev/null +++ b/.config/swaync/style.css.old @@ -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; +} diff --git a/.config/systemd/user/aggietimed.service b/.config/systemd/user/aggietimed.service new file mode 100644 index 0000000..c8de524 --- /dev/null +++ b/.config/systemd/user/aggietimed.service @@ -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 diff --git a/.config/systemd/user/alacritty.service b/.config/systemd/user/alacritty.service new file mode 100644 index 0000000..8691a51 --- /dev/null +++ b/.config/systemd/user/alacritty.service @@ -0,0 +1,9 @@ +[Unit] +Description=Terminal emulator +PartOf=sway-session.target + +[Service] +Type=simple +ExecStart=alacritty +Slice=gui.slice + diff --git a/.config/systemd/user/autolock.service b/.config/systemd/user/autolock.service new file mode 100644 index 0000000..d476d75 --- /dev/null +++ b/.config/systemd/user/autolock.service @@ -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 diff --git a/.config/systemd/user/dunst.service b/.config/systemd/user/dunst.service new file mode 100644 index 0000000..c7ef929 --- /dev/null +++ b/.config/systemd/user/dunst.service @@ -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 diff --git a/.config/systemd/user/emacs.service b/.config/systemd/user/emacs.service new file mode 100644 index 0000000..fd1f878 --- /dev/null +++ b/.config/systemd/user/emacs.service @@ -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 diff --git a/.config/systemd/user/eww.service b/.config/systemd/user/eww.service new file mode 100644 index 0000000..f36ed9f --- /dev/null +++ b/.config/systemd/user/eww.service @@ -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 diff --git a/.config/systemd/user/gnome-keyring.service b/.config/systemd/user/gnome-keyring.service new file mode 100644 index 0000000..5ec14e8 --- /dev/null +++ b/.config/systemd/user/gnome-keyring.service @@ -0,0 +1,9 @@ +[Unit] +Description = GNOME Keyring + +[Service] +Type=forking +ExecStart=gnome-keyring-daemon --daemonize + +[Install] +WantedBy=default.target diff --git a/.config/systemd/user/hypr-session.target b/.config/systemd/user/hypr-session.target new file mode 100644 index 0000000..0221273 --- /dev/null +++ b/.config/systemd/user/hypr-session.target @@ -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 diff --git a/.config/systemd/user/kdeconnect.service b/.config/systemd/user/kdeconnect.service new file mode 100644 index 0000000..e605c68 --- /dev/null +++ b/.config/systemd/user/kdeconnect.service @@ -0,0 +1,9 @@ +[Unit] +Description=KDE Connect Daemon + +[Service] +Type=simple +ExecStart=/usr/lib/kdeconnectd + +[Install] +WantedBy=default.target diff --git a/.config/systemd/user/lxpolkit.service b/.config/systemd/user/lxpolkit.service new file mode 100644 index 0000000..3292d95 --- /dev/null +++ b/.config/systemd/user/lxpolkit.service @@ -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 diff --git a/.config/systemd/user/mpris-proxy.service b/.config/systemd/user/mpris-proxy.service new file mode 100644 index 0000000..e7e331d --- /dev/null +++ b/.config/systemd/user/mpris-proxy.service @@ -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 diff --git a/.config/systemd/user/playerctld.service b/.config/systemd/user/playerctld.service new file mode 100644 index 0000000..1fa95a1 --- /dev/null +++ b/.config/systemd/user/playerctld.service @@ -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 diff --git a/.config/systemd/user/sway-session.target b/.config/systemd/user/sway-session.target new file mode 100644 index 0000000..a6dadf9 --- /dev/null +++ b/.config/systemd/user/sway-session.target @@ -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 diff --git a/.config/systemd/user/swaybg.service b/.config/systemd/user/swaybg.service new file mode 100644 index 0000000..5e5391f --- /dev/null +++ b/.config/systemd/user/swaybg.service @@ -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 diff --git a/.config/systemd/user/swayidle.service b/.config/systemd/user/swayidle.service new file mode 100644 index 0000000..29a60f0 --- /dev/null +++ b/.config/systemd/user/swayidle.service @@ -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 diff --git a/.config/systemd/user/swaync.service b/.config/systemd/user/swaync.service new file mode 100644 index 0000000..4329418 --- /dev/null +++ b/.config/systemd/user/swaync.service @@ -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 diff --git a/.config/systemd/user/test.service b/.config/systemd/user/test.service new file mode 100644 index 0000000..a7d6bb4 --- /dev/null +++ b/.config/systemd/user/test.service @@ -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 diff --git a/.config/wofi/config b/.config/wofi/config new file mode 100644 index 0000000..7a72b63 --- /dev/null +++ b/.config/wofi/config @@ -0,0 +1,2 @@ +dynamic_lines=true +layer=overlay diff --git a/.config/wofi/style.css b/.config/wofi/style.css new file mode 100644 index 0000000..df6695b --- /dev/null +++ b/.config/wofi/style.css @@ -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; +} diff --git a/.config/yadm/bootstrap b/.config/yadm/bootstrap new file mode 100644 index 0000000..4737753 --- /dev/null +++ b/.config/yadm/bootstrap @@ -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 diff --git a/.config/zsh/.#auth-agent.zsh b/.config/zsh/.#auth-agent.zsh new file mode 120000 index 0000000..57dd57d --- /dev/null +++ b/.config/zsh/.#auth-agent.zsh @@ -0,0 +1 @@ +stephen@Triskelion.703:1598899691 \ No newline at end of file diff --git a/.config/zsh/alias.zsh b/.config/zsh/alias.zsh new file mode 100644 index 0000000..6582d7e --- /dev/null +++ b/.config/zsh/alias.zsh @@ -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 $@)" +'' | 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 +} diff --git a/.config/zsh/alias.zsh~ b/.config/zsh/alias.zsh~ new file mode 100644 index 0000000..cd50e50 --- /dev/null +++ b/.config/zsh/alias.zsh~ @@ -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 +} diff --git a/.config/zsh/dir-hash.zsh b/.config/zsh/dir-hash.zsh new file mode 100644 index 0000000..e011869 --- /dev/null +++ b/.config/zsh/dir-hash.zsh @@ -0,0 +1,2 @@ +hash -d cpp=$HOME/Documents/School/FA22/CS3460 +hash -d hpc=$HOME/Documents/School/FA22/CS5030 diff --git a/.config/zsh/directories.zsh b/.config/zsh/directories.zsh new file mode 100644 index 0000000..1d887d9 --- /dev/null +++ b/.config/zsh/directories.zsh @@ -0,0 +1,2 @@ +hash -d webdev=$HOME/Documents/School/SP22/CS4610 +hash -d gamedev=$HOME/Documents/School/SP22/CS5410 diff --git a/.config/zsh/env.zsh b/.config/zsh/env.zsh new file mode 100644 index 0000000..25c707c --- /dev/null +++ b/.config/zsh/env.zsh @@ -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]" diff --git a/.config/zsh/env.zsh~ b/.config/zsh/env.zsh~ new file mode 100644 index 0000000..2064a83 --- /dev/null +++ b/.config/zsh/env.zsh~ @@ -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" diff --git a/.config/zsh/line-editing.zsh b/.config/zsh/line-editing.zsh new file mode 100644 index 0000000..7130517 --- /dev/null +++ b/.config/zsh/line-editing.zsh @@ -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 diff --git a/.config/zsh/options.zsh b/.config/zsh/options.zsh new file mode 100644 index 0000000..3b68cca --- /dev/null +++ b/.config/zsh/options.zsh @@ -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 + diff --git a/.config/zsh/prompt.zsh##distro.Arch b/.config/zsh/prompt.zsh##distro.Arch new file mode 100644 index 0000000..6f56867 --- /dev/null +++ b/.config/zsh/prompt.zsh##distro.Arch @@ -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=$( /dev/null 2>&1 +eval "$(pyenv init -)" +alias pyenv="unset _pyenv_old_pwd; pyenv" + diff --git a/.config/zsh/ros.zsh b/.config/zsh/ros.zsh new file mode 100644 index 0000000..80014a1 --- /dev/null +++ b/.config/zsh/ros.zsh @@ -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 diff --git a/.config/zsh/utils.zsh b/.config/zsh/utils.zsh new file mode 100644 index 0000000..d931e54 --- /dev/null +++ b/.config/zsh/utils.zsh @@ -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" diff --git a/.config/zsh/zz-asdf.zsh b/.config/zsh/zz-asdf.zsh new file mode 100644 index 0000000..fdba167 --- /dev/null +++ b/.config/zsh/zz-asdf.zsh @@ -0,0 +1,2 @@ +# source $HOME/.local/lib/asdf/asdf.sh +# source $HOME/.local/lib/asdf/completions/asdf.bash diff --git a/.config/zsh/zz-plugins.zsh b/.config/zsh/zz-plugins.zsh new file mode 100644 index 0000000..6f4b44b --- /dev/null +++ b/.config/zsh/zz-plugins.zsh @@ -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 diff --git a/.config/zsh/zz-ssh.zsh b/.config/zsh/zz-ssh.zsh new file mode 100644 index 0000000..d96ad41 --- /dev/null +++ b/.config/zsh/zz-ssh.zsh @@ -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 diff --git a/.emacs.d/doom-personal-theme.el b/.emacs.d/doom-personal-theme.el new file mode 100644 index 0000000..d94c0b0 --- /dev/null +++ b/.emacs.d/doom-personal-theme.el @@ -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 +;; 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 / 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 + (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 + (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 diff --git a/.emacs.d/settings.org b/.emacs.d/settings.org new file mode 100644 index 0000000..608c71e --- /dev/null +++ b/.emacs.d/settings.org @@ -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 "") '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 diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..0e72414 --- /dev/null +++ b/.gitmodules @@ -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 diff --git a/.local/lib/zsh/zsh-autosuggestions b/.local/lib/zsh/zsh-autosuggestions new file mode 160000 index 0000000..c3d4e57 --- /dev/null +++ b/.local/lib/zsh/zsh-autosuggestions @@ -0,0 +1 @@ +Subproject commit c3d4e576c9c86eac62884bd47c01f6faed043fc5 diff --git a/.local/lib/zsh/zsh-history-substring-search b/.local/lib/zsh/zsh-history-substring-search new file mode 160000 index 0000000..8dd05bf --- /dev/null +++ b/.local/lib/zsh/zsh-history-substring-search @@ -0,0 +1 @@ +Subproject commit 8dd05bfcc12b0cd1ee9ea64be725b3d9f713cf64 diff --git a/.local/lib/zsh/zsh-syntax-highlighting b/.local/lib/zsh/zsh-syntax-highlighting new file mode 160000 index 0000000..e0165ea --- /dev/null +++ b/.local/lib/zsh/zsh-syntax-highlighting @@ -0,0 +1 @@ +Subproject commit e0165eaa730dd0fa321a6a6de74f092fe87630b0 diff --git a/.ssh/authorized_keys b/.ssh/authorized_keys new file mode 100644 index 0000000..b3816ff --- /dev/null +++ b/.ssh/authorized_keys @@ -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