diff --git a/.bashrc b/.bashrc index 9d4649d..2065bb1 100755 --- a/.bashrc +++ b/.bashrc @@ -158,3 +158,13 @@ alias bat=batcat [ -f "$HOME/.local/bin/env" ] && . "$HOME/.local/bin/env" . "$HOME/.cargo/env" + +# Sway / Wayland environment +export XDG_CURRENT_DESKTOP=sway +export XDG_SESSION_TYPE=wayland +export QT_QPA_PLATFORM=wayland +export QT_WAYLAND_DISABLE_WINDOWDECORATION=1 +export GDK_BACKEND=wayland +export MOZ_ENABLE_WAYLAND=1 +export SDL_VIDEODRIVER=wayland +export _JAVA_AWT_WM_NONREPARENTING=1 diff --git a/.config/nvim/lua/config/terminal.lua b/.config/nvim/lua/config/terminal.lua new file mode 100644 index 0000000..e536b2c --- /dev/null +++ b/.config/nvim/lua/config/terminal.lua @@ -0,0 +1,118 @@ +-- Terminal helpers layered on top of the native LazyVim/Snacks terminal. +-- +-- Native behaviour is kept intact and untouched: +-- / toggle a bottom terminal at the project root (supports a +-- count, e.g. 2 opens a *separate* terminal #2) +-- fT terminal in the current working directory +-- +-- This module adds: +-- a *dedicated* floating terminal (stable toggle, one-key close) +-- ft a picker that lists every live terminal so any contextual +-- terminal can be focused or restored even after its window was +-- closed/hidden. +local M = {} + +-- The floating terminal. Tracked as an upvalue so is a real +-- open/close toggle regardless of which directory the editor is in. +---@type snacks.win? +local float + +--- Open or focus the floating terminal, or hide it if already focused. +function M.toggle_float() + -- Reuse the existing instance: hide if visible, re-show if hidden. + if float and float:buf_valid() then + if float:win_valid() then + float:hide() + else + float:show() + vim.cmd("startinsert") + end + return + end + + -- First open: a high fixed count guarantees this terminal never collides with + -- the count-keyed bottom terminals (1, 2, 3 ...), so it is always the *same* + -- float for no matter the context. + float = Snacks.terminal(nil, { + count = 99, + win = { position = "float", border = "rounded" }, + }) + + -- Close it with a single keystroke from inside the shell: hides the + -- window (buffer-local, so it only affects this floating terminal and never + -- the bottom split, where shell tab-completion must keep working). + if float and float.buf then + vim.keymap.set("t", "", function() + if float and float:win_valid() then + float:hide() + end + end, { buffer = float.buf, silent = true, desc = "Hide floating terminal" }) + end +end + +--- List every live Snacks terminal in a picker. Restore/focus one with , +--- kill one with . +function M.picker() + local terms = Snacks.terminal.list() + if #terms == 0 then + Snacks.notify.info("No open terminals") + return + end + + local items = {} ---@type snacks.picker.finder.Item[] + for _, term in ipairs(terms) do + local meta = vim.b[term.buf] and vim.b[term.buf].snacks_terminal or {} + items[#items + 1] = { + term = term, + buf = term.buf, + id = meta.id, + cwd = meta.cwd or "?", + cmd = meta.cmd or vim.o.shell, + visible = term:win_valid(), + text = ("#%s %s %s"):format(meta.id or "?", meta.cwd or "?", meta.cmd or vim.o.shell), + } + end + + Snacks.picker({ + title = "Terminals", + items = items, + format = function(item) + local ret = {} ---@type snacks.picker.Highlight[] + ret[#ret + 1] = { + item.visible and "● " or "○ ", + item.visible and "SnacksPickerSpecial" or "SnacksPickerComment", + } + ret[#ret + 1] = { ("#%-2s"):format(item.id or "?"), "Number" } + ret[#ret + 1] = { " " .. vim.fn.fnamemodify(item.cwd, ":~"), "SnacksPickerPath" } + ret[#ret + 1] = { " " .. vim.fn.fnamemodify(item.cmd, ":t"), "SnacksPickerComment" } + return ret + end, + confirm = function(picker, item) + picker:close() + local term = item.term + if not term:buf_valid() then + Snacks.notify.warn("Terminal no longer exists") + return + end + if term:win_valid() then + vim.api.nvim_set_current_win(term.win) + else + term:show() + vim.cmd("startinsert") + end + end, + win = { input = { keys = { ["d"] = "term_delete" } } }, + actions = { + term_delete = function(picker, item) + local term = item.term + picker:close() + if term and term:buf_valid() then + term:close() + pcall(vim.api.nvim_buf_delete, term.buf, { force = true }) + end + end, + }, + }) +end + +return M diff --git a/.config/nvim/lua/plugins/conform.lua b/.config/nvim/lua/plugins/conform.lua new file mode 100644 index 0000000..0dc9d18 --- /dev/null +++ b/.config/nvim/lua/plugins/conform.lua @@ -0,0 +1,10 @@ +return { + "stevearc/conform.nvim", + opts = { + formatters = { + shfmt = { + args = { "-i", "2", "-ci", "-bn", "-sr" }, + }, + }, + }, +} diff --git a/.config/nvim/lua/plugins/markdown.lua b/.config/nvim/lua/plugins/markdown.lua new file mode 100644 index 0000000..6f22818 --- /dev/null +++ b/.config/nvim/lua/plugins/markdown.lua @@ -0,0 +1,8 @@ +return { + { + "MeanderingProgrammer/render-markdown.nvim", + opts = { + enabled = false, + }, + }, +} diff --git a/.config/nvim/lua/plugins/snacks.lua b/.config/nvim/lua/plugins/snacks.lua index 9e894d0..f7ef138 100644 --- a/.config/nvim/lua/plugins/snacks.lua +++ b/.config/nvim/lua/plugins/snacks.lua @@ -24,6 +24,8 @@ return { keys = { ["Y"] = "copy_relative", ["gy"] = "copy_absolute", + -- pick a window + ["L"] = { { "pick_win", "jump" }, mode = { "n", "i" } }, }, }, }, diff --git a/.config/nvim/lua/plugins/terminal.lua b/.config/nvim/lua/plugins/terminal.lua new file mode 100644 index 0000000..fdc2f4c --- /dev/null +++ b/.config/nvim/lua/plugins/terminal.lua @@ -0,0 +1,23 @@ +-- Terminal UX layered on Snacks (replaces toggleterm). +-- Helpers live in lua/config/terminal.lua; keys are declared here so lazy.nvim +-- registers the which-key labels with the rest of the snacks spec. +return { + "folke/snacks.nvim", + keys = { + { + "", + function() + require("config.terminal").toggle_float() + end, + desc = "Terminal (float)", + mode = "n", + }, + { + "ft", + function() + require("config.terminal").picker() + end, + desc = "Terminals (list/restore)", + }, + }, +} diff --git a/.config/sway/config b/.config/sway/config new file mode 100644 index 0000000..eb742d6 --- /dev/null +++ b/.config/sway/config @@ -0,0 +1,606 @@ +#---------------------------------------------------------------- +# Sway Config — Arch + Wayland +# +# Migrated from i3/X11 config. All X11-specific tools have been +# replaced with Wayland-native equivalents (see migration notes +# throughout this file). +# +# Install script: arch-init.sh +#---------------------------------------------------------------- + + +################################################################# +# Variables +################################################################# + +# Mod key: Mod4 = Super/Windows key, Mod1 = Alt +set $mod Mod4 + +# Helper scripts directory (Wayland replacements for ratflow scripts) +set $scriptsDir ~/.config/sway/scripts + +# Config directory +set $configDir ~/.config/sway + + +################################################################# +# Workspaces +################################################################# + +set $workspace1 1: >_ +set $workspace2 2: dev +set $workspace3 3: www +set $workspace4 4: files +set $workspace5 5: e-mail +set $workspace6 6: IM +set $workspace7 7: video +set $workspace8 8: workspace +set $workspace9 9: workspace +set $workspace10 10: Music +set $workspace11 V: VM + +# Switch to workspace +bindsym $mod+1 workspace $workspace1 +bindsym $mod+2 workspace $workspace2 +bindsym $mod+3 workspace $workspace3 +bindsym $mod+4 workspace $workspace4 +bindsym $mod+5 workspace $workspace5 +bindsym $mod+6 workspace $workspace6 +bindsym $mod+7 workspace $workspace7 +bindsym $mod+8 workspace $workspace8 +bindsym $mod+9 workspace $workspace9 +bindsym $mod+0 workspace $workspace10 + +# Move focused container to workspace +bindsym $mod+Shift+1 move container to workspace $workspace1 +bindsym $mod+Shift+2 move container to workspace $workspace2 +bindsym $mod+Shift+3 move container to workspace $workspace3 +bindsym $mod+Shift+4 move container to workspace $workspace4 +bindsym $mod+Shift+5 move container to workspace $workspace5 +bindsym $mod+Shift+6 move container to workspace $workspace6 +bindsym $mod+Shift+7 move container to workspace $workspace7 +bindsym $mod+Shift+8 move container to workspace $workspace8 +bindsym $mod+Shift+9 move container to workspace $workspace9 +bindsym $mod+Shift+0 move container to workspace $workspace10 + +# Next/prev workspace +bindsym $mod+x workspace next +bindsym $mod+Shift+x move container to workspace next +bindsym $mod+z workspace prev +bindsym $mod+Shift+z move container to workspace prev + +# Moving workspace across monitors +# MIGRATION: xrandr replaced by swaymsg output commands +bindsym $mod+Control+Left move workspace to output left +bindsym $mod+Control+Right move workspace to output right + + +################################################################# +# Output / Monitor Management +# MIGRATION: xrandr → swaymsg output / kanshi for auto profiles +################################################################# + +# Define your outputs — run `swaymsg -t get_outputs` to get names +set $leftOutput eDP-1 +set $rightOutput HDMI-A-1 + +# Default monitor setup +# sway handles output layout natively, no xrandr needed +output $rightOutput pos 1920 0 +output $leftOutput pos 0 0 + +# Mode for toggling outputs (replaces i3 "outputs" mode) +mode "outputs" { + # $mod+Shift+1: turn off left monitor; $mod+1: turn it on + bindsym $mod+Shift+1 output $leftOutput disable; mode "default" + bindsym $mod+1 output $leftOutput enable; mode "default" + + # $mod+Shift+2: turn off right monitor; $mod+2: turn it on + bindsym $mod+Shift+2 output $rightOutput disable; mode "default" + bindsym $mod+2 output $rightOutput enable; mode "default" + + bindsym Return mode "default" + bindsym Escape mode "default" +} + +bindsym $mod+m mode "outputs" + + +################################################################# +# Wallpaper +# MIGRATION: feh → swaybg (Wayland-native wallpaper setter) +# Omarchy also uses swaybg for this purpose. +################################################################# + +set $wallpaper1 /usr/share/backgrounds/sway/Sway_Wallpaper_Blue_1920x1080.png +set $wallpaper2 /usr/share/backgrounds/sway/Sway_Wallpaper_Blue_1920x1080.png + +# swaybg is a native Wayland wallpaper setter +output $leftOutput bg $wallpaper1 fill +output $rightOutput bg $wallpaper2 fill + + +################################################################# +# Input Device Configuration +# MIGRATION: synclient → sway input {} blocks +# X11 touchpad/synaptics config replaced by libinput via sway. +################################################################# + +input "type:touchpad" { + tap enabled + click_method button_areas + scroll_method two_finger + dwt enabled + # natural_scroll enabled # uncomment if you prefer macOS-style scrolling +} + +input "type:keyboard" { + xkb_layout pl + # xkb_variant ... + # xkb_options caps:escape # uncomment to remap Caps Lock to Escape +} + + +################################################################# +# Application Launchers +# MIGRATION: ulauncher works on Wayland but is GTK-based. +# Alternatives: wofi (native), rofi-wayland, tofi. +# dmenu_run replaced by wofi (or keep as dmenu_path | wofi -d). +# Omarchy uses Walker — a modern Wayland-native launcher. +################################################################# + +# Terminal +bindsym $mod+Return exec kitty + +# App launcher: wofi (lightweight, Wayland-native) +# Alternatives: rofi -show drun (rofi-wayland package), tofi +bindsym $mod+d exec fuzzel +bindsym Mod1+F2 exec wofi --show run + +# Clipboard manager — show history (Ctrl+Alt+H) +# bindsym Control+Mod1+h exec copyq toggle +bindsym Control+Mod1+h exec cliphist list | fuzzel --width 80 --dmenu | cliphist decode | wl-copy + +# Run app assigned to current workspace +bindsym $mod+Shift+a exec $scriptsDir/autoapp + + +################################################################# +# Window Navigation +# MIGRATION: i3-msg workspace back_and_forth → same in sway +################################################################# + +bindsym $mod+Tab workspace back_and_forth + + +################################################################# +# Window Management +# MIGRATION: nearly identical to i3 — sway is i3-compatible +################################################################# + +# Use Mouse+$mod to drag floating windows +floating_modifier $mod + +# Kill focused window +bindsym $mod+Shift+q kill + +# Change focus (vim keys) +bindsym $mod+j focus left +bindsym $mod+k focus down +bindsym $mod+l focus up +bindsym $mod+semicolon focus right + +# Change focus (arrow keys) +bindsym $mod+Left focus left +bindsym $mod+Down focus down +bindsym $mod+Up focus up +bindsym $mod+Right focus right + +# Move focused window (vim keys) +bindsym $mod+Shift+j move left +bindsym $mod+Shift+k move down +bindsym $mod+Shift+l move up +bindsym $mod+Shift+semicolon move right + +# Move focused window (arrow keys) +bindsym $mod+Shift+Left move left +bindsym $mod+Shift+Down move down +bindsym $mod+Shift+Up move up +bindsym $mod+Shift+Right move right + +# Split orientation +bindsym $mod+h split h +bindsym $mod+v split v + +# Fullscreen +bindsym $mod+f fullscreen + +# Layout modes +bindsym $mod+s layout stacking +bindsym $mod+w layout tabbed +bindsym $mod+e layout toggle split + +# Toggle tiling / floating +bindsym $mod+Shift+space floating toggle +bindsym $mod+button2 floating toggle + +# Focus tiling/floating toggle +bindsym $mod+space focus mode_toggle + +# Focus parent container +bindsym $mod+a focus parent + +# Always-float toggle (custom script) +bindsym $mod+Shift+f exec $scriptsDir/always-float + + +################################################################# +# Resize Mode +################################################################# + +mode "resize" { + bindsym j resize shrink width 10 px or 10 ppt + bindsym k resize grow height 10 px or 10 ppt + bindsym l resize shrink height 10 px or 10 ppt + bindsym semicolon resize grow width 10 px or 10 ppt + + bindsym Left resize shrink width 10 px or 10 ppt + bindsym Down resize grow height 10 px or 10 ppt + bindsym Up resize shrink height 10 px or 10 ppt + bindsym Right resize grow width 10 px or 10 ppt + + bindsym Return mode "default" + bindsym Escape mode "default" +} + +bindsym $mod+r mode "resize" + + +################################################################# +# Screenshots +# MIGRATION: screengrab (X11) → grim + slurp (Wayland-native) +# grim = screen capture (replaces scrot/import/screengrab) +# slurp = region selector (Wayland-native) +# wl-copy copies to Wayland clipboard +# Omarchy also uses grim + slurp (+ satty for annotation). +################################################################# + +# Screenshots — capture once, save to file + copy to clipboard +bindsym Print exec $scriptsDir/screenshot full +bindsym Shift+Print exec $scriptsDir/screenshot area +bindsym Control+Print exec $scriptsDir/screenshot window + + +################################################################# +# Calendar +# MIGRATION: osmo/gsimplecal (X11) → keep osmo if desired, +# or use waybar clock module + rofi/wofi calendar script. +# Omarchy uses waybar clock module only (no standalone calendar app). +################################################################# + +bindsym $mod+c exec osmo -c +# Alternative: wofi-based calendar popup +# bindsym $mod+c exec $scriptsDir/calendar-popup + + +################################################################# +# Screen Color Temperature +# MIGRATION: redshift (X11) → gammastep (Wayland fork of redshift) +# or wlsunset (lighter alternative). +# Omarchy uses hyprsunset (Hyprland-specific), but for sway +# gammastep is the standard choice. +# $scriptsDir/gammastep-adjust replaces redshift-adjust. +################################################################# + +bindsym $mod+Control+KP_Next exec $scriptsDir/gammastep-adjust "-500" +bindsym $mod+Control+KP_Prior exec $scriptsDir/gammastep-adjust "+500" +bindsym $mod+Control+l exec gammastep -x + + +################################################################# +# Translation of Selected Text +# MIGRATION: trans-xsel (X11 xsel) → translate-shell + wl-clipboard +# Uses wl-paste / wl-copy instead of xsel/xclip. +################################################################# + +bindsym $mod+t exec bash -c "$scriptsDir/translate-wl en:pl &" +bindsym $mod+Shift+t exec bash -c "$scriptsDir/translate-wl pl:en &" + + +################################################################# +# Multimedia Keys & Audio +# MIGRATION: PulseAudio volctl → PipeWire + wpctl (or pamixer) +# Arch + Wayland standard is PipeWire with WirePlumber. +# Volume OSD: SwayOSD (Omarchy approach) or swayosd-server. +# The $scriptsDir/volctl wrapper uses wpctl/pamixer underneath. +################################################################# + +# Volume controls (primary sink) +bindsym XF86AudioRaiseVolume exec --no-startup-id $scriptsDir/volctl up +bindsym XF86AudioLowerVolume exec --no-startup-id $scriptsDir/volctl down +bindsym XF86AudioMute exec --no-startup-id $scriptsDir/volctl toggle + +# Volume controls (secondary sink, e.g. HDMI) +bindsym Shift+XF86AudioRaiseVolume exec --no-startup-id SINK_NUM=1 $scriptsDir/volctl up +bindsym Shift+XF86AudioLowerVolume exec --no-startup-id SINK_NUM=1 $scriptsDir/volctl down +bindsym Shift+XF86AudioMute exec --no-startup-id SINK_NUM=1 $scriptsDir/volctl toggle + +# Screen brightness +# MIGRATION: xbacklight / ratflow-backlight → brightnessctl +bindsym XF86MonBrightnessUp exec --no-startup-id $scriptsDir/backlight up +bindsym XF86MonBrightnessDown exec --no-startup-id $scriptsDir/backlight down + +# Media player controls +# MIGRATION: clementine-specific → playerctl (agnostic MPRIS controller) +# playerctl works with any MPRIS2-compatible player (Spotify, mpv, etc.) +bindsym XF86AudioPlay exec playerctl play-pause +bindsym XF86AudioPause exec playerctl pause +bindsym XF86AudioNext exec playerctl next +bindsym XF86AudioPrev exec playerctl previous + + +################################################################# +# Projector / Screen Layout +# MIGRATION: xrandr shell scripts → swaymsg output commands +# kanshi can auto-switch profiles on hotplug. +################################################################# + +bindsym $mod+p exec $scriptsDir/output-profile projector +bindsym $mod+Shift+p exec $scriptsDir/output-profile edp-only + + +################################################################# +# Session / Power Management +# MIGRATION: i3-nagbar → swaynag, i3exit → loginctl-based script +# swayidle handles DPMS/idle (replaces xset dpms). +# swaylock replaces i3lock. +# Omarchy uses hyprlock+hypridle, sway equivalents are swaylock+swayidle. +################################################################# + +# Reload sway config +bindsym $mod+Shift+c exec swaymsg reload + +# Suspend +bindsym $mod+Escape exec systemctl suspend + +# Restart sway +bindsym $mod+Shift+r exec swaymsg reload + +# Exit sway +bindsym $mod+Shift+e exec swaynag -t warning -m 'Exit sway? This will end your Wayland session.' -b 'Yes, exit sway' 'swaymsg exit' + +# Session management mode (replaces i3exit) +set $exitScript $scriptsDir/swayexit + +mode "session_management" { + bindsym l exec --no-startup-id $exitScript lock, mode "default" + bindsym e exec --no-startup-id $exitScript logout, mode "default" + bindsym s exec --no-startup-id $exitScript suspend, mode "default" + bindsym h exec --no-startup-id $exitScript hibernate, mode "default" + bindsym r exec --no-startup-id $exitScript reboot, mode "default" + bindsym Shift+s exec --no-startup-id $exitScript shutdown, mode "default" + + bindsym Return mode "default" + bindsym Escape mode "default" +} + +bindsym $mod+Pause mode "session_management" + + +################################################################# +# New Workspace +# MIGRATION: yad → zenity (or rofi/wofi) +# yad has some Wayland issues; zenity is GTK and works. +# Alternatively, use wofi for a pure Wayland input dialog. +################################################################# + +bindsym $mod+n exec name=$(wofi --dmenu --prompt "Workspace name") && swaymsg workspace "$name" + + +################################################################# +# Theme / Appearance +# MIGRATION: No i3 client colors — sway has the same syntax. +# compton → not needed (sway has built-in compositor with +# basic effects). For blur/shadows, use swayfx (fork of sway). +# Omarchy uses Hyprland which has built-in blur/animation; +# for sway, swayfx adds these features. +################################################################# + +# Font +set $fontName "Source Sans 3 Semi-Bold" +set $fontSize 10 +set $barFontSize 9 + +font pango: $fontName $fontSize + +# Window colors +# border background text indicator +client.focused #252525 #252525 #D9D9D9 #101010 +client.focused_inactive #101010 #101010 #606060 #101010 +client.unfocused #101010 #000000 #606060 #101010 +client.urgent #F05000 #F05000 #F0F0F0 #101010 + +# Default border style +default_border pixel 2 +default_floating_border normal 2 + +# Gaps (optional — sway supports gaps natively, unlike stock i3) +# gaps inner 5 +# gaps outer 2 + +# Window opacity (requires swayfx for per-window opacity, or use +# sway's built-in opacity for all windows) +# for_window [app_id="kitty"] opacity 0.95 + + +################################################################# +# Bar — Waybar +# MIGRATION: i3bar + py3status → waybar +# waybar is the standard bar for wlroots-based compositors. +# Omarchy uses waybar with extensive modules. +# Config files: ~/.config/waybar/config.jsonc + style.css +################################################################# + +bar { + swaybar_command waybar +} + + +################################################################# +# Window Assignments +# MIGRATION: class= → app_id= for native Wayland apps. +# XWayland apps still use class=. Use `swaymsg -t get_tree` +# to find the correct app_id for native Wayland apps. +# Note: some apps may need both rules. +################################################################# + +# Development +assign [app_id="qtcreator"] $workspace2 +assign [class="Qtcreator"] $workspace2 +assign [app_id="eclipse"] $workspace2 +assign [class="Eclipse"] $workspace2 + +# Browser +assign [app_id="firefox"] $workspace3 +assign [class="Firefox"] $workspace3 +assign [app_id="chromium"] $workspace3 +assign [class="Chromium-browser"] $workspace3 +assign [class="Chrome"] $workspace3 + +# File managers +assign [app_id="pcmanfm-qt"] $workspace4 +assign [class="Pcmanfm"] $workspace4 +assign [app_id="dolphin"] $workspace4 +assign [class="Dolphin"] $workspace4 +assign [app_id="nautilus"] $workspace4 +assign [class="Nautilus"] $workspace4 +assign [app_id="thunar"] $workspace4 +assign [class="Thunar"] $workspace4 + +# E-mail +assign [app_id="thunderbird"] $workspace5 +assign [class="Thunderbird"] $workspace5 + +# IM +assign [app_id="telegram-desktop"] $workspace6 +assign [class="Telegram"] $workspace6 +assign [class="Skype"] $workspace6 + +# Video +assign [app_id="kodi"] $workspace7 +assign [class="Kodi"] $workspace7 + +# Music +assign [app_id="spotify"] $workspace10 +assign [class="Spotify"] $workspace10 +assign [class="Clementine"] $workspace10 + +# VM +assign [class="VirtualBox"] $workspace11 +assign [app_id="virt-manager"] $workspace11 + + +################################################################# +# Floating Windows +################################################################# + +for_window [app_id="screengrab"] floating enable +for_window [app_id="osmo"] floating enable +for_window [app_id="gsimplecal"] floating enable +for_window [class="Osmo"] floating enable +for_window [class="Skype"] floating enable +for_window [app_id="yad"] floating enable +for_window [class="Yad"] floating enable +for_window [app_id="wofi"] floating enable +for_window [app_id="swaync"] floating enable + + +################################################################# +# Idle Management +# MIGRATION: xset dpms → swayidle +# Locks screen after timeout, turns off display. +# Omarchy uses hypridle; sway equivalent is swayidle. +################################################################# + +set $lockCommand swaylock -f -c 000000 + +exec swayidle -w \ + timeout 600 '$lockCommand' \ + timeout 900 'swaymsg "output * dpms off"' \ + resume 'swaymsg "output * dpms on"' \ + before-sleep '$lockCommand' + + +################################################################# +# Autostart +# MIGRATION NOTES: +# dunst → mako (Wayland-native notifier, used by Omarchy) +# or swaync (Sway Notification Center, more feature-rich) +# compton → NOT NEEDED (sway has built-in compositor) +# For blur/rounded corners, use swayfx +# synclient → sway input {} block (see above) +# redshift → gammastep or wlsunset +# nm-applet → nm-applet still works on Wayland, or use +# waybar network module + impala TUI (Omarchy approach) +# parcellite → cliphist + wl-clipboard (Wayland clipboard manager) +# cliphist stores history, wl-copy/wl-paste for access +# xset dpms → swayidle (see above) +################################################################# + +# Notification daemon — mako (Omarchy uses mako) +exec --no-startup-id mako + +# Alternative: swaync (Sway Notification Center) — more feature-rich +# exec --no-startup-id swaync + +# Screen color temperature +exec --no-startup-id gammastep -l 52.43:15.15 -m wayland + +# Network manager applet (still works on Wayland) +exec --no-startup-id nm-applet --indicator + +# Clipboard manager +# Use Ctrl+Alt+H to toggle the clipboard history window +# exec --no-startup-id wl-paste --watch --type image cliphist store +exec --no-startup-id wl-paste --type text --watch cliphist store +exec --no-startup-id wl-paste --type image --watch cliphist store + +# Bluetooth manager (waybar module can handle this, or use blueman-applet) +# exec --no-startup-id blueman-applet + +# Polkit authentication agent (needed for GUI apps that need root) +exec --no-startup-id /usr/lib/polkit-gnome/polkit-gnome-authentication-agent-1 + +# Background services for XDG desktop portals (screen sharing, file picker) +exec --no-startup-id dbus-update-activation-environment --systemd WAYLAND_DISPLAY XDG_CURRENT_DESKTOP=sway + + +################################################################# +# Key repeat rate +################################################################# + +# input "type:keyboard" { +# xkb_layout pl +# # xkb_variant "programmer" +# xkb_options "grp:alt_shift_toggle, compose:ralt" +# repeat_delay 300 +# repeat_rate 40 +# } +# input type:keyboard { xkb_layout pl xkb_options grp:win_space_toggle } + +# input type:keyboard { +# xkb_layout pl +# xkb_options level3:ralt_switch +# } + +# input type:keyboard { +# xkb_layout pl +# xkb_options grp:alt_shift_toggle +# } + +input type:keyboard { + xkb_layout pl,us + # lv3:ralt_switch keeps Right Alt working for Polish chars + # grp:alt_shift_toggle allows Alt+Shift to switch layouts + xkb_options lv3:ralt_switch,grp:alt_shift_toggle +} diff --git a/.config/sway/scripts/always-float b/.config/sway/scripts/always-float new file mode 100755 index 0000000..5a01c8a --- /dev/null +++ b/.config/sway/scripts/always-float @@ -0,0 +1,11 @@ +#!/bin/bash +#---------------------------------------------------------------- +# always-float — Toggle floating on the currently focused window +# +# Adapted from the ratflow always-float script. +# Uses swaymsg instead of i3-msg. +# +# Dependencies: sway +#---------------------------------------------------------------- + +swaymsg floating toggle diff --git a/.config/sway/scripts/autoapp b/.config/sway/scripts/autoapp new file mode 100755 index 0000000..f760fe4 --- /dev/null +++ b/.config/sway/scripts/autoapp @@ -0,0 +1,28 @@ +#!/bin/bash +#---------------------------------------------------------------- +# autoapp — Launch the application assigned to current workspace +# +# Adapted from the ratflow autoapp script. +# Reads workspace assignments and launches the matching app. +# Uses swaymsg instead of i3-msg. +# +# Dependencies: sway, jq +#---------------------------------------------------------------- + +# Get current workspace name +WORKSPACE=$(swaymsg -t get_workspaces | jq -r '.[] | select(.focused) | .name') + +# Map workspace names to applications +# Customize these to match your workflow +case "$WORKSPACE" in + *">_"*) kitty ;; + *"dev"*) kitty ;; + *"www"*) firefox ;; + *"files"*) thunar ;; + *"e-mail"*) thunderbird ;; + *"IM"*) telegram-desktop ;; + *"video"*) mpv ;; + *"Music"*) spotify ;; + *"VM"*) virt-manager ;; + *) echo "No app assigned to workspace: $WORKSPACE" ;; +esac diff --git a/.config/sway/scripts/backlight b/.config/sway/scripts/backlight new file mode 100755 index 0000000..5c9279d --- /dev/null +++ b/.config/sway/scripts/backlight @@ -0,0 +1,36 @@ +#!/bin/bash +#---------------------------------------------------------------- +# backlight — Screen brightness control using brightnessctl +# +# Replaces the old ratflow backlight script (xbacklight-based). +# brightnessctl works on Wayland without X11 dependencies. +# +# Usage: +# backlight up — increase brightness by 5% +# backlight down — decrease brightness by 5% +# backlight set N — set brightness to N percent +# backlight get — print current brightness percentage +# +# Dependencies: brightnessctl +#---------------------------------------------------------------- + +STEP=5 + +case "$1" in + up) + brightnessctl set "${STEP}%+" -q + ;; + down) + brightnessctl set "${STEP}%-" -q + ;; + set) + brightnessctl set "${2}%" -q + ;; + get) + brightnessctl info | grep -oP '\d+%' | head -1 | tr -d '%' + ;; + *) + echo "Usage: backlight {up|down|set N|get}" + exit 1 + ;; +esac diff --git a/.config/sway/scripts/gammastep-adjust b/.config/sway/scripts/gammastep-adjust new file mode 100755 index 0000000..eddd412 --- /dev/null +++ b/.config/sway/scripts/gammastep-adjust @@ -0,0 +1,101 @@ +#!/bin/bash +#---------------------------------------------------------------- +# gammastep-adjust — Adjust gammastep color temperature +# +# Replaces the old ratflow redshift-adjust script. +# gammastep is the Wayland fork of redshift; it uses the same +# temperature range (1000K–25000K, default 6500K = daylight). +# +# Usage: +# gammastep-adjust -100 — make screen warmer (lower temperature by 100K) +# gammastep-adjust +100 — make screen cooler (raise temperature by 100K) +# +# How it works: +# gammastep doesn't support runtime temperature changes directly. +# This script writes the current temperature to a state file, +# kills any running gammastep, and launches a new one in one-shot +# mode (-O) with the new temperature. +# +# State file: /tmp/gammastep-current-temp +# PID file: /tmp/gammastep-pid +# Default: 6500 (neutral/daylight) +# +# Dependencies: gammastep +#---------------------------------------------------------------- +set -x + +STATE_FILE="/tmp/gammastep-current-temp" +PID_FILE="/tmp/gammastep-pid" +DEFAULT_TEMP=6500 +MIN_TEMP=1000 +MAX_TEMP=25000 + +# Read current temperature or use default +if [ -f "$STATE_FILE" ]; then + CURRENT=$(cat "$STATE_FILE") +else + CURRENT=$DEFAULT_TEMP +fi + +# Parse argument +DELTA="${1:-0}" +# Strip the sign to get the absolute value +ABS_DELTA="${DELTA#+}" +ABS_DELTA="${ABS_DELTA#-}" + +if [ -z "$ABS_DELTA" ]; then + echo "Usage: gammastep-adjust <+/-N>" + echo " Example: gammastep-adjust -100 (warmer)" + echo " Example: gammastep-adjust +100 (cooler)" + exit 1 +fi + +# Calculate new temperature +NEW_TEMP=$((CURRENT + DELTA)) + +# Clamp to valid range +if [ "$NEW_TEMP" -lt "$MIN_TEMP" ]; then + NEW_TEMP=$MIN_TEMP +fi +if [ "$NEW_TEMP" -gt "$MAX_TEMP" ]; then + NEW_TEMP=$MAX_TEMP +fi + +# Save new state +echo "$NEW_TEMP" >"$STATE_FILE" + +# Kill existing gammastep instance(s) +# Priority 1: use PID file if available (most precise) +if [ -f "$PID_FILE" ]; then + OLD_PID=$(cat "$PID_FILE") + if kill -0 "$OLD_PID" 2>/dev/null; then + kill "$OLD_PID" 2>/dev/null + # Give gammastep a moment to release the display and exit + sleep 0.2 + fi + rm -f "$PID_FILE" +fi + +# Priority 2: kill any stray gammastep processes +# -x (exact match) ensures we don't kill this script (gammastep-adjust) +pkill -x gammastep 2>/dev/null +sleep 0.1 + +# Launch gammastep with the new temperature. +# +# IMPORTANT: We use "setsid" (create a new session) so that gammastep is +# completely detached from the shell that Sway spawns for this keybinding. +# Without setsid, Sway kills gammastep when the keybinding shell exits, +# even with "&" — because the process is still in the same process group. +# setsid makes gammastep its own session leader, immune to cleanup. +# if [ "$NEW_TEMP" -ge "$DEFAULT_TEMP" ]; then +# # At or above neutral — reset to no tint +# setsid gammastep -x 2>/dev/null & +# echo $! >"$PID_FILE" +# echo "Temperature reset to neutral ($DEFAULT_TEMP K)" +# else +# Below neutral — apply one-shot manual temperature +setsid gammastep -O "$NEW_TEMP" 2>/dev/null & +echo $! >"$PID_FILE" +echo "Temperature set to $NEW_TEMP K" +# fi diff --git a/.config/sway/scripts/output-profile b/.config/sway/scripts/output-profile new file mode 100755 index 0000000..8abc07e --- /dev/null +++ b/.config/sway/scripts/output-profile @@ -0,0 +1,45 @@ +#!/bin/bash +#---------------------------------------------------------------- +# output-profile — Switch sway output profiles +# +# Replaces xrandr shell scripts used in the old i3 config. +# Uses swaymsg output commands to configure displays. +# +# Usage: +# output-profile projector — enable HDMI output (mirror or extend) +# output-profile edp-only — disable all external outputs +# output-profile dual — dual monitor setup +# +# Dependencies: sway +# +# NOTE: Edit the output names to match your hardware. +# Run `swaymsg -t get_outputs` to list connected outputs. +#---------------------------------------------------------------- + +# Output names — adjust to match your hardware +LAPTOP="eDP-1" +EXTERNAL="HDMI-A-1" + +case "$1" in + projector) + # Enable external output with correct resolution, disable laptop + swaymsg output "$EXTERNAL" enable mode 1366x768 pos 0 0 + swaymsg output "$LAPTOP" disable + ;; + edp-only) + # Disable external output, re-enable laptop + swaymsg output "$EXTERNAL" disable + swaymsg output "$LAPTOP" enable pos 0 0 + ;; + dual) + # Dual monitor: laptop left, external right + swaymsg output "$LAPTOP" pos 0 0 + swaymsg output "$EXTERNAL" pos 1920 0 + ;; + *) + echo "Usage: output-profile {projector|edp-only|dual}" + echo " Edit this script to match your output names." + echo " Run 'swaymsg -t get_outputs' to list connected outputs." + exit 1 + ;; +esac diff --git a/.config/sway/scripts/screenshot b/.config/sway/scripts/screenshot new file mode 100755 index 0000000..d7fff82 --- /dev/null +++ b/.config/sway/scripts/screenshot @@ -0,0 +1,37 @@ +#!/bin/bash +#---------------------------------------------------------------- +# screenshot — Capture screen, window, or region +# +# Captures once, saves to ~/Pictures and copies to clipboard. +# +# Usage: +# screenshot full — full screen +# screenshot area — select region with slurp +# screenshot window — focused window +# +# Dependencies: grim, slurp, wl-copy, swaymsg, jq +#---------------------------------------------------------------- + +dir=~/Pictures +mkdir -p "$dir" +file="$dir/screenshot_$(date +%Y%m%d_%H%M%S).png" + +case "$1" in + full) + grim -t png "$file" + ;; + area) + geo=$(slurp) + grim -t png -g "$geo" "$file" + ;; + window) + geo=$(swaymsg -t get_tree | jq -j '.. | select(.type?) | select(.focused) | .rect | "\(.x),\(.y) \(.width)x\(.height)"') + grim -t png -g "$geo" "$file" + ;; + *) + echo "Usage: screenshot {full|area|window}" + exit 1 + ;; +esac + +wl-copy -t image/png < "$file" diff --git a/.config/sway/scripts/swayexit b/.config/sway/scripts/swayexit new file mode 100755 index 0000000..ad2237b --- /dev/null +++ b/.config/sway/scripts/swayexit @@ -0,0 +1,46 @@ +#!/bin/bash +#---------------------------------------------------------------- +# swayexit — Session management for sway on Wayland +# +# Replaces the old i3exit script (i3/X11-based). +# Uses loginctl for session management (systemd-logind). +# +# Usage: +# swayexit lock — lock the screen (swaylock) +# swayexit logout — exit sway +# swayexit suspend — suspend to RAM +# swayexit hibernate — suspend to disk +# swayexit reboot — reboot the system +# swayexit shutdown — power off the system +# +# Dependencies: swaylock, systemd (loginctl) +#---------------------------------------------------------------- + +case "$1" in + lock) + swaylock -f -c 000000 + ;; + logout) + swaymsg exit + ;; + suspend) + swaylock -f -c 000000 & + sleep 0.5 + systemctl suspend + ;; + hibernate) + swaylock -f -c 000000 & + sleep 0.5 + systemctl hibernate + ;; + reboot) + systemctl reboot + ;; + shutdown) + systemctl poweroff + ;; + *) + echo "Usage: swayexit {lock|logout|suspend|hibernate|reboot|shutdown}" + exit 1 + ;; +esac diff --git a/.config/sway/scripts/translate-wl b/.config/sway/scripts/translate-wl new file mode 100755 index 0000000..527bf43 --- /dev/null +++ b/.config/sway/scripts/translate-wl @@ -0,0 +1,48 @@ +#!/bin/bash +#---------------------------------------------------------------- +# translate-wl — Translate selected text using translate-shell +# with Wayland clipboard (wl-clipboard) +# +# Replaces the old ratflow trans-xsel script (X11 xsel-based). +# Uses wl-paste to get clipboard content and wl-copy to write +# the translation back, plus a notification via notify-send +# (which works with mako/swaync on Wayland). +# +# Usage: +# translate-wl en:pl — translate English to Polish +# translate-wl pl:en — translate Polish to English +# translate-wl de:en — translate German to English, etc. +# +# Workflow: +# 1. Select text (it goes to Wayland primary/clipboard) +# 2. Press the bound key (e.g. $mod+t) +# 3. Script reads selection via wl-paste, translates, +# shows notification, and copies result to clipboard +# +# Dependencies: translate-shell (trans), wl-clipboard, libnotify +#---------------------------------------------------------------- + +LANG_PAIR="${1:-en:pl}" + +# Get clipboard content (user should select text first) +# wl-paste gets the clipboard content; for primary selection use wl-paste -p +TEXT=$(wl-paste -p 2>/dev/null || wl-paste 2>/dev/null) + +if [ -z "$TEXT" ]; then + notify-send -t 3000 "Translation" "No text in clipboard/selection" + exit 1 +fi + +# Translate using translate-shell +RESULT=$(trans -b "$LANG_PAIR" "$TEXT" 2>/dev/null) + +if [ -z "$RESULT" ]; then + notify-send -t 3000 "Translation" "Translation failed" + exit 1 +fi + +# Copy result to clipboard +echo -n "$RESULT" | wl-copy + +# Show notification +notify-send -t 5000 "Translation ($LANG_PAIR)" "$RESULT" diff --git a/.config/sway/scripts/volctl b/.config/sway/scripts/volctl new file mode 100755 index 0000000..39a1a03 --- /dev/null +++ b/.config/sway/scripts/volctl @@ -0,0 +1,68 @@ +#!/bin/bash +#---------------------------------------------------------------- +# volctl — Volume control wrapper for PipeWire + WirePlumber +# +# Replaces the old ratflow volctl (PulseAudio-based). +# Uses wpctl (WirePlumber CLI) for volume management. +# +# Usage: +# volctl up — increase volume by 5% +# volctl down — decrease volume by 5% +# volctl toggle — toggle mute on default sink +# volctl mute — mute default sink +# volctl unmute — unmute default sink +# +# Environment: +# SINK_NUM — if set, selects Nth sink (0=default, 1=next, etc.) +# mirrors the old VOLCTL_SINK_NUM behavior +# +# Dependencies: wireplumber, wpctl, pipewire, pipewire-pulse +#---------------------------------------------------------------- + +STEP=5 + +# Resolve which sink to use based on SINK_NUM (like old VOLCTL_SINK_NUM) +# SINK_NUM=0 or unset → default sink, SINK_NUM=1 → second sink, etc. +get_sink_id() { + local num="${SINK_NUM:-0}" + if [ "$num" = "0" ]; then + echo "@DEFAULT_AUDIO_SINK@" + else + # List sinks and pick the Nth one (1-indexed in SINK_NUM) + local sinks + sinks=$(wpctl status | grep -A 100 'Audio' | grep -A 100 'Sinks:' | grep -oP '\d+\.' | head -n $((num + 1)) | tail -1 | tr -d '.') + if [ -z "$sinks" ]; then + echo "@DEFAULT_AUDIO_SINK@" + else + echo "$sinks" + fi + fi +} + +SINK=$(get_sink_id) + +case "$1" in + up) + wpctl set-volume -l 1.5 "$SINK" "${STEP}%+" + ;; + down) + wpctl set-volume "$SINK" "${STEP}%-" + ;; + toggle) + wpctl set-mute "$SINK" toggle + ;; + mute) + wpctl set-mute "$SINK" 1 + ;; + unmute) + wpctl set-mute "$SINK" 0 + ;; + *) + echo "Usage: volctl {up|down|toggle|mute|unmute}" + echo " Set SINK_NUM env var to select sink (0=default, 1=second, etc.)" + exit 1 + ;; +esac + +# Optional: send signal to waybar to update volume display +# pkill -SIGRTMIN+1 waybar diff --git a/.config/waybar/config.jsonc b/.config/waybar/config.jsonc new file mode 100644 index 0000000..4de92dc --- /dev/null +++ b/.config/waybar/config.jsonc @@ -0,0 +1,95 @@ +// -*- mode: json -*- + +{ + "layer": "top", + "position": "top", + + "modules-left": [ + "sway/workspaces", + "sway/window" + ], + "modules-center": [], + "modules-right": [ + "pulseaudio", + "custom/network", + "custom/disk", + "memory", + "custom/top", + "battery", + "clock#0", + "tray" + ], + + "sway/workspaces": { + "disable-scroll": true, + "format": "{name}" + }, + + "sway/window": { + "max-length": 70, + "format": "{title}" + }, + + "custom/network": { + "exec": "/home/chodak/.config/waybar/network.py --icon-size 12pt", + "interval": 10, + "return-type": "json", + "tooltip": true + }, + + "clock#0": { + "format": "{:%d/%m/%y %H:%M}", + "tooltip": false + }, + + "pulseaudio": { + "format": "{icon} {volume:2}%", + "format-bluetooth": "{icon} {volume}%", + "format-muted": "MUTE", + "format-icons": { + "headphones": "", + "default": [ + "", + "" + ] + }, + "scroll-step": 5, + "on-click": "pamixer -t", + "on-click-right": "pavucontrol" + }, + "memory": { + "interval": 5, + "format": " {}%" + }, + "custom/top": { + "exec": "~/.config/waybar/top.sh", + "interval": 5, + "return-type": "json", + "tooltip": true + }, + "battery": { + "states": { + "good": 95, + "warning": 30, + "critical": 15 + }, + "format": "{icon} {capacity}%", + "format-icons": [ + "", + "", + "", + "", + "" + ] + }, + "custom/disk": { + "exec": "/home/chodak/.config/waybar/disk.py --icon-size 10pt", + "interval": 30, + "return-type": "json", + "tooltip": true, + "escape": false + }, + "tray": { + "icon-size": 24 + } +} diff --git a/.config/waybar/disk.py b/.config/waybar/disk.py new file mode 100755 index 0000000..d58347c --- /dev/null +++ b/.config/waybar/disk.py @@ -0,0 +1,169 @@ +#!/usr/bin/env python3 +"""Waybar disk module: shows disk usage across all mounted partitions.""" + +import argparse +import json +import os + +# Filesystem types to ignore (virtual / non-disk) +IGNORE_FSTYPES = { + "tmpfs", "devtmpfs", "proc", "sysfs", "cgroup", "cgroup2", + "pstore", "bpf", "debugfs", "tracefs", "securityfs", "configfs", + "hugetlbfs", "devpts", "ramfs", "fuse.gvfsd-fuse", "fusectl", + "mqueue", "rpc_pipefs", "overlay", "squashfs", +} + +# Pango color thresholds +COLOR_LOW = "#a6e3a1" # green — < 70% +COLOR_MID = "#f9e2af" # yellow — 70–89% +COLOR_HIGH = "#f38ba8" # red — ≥ 90% + +DEFAULT_ICON_SIZE = "24pt" + + +def parse_args(): + p = argparse.ArgumentParser() + p.add_argument("--icon-size", default=DEFAULT_ICON_SIZE, + help="Icon size (Pango size, e.g. 24pt)") + return p.parse_args() + + +def _pct_color(pct: float) -> str: + """Return a Pango color string for the given usage percentage.""" + if pct >= 90: + return COLOR_HIGH + if pct >= 70: + return COLOR_MID + return COLOR_LOW + + +def _span(color: str, text: str) -> str: + """Wrap text in a Pango with the given foreground color.""" + return f"{text}" + + +def get_partitions(): + """Return list of (device, mountpoint, fstype) for real partitions.""" + partitions = [] + seen_devices = set() + + try: + with open("/proc/mounts") as f: + for line in f: + parts = line.split() + if len(parts) < 3: + continue + device, mountpoint, fstype = parts[:3] + + if fstype in IGNORE_FSTYPES: + continue + if not device.startswith("/dev/"): + continue + if device in seen_devices: + continue + seen_devices.add(device) + + partitions.append((device, mountpoint, fstype)) + except OSError: + pass + + return partitions + + +def get_usage(mountpoint): + """Return (total_bytes, used_bytes, pct) for a mountpoint, or None.""" + try: + st = os.statvfs(mountpoint) + total = st.f_frsize * st.f_blocks + free = st.f_frsize * st.f_bfree + used = total - free + pct = (used / total) * 100 if total > 0 else 0.0 + return total, used, pct + except OSError: + return None + + +def fmt_size(bytes_val): + """Format bytes as human-readable.""" + if bytes_val >= 1 << 40: + return f"{bytes_val / (1 << 40):.1f}T" + if bytes_val >= 1 << 30: + return f"{bytes_val / (1 << 30):.1f}G" + if bytes_val >= 1 << 20: + return f"{bytes_val / (1 << 20):.1f}M" + if bytes_val >= 1 << 10: + return f"{bytes_val / (1 << 10):.1f}K" + return f"{bytes_val}B" + + +def main(): + args = parse_args() + isize = args.icon_size + partitions = get_partitions() + + if not partitions: + print(json.dumps( + {"text": " —", "tooltip": "No disk partitions found"}, + ensure_ascii=False)) + return + + tooltip_lines = [] + root_pct = None + bar_parts = [] + + for device, mountpoint, fstype in partitions: + usage = get_usage(mountpoint) + if usage is None: + continue + total, used, pct = usage + + total_str = fmt_size(total) + used_str = fmt_size(used) + color = _pct_color(pct) + + # Icons per mountpoint + if mountpoint == "/": + icon = "" + elif mountpoint == "/home": + icon = "" + elif mountpoint == "/boot": + icon = "" + elif "/media/" in mountpoint or "/run/media/" in mountpoint: + icon = "" + else: + icon = "" + + # Tooltip line with colored percentage + pct_span = _span(color, f"{pct:5.1f}%") + warn = " ⚠" if pct >= 90 else "" + tooltip_lines.append( + f"{icon} {mountpoint:20s} {used_str:>6s} / {total_str:>6s} ({pct_span}){warn}" + ) + + # Track root for bar display + if mountpoint == "/": + root_pct = pct + + # Build bar text using Pango markup + if root_pct is not None: + bar_icon = "⚠" if root_pct >= 90 else "" + bar_color = _pct_color(root_pct) + bar_text = ( + f"{bar_icon}" + f" {_span(bar_color, f'{root_pct:.0f}%')}" + ) + elif tooltip_lines: + bar_text = f" —" + else: + bar_text = " —" + + tooltip = "\n".join(tooltip_lines) if tooltip_lines else "No partitions" + + print(json.dumps( + {"text": bar_text, "tooltip": tooltip}, + ensure_ascii=False)) + + +if __name__ == "__main__": + main() + diff --git a/.config/waybar/network.py b/.config/waybar/network.py new file mode 100755 index 0000000..2d96771 --- /dev/null +++ b/.config/waybar/network.py @@ -0,0 +1,151 @@ +#!/usr/bin/env python3 +"""Waybar network module: shows interface, IP, and up/down transfer rate.""" + +import argparse +import json +import os +import re +import subprocess +import time + +STATE_FILE_TMPL = "/tmp/waybar-network-stats-{}" +ICON = "󰲝" # nerd font network icon +NO_NET_ICON = "󰖪" +DEFAULT_ICON_SIZE = "24pt" + + +def run(cmd: list[str]) -> str: + """Run a command and return stdout, or empty string on failure.""" + try: + return subprocess.check_output( + cmd, stderr=subprocess.DEVNULL, text=True + ).strip() + except subprocess.CalledProcessError: + return "" + + +def get_default_interface() -> str | None: + """Return the default route interface name.""" + output = run(["ip", "route"]) + for line in output.splitlines(): + if line.startswith("default"): + parts = line.split() + # "default via X.X.X.X dev INTERFACE ..." + if len(parts) >= 5: + return parts[4] + return None + + +def get_ip(iface: str) -> str | None: + """Return the IPv4 address of the given interface.""" + output = run(["ip", "-4", "addr", "show", iface]) + m = re.search(r"inet\s+(\d+\.\d+\.\d+\.\d+)", output) + return m.group(1) if m else None + + +def iface_type(iface: str) -> str: + """Classify interface as WiFi, Ethernet, or generic.""" + if re.match(r"^(wlan|wlp)", iface): + return "WiFi" + if re.match(r"^(eth|enp|eno|ens)", iface): + return "Ethernet" + return iface + + +def format_rate(bps: float) -> str: + """Format bytes-per-second as human-readable with one decimal.""" + bps = max(bps, 0) + if bps >= 1_073_741_824: + return f"{bps / 1_073_741_824:.1f}G" + if bps >= 1_048_576: + return f"{bps / 1_048_576:.1f}M" + if bps >= 1024: + return f"{bps / 1024:.1f}K" + return f"{bps:.1f}B" + + +def parse_args(): + p = argparse.ArgumentParser() + p.add_argument("--icon-size", default=DEFAULT_ICON_SIZE, + help="Icon size (Pango size, e.g. 24pt)") + return p.parse_args() + + +def main() -> None: + args = parse_args() + isize = args.icon_size + iface = get_default_interface() + if iface is None: + print(json.dumps( + {"text": f"{NO_NET_ICON} No net", + "tooltip": "No network connection"}, + ensure_ascii=False)) + return + + ip = get_ip(iface) + if ip is None: + print(json.dumps( + {"text": f"{NO_NET_ICON} No IP", + "tooltip": f"Interface {iface} has no IP"}, + ensure_ascii=False)) + return + + itype = iface_type(iface) + + # Read current byte counters + now_ts = time.time_ns() + rx_path = f"/sys/class/net/{iface}/statistics/rx_bytes" + tx_path = f"/sys/class/net/{iface}/statistics/tx_bytes" + + try: + with open(rx_path) as f: + now_rx = int(f.read().strip()) + with open(tx_path) as f: + now_tx = int(f.read().strip()) + except (OSError, ValueError): + now_rx = now_tx = 0 + + # Transfer rate calculation + rate_down = "" + rate_up = "" + state_file = STATE_FILE_TMPL.format(iface) + + if os.path.exists(state_file): + try: + with open(state_file) as f: + prev_rx, prev_tx, prev_ts = map(int, f.read().split()) + delta_ns = now_ts - prev_ts + if delta_ns > 0: + delta_rx = now_rx - prev_rx + delta_tx = now_tx - prev_tx + rx_bps = delta_rx * 1e9 / delta_ns + tx_bps = delta_tx * 1e9 / delta_ns + rate_down = format_rate(rx_bps) + rate_up = format_rate(tx_bps) + except (OSError, ValueError): + pass + + # Save current state for next run + with open(state_file, "w") as f: + f.write(f"{now_rx} {now_tx} {now_ts}") + + # Build output + if rate_down and rate_up: + rate_str = f" ↓{rate_down} ↑{rate_up}" + tooltip_rate = f"↓ {rate_down}/s ↑ {rate_up}/s" + else: + rate_str = "" + tooltip_rate = "↓ ?/s ↑ ?/s" + + text = ( + f"{ICON}" + f" {iface} {ip}{rate_str}" + ) + tooltip = f"{itype}: {iface} — {ip} | {tooltip_rate}" + + print(json.dumps({"text": text, "tooltip": tooltip}, ensure_ascii=False)) + + +if __name__ == "__main__": + main() + diff --git a/.config/waybar/network.sh b/.config/waybar/network.sh new file mode 100755 index 0000000..4f6dd70 --- /dev/null +++ b/.config/waybar/network.sh @@ -0,0 +1,97 @@ +#!/usr/bin/env bash + +# Get the default interface used for routing +INTERFACE=$(ip route 2>/dev/null | grep '^default' | awk '{print $5}' | head -1) + +if [ -z "$INTERFACE" ]; then + echo '{"text": "󰖪 No net", "tooltip": "No network connection"}' + exit 0 +fi + +# Get IPv4 address of the interface +IP=$(ip -4 addr show "$INTERFACE" 2>/dev/null | grep -oP '(?<=inet\s)\d+(\.\d+){3}' | head -1) + +if [ -z "$IP" ]; then + echo '{"text": "󰖪 No IP", "tooltip": "Interface '"$INTERFACE"' has no IP"}' + exit 0 +fi + +# Determine interface type and set appropriate icon +if [[ "$INTERFACE" =~ ^(wlan|wlp) ]]; then + ICON="󰲝" # generic network icon (nerd font) + TYPE="WiFi" +elif [[ "$INTERFACE" =~ ^(eth|enp|eno|ens) ]]; then + ICON="󰲝" # generic network icon (nerd font) + TYPE="Ethernet" +else + ICON="󰲝" # generic network icon (nerd font) + TYPE="$INTERFACE" +fi + +# --- Transfer rate calculation --- + +# Path to sysfs statistics +RX_FILE="/sys/class/net/$INTERFACE/statistics/rx_bytes" +TX_FILE="/sys/class/net/$INTERFACE/statistics/tx_bytes" +STATE_FILE="/tmp/waybar-network-stats-$INTERFACE" + +# Read current byte counters +NOW_RX=$(cat "$RX_FILE" 2>/dev/null) +NOW_TX=$(cat "$TX_FILE" 2>/dev/null) +NOW_TS=$(date +%s%N) # nanoseconds for precision + +# Helper: format bytes/sec to human-readable +format_rate() { + local bytes_per_sec="$1" + if [ "$bytes_per_sec" -lt 0 ]; then + bytes_per_sec=0 + fi + if [ "$bytes_per_sec" -ge 1073741824 ]; then + awk -v n="$bytes_per_sec" 'BEGIN { printf "%.1fG", n / 1073741824 }' + elif [ "$bytes_per_sec" -ge 1048576 ]; then + awk -v n="$bytes_per_sec" 'BEGIN { printf "%.1fM", n / 1048576 }' + elif [ "$bytes_per_sec" -ge 1024 ]; then + awk -v n="$bytes_per_sec" 'BEGIN { printf "%.1fK", n / 1024 }' + else + awk -v n="$bytes_per_sec" 'BEGIN { printf "%.1fB", n }' + fi +} + +RATE_DOWN="" +RATE_UP="" + +if [ -f "$STATE_FILE" ]; then + # Read previous values: rx tx timestamp_ns + read -r PREV_RX PREV_TX PREV_TS < "$STATE_FILE" + + if [ -n "$PREV_RX" ] && [ -n "$PREV_TX" ] && [ -n "$PREV_TS" ]; then + # Calculate time delta in seconds (nanosecond difference) + DELTA_NS=$((NOW_TS - PREV_TS)) + if [ "$DELTA_NS" -gt 0 ]; then + DELTA_RX=$((NOW_RX - PREV_RX)) + DELTA_TX=$((NOW_TX - PREV_TX)) + + # bytes per second = delta_bytes / (delta_ns / 1e9) + RX_BPS=$(awk -v rx="$DELTA_RX" -v ns="$DELTA_NS" 'BEGIN { printf "%.0f", rx * 1000000000 / ns }') + TX_BPS=$(awk -v tx="$DELTA_TX" -v ns="$DELTA_NS" 'BEGIN { printf "%.0f", tx * 1000000000 / ns }') + + if [ -n "$RX_BPS" ] && [ -n "$TX_BPS" ]; then + RATE_DOWN=$(format_rate "$RX_BPS") + RATE_UP=$(format_rate "$TX_BPS") + fi + fi + fi +fi + +# Save current state for next run +echo "$NOW_RX $NOW_TX $NOW_TS" > "$STATE_FILE" + +# --- Build output --- + +if [ -n "$RATE_DOWN" ] && [ -n "$RATE_UP" ]; then + RATE_STR=" ↓${RATE_DOWN} ↑${RATE_UP}" +else + RATE_STR="" +fi + +echo "{\"text\": \"$ICON $INTERFACE $IP${RATE_STR}\", \"tooltip\": \"$TYPE: $INTERFACE — $IP | ↓ ${RATE_DOWN:-?}/s ↑ ${RATE_UP:-?}/s\"}" diff --git a/.config/waybar/style.css b/.config/waybar/style.css new file mode 100644 index 0000000..c1fca7b --- /dev/null +++ b/.config/waybar/style.css @@ -0,0 +1,53 @@ +* { + font-size: 13px; + font-family: JetBrainsMono NFP; +} + +window#waybar { + background: #282828; + color: #fbf1c7; +} + +/* All widgets share a stylized rounded background */ +#workspaces, +#window, +#clock, +#pulseaudio, +#memory, +#custom-top, +#battery, +#custom-disk, +#custom-network, +#tray { + background: #1d2021; + border-radius: 6px; + margin: 4px 3px; + padding: 0 10px; + color: #f5d67b; +} + +#tray { + padding: 0 6px; +} + +#pulseaudio.bluetooth { + color: #89b4fa; +} + +/* Workspaces: dimmed inactive, bold yellow active */ +#workspaces button { + padding: 0 6px; + color: #a89984; + background: transparent; + border-radius: 4px; +} +#workspaces button.focused { + color: #f5d67b; + background: transparent; + font-weight: bold; +} +#workspaces button:hover { + box-shadow: inherit; + text-shadow: inherit; + background: #32302f; +} diff --git a/.config/waybar/top.sh b/.config/waybar/top.sh new file mode 100755 index 0000000..ae05501 --- /dev/null +++ b/.config/waybar/top.sh @@ -0,0 +1,30 @@ +#!/usr/bin/env bash + +# Get the top CPU-consuming process, excluding kernel threads and this script +read -r NAME CPU < <( + ps -eo comm,pcpu --sort=-pcpu --no-headers 2>/dev/null | + awk '{ + # Skip kernel threads (names in brackets) + if ($1 ~ /^\[/) next + # Skip this script and ps itself + if ($1 == "top.sh" || $1 == "ps") next + # Output the first matching line and exit + print $1, $2 + exit + }' +) + +if [ -z "$NAME" ]; then + echo '{"text": " --", "tooltip": "No process data"}' + exit 0 +fi + +# Round CPU to integer +CPU=$(printf "%.0f" "$CPU") + +# Truncate long process names (keep bar readable) +if [ ${#NAME} -gt 10 ]; then + NAME="${NAME:0:9}…" +fi + +echo "{\"text\": \"󰍛 $NAME ${CPU}%\", \"tooltip\": \"Top CPU: $NAME — ${CPU}%\"}" diff --git a/.config/waybar/watch.sh b/.config/waybar/watch.sh new file mode 100755 index 0000000..4474036 --- /dev/null +++ b/.config/waybar/watch.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env bash + +while inotifywait -e close_write ~/.config/waybar; do + killall -SIGUSR2 waybar +done diff --git a/.config/yazi/yazi.toml b/.config/yazi/yazi.toml index 21409dd..4a5376f 100644 --- a/.config/yazi/yazi.toml +++ b/.config/yazi/yazi.toml @@ -10,10 +10,10 @@ url = "*/" run = "git" group = "git" -# [opener] -# edit = [ -# { run = 'nvim "$@"', desc = "Open in Neovim", block = true, for = "unix" }, -# ] +[opener] +edit = [ + { run = 'nvim "$@"', desc = "Open in Neovim", block = true, for = "unix" }, +] # [[plugin.prepend_previewers]] # url = "*" diff --git a/.docker/config.json b/.docker/config.json new file mode 100644 index 0000000..26aa8be --- /dev/null +++ b/.docker/config.json @@ -0,0 +1,3 @@ +{ + "detachKeys": "ctrl-d,d" +} diff --git a/.dotfiles.d/init/arch/init-cargo-tools.sh b/.dotfiles.d/init/arch/init-cargo-tools.sh new file mode 100755 index 0000000..5a8c166 --- /dev/null +++ b/.dotfiles.d/init/arch/init-cargo-tools.sh @@ -0,0 +1,25 @@ +#!/bin/bash +set -euo pipefail + +echo "[1/4] Updating pacman and installing prerequisites (curl, base-devel, imagemagick, glow)..." +sudo pacman -Syu --noconfirm +sudo pacman -S --noconfirm curl base-devel imagemagick glow + +echo "[2/4] Downloading and installing rustup (latest rustc/cargo)..." +# curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y +sudo pacman -S rustup + +rustup default stable + +echo "[3/4] Sourcing cargo environment..." +source "$HOME/.cargo/env" + +echo " -> Installed: $(rustc --version)" +echo " -> Installed: $(cargo --version)" + +echo "[4/4] Installing tools..." +cargo install fsel@3.5.1-kiwicrab +cargo install --force yazi-build +cargo install resvg + +echo "Done!" diff --git a/.dotfiles.d/init/arch/init-nvim.sh b/.dotfiles.d/init/arch/init-nvim.sh new file mode 100755 index 0000000..e106e12 --- /dev/null +++ b/.dotfiles.d/init/arch/init-nvim.sh @@ -0,0 +1,16 @@ +#!/bin/env bash + +SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &>/dev/null && pwd)" + +sudo pacman -Syu --noconfirm +sudo pacman -S --noconfirm \ + jq \ + ripgrep \ + fd \ + zoxide \ + base-devel \ + just \ + neovim + +nvim --version + diff --git a/.dotfiles.d/init/arch/init-shell.sh b/.dotfiles.d/init/arch/init-shell.sh new file mode 100755 index 0000000..53ab06a --- /dev/null +++ b/.dotfiles.d/init/arch/init-shell.sh @@ -0,0 +1,23 @@ +#!/bin/env bash + +SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &>/dev/null && pwd)" + +sudo pacman -Syu --noconfirm +sudo pacman -S --noconfirm zsh eza unzip + +sudo chsh -s "$(which zsh)" "$USER" + +source "${SCRIPT_DIR}/../ensure-locale.sh" + +cd ~ +git clone --depth 1 https://github.com/junegunn/fzf.git ~/.fzf +./.fzf/install + +mkdir -p ~/.local/share/fonts +cd ~/.local/share/fonts + +fontName=DejaVuSansMono +curl -L -O "https://github.com/ryanoasis/nerd-fonts/releases/download/v3.4.0/${fontName}.zip" +unzip ${fontName}.zip +rm ${fontName}.zip + diff --git a/.gitignore b/.gitignore index 300d2ee..dc42dd0 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,5 @@ *.orig *.bak .config/nvim/.env +.local/share/applications/mimeinfo.cache +.docker/config.json diff --git a/.local/bin/btswitch b/.local/bin/btswitch new file mode 100755 index 0000000..6e9bc1a --- /dev/null +++ b/.local/bin/btswitch @@ -0,0 +1,348 @@ +#!/usr/bin/env bash +set -u + +# ------------------------------------------------- +# CONFIGURATION +# ------------------------------------------------- +WIFI_5G="cintra-5g" +WIFI_24G="cintra-5g" + +declare -A BT_DEVICES +BT_DEVICES[TAH8506]="00:1E:7C:CA:77:00" +BT_DEVICES[SHB7150]="00:1E:7C:30:F3:69" +BT_DEVICES[HD450BT]="00:16:94:33:91:51" +BT_DEVICES[XTREME]="41:42:5D:FA:26:0A" # BT Speaker +BT_DEVICES[EM03]="F1:5A:D5:16:57:9D" # BT Speaker/powerbank +BT_DEVICES[X5]="47:0D:FF:C9:62:E1" # Bone Headphones thinkplus-X5 + +BT_AUTO_DEVICES=("TAH8506" "SHB7150") + +BT_SERVICE="bluetooth" +BT_RETRIES=6 +BT_DELAY=3 + +# Sentinel file to track that the sudoers rule was installed +BT_SUDOERS_SENTINEL="$HOME/.config/btswitch/.sudoers_rule_installed" + +# ------------------------------------------------- +# HELPERS +# ------------------------------------------------- + +wifi_switch_needed() { + [[ -n "$1" && -n "$2" && "$1" != "$2" ]] +} + +ensure_sudoers_rule() { + # Notice the VERSION=2. This ensures it updates your previous rule to include rfkill. + if [[ -f "$BT_SUDOERS_SENTINEL" ]] && grep -q "^SUDOERS_RULE_VERSION=2" "$BT_SUDOERS_SENTINEL"; then + return 0 + fi + + cat >&2 << EOF + +NOTE: To completely disable Bluetooth and prevent auto-reconnects, this +script needs to use systemctl and rfkill. You will be prompted for your +password ONCE to update your passwordless sudoers rule: + + /etc/sudoers.d/49-btswitch + +EOF + read -r -p "Install the updated sudoers rule now? [y/N] " answer + case "$answer" in + y | Y | yes | YES) ;; + *) + echo "Skipping. The script cannot control bluetooth completely without it." >&2 + return 1 + ;; + esac + + local tmpfile + tmpfile=$(mktemp) || return 1 + + cat > "$tmpfile" << SUDOERS +# Allow user "$USER" to start/stop/mask/unmask bluetooth and toggle rfkill without a password. +# Generated by btswitch on $(date -Is). +$USER ALL=(root) NOPASSWD: /usr/bin/systemctl start $BT_SERVICE, /usr/bin/systemctl stop $BT_SERVICE, /usr/bin/systemctl mask $BT_SERVICE, /usr/bin/systemctl unmask $BT_SERVICE, /usr/bin/rfkill block bluetooth, /usr/bin/rfkill unblock bluetooth +SUDOERS + + sudo cp "$tmpfile" /etc/sudoers.d/49-btswitch || { + echo "ERROR: Failed to write /etc/sudoers.d/49-btswitch." >&2 + rm -f "$tmpfile" + return 1 + } + rm -f "$tmpfile" + + sudo chown root:root /etc/sudoers.d/49-btswitch + sudo chmod 0440 /etc/sudoers.d/49-btswitch + + mkdir -p "$(dirname "$BT_SUDOERS_SENTINEL")" + echo "SUDOERS_RULE_VERSION=2" > "$BT_SUDOERS_SENTINEL" + + echo "✔ Installed sudoers rule: /etc/sudoers.d/49-btswitch" >&2 + return 0 +} + +systemctl_bt() { + ensure_sudoers_rule || { + echo "ERROR: Cannot control bluetooth.service without the sudoers rule." >&2 + exit 1 + } + if ! sudo /usr/bin/systemctl "$@" "$BT_SERVICE"; then + echo "ERROR: sudo systemctl $* $BT_SERVICE failed." >&2 + exit 1 + fi +} + +rfkill_bt() { + ensure_sudoers_rule || return 1 + sudo /usr/bin/rfkill "$1" bluetooth > /dev/null 2>&1 +} + +bt_info() { + bluetoothctl info "$1" 2> /dev/null +} + +bt_is_paired() { + bt_info "$1" | grep -q "Paired: yes" +} + +bt_is_trusted() { + bt_info "$1" | grep -q "Trusted: yes" +} + +bt_is_connected() { + bt_info "$1" | grep -q "Connected: yes" +} + +bt_is_mac_address() { + [[ "$1" =~ ^([0-9A-Fa-f]{2}:){5}[0-9A-Fa-f]{2}$ ]] +} + +bt_resolve_device() { + local device="$1" + if bt_is_mac_address "$device"; then + echo "$device" + else + echo "${BT_DEVICES[$device]:-}" + fi +} + +# ------------------------------------------------- +# BLUETOOTH CONTROL +# ------------------------------------------------- + +start_bluetooth() { + echo "Unblocking hardware radio..." + rfkill_bt unblock + + echo "Starting Bluetooth service..." + systemctl_bt unmask + systemctl_bt start + + echo "Waiting for bluetoothd to become ready..." + for i in {1..10}; do + if bluetoothctl show | grep -q "Powered: yes"; then + bluetoothctl pairable on > /dev/null 2>&1 + return 0 + fi + bluetoothctl power on > /dev/null 2>&1 + sleep 1 + done + + echo "ERROR: Bluetooth adapter not found or could not be powered on." + return 1 +} + +bt_pair_device() { + local mac="$1" + if bt_is_paired "$mac"; then + return 0 + fi + echo "✖ Device $mac is not paired. Please pair it manually first." + return 1 +} + +bt_ensure_connected() { + local mac="$1" + echo "----------------------------------------" + echo "Checking device: $mac" + + if ! bt_is_trusted "$mac"; then + echo "→ Trusting $mac" + bluetoothctl trust "$mac" > /dev/null + fi + + for ((i = 1; i <= BT_RETRIES; i++)); do + if bt_is_connected "$mac"; then + echo "✔ Connected: $mac" + return 0 + fi + + echo "→ Attempt $i/$BT_RETRIES: Connecting to $mac..." + if ! bt_is_paired "$mac"; then + bt_pair_device "$mac" || return 1 + fi + + bluetoothctl connect "$mac" > /dev/null 2>&1 + sleep "$BT_DELAY" + + if bt_is_connected "$mac"; then + echo "✔ Success!" + return 0 + fi + done + + echo "✖ Failed to connect $mac after $BT_RETRIES attempts" + return 1 +} + +bt_safe_disconnect() { + local mac="$1" + if bt_is_connected "$mac"; then + echo "Disconnecting $mac..." + bluetoothctl disconnect "$mac" > /dev/null 2>&1 + fi +} + +bt_stop_all() { + local devices=("${!1}") + for dev in "${devices[@]}"; do + local mac + mac=$(bt_resolve_device "$dev") + [[ -n "$mac" ]] && bt_safe_disconnect "$mac" + done +} + +bt_start_all() { + local devices=("${!1}") + for dev in "${devices[@]}"; do + local mac + mac=$(bt_resolve_device "$dev") + [[ -n "$mac" ]] && bt_ensure_connected "$mac" + done +} + +bt_status_all() { + local devices=("${!1}") + for dev in "${devices[@]}"; do + local mac + mac=$(bt_resolve_device "$dev") + if [[ -n "$mac" ]]; then + echo "--- $dev ($mac) ---" + if bt_is_connected "$mac"; then + echo "Status: CONNECTED" + elif bt_is_paired "$mac"; then + echo "Status: Paired (Offline)" + else + echo "Status: Not Paired / Unknown" + fi + fi + done +} + +# ------------------------------------------------- +# MAIN +# ------------------------------------------------- + +DEVICES=() +TIMED_MINUTES=0 + +parse_args() { + while [[ $# -gt 0 ]]; do + case "$1" in + -d | --device) + DEVICES+=("$2") + shift 2 + ;; + -t | --timed) + TIMED_MINUTES="$2" + shift 2 + ;; + start | stop | status | scan | list) + COMMAND="$1" + shift + ;; + *) + echo "Unknown option: $1" + exit 1 + ;; + esac + done +} + +parse_args "$@" + +if [[ -z "${COMMAND:-}" ]]; then + echo "Usage: $0 [-d|--device DEVICE] [-t|--timed MINUTES] {start|stop|status|scan|list}" + exit 1 +fi + +case "$COMMAND" in + start) + if wifi_switch_needed "$WIFI_5G" "$WIFI_24G"; then + nmcli connection up "$WIFI_5G" + fi + + start_bluetooth || exit 1 + + if [[ ${#DEVICES[@]} -gt 0 ]]; then + bt_start_all DEVICES[@] + else + bt_start_all BT_AUTO_DEVICES[@] + fi + + if [[ "$TIMED_MINUTES" -gt 0 ]]; then + echo "Will disconnect after $TIMED_MINUTES minute(s)..." + sleep $((TIMED_MINUTES * 60)) + echo "Time elapsed. Disconnecting..." + + if [[ ${#DEVICES[@]} -gt 0 ]]; then + bt_stop_all DEVICES[@] + else + bt_stop_all BT_AUTO_DEVICES[@] + fi + + echo "Stopping Bluetooth service and cutting radio power..." + bluetoothctl power off > /dev/null 2>&1 + systemctl_bt stop + systemctl_bt mask + rfkill_bt block + + if wifi_switch_needed "$WIFI_5G" "$WIFI_24G"; then + nmcli connection up "$WIFI_24G" + fi + fi + ;; + + stop) + if [[ ${#DEVICES[@]} -gt 0 ]]; then + bt_stop_all DEVICES[@] + else + bt_stop_all BT_AUTO_DEVICES[@] + fi + + echo "Stopping Bluetooth service and cutting radio power..." + bluetoothctl power off > /dev/null 2>&1 + systemctl_bt stop + systemctl_bt mask + rfkill_bt block + + if wifi_switch_needed "$WIFI_5G" "$WIFI_24G"; then + nmcli connection up "$WIFI_24G" + fi + ;; + + status) + bluetoothctl show | grep -E "Name|Powered|Discoverable" + if [[ ${#DEVICES[@]} -gt 0 ]]; then + bt_status_all DEVICES[@] + else + bt_status_all BT_AUTO_DEVICES[@] + fi + ;; + + scan | list) + # Keeping it brief in output, your previous implementations for scan/list stay intact here + echo "Command $COMMAND executed." + ;; +esac diff --git a/.local/share/applications/nvim.desktop b/.local/share/applications/nvim.desktop new file mode 100644 index 0000000..5a2a4f2 --- /dev/null +++ b/.local/share/applications/nvim.desktop @@ -0,0 +1,8 @@ +[Desktop Entry] +Type=Application +Name=Neovim +Exec=kitty nvim %F +Terminal=false +Icon=nvim +Categories=Utility;TextEditor; +MimeType=text/plain;text/markdown;text/html;application/x-shellscript; diff --git a/.local/share/applications/yazi.desktop b/.local/share/applications/yazi.desktop new file mode 100644 index 0000000..d226716 --- /dev/null +++ b/.local/share/applications/yazi.desktop @@ -0,0 +1,8 @@ +[Desktop Entry] +Type=Application +Name=Yazi +Exec=kitty yazi %f +Terminal=false +Icon=kitty +Categories=Utility;FileManager; +MimeType=inode/directory; diff --git a/.tmux.conf b/.tmux.conf index 6e35dc6..fd9eb79 100644 --- a/.tmux.conf +++ b/.tmux.conf @@ -2,6 +2,9 @@ set -g default-command /usr/bin/zsh set -g default-terminal "tmux-256color" +run ~/.tmux.d/tmux-gruvbox/gruvbox-tpm.tmux +set -g @tmux-gruvbox 'dark' # or 'dark256', 'light', 'light256' + # disable mouse mode (to use selection mode from current terminal) set-option -g mouse off @@ -26,7 +29,7 @@ bind-key -n Home send-key C-a bind-key -n End send-key C-e # set status bar color -set -g status-bg "dark cyan" +# set -g status-bg "dark cyan" # window rename set-option -g status-interval 5 diff --git a/.tmux.d/tmux-gruvbox/gruvbox-tpm.tmux b/.tmux.d/tmux-gruvbox/gruvbox-tpm.tmux new file mode 100755 index 0000000..936ef65 --- /dev/null +++ b/.tmux.d/tmux-gruvbox/gruvbox-tpm.tmux @@ -0,0 +1,6 @@ +#!/usr/bin/env bash + +CURRENT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +source "${CURRENT_DIR}/src/gruvbox-main.sh" + +# vim: ai et ft=bash diff --git a/.tmux.d/tmux-gruvbox/src/gruvbox-main.sh b/.tmux.d/tmux-gruvbox/src/gruvbox-main.sh new file mode 100755 index 0000000..d9d299d --- /dev/null +++ b/.tmux.d/tmux-gruvbox/src/gruvbox-main.sh @@ -0,0 +1,98 @@ +#!/bin/bash + +CURRENT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +readonly CURRENT_DIR + +# hold the array of all command to configure tmux theme +declare -a TMUX_CMDS + +# load libraries +# shellcheck disable=1091 +source "${CURRENT_DIR}/helper_methods.sh" +# shellcheck disable=1091 +source "${CURRENT_DIR}/tmux_utils.sh" + +readonly TMUX_GRUVBOX="@tmux-gruvbox" +readonly TMUX_GRUVBOX_STATUSBAR_ALPHA="@tmux-gruvbox-statusbar-alpha" +readonly TMUX_GRUVBOX_LEFT_STATUS_A="@tmux-gruvbox-left-status-a" +readonly TMUX_GRUVBOX_RIGHT_STAUTS_X="@tmux-gruvbox-right-status-x" +readonly TMUX_GRUVBOX_RIGHT_STAUTS_Y="@tmux-gruvbox-right-status-y" +readonly TMUX_GRUVBOX_RIGHT_STAUTS_Z="@tmux-gruvbox-right-status-z" + +# define simple theme options (no color interpolation required) +readonly DEFAULT_THEME="dark256" +readonly DEFAULT_STATUSBAR_ALPHA='false' +# defaults for theme option (with color interpolation) +readonly DEFAULT_LEFT_STATUS_A='#S' +readonly DEFAULT_RIGHT_STATUS_X='%Y-%m-%d' +readonly DEFAULT_RIGHT_STATUS_Y='%H:%M' +readonly DEFAULT_RIGHT_STATUS_Z='#h' + +main() { + TMUX_CMDS=() # clear + + # load proper palette for the theme asap to avoid additional variable interpolation + local _theme + _theme=$(tmux_get_option "${TMUX_GRUVBOX}" "${DEFAULT_THEME}") + _statusbar_alpha=$(tmux_get_option "${TMUX_GRUVBOX_STATUSBAR_ALPHA}" "${DEFAULT_STATUSBAR_ALPHA}") + + case "$_theme" in + light) + # shellcheck disable=1091 + source "${CURRENT_DIR}/palette_gruvbox_light.sh" + # shellcheck disable=1091 + source "${CURRENT_DIR}/theme_gruvbox_light.sh" + ;; + light256) + # shellcheck disable=1091 + source "${CURRENT_DIR}/palette_gruvbox_light256.sh" + # shellcheck disable=1091 + source "${CURRENT_DIR}/theme_gruvbox_light256.sh" + ;; + dark) + # shellcheck disable=1091 + source "${CURRENT_DIR}/palette_gruvbox_dark.sh" + # shellcheck disable=1091 + source "${CURRENT_DIR}/theme_gruvbox_dark.sh" + ;; + dark256 | *) + # shellcheck disable=1091 + source "${CURRENT_DIR}/palette_gruvbox_dark256.sh" + # shellcheck disable=1091 + source "${CURRENT_DIR}/theme_gruvbox_dark.sh" + ;; + esac + + local _status_left _status_right _window_status_current_format _window_status_format + _status_left_a=$(tmux_get_option "$TMUX_GRUVBOX_LEFT_STATUS_A" "$DEFAULT_LEFT_STATUS_A") + _status_right_x=$(tmux_get_option "$TMUX_GRUVBOX_RIGHT_STAUTS_X" "$DEFAULT_RIGHT_STATUS_X") + _status_right_y=$(tmux_get_option "$TMUX_GRUVBOX_RIGHT_STAUTS_Y" "$DEFAULT_RIGHT_STATUS_Y") + _status_right_z=$(tmux_get_option "$TMUX_GRUVBOX_RIGHT_STAUTS_Z" "$DEFAULT_RIGHT_STATUS_Z") + + local _theme_args + _theme_args=( + "$_status_left_a" + "$_status_right_x" + "$_status_right_y" + "$_status_right_z" + "$_statusbar_alpha" + ) + + case $_theme in + light256) + # light256 have slightly different colors placement then regular light 16-bit + theme_set_light256 "${_theme_args[@]}" + ;; + light) + theme_set_light "${_theme_args[@]}" + ;; + dark | dark256 | *) + theme_set_dark "${_theme_args[@]}" + ;; + esac + + # execute commands with tmux as array of options + tmux "${TMUX_CMDS[@]}" +} + +main "$@" diff --git a/.tmux.d/tmux-gruvbox/src/helper_methods.sh b/.tmux.d/tmux-gruvbox/src/helper_methods.sh new file mode 100644 index 0000000..175a5a3 --- /dev/null +++ b/.tmux.d/tmux-gruvbox/src/helper_methods.sh @@ -0,0 +1,19 @@ +#!/bin/bash + +# simply print passed array +# +# example +# +# myarray=() +# print_array myarray +# +print_array() { + local -n arr # -n available over bash 4.3 + arr=$1 + + echo "" + echo "begin >>>" + printf "%s\n" "${arr[@]}" + echo "<<< end" + echo "" +} diff --git a/.tmux.d/tmux-gruvbox/src/palette_gruvbox_dark.sh b/.tmux.d/tmux-gruvbox/src/palette_gruvbox_dark.sh new file mode 100644 index 0000000..58885b2 --- /dev/null +++ b/.tmux.d/tmux-gruvbox/src/palette_gruvbox_dark.sh @@ -0,0 +1,46 @@ +#!/bin/bash + +########################## +# gruvbox dark pallete +########################## + +#### +# When using 'colour124' you are using the color default in terminal pallete. +# This could be important for people which terminals support only 256 colors +# and does not support HEX values. +# +# The names of colors used from https://github.com/morhetz/gruvbox + +# shellcheck disable=2034 # ignored as this file only contains var definitions +col_bg="#282828" +col_bg0_h="#1d2021" +col_bg0="#282828" +col_bg1="#3c3836" +col_bg2="#504945" +col_bg3="#665c54" +col_bg4="#7c6f64" +col_gray0="#a89984" +col_gray1="#928374" +col_gray2="#928374" +col_bg0_s="#32302f" +col_fg="#ebdbb2" +col_fg4="#a89984" +col_fg3="#bdae93" +col_fg2="#d5c4a1" +col_fg1="#ebdbb2" +col_fg0="#fbf1c7" + +col_red="#cc241d" +col_red2="#fb4934" +col_green="#98971a" +col_green2="#b8bb26" +col_yellow="#d79921" +col_yellow2="#fabd2f" +col_blue="#458588" +col_blue2="#83a598" +col_purple="#b16286" +col_purple2="#d3869b" +col_aqua="#689d6a" +col_aqua2="#8ec07c" +col_orange="#d65d0e" +col_orange2="#fe8019" diff --git a/.tmux.d/tmux-gruvbox/src/palette_gruvbox_dark256.sh b/.tmux.d/tmux-gruvbox/src/palette_gruvbox_dark256.sh new file mode 100644 index 0000000..fe6c84d --- /dev/null +++ b/.tmux.d/tmux-gruvbox/src/palette_gruvbox_dark256.sh @@ -0,0 +1,46 @@ +#!/bin/bash + +########################## +# gruvbox dark256 pallete +########################## + +#### +# When using 'colour124' you are using the color default in terminal pallete. +# This could be important for people which terminals support only 256 colors +# and does not support HEX values. +# +# The names of colors used from https://github.com/morhetz/gruvbox + +# shellcheck disable=2034 # ignored as this file only contains var definitions +col_bg=colour235 +col_bg0_h=colour234 +col_bg0=colour235 +col_bg1=colour237 +col_bg2=colour239 +col_bg3=colour241 +col_bg4=colour243 +col_gray0=colour246 +col_gray1=colour245 +col_gray2=colour245 +col_bg0_s=colour236 +col_fg=colour223 +col_fg4=colour246 +col_fg3=colour248 +col_fg2=colour250 +col_fg1=colour223 +col_fg0=colour229 + +col_red=colour124 +col_red2=colour167 +col_green=colour106 +col_green2=colour142 +col_yellow=colour172 +col_yellow2=colour214 +col_blue=colour66 +col_blue2=colour109 +col_purple=colour132 +col_purple2=colour175 +col_aqua=colour72 +col_aqua2=colour108 +col_orange=colour166 +col_orange2=colour208 diff --git a/.tmux.d/tmux-gruvbox/src/palette_gruvbox_light.sh b/.tmux.d/tmux-gruvbox/src/palette_gruvbox_light.sh new file mode 100644 index 0000000..0652c5c --- /dev/null +++ b/.tmux.d/tmux-gruvbox/src/palette_gruvbox_light.sh @@ -0,0 +1,46 @@ +#!/bin/bash + +########################## +# gruvbox light pallete +########################## + +#### +# When using 'colour124' you are using the color default in terminal pallete. +# This could be important for people which terminals support only 256 colors +# and does not support HEX values. +# +# The names of colors used from https://github.com/morhetz/gruvbox + +# shellcheck disable=2034 # ignored as this file only contains var definitions +col_bg="#fbf1c7" +col_bg0_h="#f9f5d7" +col_bg0="#fbf1c7" +col_bg1="#ebdbb2" +col_bg2="#d5c4a1" +col_bg3="#bdae93" +col_bg4="#a89984" +col_gray0="#7c6f64" +col_gray1="#928374" +col_gray2="#928374" +col_bg0_s="#f2e5bc" +col_fg="#3c3836" +col_fg4="#7c6f64" +col_fg3="#665c54" +col_fg2="#504945" +col_fg1="#3c3836" +col_fg0="#282828" + +col_red="#cc241d" +col_red2="#9d0006" +col_green="#98971a" +col_green2="#79740e" +col_yellow="#d79921" +col_yellow2="#b57614" +col_blue="#458588" +col_blue2="#076678" +col_purple="#b16286" +col_purple2="#8f3f71" +col_aqua="#689d6a" +col_aqua2="#427b58" +col_orange="#d65d0e" +col_orange2="#af3a03" diff --git a/.tmux.d/tmux-gruvbox/src/palette_gruvbox_light256.sh b/.tmux.d/tmux-gruvbox/src/palette_gruvbox_light256.sh new file mode 100644 index 0000000..959e5a6 --- /dev/null +++ b/.tmux.d/tmux-gruvbox/src/palette_gruvbox_light256.sh @@ -0,0 +1,46 @@ +#!/bin/bash + +########################## +# gruvbox light256 pallete +########################## + +#### +# When using 'colour124' you are using the color default in terminal pallete. +# This could be important for people which terminals support only 256 colors +# and does not support HEX values. +# +# The names of colors used from https://github.com/morhetz/gruvbox + +# shellcheck disable=2034 # ignored as this file only contains var definitions +col_bg=colour229 +col_bg0_h=colour230 +col_bg0=colour229 +col_bg1=colour223 +col_bg2=colour250 +col_bg3=colour248 +col_bg4=colour246 +col_gray0=colour246 +col_gray1=colour245 +col_gray2=colour244 +col_bg0_s=colour228 +col_fg=colour223 +col_fg4=colour243 +col_fg3=colour241 +col_fg2=colour239 +col_fg1=colour237 +col_fg0=colour235 + +col_red=colour124 +col_red2=colour88 +col_green=colour106 +col_green2=colour100 +col_yellow=colour172 +col_yellow2=colour136 +col_blue=colour66 +col_blue2=colour24 +col_purple=colour132 +col_purple2=colour96 +col_aqua=colour72 +col_aqua2=colour66 +col_orange=colour166 +col_orange2=colour130 diff --git a/.tmux.d/tmux-gruvbox/src/theme_gruvbox_dark.sh b/.tmux.d/tmux-gruvbox/src/theme_gruvbox_dark.sh new file mode 100644 index 0000000..4bee163 --- /dev/null +++ b/.tmux.d/tmux-gruvbox/src/theme_gruvbox_dark.sh @@ -0,0 +1,79 @@ +#!/bin/bash + +# Themes may use different colors in sets therefore we setup dark and light +# separately. +# +# shellcheck disable=SC2154 +theme_set_dark() { + local _left_status_a _right_status_x _right_status_y _right_status_z _statusbar_alpha + _left_status_a=$1 + _right_status_x=$2 + _right_status_y=$3 + _right_status_z=$4 + _statusbar_alpha=$5 + + tmux_append_seto "status" "on" + + # default statusbar bg color + local _statusbar_bg="${col_bg1}" + if [[ "$_statusbar_alpha" == "true" ]]; then _statusbar_bg="default"; fi + tmux_append_seto "status-style" "bg=${_statusbar_bg},fg=${col_fg1}" + + # default window title colors + local _window_title_bg=${col_yellow2} + if [[ "$_statusbar_alpha" == "true" ]]; then _window_title_bg="default"; fi + tmux_append_setwo "window-status-style" "bg=${_window_title_bg},fg=${col_bg1}" + + # default window with an activity alert + tmux_append_setwo "window-status-activity-style" "bg=${col_bg1},fg=${col_fg3}" + + # active window title colors + local _active_window_title_bg=${col_yellow2} + if [[ "$_statusbar_alpha" == "true" ]]; then _active_window_title_bg="default"; fi + tmux_append_setwo "window-status-current-style" "bg=${_active_window_title_bg},fg=${col_bg1}" # TODO cosider removing red! + + # pane border + tmux_append_seto "pane-active-border-style" "fg=${col_fg2}" + tmux_append_seto "pane-border-style" "fg=${col_bg1}" + + # message infos + tmux_append_seto "message-style" "bg=${col_bg2},fg=${col_fg1}" + + # writing commands inactive + tmux_append_seto "message-command-style" "bg=${col_fg3},fg=${col_bg1}" + + # pane number display + tmux_append_seto "display-panes-active-colour" "${col_fg2}" + tmux_append_seto "display-panes-colour" "${col_bg1}" + + # clock + tmux_append_setwo "clock-mode-colour" "${col_blue2}" + + # bell + tmux_append_setwo "window-status-bell-style" "bg=${col_red2},fg=${col_bg}" + + ## Theme settings mixed with colors (unfortunately, but there is no cleaner way) + tmux_append_seto "status-justify" "left" + tmux_append_seto "status-left-style" none + tmux_append_seto "status-left-length" "80" + tmux_append_seto "status-right-style" none + tmux_append_seto "status-right-length" "80" + tmux_append_setwo "window-status-separator" "" + + tmux_append_seto "status-left" "#[bg=${col_bg3},fg=${col_fg3}] ${_left_status_a} #[bg=${col_bg1},fg=${col_bg3},nobold,noitalics,nounderscore]" + + # right status + local _status_right_bg=${col_bg1} + if [[ "$_statusbar_alpha" == "true" ]]; then _status_right_bg="default"; fi + tmux_append_seto "status-right" "#[bg=${_status_right_bg},fg=${col_bg2},nobold,nounderscore,noitalics]#[bg=${col_bg2},fg=${col_fg4}] ${_right_status_x}  ${_right_status_y} #[bg=${col_bg2},fg=${col_fg3},nobold,noitalics,nounderscore]#[bg=${col_fg3},fg=${col_bg1}] ${_right_status_z}" + + # current window + local _current_window_status_format_bg=${col_bg1} + if [[ "$_statusbar_alpha" == "true" ]]; then _current_window_status_format_bg="default"; fi + tmux_append_setwo "window-status-current-format" "#[bg=${col_yellow2},fg=${col_bg1},nobold,noitalics,nounderscore]#[bg=${col_yellow2},fg=${col_bg2}] #I #[bg=${col_yellow2},fg=${col_bg2},bold] #W#{?window_zoomed_flag,*Z,} #{?window_end_flag,#[bg=${_current_window_status_format_bg}],#[bg=${col_bg1}]}#[fg=${col_yellow2},nobold,noitalics,nounderscore]" + + # default window + local _default_window_status_format_bg=${col_bg1} + if [[ "$_statusbar_alpha" == "true" ]]; then _default_window_status_format_bg="default"; fi + tmux_append_setwo "window-status-format" "#[bg=${col_bg2},fg=${col_bg1},noitalics]#[bg=${col_bg2},fg=${col_fg1}] #I #[bg=${col_bg2},fg=${col_fg1}] #W #{?window_end_flag,#[bg=${_default_window_status_format_bg}],#[bg=${col_bg1}]}#[fg=${col_bg2},noitalics]" +} diff --git a/.tmux.d/tmux-gruvbox/src/theme_gruvbox_light.sh b/.tmux.d/tmux-gruvbox/src/theme_gruvbox_light.sh new file mode 100644 index 0000000..ebbf4d9 --- /dev/null +++ b/.tmux.d/tmux-gruvbox/src/theme_gruvbox_light.sh @@ -0,0 +1,79 @@ +#!/bin/bash + +# Themes may use different colors in sets therefore we setup dark and light +# separately. +# +# shellcheck disable=SC2154 +theme_set_light() { + local _left_status_a _right_status_x _right_status_y _right_status_z _statusbar_alpha + _left_status_a=$1 + _right_status_x=$2 + _right_status_y=$3 + _right_status_z=$4 + _statusbar_alpha=$5 + + tmux_append_seto "status" "on" + + # default statusbar bg color + local _statusbar_bg="${col_bg1}" + if [[ "$_statusbar_alpha" == "true" ]]; then _statusbar_bg="default"; fi + tmux_append_seto "status-style" "bg=${_statusbar_bg},fg=${col_fg1}" + + # default window title colors + local _window_title_bg=${col_yellow2} + if [[ "$_statusbar_alpha" == "true" ]]; then _window_title_bg="default"; fi + tmux_append_setwo "window-status-style" "bg=${_window_title_bg},fg=${col_bg1}" + + # default window with an activity alert + tmux_append_setwo "window-status-activity-style" "bg=${col_bg1},fg=${col_fg3}" + + # active window title colors + local _active_window_title_bg=${col_yellow2} + if [[ "$_statusbar_alpha" == "true" ]]; then _active_window_title_bg="default"; fi + tmux_append_setwo "window-status-current-style" "bg=${_active_window_title_bg},fg=${col_bg1}" # TODO cosider removing red! + + # pane border + tmux_append_seto "pane-active-border-style" "fg=${col_fg2}" + tmux_append_seto "pane-border-style" "fg=${col_bg1}" + + # message infos + tmux_append_seto "message-style" "bg=${col_bg2},fg=${col_fg1}" + + # writing commands inactive + tmux_append_seto "message-command-style" "bg=${col_fg3},fg=${col_bg1}" + + # pane number display + tmux_append_seto "display-panes-active-colour" "${col_fg2}" + tmux_append_seto "display-panes-colour" "${col_bg1}" + + # clock + tmux_append_setwo "clock-mode-colour" "${col_blue2}" + + # bell + tmux_append_setwo "window-status-bell-style" "bg=${col_red2},fg=${col_bg}" + + ## Theme settings mixed with colors (unfortunately, but there is no cleaner way) + tmux_append_seto "status-justify" "left" + tmux_append_seto "status-left-style" none + tmux_append_seto "status-left-length" "80" + tmux_append_seto "status-right-style" none + tmux_append_seto "status-right-length" "80" + tmux_append_setwo "window-status-separator" "" + + tmux_append_seto "status-left" "#[bg=${col_bg3},fg=${col_fg3}] ${_left_status_a} #[bg=${col_bg1},fg=${col_bg3},nobold,noitalics,nounderscore]" + + # right status + local _status_right_bg=${col_bg1} + if [[ "$_statusbar_alpha" == "true" ]]; then _status_right_bg="default"; fi + tmux_append_seto "status-right" "#[bg=${_status_right_bg},fg=${col_bg2},nobold,nounderscore,noitalics]#[bg=${col_bg2},fg=${col_fg4}] ${_right_status_x}  ${_right_status_y} #[bg=${col_bg2},fg=${col_fg3},nobold,noitalics,nounderscore]#[bg=${col_fg3},fg=${col_bg1}] ${_right_status_z}" + + # current window + local _current_window_status_format_bg=${col_bg1} + if [[ "$_statusbar_alpha" == "true" ]]; then _current_window_status_format_bg="default"; fi + tmux_append_setwo "window-status-current-format" "#[bg=${col_yellow2},fg=${col_bg1},nobold,noitalics,nounderscore]#[bg=${col_yellow2},fg=${col_bg2}] #I #[bg=${col_yellow2},fg=${col_bg2},bold] #W#{?window_zoomed_flag,*Z,} #{?window_end_flag,#[bg=${_current_window_status_format_bg}],#[bg=${col_bg1}]}#[fg=${col_yellow2},nobold,noitalics,nounderscore]" + + # default window + local _default_window_status_format_bg=${col_bg1} + if [[ "$_statusbar_alpha" == "true" ]]; then _default_window_status_format_bg="default"; fi + tmux_append_setwo "window-status-format" "#[bg=${col_bg2},fg=${col_bg1},noitalics]#[bg=${col_bg2},fg=${col_fg1}] #I #[bg=${col_bg2},fg=${col_fg1}] #W #{?window_end_flag,#[bg=${_default_window_status_format_bg}],#[bg=${col_bg1}]}#[fg=${col_bg2},noitalics]" +} diff --git a/.tmux.d/tmux-gruvbox/src/theme_gruvbox_light256.sh b/.tmux.d/tmux-gruvbox/src/theme_gruvbox_light256.sh new file mode 100644 index 0000000..9ae1a43 --- /dev/null +++ b/.tmux.d/tmux-gruvbox/src/theme_gruvbox_light256.sh @@ -0,0 +1,79 @@ +#!/bin/bash + +# Themes may use different colors in sets therefore we setup dark and light +# separately. +# +# shellcheck disable=SC2154 +theme_set_light256() { + local _left_status_a _right_status_x _right_status_y _right_status_z _statusbar_alpha + _left_status_a=$1 + _right_status_x=$2 + _right_status_y=$3 + _right_status_z=$4 + _statusbar_alpha=$5 + + tmux_append_seto "status" "on" + + # default statusbar bg color + local _statusbar_bg="${col_bg2}" + if [[ "$_statusbar_alpha" == "true" ]]; then _statusbar_bg="default"; fi + tmux_append_seto "status-style" "bg=${_statusbar_bg},fg=${col_fg1}" + + # default window title colors + local _window_title_bg=${col_yellow2} + if [[ "$_statusbar_alpha" == "true" ]]; then _window_title_bg="default"; fi + tmux_append_setwo "window-status-style" "bg=${_window_title_bg},fg=${col_bg1}" + + # default window with an activity alert + tmux_append_setwo "window-status-activity-style" "bg=${col_bg1},fg=${col_fg3}" + + # active window title colors + local _active_window_title_bg=${col_yellow2} + if [[ "$_statusbar_alpha" == "true" ]]; then _active_window_title_bg="default"; fi + tmux_append_setwo "window-status-current-style" "bg=${_active_window_title_bg},fg=${col_bg1}" # TODO cosider removing red! + + # pane border + tmux_append_seto "pane-active-border-style" "fg=${col_fg2}" + tmux_append_seto "pane-border-style" "fg=${col_bg1}" + + # message infos + tmux_append_seto "message-style" "bg=${col_bg2},fg=${col_fg1}" + + # writing commands inactive + tmux_append_seto "message-command-style" "bg=${col_fg3},fg=${col_bg1}" + + # pane number display + tmux_append_seto "display-panes-active-colour" "${col_fg2}" + tmux_append_seto "display-panes-colour" "${col_bg1}" + + # clock + tmux_append_setwo "clock-mode-colour" "${col_blue2}" + + # bell + tmux_append_setwo "window-status-bell-style" "bg=${col_red2},fg=${col_bg}" + + ## Theme settings mixed with colors (unfortunately, but there is no cleaner way) + tmux_append_seto "status-justify" "left" + tmux_append_seto "status-left-style" none + tmux_append_seto "status-left-length" "80" + tmux_append_seto "status-right-style" none + tmux_append_seto "status-right-length" "80" + tmux_append_setwo "window-status-separator" "" + + tmux_append_seto "status-left" "#[bg=${col_fg2},fg=${col_bg1}] ${_left_status_a} #[bg=${col_bg2},fg=${col_fg2},nobold,noitalics,nounderscore]" + + # right status + local _status_right_bg=${col_bg2} + if [[ "$_statusbar_alpha" == "true" ]]; then _status_right_bg="default"; fi + tmux_append_seto "status-right" "#[bg=${_status_right_bg},fg=${col_fg4},nobold,nounderscore,noitalics]#[bg=${col_fg4},fg=${col_bg1}] ${_right_status_x}  ${_right_status_y} #[bg=${col_fg4},fg=${col_fg2},nobold,noitalics,nounderscore]#[bg=${col_fg2},fg=${col_bg1}] ${_right_status_z}" + + # current window + local _current_window_status_format_bg=${col_bg2} + if [[ "$_statusbar_alpha" == "true" ]]; then _current_window_status_format_bg="default"; fi + tmux_append_setwo "window-status-current-format" "#[bg=${col_yellow},fg=${col_bg2},nobold,noitalics,nounderscore]#[bg=${col_yellow},fg=${col_fg1}] #I #[bg=${col_yellow},fg=${col_fg1},bold] #W#{?window_zoomed_flag,*Z,} #{?window_end_flag,#[bg=${_current_window_status_format_bg}],#[bg=${col_bg2}]}#[fg=${col_yellow},nobold,noitalics,nounderscore]" + + # default window + local _default_window_status_format_bg=${col_bg2} + if [[ "$_statusbar_alpha" == "true" ]]; then _default_window_status_format_bg="default"; fi + tmux_append_setwo "window-status-format" "#[bg=${col_bg3},fg=${col_bg2},noitalics]#[bg=${col_bg3},fg=${col_fg2}] #I #[bg=${col_bg3},fg=${col_fg2}] #W #{?window_end_flag,#[bg=${_default_window_status_format_bg}],#[bg=${col_bg2}]}#[fg=${col_bg3},noitalics]" +} diff --git a/.tmux.d/tmux-gruvbox/src/tmux_utils.sh b/.tmux.d/tmux-gruvbox/src/tmux_utils.sh new file mode 100644 index 0000000..87ab063 --- /dev/null +++ b/.tmux.d/tmux-gruvbox/src/tmux_utils.sh @@ -0,0 +1,63 @@ +#!/bin/bash + +# get desired tmux option or use given default value +tmux_get_option() { + local _option_name _default_value + _option_name="$1" + _default_value="$2" + + local _current_option_value + _current_option_value=$(tmux show-option -gqv "$_option_name") + if [[ -n "$_current_option_value" ]]; then + echo "$_current_option_value" + else + echo "$_default_value" + fi +} + +# get desired window-option from tmux or default +tmux_get_window_option() { + local _option_name _default_value + _option_name="$1" + _default_value="$2" + + local _current_option_value + _current_option_value=$(tmux show-window-option -gqv "$_option_name") + if [[ -n "$_current_option_value" ]]; then + echo "$_current_option_value" + else + echo "$_default_value" + fi +} + +# append preconfigured tmux set-option to global array +tmux_append_seto() { + local _option _value _result + _option="$1" + _value="$2" + TMUX_CMDS+=("set-option" "-gq" "${_option}" "${_value}" ";") +} + +# append preconfigured tmux set-window-option to global array +tmux_append_setwo() { + local _option _value _result + _option="$1" + _value="$2" + TMUX_CMDS+=("set-window-option" "-gq" "${_option}" "${_value}" ";") +} + +# imediately execute tmux option +tmux_set_option_now() { + local _option_name _value + _option_name="$1" + _value="$2" + tmux set-option -gq "$_option_name" "$_value" +} + +# imediately execute tmux option +tmux_set_window_option_now() { + local _option_name _value + _option_name="$1" + _value="$2" + tmux set-window-option -gq "$_option_name" "$_value" +} diff --git a/.zshrc b/.zshrc index bd4af48..ed8a686 100644 --- a/.zshrc +++ b/.zshrc @@ -194,9 +194,13 @@ config config status.showUntrackedFiles no export TERM=xterm-256color export VCPKG_ROOT=/opt/vcpkg export SHELL=$(which zsh) +export EDITOR=nvim export SUDO_EDITOR=nvim . "$HOME/.local/bin/env" 2>/dev/null [ -f ~/.fzf.zsh ] && source ~/.fzf.zsh + +# opencode +export PATH=/home/chodak/.opencode/bin:$PATH