Compare commits
37 Commits
cb6606340f
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
311a89c0e6
|
|||
|
874311fcb0
|
|||
|
e648c1f1a6
|
|||
|
f789df0f02
|
|||
|
417d48f0f5
|
|||
|
a60f923e59
|
|||
|
fff6a726d8
|
|||
|
ac91f71a92
|
|||
|
5fefee5e2c
|
|||
|
6f90fe5d28
|
|||
|
b043039705
|
|||
|
9453784fb8
|
|||
|
410021ae9e
|
|||
|
6a70cb85a3
|
|||
|
24b90c6721
|
|||
|
26e7b292d7
|
|||
|
6c1bc55687
|
|||
|
de839f7faf
|
|||
|
12d3fdcaa5
|
|||
|
88c522e9d1
|
|||
|
e3c273516e
|
|||
|
c09865abbc
|
|||
|
8e2029a768
|
|||
|
1d9a7cfecf
|
|||
|
73c5a74d0f
|
|||
|
294788a314
|
|||
|
454262a803
|
|||
|
266ea92f4a
|
|||
|
8562298d83
|
|||
| 315f9442ae | |||
|
1f52782226
|
|||
|
7f41488da6
|
|||
|
561be8b27a
|
|||
|
fb6289e032
|
|||
|
e022516712
|
|||
|
18ac682f98
|
|||
|
93e8a13765
|
@@ -4,3 +4,6 @@
|
||||
[submodule "assets/yazi-catppuccin"]
|
||||
path = assets/yazi-catppuccin
|
||||
url = https://github.com/catppuccin/yazi.git
|
||||
[submodule "config/ghostty/.config/ghostty/shaders"]
|
||||
path = config/ghostty/.config/ghostty/shaders
|
||||
url = https://github.com/0xhckr/ghostty-shaders.git
|
||||
|
||||
@@ -3,19 +3,9 @@
|
||||
## How it looks like...
|
||||
|
||||
<details>
|
||||
<summary>Hyprland & Waybar & Eww</summary>
|
||||
|
||||
<figure>
|
||||
<img src="https://github.com/Uyanide/backgrounds/blob/master/screenshots/desktop.jpg?raw=true"/>
|
||||
</figure>
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Niri & Quickshell</summary>
|
||||
|
||||
https://github.com/user-attachments/assets/1fd0f3be-e83f-4d1c-9e4f-16cc77e3981b
|
||||
https://github.com/user-attachments/assets/2550607a-48ea-4662-98ba-d26722b26b1b
|
||||
|
||||
<figure>
|
||||
<img src="https://github.com/Uyanide/backgrounds/blob/master/screenshots/desktop-alt.webp?raw=true"/>
|
||||
@@ -47,10 +37,10 @@ https://github.com/user-attachments/assets/1fd0f3be-e83f-4d1c-9e4f-16cc77e3981b
|
||||
- Bar: ~~Waybar~~ | **Quickshell**
|
||||
- Shell: (bash & fish) | **Zsh**
|
||||
- Prompt: Oh My Posh | **Starship**
|
||||
- Terminal: **Kitty** & (**WezTerm** | Ghostty)
|
||||
- Terminal: **Kitty** | WezTerm | Ghostty
|
||||
- Power Menu: **Wlogout** & Quickshell
|
||||
- Colorscheme: **Catppuccin Mocha**
|
||||
- App Launcher: **Rofi** | ~~Fuzzel~~
|
||||
- App Launcher: ~~Rofi~~ | ~~Fuzzel~~ | **vicinae**
|
||||
- Desktop Widgets: ~~Eww~~ | **Quickshell**
|
||||
- Wallpaper Daemon: ~~Awww~~ | **Quickshell**
|
||||
- Notification Daemon: ~~Mako~~ | **Quickshell**
|
||||
@@ -66,22 +56,12 @@ Not based on, but heavily depends on many modules from (an old version of) [noct
|
||||
|
||||
This setup is currently only adapted for Niri.
|
||||
|
||||
## Eww
|
||||
|
||||
- `main`, main dashboard, modified from [syndrizzle/hotfiles](https://github.com/syndrizzle/hotfiles/tree/bspwm) but without notification center.
|
||||
- `lyrics`, scrolling lyrics player, depends on [a small utility](https://github.com/Uyanide/Spotify_Lyrics) from myself <small>(which also happens to be my frist Golang program :D)</small>.
|
||||
- `lyrics-single`, similar to `lyrics`, but only with a single line and can be easily embeded into the status bar.
|
||||
|
||||
## Wallpaper & Colortheme
|
||||
|
||||
- [WallReel](https://github.com/Uyanide/WallReel): an Image Carousel implemented with QtQuick to browse and set wallpapers from.
|
||||
- [change-colortheme](./config/scripts/.local/scripts/change-colortheme): script that extract colors from the current wallpaper and generate a catppuccin color scheme accordingly.
|
||||
- [backgrounds](https://github.com/Uyanide/backgrounds) collection for personal use (mostly waifus).
|
||||
|
||||
## Rofi
|
||||
|
||||
Based on [codeopshq/dotfiles](https://github.com/codeopshq/dotfiles), also serves as the clipboard history browser and emoji picker.
|
||||
|
||||
## Grub theme
|
||||
|
||||
Based on [vinceliuice/Elegant-grub2-themes](https://github.com/vinceliuice/Elegant-grub2-themes) with an [illustration from 紺屋](https://www.pixiv.net/artworks/119683453).
|
||||
@@ -89,3 +69,43 @@ Based on [vinceliuice/Elegant-grub2-themes](https://github.com/vinceliuice/Elega
|
||||
## Fonts
|
||||
|
||||
See [fontconfig.md](https://github.com/Uyanide/dotfiles/blob/main/memo/fontconfig.md).
|
||||
|
||||
---
|
||||
|
||||
<details>
|
||||
<summary>Previous setup</summary>
|
||||
|
||||
## How it looks like...
|
||||
|
||||
<figure>
|
||||
<img src="https://github.com/Uyanide/backgrounds/blob/master/screenshots/desktop.jpg?raw=true"/>
|
||||
</figure>
|
||||
|
||||
## Hyprland & friends
|
||||
|
||||
Based on an old version of [end-4/dots-hyprland](https://github.com/end-4/dots-hyprland) but without ags, quickshell, eww and tons of other stuff.
|
||||
|
||||
## Eww
|
||||
|
||||
- `main`, main dashboard, modified from [syndrizzle/hotfiles](https://github.com/syndrizzle/hotfiles/tree/bspwm) but without notification center.
|
||||
- `lyrics`, scrolling lyrics player, depends on [a small utility](https://github.com/Uyanide/Spotify_Lyrics) from myself <small>(which also happens to be my frist Golang program :D)</small>.
|
||||
- `lyrics-single`, similar to `lyrics`, but only with a single line and can be easily embeded into the status bar.
|
||||
|
||||
## Swww
|
||||
|
||||
The wallpaper will be automatically blurred when there is a window in focus, which is implemented in the [wallpaper-daemon](https://github.com/Uyanide/dotfiles/blob/main/.scripts/wallpaper-daemon) script.
|
||||
|
||||
This feature is only enabled in Niri. Swww also manages wallpapers of the Hyprland setup, yet only in the regular way.
|
||||
|
||||
## Wallpaper & Colortheme
|
||||
|
||||
The most suitable primary color (or so-called flavor) will be chosen from the [Catppuccin Mocha](https://catppuccin.com/palette/) palette and applied to various apps automatically after changing wallpaper. And also:
|
||||
|
||||
- [wallpaper-chooser](https://github.com/Uyanide/Wallpaper_Chooser) to select wallpaper, which implements an Image Carousel with Qt Widgets.
|
||||
- [backgrounds collection](https://github.com/Uyanide/backgrounds) for personal use.
|
||||
|
||||
## Rofi
|
||||
|
||||
Based on [codeopshq/dotfiles](https://github.com/codeopshq/dotfiles), also serves as the clipboard history browser and emoji picker.
|
||||
|
||||
</details>
|
||||
|
||||
@@ -17,7 +17,6 @@ TUI_PKGS = [
|
||||
*BASE_PKGS,
|
||||
"fastfetch", # sys info,
|
||||
"helix", # editor
|
||||
"nvim", # editor
|
||||
"shell", # fish & .bash_profile & shell prompt
|
||||
"yazi", # terminal file manager
|
||||
]
|
||||
@@ -55,7 +54,7 @@ NIRI_PKGS = [
|
||||
"hypr", # for hyprlock & hypridle
|
||||
"niri", # wm config
|
||||
"quickshell", # widgets & status bar & notifications & ...
|
||||
"rofi", # application launcher
|
||||
"vicinae", # application launcher
|
||||
"wlogout", # logout menu
|
||||
]
|
||||
|
||||
@@ -67,12 +66,6 @@ PKGS = {
|
||||
"niri": NIRI_PKGS,
|
||||
}
|
||||
|
||||
SESSION_NAME = {
|
||||
"hyprland": "Hyprland",
|
||||
"niri": "niri",
|
||||
"default": "default",
|
||||
}
|
||||
|
||||
|
||||
PKGS_PATH = Path(__file__).resolve().parent.resolve() / "config"
|
||||
DEST_PATH = Path.home().expanduser()
|
||||
@@ -103,13 +96,8 @@ def stow(pkg: str):
|
||||
|
||||
def unstow(pkg: str):
|
||||
subprocess.run(
|
||||
["stow", "-v", "-d", str(PKGS_PATH), "-t", str(DEST_PATH), "-D", pkg], check=True,
|
||||
)
|
||||
|
||||
|
||||
def switch(session: str):
|
||||
subprocess.run(
|
||||
[str(Path("~/.local/scripts/config-switch").expanduser()), session], check=True
|
||||
["stow", "-v", "-d", str(PKGS_PATH), "-t", str(DEST_PATH), "-D", pkg],
|
||||
check=True,
|
||||
)
|
||||
|
||||
|
||||
@@ -147,17 +135,6 @@ def main():
|
||||
if is_unstow:
|
||||
return # No need to switch session if we're just unstowing
|
||||
|
||||
if args.package in SESSION_NAME:
|
||||
session = SESSION_NAME[args.package]
|
||||
else:
|
||||
session = SESSION_NAME["default"]
|
||||
|
||||
try:
|
||||
switch(session)
|
||||
_log("INFO", f"Switched to session profile '{session}'.")
|
||||
except subprocess.CalledProcessError as e:
|
||||
_log("ERROR", f"Failed to switch session profile '{session}': {e}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
shaders
|
||||
@@ -1,11 +1,14 @@
|
||||
theme = Catppuccin Mocha
|
||||
|
||||
background-opacity = 0.75
|
||||
background-opacity = 0.9
|
||||
background-blur = true
|
||||
|
||||
window-padding-x = 10
|
||||
window-padding-y = 10
|
||||
|
||||
window-width = 100
|
||||
window-height = 36
|
||||
|
||||
keybind = ctrl+shift+r=reload_config
|
||||
|
||||
keybind = ctrl+shift+h=write_screen_file:copy
|
||||
|
||||
@@ -2,48 +2,56 @@ theme = "catppuccin_mocha"
|
||||
|
||||
[editor]
|
||||
default-yank-register = "+"
|
||||
shell = ["bash", "-c"]
|
||||
line-number = "relative"
|
||||
indent-guides.render = true
|
||||
shell = ["bash", "-c"]
|
||||
line-number = "relative"
|
||||
indent-guides.render = true
|
||||
trim-trailing-whitespace = true
|
||||
|
||||
[editor.cursor-shape]
|
||||
insert = "bar"
|
||||
normal = "block"
|
||||
select = "underline"
|
||||
|
||||
[editor.whitespace.render]
|
||||
space = "none"
|
||||
tab = "all"
|
||||
nbsp = "none"
|
||||
nnbsp = "none"
|
||||
newline = "none"
|
||||
|
||||
[keys.normal]
|
||||
# "esc" = "collapse_selection"
|
||||
"-" = "collapse_selection"
|
||||
"-" = "collapse_selection"
|
||||
"A-minus" = "flip_selections"
|
||||
"#" = "switch_to_lowercase"
|
||||
"A-#" = "switch_to_uppercase"
|
||||
"#" = "switch_to_lowercase"
|
||||
"A-#" = "switch_to_uppercase"
|
||||
"+" = "select_register"
|
||||
|
||||
# Previously "["
|
||||
[keys.normal."ö"]
|
||||
"d" = "goto_prev_diag"
|
||||
"D" = "goto_first_diag"
|
||||
"f" = "goto_prev_function"
|
||||
"t" = "goto_prev_class"
|
||||
"a" = "goto_prev_parameter"
|
||||
"c" = "goto_prev_comment"
|
||||
"T" = "goto_prev_test"
|
||||
"p" = "goto_prev_paragraph"
|
||||
"g" = "goto_prev_change"
|
||||
"G" = "goto_first_change"
|
||||
"d" = "goto_prev_diag"
|
||||
"D" = "goto_first_diag"
|
||||
"f" = "goto_prev_function"
|
||||
"t" = "goto_prev_class"
|
||||
"a" = "goto_prev_parameter"
|
||||
"c" = "goto_prev_comment"
|
||||
"T" = "goto_prev_test"
|
||||
"p" = "goto_prev_paragraph"
|
||||
"g" = "goto_prev_change"
|
||||
"G" = "goto_first_change"
|
||||
"space" = "add_newline_above"
|
||||
|
||||
# Previously "]"
|
||||
[keys.normal."ä"]
|
||||
"d" = "goto_next_diag"
|
||||
"D" = "goto_last_diag"
|
||||
"f" = "goto_next_function"
|
||||
"t" = "goto_next_class"
|
||||
"a" = "goto_next_parameter"
|
||||
"c" = "goto_next_comment"
|
||||
"T" = "goto_next_test"
|
||||
"p" = "goto_next_paragraph"
|
||||
"g" = "goto_next_change"
|
||||
"G" = "goto_last_change"
|
||||
"d" = "goto_next_diag"
|
||||
"D" = "goto_last_diag"
|
||||
"f" = "goto_next_function"
|
||||
"t" = "goto_next_class"
|
||||
"a" = "goto_next_parameter"
|
||||
"c" = "goto_next_comment"
|
||||
"T" = "goto_next_test"
|
||||
"p" = "goto_next_paragraph"
|
||||
"g" = "goto_next_change"
|
||||
"G" = "goto_last_change"
|
||||
"space" = "add_newline_below"
|
||||
|
||||
# [keys.insert."j"]
|
||||
|
||||
@@ -1,13 +1,7 @@
|
||||
[[language]]
|
||||
name = "c"
|
||||
auto-format = true
|
||||
indent = { tab-width = 4, unit = " " }
|
||||
|
||||
[[language]]
|
||||
name = "cpp"
|
||||
auto-format = true
|
||||
indent = { tab-width = 4, unit = " " }
|
||||
|
||||
[[language]]
|
||||
name = "toml"
|
||||
auto-format = true
|
||||
|
||||
@@ -1,48 +0,0 @@
|
||||
allow_remote_control yes
|
||||
listen_on unix:/tmp/kitty
|
||||
shell_integration enabled
|
||||
|
||||
# kitty-scrollback.nvim Kitten alias
|
||||
action_alias kitty_scrollback_nvim kitten $HOME/.local/share/nvim/lazy/kitty-scrollback.nvim/python/kitty_scrollback_nvim.py
|
||||
# Browse scrollback buffer in nvim
|
||||
map kitty_mod+h kitty_scrollback_nvim
|
||||
# Browse output of the last shell command in nvim
|
||||
map kitty_mod+g kitty_scrollback_nvim --config ksb_builtin_last_cmd_output
|
||||
# Show clicked command output in nvim
|
||||
mouse_map ctrl+shift+right press ungrabbed combine : mouse_select_command_output : kitty_scrollback_nvim --config ksb_builtin_last_visited_cmd_output
|
||||
|
||||
# disable the stupid notification
|
||||
confirm_os_window_close 0
|
||||
|
||||
# set shell to zsh
|
||||
shell /bin/zsh
|
||||
|
||||
# hide_window_decorations yes
|
||||
window_padding_width 10
|
||||
|
||||
background_opacity 0.75
|
||||
background_blur 16
|
||||
|
||||
font_family monospace
|
||||
font_size 12
|
||||
|
||||
tab_bar_style powerline
|
||||
tab_powerline_style round
|
||||
tab_title_template {title}{' :{}:'.format(num_windows) if num_windows > 1 else ''}
|
||||
|
||||
map ctrl+up previous_window
|
||||
map ctrl+down next_window
|
||||
|
||||
cursor_trail 1
|
||||
cursor_shape beam
|
||||
|
||||
include Catppuccin-Mocha.conf
|
||||
|
||||
map ctrl+plus change_font_size all +1
|
||||
map ctrl+kp_add change_font_size all +1
|
||||
|
||||
map ctrl+minus change_font_size all -1
|
||||
map ctrl+kp_subtract change_font_size all -1
|
||||
|
||||
map ctrl+0 change_font_size all 0
|
||||
map ctrl+kp_0 change_font_size all 0
|
||||
@@ -1,80 +0,0 @@
|
||||
# vim:ft=kitty
|
||||
|
||||
## name: Catppuccin-Mocha
|
||||
## author: Pocco81 (https://github.com/Pocco81)
|
||||
## license: MIT
|
||||
## upstream: https://github.com/catppuccin/kitty/blob/main/mocha.conf
|
||||
## blurb: Soothing pastel theme for the high-spirited!
|
||||
|
||||
|
||||
|
||||
# The basic colors
|
||||
foreground #CDD6F4
|
||||
background #1E1E2E
|
||||
selection_foreground #1E1E2E
|
||||
selection_background #F5E0DC
|
||||
|
||||
# Cursor colors
|
||||
cursor #F5E0DC
|
||||
cursor_text_color #1E1E2E
|
||||
|
||||
# URL underline color when hovering with mouse
|
||||
url_color #F5E0DC
|
||||
|
||||
# Kitty window border colors
|
||||
active_border_color #B4BEFE
|
||||
inactive_border_color #6C7086
|
||||
bell_border_color #F9E2AF
|
||||
|
||||
# OS Window titlebar colors
|
||||
wayland_titlebar_color system
|
||||
macos_titlebar_color system
|
||||
|
||||
# Tab bar colors
|
||||
active_tab_foreground #11111B
|
||||
active_tab_background #CBA6F7
|
||||
inactive_tab_foreground #CDD6F4
|
||||
inactive_tab_background #181825
|
||||
tab_bar_background #11111B
|
||||
|
||||
# Colors for marks (marked text in the terminal)
|
||||
mark1_foreground #1E1E2E
|
||||
mark1_background #B4BEFE
|
||||
mark2_foreground #1E1E2E
|
||||
mark2_background #CBA6F7
|
||||
mark3_foreground #1E1E2E
|
||||
mark3_background #74C7EC
|
||||
|
||||
# The 16 terminal colors
|
||||
|
||||
# black
|
||||
color0 #45475A
|
||||
color8 #585B70
|
||||
|
||||
# red
|
||||
color1 #F38BA8
|
||||
color9 #F38BA8
|
||||
|
||||
# green
|
||||
color2 #A6E3A1
|
||||
color10 #A6E3A1
|
||||
|
||||
# yellow
|
||||
color3 #F9E2AF
|
||||
color11 #F9E2AF
|
||||
|
||||
# blue
|
||||
color4 #89B4FA
|
||||
color12 #89B4FA
|
||||
|
||||
# magenta
|
||||
color5 #F5C2E7
|
||||
color13 #F5C2E7
|
||||
|
||||
# cyan
|
||||
color6 #94E2D5
|
||||
color14 #94E2D5
|
||||
|
||||
# white
|
||||
color7 #BAC2DE
|
||||
color15 #A6ADC8
|
||||
@@ -0,0 +1,7 @@
|
||||
include kitty.conf
|
||||
|
||||
remember_window_size false
|
||||
initial_window_width 960
|
||||
initial_window_height 720
|
||||
|
||||
window_padding_width 5
|
||||
@@ -3,13 +3,13 @@ listen_on unix:/tmp/kitty
|
||||
shell_integration enabled
|
||||
|
||||
# kitty-scrollback.nvim Kitten alias
|
||||
action_alias kitty_scrollback_nvim kitten $HOME/.local/share/nvim/lazy/kitty-scrollback.nvim/python/kitty_scrollback_nvim.py
|
||||
# action_alias kitty_scrollback_nvim kitten $HOME/.local/share/nvim/lazy/kitty-scrollback.nvim/python/kitty_scrollback_nvim.py
|
||||
# Browse scrollback buffer in nvim
|
||||
map kitty_mod+h kitty_scrollback_nvim
|
||||
# map kitty_mod+h kitty_scrollback_nvim
|
||||
# Browse output of the last shell command in nvim
|
||||
map kitty_mod+g kitty_scrollback_nvim --config ksb_builtin_last_cmd_output
|
||||
# map kitty_mod+g kitty_scrollback_nvim --config ksb_builtin_last_cmd_output
|
||||
# Show clicked command output in nvim
|
||||
mouse_map ctrl+shift+right press ungrabbed combine : mouse_select_command_output : kitty_scrollback_nvim --config ksb_builtin_last_visited_cmd_output
|
||||
# mouse_map ctrl+shift+right press ungrabbed combine : mouse_select_command_output : kitty_scrollback_nvim --config ksb_builtin_last_visited_cmd_output
|
||||
|
||||
# disable the stupid notification
|
||||
confirm_os_window_close 0
|
||||
@@ -20,7 +20,7 @@ shell /bin/zsh
|
||||
# hide_window_decorations yes
|
||||
window_padding_width 10
|
||||
|
||||
background_opacity 0.95
|
||||
background_opacity 0.9
|
||||
background_blur 16
|
||||
|
||||
font_family monospace
|
||||
@@ -12,16 +12,18 @@ binds {
|
||||
// Apps
|
||||
Mod+C repeat=false { spawn "code"; }
|
||||
Mod+E repeat=false { spawn "dolphin" "--new-window"; }
|
||||
Mod+Shift+E repeat=false { spawn "nautilus" "--new-window"; }
|
||||
Mod+W repeat=false { spawn-sh "zen || zen-browser"; }
|
||||
Mod+B repeat=false { spawn-sh "pkill -x -n btop || wezterm -e btop"; }
|
||||
Mod+Shift+T repeat=false { spawn "wezterm"; }
|
||||
Mod+Shift+Return repeat=false { spawn "wezterm"; }
|
||||
Mod+B repeat=false { spawn-sh "pkill -x -n btop || kitty-floating -e btop"; }
|
||||
Mod+Shift+T repeat=false { spawn "kitty-floating"; }
|
||||
Mod+Shift+Return repeat=false { spawn "kitty-floating"; }
|
||||
Mod+T repeat=false { spawn "kitty"; }
|
||||
Mod+Return repeat=false { spawn "kitty"; }
|
||||
Mod+Shift+W repeat=false { spawn "wallreel"; }
|
||||
Mod+O repeat=false { spawn-sh "pkill -x -n pwvucontrol || pwvucontrol"; }
|
||||
Ctrl+Alt+Delete repeat=false { spawn-sh "pkill -x wlogout || wlogout"; }
|
||||
Mod+P repeat=false { spawn-sh "wl-mirror $(niri msg --json focused-output | jq -r .name)"; }
|
||||
Mod+H repeat=false { spawn "hexecute"; }
|
||||
|
||||
|
||||
// Quickshell
|
||||
@@ -32,20 +34,20 @@ binds {
|
||||
Mod+I repeat=false { spawn "qs" "ipc" "call" "idleInhibitor" "toggle"; }
|
||||
Mod+Alt+R repeat=false { spawn "qs" "ipc" "call" "recording" "startOrStop"; }
|
||||
Mod+Alt+G repeat=false { spawn "qs" "ipc" "call" "recording" "saveReplay"; }
|
||||
Mod+Shift+E repeat=false { spawn "qs" "ipc" "call" "sunset" "toggle"; }
|
||||
Mod+S repeat=false { spawn "qs" "ipc" "call" "sunset" "toggle"; }
|
||||
Mod+X repeat=false { spawn "qs" "ipc" "call" "notes" "openRecent"; }
|
||||
Mod+Shift+X repeat=false { spawn "qs" "ipc" "call" "notes" "create"; }
|
||||
|
||||
// Rofi
|
||||
Mod+D repeat=false { spawn-sh "pkill -x rofi || rofi -show run"; }
|
||||
Alt+Space repeat=false { spawn-sh "pkill -x rofi || rofi -show drun"; }
|
||||
// Launcher
|
||||
Alt+Space repeat=false { spawn "vicinae" "toggle"; }
|
||||
Mod+V repeat=false { spawn "vicinae" "vicinae://launch/clipboard/history?toggle=true"; }
|
||||
Mod+Period repeat=false { spawn "vicinae" "vicinae://launch/core/search-emojis?toggle=true"; }
|
||||
Mod+D repeat=false { spawn "vicinae" "vicinae://launch/system/run?toggle=true"; }
|
||||
|
||||
// Actions
|
||||
Mod+V repeat=false { spawn "wezterm" "start" "--" "fzfclip-wrap"; }
|
||||
Mod+Period repeat=false { spawn-sh "pkill -x rofi || rofi-emoji"; }
|
||||
Print repeat=false { screenshot-screen; }
|
||||
Mod+Shift+S repeat=false { screenshot; }
|
||||
Mod+Ctrl+Shift+S repeat=false { screenshot-window; }
|
||||
Print repeat=false { screenshot-screen show-pointer=false; }
|
||||
Mod+Shift+S repeat=false { screenshot show-pointer=false; }
|
||||
Mod+Ctrl+Shift+S repeat=false { screenshot-window show-pointer=false; }
|
||||
Mod+Shift+C repeat=false { spawn "hyprpicker" "-a"; }
|
||||
|
||||
// Media
|
||||
@@ -63,10 +65,11 @@ binds {
|
||||
XF86MonBrightnessDown allow-when-locked=true { spawn "qs" "ipc" "call" "brightness" "down"; }
|
||||
|
||||
// Window management
|
||||
Mod+Tab repeat=false { toggle-overview; }
|
||||
Mod+Tab repeat=false { toggle-overview; }
|
||||
|
||||
Mod+Q repeat=false { close-window; }
|
||||
Alt+F4 repeat=false { close-window; } // can't imagine this does not come as default
|
||||
Mod+Q repeat=false { close-window; }
|
||||
Mod+Shift+Q repeat=false { spawn "niri-force-kill-window"; }
|
||||
Alt+F4 repeat=false { close-window; } // can't imagine this does not come as default
|
||||
|
||||
Mod+Left { focus-column-left; }
|
||||
Mod+Down { focus-window-or-workspace-down; }
|
||||
@@ -159,8 +162,8 @@ binds {
|
||||
Mod+Escape allow-inhibiting=false repeat=false { toggle-keyboard-shortcuts-inhibit; }
|
||||
|
||||
// Session
|
||||
Mod+Shift+Q allow-inhibiting=false repeat=false { quit; }
|
||||
Mod+Shift+P allow-inhibiting=false repeat=false { spawn-sh "hyprlock & niri msg action power-off-monitors"; }
|
||||
Mod+K allow-inhibiting=false repeat=false { quit; }
|
||||
Mod+Shift+P allow-inhibiting=false repeat=false { spawn-sh "loginctl lock-session; niri msg action power-off-monitors"; }
|
||||
Mod+L allow-inhibiting=false repeat=false { spawn "loginctl" "lock-session"; }
|
||||
|
||||
}
|
||||
|
||||
@@ -1,21 +1,8 @@
|
||||
// Switch configs
|
||||
spawn-at-startup "config-switch" "niri"
|
||||
|
||||
// Not necessary maybe ...
|
||||
spawn-at-startup "fcitx5"
|
||||
|
||||
// Core
|
||||
spawn-at-startup "nm-applet"
|
||||
spawn-at-startup "gnome-keyring-daemon" "--start" "--components=secrets"
|
||||
spawn-at-startup "/usr/lib/polkit-gnome/polkit-gnome-authentication-agent-1"
|
||||
|
||||
// Clipboard history
|
||||
spawn-at-startup "wl-paste" "--type" "text" "--watch" "cliphist" "store"
|
||||
spawn-at-startup "wl-paste" "--type" "image" "--watch" "cliphist" "store"
|
||||
|
||||
// wlsunset
|
||||
// spawn-at-startup "sunset" // managed by quickshell
|
||||
|
||||
// Logitech
|
||||
spawn-at-startup "solaar" "-w" "hide"
|
||||
|
||||
@@ -30,7 +17,5 @@ spawn-at-startup "hypridle"
|
||||
// QuickShell
|
||||
spawn-at-startup "quickshell"
|
||||
|
||||
// According to (https://ghostty.org/docs/linux/systemd#starting-ghostty-at-login)
|
||||
// spawn-sh-at-startup "systemctl start --user app-com.mitchellh.ghostty.service"
|
||||
//
|
||||
// spawn-at-startup "flatpak" "run" "com.gopeed.Gopeed" "--hidden"
|
||||
// Vicinae
|
||||
spawn-at-startup "vicinae" "server"
|
||||
|
||||
@@ -2,6 +2,7 @@ screenshot-path "~/Pictures/Screenshots/niri_screenshot_%Y-%m-%d_%H-%M-%S.png"
|
||||
|
||||
debug {
|
||||
render-drm-device "/dev/dri/renderD129"
|
||||
honor-xdg-activation-with-invalid-serial
|
||||
}
|
||||
|
||||
// gestures {
|
||||
|
||||
@@ -19,6 +19,8 @@ window-rule {
|
||||
// FLoating terminal
|
||||
window-rule {
|
||||
match app-id="org.wezfurlong.wezterm"
|
||||
match app-id="com.mitchellh.ghostty"
|
||||
match app-id="kitty-floating"
|
||||
open-floating true
|
||||
default-column-width { proportion 0.5; }
|
||||
}
|
||||
@@ -60,9 +62,16 @@ window-rule {
|
||||
open-floating true
|
||||
}
|
||||
|
||||
// QQ
|
||||
window-rule {
|
||||
match app-id="QQ" title="资料卡"
|
||||
match app-id="QQ" title="天气"
|
||||
open-focused false
|
||||
}
|
||||
|
||||
// Block from recording
|
||||
window-rule {
|
||||
match app-id="thunderbird"
|
||||
match app-id="org.mozilla.Thunderbird"
|
||||
|
||||
block-out-from "screen-capture"
|
||||
}
|
||||
|
||||
@@ -66,8 +66,13 @@ animations {
|
||||
// slowdown 3.0
|
||||
|
||||
workspace-switch {
|
||||
duration-ms 300
|
||||
curve "ease-out-cubic"
|
||||
duration-ms 300
|
||||
curve "ease-out-cubic"
|
||||
}
|
||||
|
||||
overview-open-close {
|
||||
duration-ms 300
|
||||
curve "ease-out-cubic"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,10 +82,20 @@ layer-rule {
|
||||
|
||||
}
|
||||
|
||||
cursor {
|
||||
xcursor-theme "Bibata-Modern-Ice"
|
||||
xcursor-size 24
|
||||
hide-when-typing
|
||||
layer-rule {
|
||||
match layer="top"
|
||||
match layer="overlay"
|
||||
|
||||
background-effect {
|
||||
xray false
|
||||
}
|
||||
}
|
||||
|
||||
window-rule {
|
||||
match is-floating=true
|
||||
background-effect {
|
||||
xray false
|
||||
}
|
||||
}
|
||||
|
||||
// I love rounded corners
|
||||
@@ -89,6 +104,12 @@ window-rule {
|
||||
clip-to-geometry true
|
||||
}
|
||||
|
||||
cursor {
|
||||
xcursor-theme "Bibata-Modern-Ice"
|
||||
xcursor-size 24
|
||||
hide-when-typing
|
||||
}
|
||||
|
||||
recent-windows {
|
||||
highlight {
|
||||
active-color "#89b4fa"
|
||||
|
||||
@@ -1 +1,4 @@
|
||||
file:///home/kolkas/Videos Videos
|
||||
file:///home/kolkas/Repositories Repositories
|
||||
file:///home/kolkas/Pictures Pictures
|
||||
file:///home/kolkas/Desktop
|
||||
|
||||
@@ -12,8 +12,9 @@ gtk-enable-input-feedback-sounds=0
|
||||
gtk-font-name=Sarasa UI SC, 10
|
||||
gtk-icon-theme-name=Papirus
|
||||
gtk-menu-images=true
|
||||
gtk-modules=colorreload-gtk-module
|
||||
gtk-modules=colorreload-gtk-module:appmenu-gtk-module
|
||||
gtk-primary-button-warps-slider=true
|
||||
gtk-shell-shows-menubar=1
|
||||
gtk-sound-theme-name=ocean
|
||||
gtk-theme-name=catppuccin-mocha-blue-standard+default
|
||||
gtk-toolbar-icon-size=GTK_ICON_SIZE_LARGE_TOOLBAR
|
||||
|
||||
@@ -14,6 +14,7 @@ Rectangle {
|
||||
id: root
|
||||
|
||||
property ShellScreen screen
|
||||
property var activeTrayItem: null
|
||||
|
||||
implicitWidth: trayFlow.implicitWidth + 20
|
||||
implicitHeight: parent.height
|
||||
@@ -90,10 +91,15 @@ Rectangle {
|
||||
|
||||
modelData.secondaryActivate && modelData.secondaryActivate()
|
||||
} else if (mouse.button === Qt.RightButton) {
|
||||
// Close the menu if it was visible
|
||||
if (trayPanel && trayPanel.visible) {
|
||||
// Right-click the same icon toggles menu off.
|
||||
if (root.activeTrayItem === modelData) {
|
||||
trayPanel.close()
|
||||
return
|
||||
}
|
||||
|
||||
// Switch directly to another tray item's menu.
|
||||
trayPanel.close()
|
||||
return
|
||||
}
|
||||
|
||||
if (modelData.hasMenu && modelData.menu && trayMenu.item) {
|
||||
@@ -105,15 +111,13 @@ Rectangle {
|
||||
menuX = (width / 2) - (trayMenu.item.width / 2)
|
||||
menuY = root.height
|
||||
trayMenu.item.menu = modelData.menu
|
||||
root.activeTrayItem = modelData
|
||||
trayMenu.item.showAt(parent, menuX, menuY)
|
||||
} else {
|
||||
Logger.d("Tray", "No menu available for", modelData.id, "or trayMenu not set")
|
||||
}
|
||||
}
|
||||
}
|
||||
onEntered: {
|
||||
trayPanel.close()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -136,6 +140,7 @@ Rectangle {
|
||||
|
||||
function close() {
|
||||
visible = false
|
||||
root.activeTrayItem = null
|
||||
if (trayMenu.item) {
|
||||
trayMenu.item.hideMenu()
|
||||
}
|
||||
|
||||
@@ -14,7 +14,6 @@ PopupWindow {
|
||||
property real anchorX
|
||||
property real anchorY
|
||||
property bool isSubMenu: false
|
||||
property bool isHovered: rootMouseArea.containsMouse
|
||||
property ShellScreen screen
|
||||
|
||||
readonly property int menuWidth: 180
|
||||
@@ -67,11 +66,15 @@ PopupWindow {
|
||||
}
|
||||
}
|
||||
|
||||
// Full-sized, transparent MouseArea to track the mouse.
|
||||
MouseArea {
|
||||
id: rootMouseArea
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
function closeSiblingSubMenus(currentEntry) {
|
||||
for (var i = 0; i < columnLayout.children.length; i++) {
|
||||
const sibling = columnLayout.children[i]
|
||||
if (sibling !== currentEntry && sibling?.subMenu) {
|
||||
sibling.subMenu.hideMenu()
|
||||
sibling.subMenu.destroy()
|
||||
sibling.subMenu = null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
@@ -176,66 +179,46 @@ PopupWindow {
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
enabled: (modelData?.enabled ?? true) && !(modelData?.isSeparator ?? false) && root.visible
|
||||
acceptedButtons: Qt.LeftButton | Qt.RightButton
|
||||
|
||||
onClicked: {
|
||||
if (modelData && !modelData.isSeparator && !modelData.hasChildren) {
|
||||
modelData.triggered()
|
||||
root.hideMenu()
|
||||
}
|
||||
}
|
||||
|
||||
onEntered: {
|
||||
if (!root.visible)
|
||||
onClicked: mouse => {
|
||||
if (!modelData || modelData.isSeparator) {
|
||||
return
|
||||
|
||||
// Close all sibling submenus
|
||||
for (var i = 0; i < columnLayout.children.length; i++) {
|
||||
const sibling = columnLayout.children[i]
|
||||
if (sibling !== entry && sibling?.subMenu) {
|
||||
sibling.subMenu.hideMenu()
|
||||
sibling.subMenu.destroy()
|
||||
sibling.subMenu = null
|
||||
}
|
||||
}
|
||||
|
||||
// Create submenu if needed
|
||||
if (modelData?.hasChildren) {
|
||||
if (modelData.hasChildren) {
|
||||
if (entry.subMenu) {
|
||||
entry.subMenu.hideMenu()
|
||||
entry.subMenu.destroy()
|
||||
entry.subMenu = null
|
||||
return
|
||||
}
|
||||
|
||||
// Need a slight overlap so that menu don't close when moving the mouse to a submenu
|
||||
const submenuWidth = menuWidth // Assuming a similar width as the parent
|
||||
const overlap = 4 // A small overlap to bridge the mouse path
|
||||
root.closeSiblingSubMenus(entry)
|
||||
|
||||
// Position with overlap
|
||||
const anchorX = -submenuWidth + overlap
|
||||
const submenuWidth = menuWidth
|
||||
const overlap = 12
|
||||
const subAnchorX = -submenuWidth + overlap
|
||||
|
||||
// Create submenu
|
||||
entry.subMenu = Qt.createComponent("TrayMenu.qml").createObject(root, {
|
||||
"menu": modelData,
|
||||
"anchorItem": entry,
|
||||
"anchorX": anchorX,
|
||||
"anchorX": subAnchorX,
|
||||
"anchorY": 0,
|
||||
"isSubMenu": true,
|
||||
"screen": root.screen
|
||||
})
|
||||
|
||||
if (entry.subMenu) {
|
||||
entry.subMenu.showAt(entry, anchorX, 0)
|
||||
entry.subMenu.showAt(entry, subAnchorX, 0)
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
onExited: {
|
||||
Qt.callLater(() => {
|
||||
if (entry.subMenu && !entry.subMenu.isHovered) {
|
||||
entry.subMenu.hideMenu()
|
||||
entry.subMenu.destroy()
|
||||
entry.subMenu = null
|
||||
}
|
||||
})
|
||||
if (mouse.button === Qt.LeftButton || mouse.button === Qt.RightButton) {
|
||||
modelData.triggered()
|
||||
root.hideMenu()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,8 +6,6 @@ import qs.Modules.Bar.Services
|
||||
import qs.Services
|
||||
|
||||
UProgressExpand {
|
||||
// Quickshell.execDetached(["wezterm", "start", "--", "btop"]);
|
||||
|
||||
iconName: "cpu"
|
||||
fillColor: Colors.mCyan
|
||||
critical: SystemStatService.cpuUsage > 90
|
||||
|
||||
@@ -11,15 +11,23 @@ Item {
|
||||
property color fillColor: Colors.mRed
|
||||
property color _actualColor: Colors.mRed
|
||||
property bool _expand: mouseArea.containsMouse
|
||||
property string displayText: Niri.castOutputs.length > 0 ? Niri.castOutputs.join(", ") : "Casting"
|
||||
|
||||
visible: RecordService.isRecording
|
||||
visible: Niri.isCasting
|
||||
implicitHeight: Math.max(symbolIcon.implicitHeight, textLabel.implicitHeight)
|
||||
implicitWidth: height + expander.implicitWidth
|
||||
|
||||
Connections {
|
||||
target: Niri
|
||||
onCastOutputsListChanged: {
|
||||
root.displayText = Niri.castOutputs.length > 0 ? Niri.castOutputs.join(", ") : "Casting";
|
||||
}
|
||||
}
|
||||
|
||||
SequentialAnimation {
|
||||
id: blinkAnimation
|
||||
|
||||
running: RecordService.isRecording
|
||||
running: root.visible
|
||||
loops: Animation.Infinite
|
||||
|
||||
ColorAnimation {
|
||||
@@ -70,7 +78,7 @@ Item {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 5
|
||||
text: RecordService.recordingDisplay || "Recording"
|
||||
text: root.displayText
|
||||
color: root.fillColor
|
||||
}
|
||||
|
||||
@@ -92,12 +100,6 @@ Item {
|
||||
anchors.fill: parent
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
hoverEnabled: true
|
||||
acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.MiddleButton
|
||||
onClicked: (mouse) => {
|
||||
if (mouse.button === Qt.LeftButton)
|
||||
RecordService.startOrStop();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on _actualColor {
|
||||
|
||||
@@ -1,28 +1,102 @@
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import Quickshell.Io
|
||||
import qs.Components
|
||||
import qs.Constants
|
||||
import qs.Services
|
||||
|
||||
Text {
|
||||
text: TimeService.time + " | " + TimeService.dateString
|
||||
font.pointSize: Style.fontSizeM
|
||||
font.family: Fonts.primary
|
||||
color: Colors.mPrimary
|
||||
Item {
|
||||
id: root
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
acceptedButtons: Qt.LeftButton
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
action.running = !action.running;
|
||||
readonly property int switchDistance: Style.barHeight
|
||||
readonly property int animationDuration: Style.animationNormal
|
||||
|
||||
implicitWidth: Math.max(timeLayer.implicitWidth, notiLayer.implicitWidth)
|
||||
implicitHeight: Math.max(timeLayer.implicitHeight, notiLayer.implicitHeight)
|
||||
clip: true
|
||||
|
||||
UText {
|
||||
id: timeLayer
|
||||
|
||||
readonly property real restY: (root.height - implicitHeight) / 2
|
||||
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
y: TempNotificationService.active ? restY + root.switchDistance : restY
|
||||
opacity: TempNotificationService.active ? 0 : 1
|
||||
text: TimeService.time + " | " + TimeService.dateString
|
||||
color: Colors.mPrimary
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
acceptedButtons: Qt.LeftButton
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
action.running = !action.running;
|
||||
}
|
||||
}
|
||||
|
||||
Process {
|
||||
id: action
|
||||
|
||||
running: false
|
||||
command: ["vicinae", "toggle"]
|
||||
}
|
||||
|
||||
Behavior on y {
|
||||
NumberAnimation {
|
||||
duration: root.animationDuration
|
||||
easing.type: Easing.OutCubic
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Behavior on opacity {
|
||||
NumberAnimation {
|
||||
duration: root.animationDuration
|
||||
easing.type: Easing.OutCubic
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Process {
|
||||
id: action
|
||||
RowLayout {
|
||||
id: notiLayer
|
||||
|
||||
readonly property real restY: (root.height - implicitHeight) / 2
|
||||
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
y: TempNotificationService.active ? restY : restY - root.switchDistance
|
||||
opacity: TempNotificationService.active ? 1 : 0
|
||||
spacing: Style.marginXS
|
||||
|
||||
UIcon {
|
||||
visible: TempNotificationService.iconName !== ""
|
||||
iconName: TempNotificationService.iconName
|
||||
color: Colors.mPrimary
|
||||
}
|
||||
|
||||
UText {
|
||||
text: TempNotificationService.message
|
||||
color: Colors.mPrimary
|
||||
}
|
||||
|
||||
Behavior on y {
|
||||
NumberAnimation {
|
||||
duration: root.animationDuration
|
||||
easing.type: Easing.OutCubic
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Behavior on opacity {
|
||||
NumberAnimation {
|
||||
duration: root.animationDuration
|
||||
easing.type: Easing.OutCubic
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
running: false
|
||||
command: ["rofi", "-show", "drun"]
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ Singleton {
|
||||
id: process
|
||||
|
||||
running: false
|
||||
command: ["wezterm", "start", "--", "btop"]
|
||||
command: ["kitty-floating", "-e", "btop"]
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -633,4 +633,42 @@ Singleton {
|
||||
}
|
||||
Pipewire.preferredDefaultAudioSource = newSource;
|
||||
}
|
||||
|
||||
onVolumeChanged: {
|
||||
if (root.consumeOutputOSDSuppression()) {
|
||||
return;
|
||||
}
|
||||
if (root.muted) {
|
||||
TempNotificationService.showWithIcon("volume-mute", "Muted");
|
||||
return;
|
||||
}
|
||||
TempNotificationService.showWithIcon(root.getOutputIcon(), Math.round(root.volume * 100) + "%");
|
||||
}
|
||||
|
||||
onInputVolumeChanged: {
|
||||
if (root.consumeInputOSDSuppression()) {
|
||||
return;
|
||||
}
|
||||
if (root.inputMuted) {
|
||||
TempNotificationService.showWithIcon("volume-mute", "Muted");
|
||||
return;
|
||||
}
|
||||
TempNotificationService.showWithIcon(root.getInputIcon(), Math.round(root.inputVolume * 100) + "%");
|
||||
}
|
||||
|
||||
onMutedChanged: {
|
||||
if (root.muted) {
|
||||
TempNotificationService.showWithIcon("volume-mute", "Muted");
|
||||
} else {
|
||||
TempNotificationService.showWithIcon(root.getOutputIcon(), Math.round(root.volume * 100) + "%");
|
||||
}
|
||||
}
|
||||
|
||||
onInputMutedChanged: {
|
||||
if (root.inputMuted) {
|
||||
TempNotificationService.showWithIcon("microphone-mute", "Input Muted");
|
||||
} else {
|
||||
TempNotificationService.showWithIcon("microphone", "Input Unmuted");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import QtQuick
|
||||
import Quickshell
|
||||
import Quickshell.Io
|
||||
import qs.Services
|
||||
import qs.Utils
|
||||
pragma Singleton
|
||||
|
||||
@@ -161,6 +162,9 @@ Singleton {
|
||||
Component.onDestruction: {
|
||||
stopInhibition();
|
||||
}
|
||||
onIsInhibitedChanged: {
|
||||
TempNotificationService.showWithIcon("mug-filled", isInhibited ? "Inhibition active: " + reason : "Inhibition stopped");
|
||||
}
|
||||
|
||||
// Process for maintaining the inhibition (subprocess fallback only)
|
||||
Process {
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
import QtQuick
|
||||
import Quickshell
|
||||
import Quickshell.Io
|
||||
import qs.Services
|
||||
import qs.Utils
|
||||
pragma Singleton
|
||||
|
||||
Singleton {
|
||||
id: root
|
||||
|
||||
property bool isCapslockOn: false
|
||||
|
||||
onIsCapslockOnChanged: {
|
||||
if (root.isCapslockOn) {
|
||||
TempNotificationService.showWithIcon("letter-case-toggle", "CAPS LOCK ON");
|
||||
} else {
|
||||
TempNotificationService.showWithIcon("letter-case", "caps lock off");
|
||||
}
|
||||
}
|
||||
|
||||
Process {
|
||||
id: capslockMonitorProcess
|
||||
|
||||
running: true
|
||||
command: ["led-monitor", "-l", "capslock"]
|
||||
|
||||
stdout: SplitParser {
|
||||
splitMarker: "\n"
|
||||
onRead: (line) => {
|
||||
if (line.trim() === "1")
|
||||
root.isCapslockOn = true;
|
||||
else if (line.trim() === "0")
|
||||
root.isCapslockOn = false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -153,4 +153,16 @@ Item {
|
||||
target: "notes"
|
||||
}
|
||||
|
||||
IpcHandler {
|
||||
function showMsg(message: string, duration: int) {
|
||||
TempNotificationService.show(message, duration);
|
||||
}
|
||||
|
||||
function showWithIcon(iconName: string, message: string, duration: int) {
|
||||
TempNotificationService.showWithIcon(iconName, message, duration);
|
||||
}
|
||||
|
||||
target: "tempNotification"
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ Singleton {
|
||||
property bool dirsLoaded: false
|
||||
property bool initialized: dirsLoaded && ImageCacheService.initialized && ShellState.isLoaded && SettingsService.isLoaded
|
||||
|
||||
Component.onCompleted: {
|
||||
function mkdirs() {
|
||||
let mkdirs = "";
|
||||
for (const dir of [Paths.cacheDir, Paths.configDir, Paths.recordingDir, Paths.notesDir]) {
|
||||
mkdirs += `mkdir -p "${dir}" && `;
|
||||
@@ -22,6 +22,11 @@ Singleton {
|
||||
process.running = true;
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
ImageCacheService.init();
|
||||
root.mkdirs();
|
||||
}
|
||||
|
||||
Process {
|
||||
id: process
|
||||
|
||||
|
||||
@@ -193,7 +193,10 @@ Singleton {
|
||||
}
|
||||
}
|
||||
onInternalPositionChanged: updateIndex()
|
||||
onLyricsOffsetChanged: updateIndex()
|
||||
onLyricsOffsetChanged: () => {
|
||||
TempNotificationService.showWithIcon("hourglass-empty", root.lyricsOffset + "ms");
|
||||
updateIndex()
|
||||
}
|
||||
|
||||
Connections {
|
||||
function onCurrentPlayerChanged() {
|
||||
@@ -251,7 +254,7 @@ Singleton {
|
||||
}
|
||||
const player = this.queuedPlayer.toLowerCase();
|
||||
this.queuedPlayer = "";
|
||||
this.command = ["lrx", "--player", player, "fetch"];
|
||||
this.command = ["lrx", "--player", player, "fetch", "--normalize"];
|
||||
this.running = true;
|
||||
}
|
||||
|
||||
|
||||
@@ -271,6 +271,10 @@ Singleton {
|
||||
}
|
||||
}
|
||||
|
||||
function notifyTrackChange() {
|
||||
TempNotificationService.showWithIcon("music", (trackArtist ? trackArtist + " - " : "") + trackTitle, 3000);
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
updateCurrentPlayer();
|
||||
}
|
||||
@@ -280,6 +284,8 @@ Singleton {
|
||||
currentPosition = 0;
|
||||
|
||||
}
|
||||
onTrackTitleChanged: Qt.callLater(notifyTrackChange)
|
||||
onTrackArtistChanged: Qt.callLater(notifyTrackChange)
|
||||
|
||||
// Update progress bar every second while playing
|
||||
Timer {
|
||||
|
||||
@@ -35,11 +35,16 @@ Singleton {
|
||||
})
|
||||
property var workspaceCache: ({
|
||||
})
|
||||
property var castCache: ({
|
||||
})
|
||||
property var castOutputs: []
|
||||
property bool isCasting: false
|
||||
|
||||
signal workspaceChanged()
|
||||
signal activeWindowChanged()
|
||||
signal windowListChanged()
|
||||
signal outputsChanged()
|
||||
signal castOutputsListChanged()
|
||||
|
||||
function initialize() {
|
||||
niriEventStream.connected = true;
|
||||
@@ -434,6 +439,79 @@ Singleton {
|
||||
}
|
||||
}
|
||||
|
||||
function _syncCasts() {
|
||||
isCasting = Object.keys(castCache).length > 0;
|
||||
castOutputs = [];
|
||||
for (const castId in castCache) {
|
||||
const cast = castCache[castId];
|
||||
if (cast.output) {
|
||||
if (!castOutputs.includes(cast.output))
|
||||
castOutputs.push(cast.output);
|
||||
}
|
||||
}
|
||||
castOutputsListChanged();
|
||||
}
|
||||
|
||||
function _handleCastsChanged(eventData) {
|
||||
try {
|
||||
const casts = eventData.casts || [];
|
||||
castCache = {
|
||||
};
|
||||
castOutputs = [];
|
||||
for (const cast of casts) {
|
||||
const castData = {
|
||||
"id": cast.stream_id,
|
||||
"stream_id": cast.stream_id,
|
||||
"session_id": cast.session_id,
|
||||
"kind": cast.kind,
|
||||
"output": cast.target?.Output?.name,
|
||||
"pid": cast.pid
|
||||
};
|
||||
castCache[castData.id] = castData;
|
||||
}
|
||||
_syncCasts();
|
||||
} catch (e) {
|
||||
Logger.e("NiriService", "Error handling CastsChanged:", e);
|
||||
}
|
||||
}
|
||||
|
||||
function _handleCastStopped(eventData) {
|
||||
try {
|
||||
const castId = eventData.stream_id;
|
||||
delete castCache[castId];
|
||||
_syncCasts();
|
||||
} catch (e) {
|
||||
Logger.e("NiriService", "Error handling CastStopped:", e);
|
||||
}
|
||||
}
|
||||
|
||||
function _handleCastStartedOrChanged(eventData) {
|
||||
try {
|
||||
const cast = eventData.cast;
|
||||
if (!cast)
|
||||
return ;
|
||||
if (cast.is_active === true) {
|
||||
// If the cast is active, we can treat it as a new or updated cast
|
||||
const castData = {
|
||||
"id": cast.stream_id,
|
||||
"stream_id": cast.stream_id,
|
||||
"session_id": cast.session_id,
|
||||
"kind": cast.kind,
|
||||
"output": cast.target?.Output?.name,
|
||||
"pid": cast.pid
|
||||
};
|
||||
castCache[castData.id] = castData;
|
||||
} else {
|
||||
// If the cast is not active, we should remove it from the cache
|
||||
const castId = cast.stream_id;
|
||||
delete castCache[castId];
|
||||
}
|
||||
_syncCasts();
|
||||
} catch (e) {
|
||||
Logger.e("NiriService", "Error handling CastStartedOrChanged:", e);
|
||||
}
|
||||
}
|
||||
|
||||
function switchToWorkspace(workspace) {
|
||||
try {
|
||||
Quickshell.execDetached(["niri", "msg", "action", "focus-workspace", workspace.idx.toString()]);
|
||||
@@ -578,6 +656,12 @@ Singleton {
|
||||
_queryDisplayScales();
|
||||
else if (event.ScreenshotCaptured)
|
||||
_handleScreenshotCaptured(event.ScreenshotCaptured);
|
||||
else if (event.CastsChanged)
|
||||
_handleCastsChanged(event.CastsChanged);
|
||||
else if (event.CastStopped)
|
||||
_handleCastStopped(event.CastStopped);
|
||||
else if (event.CastStartedOrChanged)
|
||||
_handleCastStartedOrChanged(event.CastStartedOrChanged);
|
||||
} catch (e) {
|
||||
Logger.e("NiriService", "Error parsing event stream:", e, data);
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@ Singleton {
|
||||
|
||||
function openNote(path) {
|
||||
recentNotePath = path;
|
||||
Quickshell.execDetached(["wezterm", "start", "--", "sh", "-c", `exec nvim "${path}"`]);
|
||||
Quickshell.execDetached(["kitty-floating", "-e", "helix", path]);
|
||||
}
|
||||
|
||||
function openRecent() {
|
||||
|
||||
@@ -46,8 +46,10 @@ Singleton {
|
||||
if (!sunsetProcess.running) {
|
||||
temperature = 0;
|
||||
Logger.i("Sunset", "Stopped sunset process");
|
||||
TempNotificationService.showWithIcon("sunset-2-filled", "Sunset disabled");
|
||||
} else {
|
||||
Logger.i("Sunset", "Started sunset process");
|
||||
TempNotificationService.showWithIcon("sunset-2-filled", "Sunset enabled");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
pragma Singleton
|
||||
|
||||
import QtQuick
|
||||
import Quickshell
|
||||
|
||||
Singleton {
|
||||
id: root
|
||||
|
||||
readonly property int defaultDuration: 2000
|
||||
|
||||
property bool active: false
|
||||
property string message: ""
|
||||
property string iconName: ""
|
||||
|
||||
function show(message: string, duration: int) {
|
||||
root._showInternal("", message, duration);
|
||||
}
|
||||
|
||||
function showWithIcon(iconName: string, message: string, duration: int) {
|
||||
root._showInternal(iconName, message, duration);
|
||||
}
|
||||
|
||||
function _showInternal(iconName: string, message: string, duration: int) {
|
||||
root.iconName = iconName;
|
||||
root.message = message;
|
||||
root.active = true;
|
||||
resetTimer.interval = duration > 0 ? duration : root.defaultDuration;
|
||||
resetTimer.restart();
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: resetTimer
|
||||
|
||||
repeat: false
|
||||
onTriggered: root.active = false
|
||||
}
|
||||
|
||||
}
|
||||
@@ -10,10 +10,6 @@ import qs.Services
|
||||
ShellRoot {
|
||||
id: root
|
||||
|
||||
Component.onCompleted: {
|
||||
ImageCacheService.init();
|
||||
}
|
||||
|
||||
Loader {
|
||||
id: loader
|
||||
|
||||
@@ -24,6 +20,7 @@ ShellRoot {
|
||||
SunsetService;
|
||||
NotesService;
|
||||
WallpaperCycle;
|
||||
CapslockService;
|
||||
}
|
||||
|
||||
IPCService {
|
||||
|
||||
@@ -40,13 +40,9 @@ CONFIG_DIR = Path("~/.config").expanduser()
|
||||
|
||||
# An application may have multiple scripts (e.g. due to config-switch)
|
||||
SCRIPTS = {
|
||||
"eww": [CONFIG_DIR / "eww" / "apply-color"],
|
||||
"fastfetch": [CONFIG_DIR / "fastfetch" / "apply-color"],
|
||||
"fuzzel": [CONFIG_DIR / "fuzzel" / "apply-color"],
|
||||
"hypr": [CONFIG_DIR / "hypr" / "apply-color"],
|
||||
"kvantum": [CONFIG_DIR / "Kvantum" / "apply-color"],
|
||||
"nwg-look": [CONFIG_DIR / "nwg-look" / "apply-color"],
|
||||
"mako": [CONFIG_DIR / "mako" / "apply-color"],
|
||||
"niri": [CONFIG_DIR / "niri" / "apply-color"],
|
||||
"oh-my-posh": [
|
||||
CONFIG_DIR / "fish" / "apply-color-omp"
|
||||
@@ -55,12 +51,7 @@ SCRIPTS = {
|
||||
CONFIG_DIR / "fish" / "apply-color-starship"
|
||||
], # borrowing fish's directory
|
||||
"quickshell": [CONFIG_DIR / "quickshell" / "apply-color"],
|
||||
"rofi": [CONFIG_DIR / "rofi" / "apply-color"],
|
||||
"waybar": [CONFIG_DIR / "waybar" / "apply-color"],
|
||||
"wlogout": [
|
||||
CONFIG_DIR / ".alt" / "wlogout-default" / "apply-color",
|
||||
CONFIG_DIR / ".alt" / "wlogout-niri" / "apply-color",
|
||||
],
|
||||
"wlogout": [CONFIG_DIR / "wlogout" / "apply-color"],
|
||||
"yazi": [CONFIG_DIR / "yazi" / "apply-color"],
|
||||
}
|
||||
# or simply `find [-L] <CONFIG_DIR> -type f -name 'apply-color*'` to get all available scripts,
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
#!/bin/sh
|
||||
|
||||
kitty --app-id kitty-floating --config "$HOME/.config/kitty/floating.conf" "$@"
|
||||
@@ -0,0 +1,175 @@
|
||||
#!/usr/bin/env python3
|
||||
import sys
|
||||
import glob
|
||||
import argparse
|
||||
import select
|
||||
import os
|
||||
import struct
|
||||
|
||||
EVENT_FORMAT = '@llHHi'
|
||||
EVENT_SIZE = struct.calcsize(EVENT_FORMAT)
|
||||
|
||||
EV_LED = 0x11
|
||||
|
||||
LED_CODES = {
|
||||
'numlock': 0x00,
|
||||
'capslock': 0x01,
|
||||
'scrolllock': 0x02
|
||||
}
|
||||
|
||||
def get_led_state(led_type: str) -> int:
|
||||
pattern = f"/sys/class/leds/*::{led_type}/brightness"
|
||||
paths = glob.glob(pattern)
|
||||
if not paths:
|
||||
return 0
|
||||
for path in paths:
|
||||
try:
|
||||
with open(path, 'r') as f:
|
||||
if int(f.read().strip()) > 0:
|
||||
return 1
|
||||
except (IOError, ValueError, OSError):
|
||||
continue
|
||||
return 0
|
||||
|
||||
def has_led_capability(event_path: str) -> bool:
|
||||
try:
|
||||
basename = os.path.basename(event_path)
|
||||
cap_path = f"/sys/class/input/{basename}/device/capabilities/led"
|
||||
if os.path.exists(cap_path):
|
||||
with open(cap_path, 'r') as f:
|
||||
return f.read().strip() != "0"
|
||||
except OSError:
|
||||
pass
|
||||
return False
|
||||
|
||||
class DeviceMonitor:
|
||||
def __init__(self, target_led: str):
|
||||
self.target_led = target_led
|
||||
self.target_led_code = LED_CODES[target_led]
|
||||
|
||||
self.poller = select.poll()
|
||||
self.active_fds = {}
|
||||
|
||||
self.last_state = get_led_state(self.target_led)
|
||||
self.emit_state(self.last_state)
|
||||
|
||||
def emit_state(self, state: int) -> None:
|
||||
try:
|
||||
sys.stdout.write(f"{state}\n")
|
||||
sys.stdout.flush()
|
||||
except BrokenPipeError:
|
||||
devnull = os.open(os.devnull, os.O_WRONLY)
|
||||
os.dup2(devnull, sys.stdout.fileno())
|
||||
sys.exit(0)
|
||||
|
||||
def scan_devices(self) -> None:
|
||||
current_fds = set(self.active_fds.keys())
|
||||
paths = glob.glob('/dev/input/event*')
|
||||
found_fds = set()
|
||||
|
||||
for path in paths:
|
||||
if not has_led_capability(path):
|
||||
continue
|
||||
|
||||
already_open = False
|
||||
for fd, opened_path in self.active_fds.items():
|
||||
if opened_path == path:
|
||||
found_fds.add(fd)
|
||||
already_open = True
|
||||
break
|
||||
|
||||
if not already_open:
|
||||
try:
|
||||
fd = os.open(path, os.O_RDONLY | os.O_NONBLOCK)
|
||||
self.poller.register(fd, select.POLLIN)
|
||||
self.active_fds[fd] = path
|
||||
found_fds.add(fd)
|
||||
except PermissionError:
|
||||
sys.stderr.write(f"Error: Permission denied when opening {path}.\n")
|
||||
sys.exit(1)
|
||||
except OSError:
|
||||
continue
|
||||
|
||||
for fd in current_fds - found_fds:
|
||||
self.remove_device(fd)
|
||||
|
||||
def remove_device(self, fd: int) -> None:
|
||||
if fd in self.active_fds:
|
||||
try:
|
||||
self.poller.unregister(fd)
|
||||
os.close(fd)
|
||||
del self.active_fds[fd]
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
def handle_device_events(self, events: list) -> None:
|
||||
fds_to_remove = []
|
||||
|
||||
for fd, event in events:
|
||||
if event & select.POLLIN:
|
||||
try:
|
||||
while True:
|
||||
data = os.read(fd, 4096)
|
||||
if not data:
|
||||
fds_to_remove.append(fd)
|
||||
break
|
||||
|
||||
events_count = len(data) // EVENT_SIZE
|
||||
for i in range(events_count):
|
||||
chunk = data[i * EVENT_SIZE : (i + 1) * EVENT_SIZE]
|
||||
_, _, ev_type, ev_code, ev_value = struct.unpack(EVENT_FORMAT, chunk)
|
||||
|
||||
if ev_type == EV_LED and ev_code == self.target_led_code:
|
||||
if ev_value != self.last_state:
|
||||
self.emit_state(ev_value)
|
||||
self.last_state = ev_value
|
||||
|
||||
except BlockingIOError:
|
||||
pass
|
||||
except OSError:
|
||||
fds_to_remove.append(fd)
|
||||
|
||||
for fd in fds_to_remove:
|
||||
self.remove_device(fd)
|
||||
|
||||
def run(self) -> None:
|
||||
self.scan_devices()
|
||||
|
||||
try:
|
||||
while True:
|
||||
events = self.poller.poll(1000)
|
||||
|
||||
if not events:
|
||||
self.scan_devices()
|
||||
current_state = get_led_state(self.target_led)
|
||||
if current_state != self.last_state:
|
||||
self.emit_state(current_state)
|
||||
self.last_state = current_state
|
||||
else:
|
||||
self.handle_device_events(events)
|
||||
|
||||
except KeyboardInterrupt:
|
||||
sys.exit(0)
|
||||
finally:
|
||||
for fd in list(self.active_fds.keys()):
|
||||
try:
|
||||
os.close(fd)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description="Zero-polling keyboard LED monitor.")
|
||||
parser.add_argument(
|
||||
'-l', '--led',
|
||||
type=str,
|
||||
default='capslock',
|
||||
choices=['capslock', 'numlock', 'scrolllock'],
|
||||
help="Target LED to monitor"
|
||||
)
|
||||
args = parser.parse_args()
|
||||
|
||||
monitor = DeviceMonitor(args.led)
|
||||
monitor.run()
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,182 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# https://github.com/SHORiN-KiWATA/shorin-contrib
|
||||
#
|
||||
# niri-force-kill-window
|
||||
# 通过鼠标点击强制结束 (SIGKILL) 任意窗口。
|
||||
# 完美支持 Wayland 原生与 XWayland 代理窗口的独立精准击杀。
|
||||
# 具备多语言自适应 (i18n) 与智能依赖提示功能。
|
||||
#
|
||||
# 实现原理:
|
||||
# 1. 通过 niri msg pick-window 点选窗口
|
||||
# 2. 利用窗口的 PID,通过进程名称判断它是 xwayland 还是 wayland
|
||||
# 3. 获取真实的底层 PID(Wayland 直接取用,XWayland 利用 xprop 获取焦点窗口的真实 PID)
|
||||
# 4. 向上追溯该真实 PID,找到所属应用的根进程 (App Root),并利用防火墙逻辑避开系统进程
|
||||
# 5. 从根进程向下遍历收集所有子孙进程,利用 kill -9 执行“九头蛇绞杀”,防止多进程软件死灰复燃
|
||||
|
||||
# ==========================================
|
||||
# 0. 多语言 (Locale) 自适应支持
|
||||
# ==========================================
|
||||
if [[ "${LANG}" == zh_* ]]; then
|
||||
STR_ERR_DEP_TITLE="依赖缺失"
|
||||
STR_ERR_DEP_MSG="缺少必需命令: %s\n请尝试安装包: %s"
|
||||
STR_ERR_INFO_TITLE="获取信息失败"
|
||||
STR_ERR_INFO_MSG="无法获取窗口或进程信息。"
|
||||
STR_ERR_KILL_TITLE="结束失败"
|
||||
STR_ERR_KILL_MSG="无法提取目标真实 PID。"
|
||||
STR_SUCC_TITLE="强制杀死 (%s)"
|
||||
STR_SUCC_MSG="应用: %s\n连根拔起: 成功摧毁 %s 个相关进程。"
|
||||
STR_UNKNOWN_APP="未知应用"
|
||||
else
|
||||
STR_ERR_DEP_TITLE="Missing Dependency"
|
||||
STR_ERR_DEP_MSG="Command not found: %s\nPlease install package: %s"
|
||||
STR_ERR_INFO_TITLE="Info Error"
|
||||
STR_ERR_INFO_MSG="Could not determine window or process information."
|
||||
STR_ERR_KILL_TITLE="Kill Failed"
|
||||
STR_ERR_KILL_MSG="Could not extract target real PID."
|
||||
STR_SUCC_TITLE="Headshot! (%s)"
|
||||
STR_SUCC_MSG="App: %s\nHydra Kill: %s processes terminated."
|
||||
STR_UNKNOWN_APP="Unknown App"
|
||||
fi
|
||||
|
||||
# ==========================================
|
||||
# 1. 环境与依赖检查
|
||||
# ==========================================
|
||||
check_dependency() {
|
||||
local cmd="$1"
|
||||
local pkg="$2"
|
||||
if ! command -v "$cmd" &> /dev/null; then
|
||||
local msg
|
||||
printf -v msg "$STR_ERR_DEP_MSG" "$cmd" "$pkg"
|
||||
|
||||
# 如果 notify-send 存在,则发送桌面通知;否则输出到终端标准错误
|
||||
if command -v notify-send &> /dev/null; then
|
||||
notify-send "$STR_ERR_DEP_TITLE" "$msg" -u critical -i dialog-error
|
||||
else
|
||||
echo -e "[${STR_ERR_DEP_TITLE}]\n${msg}" >&2
|
||||
fi
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# 检查三大核心依赖并提示对应软件包
|
||||
check_dependency "niri" "niri"
|
||||
check_dependency "notify-send" "libnotify"
|
||||
check_dependency "xprop" "xorg-xprop"
|
||||
|
||||
# ==========================================
|
||||
# 2. 辅助函数:发送通知与音效 (非阻塞)
|
||||
# ==========================================
|
||||
notify_and_play() {
|
||||
local title="$1"
|
||||
local msg="$2"
|
||||
notify-send "$title" "$msg" -a "Window Killer" -i application-exit
|
||||
|
||||
# pw-play 不是强依赖,如果有则播放音效,放入后台运行防止阻塞
|
||||
if command -v pw-play &> /dev/null; then
|
||||
pw-play /usr/share/sounds/freedesktop/stereo/dialog-error.oga >/dev/null 2>&1 &
|
||||
fi
|
||||
}
|
||||
|
||||
# ==========================================
|
||||
# 3. 抓取目标窗口信息
|
||||
# ==========================================
|
||||
# 执行命令并捕获退出码。如果用户按 Esc 取消,返回非零退出码,静默退出
|
||||
if ! output=$(niri msg pick-window 2>/dev/null); then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# 如果没有任何输出,直接退出
|
||||
if [[ -z "$output" ]]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# 提取 Niri 视角下的 PID 和 App ID
|
||||
pid=$(grep -oP 'PID:\s*\K\d+' <<< "$output")
|
||||
app_id=$(grep -oP 'App ID:\s*"\K[^"]+' <<< "$output")
|
||||
app_name="${app_id:-$STR_UNKNOWN_APP}"
|
||||
|
||||
# 如果正则没有提取到 PID(未命中合法窗口),静默退出
|
||||
if [[ -z "$pid" ]]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# 如果确实抓到了 PID,但此时进程已不存在,发出异常通知
|
||||
if [[ ! -f "/proc/$pid/comm" ]]; then
|
||||
notify-send "$STR_ERR_INFO_TITLE" "$STR_ERR_INFO_MSG" -a "Window Killer" -i dialog-error
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# ==========================================
|
||||
# 4. 判定协议类型并获取真实 PID
|
||||
# ==========================================
|
||||
process_name=$(cat "/proc/$pid/comm")
|
||||
process_name_lower="${process_name,,}"
|
||||
|
||||
if [[ "$process_name_lower" == *"xwayland"* ]]; then
|
||||
proto_str="XWayland"
|
||||
# 给内核与 X11 服务端预留 50 毫秒的时间传递和同步焦点
|
||||
sleep 0.05
|
||||
# 顺着焦点,询问 X11 当前活动的窗口 ID
|
||||
active_wid=$(xprop -root -notype _NET_ACTIVE_WINDOW 2>/dev/null | grep -o '0x[0-9a-fA-F]\+')
|
||||
# 顺藤摸瓜:提取这个 X11 窗口绑定的真实底层 Linux PID
|
||||
real_pid=$(xprop -id "$active_wid" -notype _NET_WM_PID 2>/dev/null | grep -oP '\d+')
|
||||
else
|
||||
proto_str="Wayland"
|
||||
real_pid="$pid"
|
||||
fi
|
||||
|
||||
if [[ -z "$real_pid" ]]; then
|
||||
notify-send "$STR_ERR_KILL_TITLE" "$STR_ERR_KILL_MSG" -a "Window Killer" -i dialog-error
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# ==========================================
|
||||
# 5. 九头蛇绞杀逻辑 (Hydra Kill)
|
||||
# ==========================================
|
||||
# 向上追溯,寻找进程家族的老祖宗 (App Root)
|
||||
app_root=$real_pid
|
||||
current=$real_pid
|
||||
|
||||
while true; do
|
||||
ppid=$(ps -o ppid= -p "$current" 2>/dev/null | tr -d ' ')
|
||||
|
||||
# 如果找不到父进程,或者父进程是系统最高层 PID 1,停止追溯
|
||||
if [[ -z "$ppid" || "$ppid" == "1" ]]; then
|
||||
break
|
||||
fi
|
||||
|
||||
pname=$(ps -o comm= -p "$ppid" 2>/dev/null)
|
||||
|
||||
# 【核心防火墙】:遇到桌面环境、终端、系统核心服务,立刻停止溯源!
|
||||
if [[ "$pname" =~ ^(systemd|niri|bash|zsh|fish|tmux|screen|xwayland.*|sshd|login|init|sway|hyprland)$ ]]; then
|
||||
break
|
||||
fi
|
||||
|
||||
app_root=$ppid
|
||||
current=$ppid
|
||||
done
|
||||
|
||||
# 向下递归,收集家族所有子孙 PID
|
||||
get_descendants() {
|
||||
local p=$1
|
||||
echo "$p"
|
||||
# pgrep -P 获取直接子进程
|
||||
for c in $(pgrep -P "$p" 2>/dev/null); do
|
||||
get_descendants "$c"
|
||||
done
|
||||
}
|
||||
|
||||
family_pids=$(get_descendants "$app_root")
|
||||
pid_count=$(echo "$family_pids" | wc -w)
|
||||
|
||||
# 执行联合绞杀:把所有收集到的 PID 一次性全部强制终止
|
||||
kill -9 $family_pids 2>/dev/null
|
||||
|
||||
# ==========================================
|
||||
# 6. 发送战果通知与音效
|
||||
# ==========================================
|
||||
printf -v final_title "$STR_SUCC_TITLE" "$proto_str"
|
||||
printf -v final_msg "$STR_SUCC_MSG" "$app_name" "$pid_count"
|
||||
|
||||
notify_and_play "$final_title" "$final_msg"
|
||||
@@ -10,8 +10,7 @@ pids=$(pgrep -x quickshell)
|
||||
children=()
|
||||
|
||||
for pid in $pids; do
|
||||
# children=$(pgrep -P "$pid" 2>/dev/null)
|
||||
children+=($!)
|
||||
mapfile -t -O "${#children[@]}" children < <(pgrep -P "$pid" 2>/dev/null)
|
||||
kill "$pid" || true
|
||||
done
|
||||
|
||||
|
||||
@@ -45,22 +45,20 @@ prepend_path "$HOME/.local/scripts"
|
||||
prepend_path "$HOME/.local/share/fnm"
|
||||
export PATH
|
||||
|
||||
# fnm
|
||||
if type fnm &>/dev/null; then
|
||||
eval "$(fnm env --shell bash)"
|
||||
fi
|
||||
|
||||
# export UY_ENABLE_GPG_AGENT_SSH=1 in .profile to enable GPG agent for SSH
|
||||
if type gpgconf &>/dev/null && type gpg-connect-agent &>/dev/null &&
|
||||
[ -x "$HOME/.local/scripts/gpg-init" ] &&
|
||||
[ "${UY_ENABLE_GPG_AGENT_SSH:-0}" = "1" ]; then
|
||||
[ "${UY_ENABLE_GPG_AGENT_SSH:-0}" = "1" ]; then
|
||||
# GPG agent for SSH
|
||||
eval "$($HOME/.local/scripts/gpg-init 2>/dev/null)" &>/dev/null
|
||||
fi
|
||||
|
||||
if type ssh-add &>/dev/null && type ssh-agent &>/dev/null &&
|
||||
{ [ -z "$SSH_AUTH_SOCK" ] ||
|
||||
[ "$(ssh-add -l &>/dev/null; echo $?)" -eq 2 ]; } &&
|
||||
[ "$(
|
||||
ssh-add -l &>/dev/null
|
||||
echo $?
|
||||
)" -eq 2 ]; } &&
|
||||
[ -x "$HOME/.local/scripts/ssh-init" ]; then
|
||||
unset SSH_AUTH_SOCK
|
||||
# SSH with cross-session ssh-agent
|
||||
|
||||
@@ -2,6 +2,16 @@
|
||||
|
||||
[[ $- == *i* ]] || return
|
||||
|
||||
if type fish &>/dev/null; then
|
||||
alias f="exec fish"
|
||||
|
||||
if [[ ${UY_ENABLE_FISH_AUTO_LOGIN:-0} == 1 ]] &&
|
||||
[[ $(ps --no-header --pid=$PPID --format=comm) != "fish" && -z ${BASH_EXECUTION_STRING} && ${SHLVL} == 1 ]]; then
|
||||
shopt -q login_shell && LOGIN_OPTION='--login' || LOGIN_OPTION=''
|
||||
exec fish $LOGIN_OPTION
|
||||
fi
|
||||
fi
|
||||
|
||||
HISTCONTROL=ignoreboth
|
||||
HISTSIZE=16384
|
||||
HISTFILESIZE=32768
|
||||
@@ -39,6 +49,10 @@ if type gpg &>/dev/null; then
|
||||
export GPG_TTY
|
||||
fi
|
||||
|
||||
if type fnm &>/dev/null; then
|
||||
eval "$(fnm env --shell bash --use-on-cd)"
|
||||
fi
|
||||
|
||||
if [[ ${UY_USING_SSH_AGENT:-0} == 1 ]]; then
|
||||
function sshs() {
|
||||
if ! ssh-add -l &>/dev/null; then
|
||||
@@ -52,16 +66,6 @@ if [[ ${UY_USING_SSH_AGENT:-0} == 1 ]]; then
|
||||
}
|
||||
fi
|
||||
|
||||
if type fish &>/dev/null; then
|
||||
alias f="exec fish"
|
||||
|
||||
if [[ ${UY_ENABLE_FISH_AUTO_LOGIN:-0} == 1 ]] &&
|
||||
[[ $(ps --no-header --pid=$PPID --format=comm) != "fish" && -z ${BASH_EXECUTION_STRING} && ${SHLVL} == 1 ]]; then
|
||||
shopt -q login_shell && LOGIN_OPTION='--login' || LOGIN_OPTION=''
|
||||
exec fish $LOGIN_OPTION
|
||||
fi
|
||||
fi
|
||||
|
||||
if type starship &>/dev/null; then
|
||||
eval $(starship init bash)
|
||||
eval "$(starship init bash)"
|
||||
fi
|
||||
|
||||
@@ -26,3 +26,8 @@ set -x -g GPG_TTY (tty)
|
||||
# done
|
||||
set -U __done_min_cmd_duration 10000
|
||||
set -U __done_notification_urgency_level low
|
||||
|
||||
# fnm
|
||||
if type -q fnm
|
||||
fnm env --shell fish --use-on-cd | source
|
||||
end
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# ssh with encrypted private keys
|
||||
# $ssh_keys should be set in advance or left empty to use the default keys
|
||||
|
||||
if set -q ENABLE_GPG_AGENT_SSH; and test $ENABLE_GPG_AGENT_SSH != "0";\
|
||||
if set -q UY_ENABLE_GPG_AGENT_SSH; and test $UY_ENABLE_GPG_AGENT_SSH != "0";\
|
||||
and type -q gpg-init; and type -q gpgconf
|
||||
|
||||
true # do nothing
|
||||
|
||||
@@ -1,4 +1,10 @@
|
||||
fpath=(~/.zfunc $fpath)
|
||||
if [ -d "$HOME/.zfunc" ]; then
|
||||
fpath=($HOME/.zfunc $fpath)
|
||||
fi
|
||||
|
||||
if [ -d "$HOME/.zsh/completions" ]; then
|
||||
fpath=($HOME/.zsh/completions $fpath)
|
||||
fi
|
||||
|
||||
# Cache compinit: only regenerate dump once daily
|
||||
autoload -Uz compinit
|
||||
|
||||
@@ -29,3 +29,22 @@ fi
|
||||
# Catppuccin Mocha — autosuggestions color
|
||||
|
||||
ZSH_AUTOSUGGEST_HIGHLIGHT_STYLE="fg=#6c7086"
|
||||
|
||||
# Vscode shell integration
|
||||
|
||||
if (( $+commands[code] )) && [[ "$TERM_PROGRAM" == "vscode" ]]; then
|
||||
source "$(code --locate-shell-integration-path zsh)"
|
||||
fi
|
||||
|
||||
# fnm
|
||||
|
||||
if (( $+commands[fnm] )); then
|
||||
eval "$(fnm env --shell zsh --use-on-cd)"
|
||||
fi
|
||||
|
||||
# bat
|
||||
|
||||
if (( $+commands[bat] )); then
|
||||
export BAT_THEME="Catppuccin Mocha"
|
||||
export BAT_STYLE="default,-numbers"
|
||||
fi
|
||||
|
||||
@@ -54,12 +54,12 @@ if (( $+commands[fzf] )); then
|
||||
|
||||
if (( $+commands[yay] )); then
|
||||
# fyq: fuzzy yay local query
|
||||
alias fyq="yay -Qq | fzf --preview 'yay -Qi {}'"
|
||||
alias fyq="yay -Qq | fzf --preview 'yay -Qi {}' --preview-window='right,70%,wrap'"
|
||||
|
||||
# fyi: fuzzy yay install
|
||||
fyi() {
|
||||
local pkg
|
||||
pkg=$(yay -Sl | awk '{print $1"/"$2}' | fzf -m --preview 'yay -Si {}' --header "[install package]" "$@")
|
||||
pkg=$(yay -Sl | awk '{print $1"/"$2}' | fzf -m --preview 'yay -Si {}' --preview-window='right,70%,wrap' --header "[install package]" "$@")
|
||||
# yay supports "repo/package" format
|
||||
[[ -n "$pkg" ]] && yay -S ${=pkg}
|
||||
}
|
||||
@@ -67,7 +67,7 @@ if (( $+commands[fzf] )); then
|
||||
# fyr: fuzzy yay remove
|
||||
fyr() {
|
||||
local pkg
|
||||
pkg=$(yay -Qq | fzf -m --preview 'yay -Qi {}' --header "[remove package]" "$@")
|
||||
pkg=$(yay -Qq | fzf -m --preview 'yay -Qi {}' --preview-window='right,70%,wrap' --header "[remove package]" "$@")
|
||||
[[ -n "$pkg" ]] && yay -Rn ${=pkg}
|
||||
}
|
||||
fi
|
||||
@@ -180,17 +180,20 @@ if (( $+commands[git] )); then
|
||||
print -r -- "$repo"
|
||||
}
|
||||
|
||||
gc() {
|
||||
gcl() {
|
||||
local repo
|
||||
repo=$(uy_git_repo_from_clipboard) || return 1
|
||||
git clone "$repo"
|
||||
}
|
||||
|
||||
pingo() {
|
||||
cd "$HOME/Repositories/PGdP" || return 1
|
||||
builtin cd "$HOME/Repositories/Uni" || return 1
|
||||
local repo
|
||||
repo=$(uy_git_repo_from_clipboard) || return 1
|
||||
local dir_name="${repo:t:r}"
|
||||
local course="${${dir_name%%[^[:lower:]]*}:u}"
|
||||
mkdir -p "$course"
|
||||
builtin cd "$course" || return 1
|
||||
if [[ ! -d "$dir_name" ]]; then
|
||||
git clone "$repo" || return 1
|
||||
fi
|
||||
@@ -201,12 +204,28 @@ if (( $+commands[git] )); then
|
||||
disown
|
||||
else
|
||||
echo "Opening method missing or invalid"
|
||||
cd "$dir_name"
|
||||
builtin cd "$dir_name"
|
||||
fi
|
||||
}
|
||||
fi
|
||||
fi
|
||||
|
||||
# jj
|
||||
if (( $+commands[jj] )); then
|
||||
jjc() {
|
||||
jj describe -m "$*"
|
||||
jj new
|
||||
}
|
||||
|
||||
jjp() {
|
||||
local branch pos
|
||||
branch=${1:-master}
|
||||
pos=${2:-@-}
|
||||
jj bookmark move "$branch" --to "$pos"
|
||||
jj git push
|
||||
}
|
||||
fi
|
||||
|
||||
# Global aliases (can be used as part of a command)
|
||||
|
||||
# wl-paste
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
*
|
||||
!.gitignore
|
||||
@@ -44,18 +44,14 @@ fi
|
||||
# Paths
|
||||
|
||||
[[ -f "$HOME/.cargo/env" ]] && source "$HOME/.cargo/env"
|
||||
(( $+commands[opam] )) && eval "$(opam env)"
|
||||
prepend_path "$HOME/.cargo/bin"
|
||||
prepend_path "$HOME/go/bin"
|
||||
prepend_path "$HOME/.local/bin"
|
||||
prepend_path "$HOME/.local/scripts"
|
||||
prepend_path "$HOME/.local/share/fnm"
|
||||
export PATH
|
||||
|
||||
# fnm
|
||||
|
||||
if (( $+commands[fnm] )); then
|
||||
eval "$(fnm env --shell zsh)"
|
||||
fi
|
||||
|
||||
# GPG agent for SSH
|
||||
|
||||
if (( $+commands[gpgconf] )) && (( $+commands[gpg-connect-agent] )) &&
|
||||
|
||||
@@ -1,21 +1,9 @@
|
||||
# lrx completions
|
||||
fpath=(/home/kolkas/.zsh/completions $fpath)
|
||||
#!/hint/zsh
|
||||
|
||||
[[ $- != *i* ]] && return
|
||||
|
||||
|
||||
for _f in "${XDG_CONFIG_HOME:-$HOME/.config}"/zsh/conf.d/*.zsh(N); do
|
||||
source "$_f"
|
||||
done
|
||||
|
||||
for _f in "${XDG_CONFIG_HOME:-$HOME/.config}"/zsh/funcs.d/*.zsh(N); do
|
||||
source "$_f"
|
||||
done
|
||||
|
||||
for _f in "${XDG_CONFIG_HOME:-$HOME/.config}"/zsh/funcs.d/_*(N); do
|
||||
source "$_f"
|
||||
done
|
||||
|
||||
|
||||
unset _f
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
// This configuration is merged with the default vicinae configuration file, which you can obtain by running the `vicinae config default` command.
|
||||
// Every item defined in this file takes precedence over the values defined in the default config or any other imported file.
|
||||
//
|
||||
// You can make manual edits to this file, however you should keep in mind that this file may be written to by vicinae when a configuration change is made through the GUI.
|
||||
// When that happens, any custom comments or formatting will be lost.
|
||||
//
|
||||
// If you want to maintain a configuration file with your own comments and formatting, you should create a separate file and add it to the 'imports' array.
|
||||
//
|
||||
// Learn more about configuration at https://docs.vicinae.com/config
|
||||
|
||||
{
|
||||
"$schema": "https://vicinae.com/schemas/config.json",
|
||||
"font": {
|
||||
"normal": {
|
||||
"family": "LXGW WenKai"
|
||||
}
|
||||
},
|
||||
"theme": {
|
||||
"dark": {
|
||||
"name": "catppuccin-mocha"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
[ -f "$HOME/.local/snippets/apply-color-helper" ] || {
|
||||
echo "Missing helper script: $HOME/.local/snippets/apply-color-helper"
|
||||
exit 1
|
||||
}
|
||||
. "$HOME/.local/snippets/apply-color-helper"
|
||||
|
||||
for file in "$path"/icons/*.svg; do
|
||||
[ -f "$file" ] || continue
|
||||
sed -i -E "s/(fill=\"#)([0-9A-Fa-f]{6})(\")/\1${colorHex}\3/" "$file" || {
|
||||
log_error "Failed to edit ${file}"
|
||||
exit 1
|
||||
}
|
||||
done
|
||||
|
||||
file="$path"/style.css
|
||||
|
||||
sed -i -E "s/(border-color:\s*#)([0-9A-Fa-f]{6})(;)/\1${colorHex}\3/" "$file" || {
|
||||
log_error "Failed to edit ${file}"
|
||||
exit 1
|
||||
}
|
||||
|
||||
log_success "wlogout"
|
||||
@@ -1,36 +0,0 @@
|
||||
{
|
||||
"label": "lock",
|
||||
"action": "loginctl lock-session",
|
||||
"text": "Lock",
|
||||
"keybind": "l"
|
||||
}
|
||||
{
|
||||
"label": "hibernate",
|
||||
"action": "systemctl hibernate",
|
||||
"text": "Hibernate",
|
||||
"keybind": "h"
|
||||
}
|
||||
{
|
||||
"label": "logout",
|
||||
"action": "hyprctl dispatch exit",
|
||||
"text": "Logout",
|
||||
"keybind": "e"
|
||||
}
|
||||
{
|
||||
"label": "shutdown",
|
||||
"action": "systemctl poweroff",
|
||||
"text": "Shutdown",
|
||||
"keybind": "s"
|
||||
}
|
||||
{
|
||||
"label": "suspend",
|
||||
"action": "sleep 0.1 && systemctl suspend",
|
||||
"text": "Suspend",
|
||||
"keybind": "u"
|
||||
}
|
||||
{
|
||||
"label": "reboot",
|
||||
"action": "systemctl reboot",
|
||||
"text": "Reboot",
|
||||
"keybind": "r"
|
||||
}
|
||||
@@ -1,120 +0,0 @@
|
||||
* {
|
||||
background-image: none;
|
||||
font-size: 24px;
|
||||
font-family: 'Sour Gummy Light';
|
||||
}
|
||||
|
||||
window {
|
||||
background-color: rgba(30, 30, 46, 0.5);
|
||||
}
|
||||
|
||||
button {
|
||||
color: #cdd6f4;
|
||||
border-radius: 0;
|
||||
outline-style: none;
|
||||
background-color: alpha(#1e1e2e, 0.8);
|
||||
border: none;
|
||||
border-width: 0px;
|
||||
border-radius: 0px;
|
||||
border-color: #89b4fa;
|
||||
box-shadow: none;
|
||||
text-shadow: none;
|
||||
text-decoration-color: #cdd6f4;
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
background-size: 20%;
|
||||
animation: gradient_f 20s ease-in infinite;
|
||||
}
|
||||
|
||||
button:focus,
|
||||
button:active,
|
||||
button:hover {
|
||||
background-size: 20%;
|
||||
background-color: alpha(#1e1e2e, 0.7);
|
||||
animation: gradient_f 20s ease-in infinite;
|
||||
transition: all 0.3s cubic-bezier(0.55, 0, 0.28, 1.682);
|
||||
}
|
||||
|
||||
#lock {
|
||||
background-image: image(url('./icons/lock.svg'));
|
||||
border-radius: 32px 0 0 0;
|
||||
}
|
||||
|
||||
#logout {
|
||||
background-image: image(url('./icons/logout.svg'));
|
||||
}
|
||||
|
||||
#suspend {
|
||||
background-image: image(url('./icons/suspend.svg'));
|
||||
border-radius: 0 32px 0 0;
|
||||
}
|
||||
|
||||
#hibernate {
|
||||
background-image: image(url('./icons/hibernate.svg'));
|
||||
border-radius: 0 0 0 32px;
|
||||
}
|
||||
|
||||
#shutdown {
|
||||
background-image: image(url('./icons/shutdown.svg'));
|
||||
}
|
||||
|
||||
#reboot {
|
||||
background-image: image(url('./icons/reboot.svg'));
|
||||
border-radius: 0 0 32px 0;
|
||||
}
|
||||
|
||||
#lock:hover {
|
||||
border-radius: 30px 0 0 0;
|
||||
margin: -30px 0 0 -30px;
|
||||
}
|
||||
|
||||
#logout:hover {
|
||||
margin: -30px 0 0 0;
|
||||
}
|
||||
|
||||
#suspend:hover {
|
||||
border-radius: 0 30px 0 0;
|
||||
margin: -30px -30px 0 0;
|
||||
}
|
||||
|
||||
#hibernate:hover {
|
||||
border-radius: 0 0 0 30px;
|
||||
margin: 0 0 -30 -30px;
|
||||
}
|
||||
|
||||
#shutdown:hover {
|
||||
margin: 0 0 -30px 0;
|
||||
}
|
||||
|
||||
#reboot:hover {
|
||||
border-radius: 0 0 30px 0;
|
||||
margin: 0 -30px -30px 0;
|
||||
}
|
||||
|
||||
#lock:focus {
|
||||
border-radius: 60px 0 0 0;
|
||||
margin: -60px 0 0 -60px;
|
||||
}
|
||||
|
||||
#logout:focus {
|
||||
margin: -60px 0 0 0;
|
||||
}
|
||||
|
||||
#suspend:focus {
|
||||
border-radius: 0 60px 0 0;
|
||||
margin: -60px -60px 0 0;
|
||||
}
|
||||
|
||||
#hibernate:focus {
|
||||
border-radius: 0 0 0 60px;
|
||||
margin: 0 0 -60 -60px;
|
||||
}
|
||||
|
||||
#shutdown:focus {
|
||||
margin: 0 0 -60px 0;
|
||||
}
|
||||
|
||||
#reboot:focus {
|
||||
border-radius: 0 0 60px 0;
|
||||
margin: 0 -60px -60px 0;
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Svg Vector Icons : http://www.onlinewebfonts.com/icon -->
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg fill="#89b4fa" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 1000 1000" enable-background="new 0 0 1000 1000" xml:space="preserve">
|
||||
<metadata> Svg Vector Icons : http://www.onlinewebfonts.com/icon </metadata>
|
||||
<g><g><path d="M500,10C229.4,10,10,229.4,10,500s219.4,490,490,490s490-219.4,490-490S770.6,10,500,10z M500,885.1c-212.7,0-385.1-172.4-385.1-385.1S287.3,114.9,500,114.9S885.1,287.3,885.1,500S712.7,885.1,500,885.1z M576.5,308.7v382.4c0,42.2-34.2,76.5-76.5,76.5c-42.3,0-76.5-34.2-76.5-76.5V308.7c0-42.2,34.2-76.5,76.5-76.5C542.2,232.3,576.5,266.5,576.5,308.7z"/></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g></g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 969 B |
@@ -1,7 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Svg Vector Icons : http://www.onlinewebfonts.com/icon -->
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg fill="#89b4fa" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 1000 1000" enable-background="new 0 0 1000 1000" xml:space="preserve">
|
||||
<metadata> Svg Vector Icons : http://www.onlinewebfonts.com/icon </metadata>
|
||||
<g><g><path d="M321.8,455.5h356.4V321.8c0-49.2-17.4-91.2-52.2-126c-34.8-34.8-76.8-52.2-126-52.2c-49.2,0-91.2,17.4-126,52.2c-34.8,34.8-52.2,76.8-52.2,126L321.8,455.5L321.8,455.5z M900.9,522.3v400.9c0,18.6-6.5,34.3-19.5,47.3c-13,13-28.8,19.5-47.3,19.5H165.9c-18.6,0-34.3-6.5-47.3-19.5s-19.5-28.8-19.5-47.3V522.3c0-18.6,6.5-34.3,19.5-47.3c13-13,28.8-19.5,47.3-19.5h22.3V321.8c0-85.4,30.6-158.7,91.9-219.9C341.3,40.6,414.6,10,500,10c85.4,0,158.7,30.6,219.9,91.9c61.3,61.3,91.9,134.6,91.9,219.9v133.6h22.3c18.6,0,34.3,6.5,47.3,19.5C894.4,487.9,900.9,503.7,900.9,522.3L900.9,522.3z"/></g></g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.1 KiB |
@@ -1,7 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Svg Vector Icons : http://www.onlinewebfonts.com/icon -->
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg fill="#89b4fa" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 1000 1000" enable-background="new 0 0 1000 1000" xml:space="preserve">
|
||||
<metadata> Svg Vector Icons : http://www.onlinewebfonts.com/icon </metadata>
|
||||
<g><path d="M622.5,990H50.8C26.3,990,10,973.7,10,949.2V50.8C10,26.3,26.3,10,50.8,10h571.7c24.5,0,40.8,16.3,40.8,40.8v285.8c0,24.5-16.3,40.8-40.8,40.8s-40.8-16.3-40.8-40.8v-245h-490v816.7h490v-245c0-24.5,16.3-40.8,40.8-40.8s40.8,16.3,40.8,40.8v285.8C663.3,973.7,647,990,622.5,990z"/><path d="M949.2,540.8H336.7c-24.5,0-40.8-16.3-40.8-40.8c0-24.5,16.3-40.8,40.8-40.8h612.5c24.5,0,40.8,16.3,40.8,40.8C990,524.5,973.7,540.8,949.2,540.8z"/><path d="M949.2,540.8c-12.3,0-20.4-4.1-28.6-12.3L757.3,365.3c-16.3-16.3-16.3-40.8,0-57.2c16.3-16.3,40.8-16.3,57.2,0l163.3,163.3c16.3,16.3,16.3,40.8,0,57.2C969.6,536.8,961.4,540.8,949.2,540.8z"/><path d="M785.8,704.2c-12.3,0-20.4-4.1-28.6-12.3c-16.3-16.3-16.3-40.8,0-57.2l163.3-163.3c16.3-16.3,40.8-16.3,57.2,0c16.3,16.3,16.3,40.8,0,57.2L814.4,691.9C806.3,700.1,798.1,704.2,785.8,704.2z"/></g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.3 KiB |
@@ -1,7 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Svg Vector Icons : http://www.onlinewebfonts.com/icon -->
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg fill="#89b4fa" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 1000 1000" enable-background="new 0 0 1000 1000" xml:space="preserve">
|
||||
<metadata> Svg Vector Icons : http://www.onlinewebfonts.com/icon </metadata>
|
||||
<g><path d="M134.6,285.6C64.9,420.7,60.1,590,137.1,723.4L42,668.5l-32,55.4c93.1,52.1,133.6,75.9,184,106.2c28.5-51.5,52.8-94.4,107.4-186.1L246,612l-53.4,92.5C65.4,502.7,167.2,200.3,398.8,126.2C638,29.3,929,223.5,931.5,481.5c19.6,236.7-208.9,443.6-439.3,416.2l-29.5,51c277.7,54.4,556.5-201.7,524.7-483.1C976.1,170.8,637.1-41.2,367.1,77.5C262.8,114.2,183.1,191.5,134.6,285.6z"/></g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 877 B |
@@ -1,7 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Svg Vector Icons : http://www.onlinewebfonts.com/icon -->
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg fill="#89b4fa" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 1000 1000" enable-background="new 0 0 1000 1000" xml:space="preserve">
|
||||
<metadata> Svg Vector Icons : http://www.onlinewebfonts.com/icon </metadata>
|
||||
<g><path d="M764,152.1c30.9,22,58.3,46.8,82.4,74.6c24,27.8,44.6,57.8,61.8,90.1c17.2,32.3,30.2,66.4,39.1,102.4c8.9,36,13.4,72.6,13.4,109.6c0,63.8-12.2,123.7-36.5,179.6c-24.4,55.9-57.3,104.7-98.8,146.2c-41.5,41.5-90.2,74.5-146.2,98.8C623.2,977.8,563.3,990,499.5,990c-63.1,0-122.7-12.2-178.6-36.5c-55.9-24.4-104.8-57.3-146.7-98.8c-41.9-41.5-74.8-90.2-98.8-146.2c-24-55.9-36-115.8-36-179.6c0-36.4,4.3-72.1,12.9-107.1c8.6-35,20.8-68.3,36.5-99.9c15.8-31.6,35.3-61.1,58.7-88.5c23.3-27.5,49.4-52.2,78.2-74.1c15.1-11,31.4-15.1,48.9-12.4c17.5,2.7,31.7,11.3,42.7,25.7c11,14.4,15.1,30.5,12.4,48.4c-2.7,17.8-11.3,32.3-25.7,43.2c-43.2,31.6-76.4,70.3-99.3,116.3c-23,46-34.5,95.4-34.5,148.2c0,45.3,8.6,88,25.7,128.2c17.2,40.1,40.7,75.1,70.5,105c29.9,29.9,64.9,53.5,105,71c40.1,17.5,82.9,26.3,128.2,26.3c45.3,0,88-8.7,128.2-26.3c40.1-17.5,75.1-41.2,105-71s53.5-64.9,71-105c17.5-40.1,26.3-82.9,26.3-128.2c0-53.5-12.4-104.1-37.1-151.8c-24.7-47.7-59.4-87-104-117.9c-15.1-10.3-24.2-24.4-27.3-42.2c-3.1-17.8,0.5-34.3,10.8-49.4c10.3-14.4,24.4-23.2,42.2-26.2C732.5,138.2,748.9,141.8,764,152.1L764,152.1z M499.5,531.9c-17.8,0-33.1-6.3-45.8-19c-12.7-12.7-19-28-19-45.8V75.9c0-17.8,6.3-33.3,19-46.3c12.7-13,28-19.6,45.8-19.6c18.5,0,34.1,6.5,46.8,19.6c12.7,13,19,28.5,19,46.3v391.2c0,17.8-6.3,33.1-19,45.8C533.6,525.6,518,531.9,499.5,531.9L499.5,531.9z"/></g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.8 KiB |
@@ -1,7 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Svg Vector Icons : http://www.onlinewebfonts.com/icon -->
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg fill="#89b4fa" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 1000 1000" enable-background="new 0 0 1000 1000" xml:space="preserve">
|
||||
<metadata> Svg Vector Icons : http://www.onlinewebfonts.com/icon </metadata>
|
||||
<g><path d="M500,990c-66.1,0-130.3-13-190.7-38.5c-58.4-24.7-110.8-60-155.7-105s-80.3-97.4-105-155.7C23,630.3,10,566.1,10,500c0-66.1,13-130.3,38.5-190.7c24.7-58.4,60-110.8,105-155.7c45-45,97.4-80.3,155.7-105C369.7,23,433.9,10,500,10c66.1,0,130.3,13,190.7,38.5c58.4,24.7,110.8,60,155.7,105c45,45,80.3,97.4,105,155.7C977,369.7,990,433.9,990,500c0,66.1-13,130.3-38.5,190.7c-24.7,58.4-60,110.8-105,155.7s-97.4,80.3-155.7,105C630.3,977,566.1,990,500,990z M500,79.6c-112.3,0-217.9,43.7-297.3,123.1C123.3,282.1,79.6,387.7,79.6,500s43.7,217.9,123.1,297.3c79.4,79.4,185,123.1,297.3,123.1c112.3,0,217.9-43.7,297.3-123.1c79.4-79.4,123.1-185,123.1-297.3s-43.7-217.9-123.1-297.3C717.9,123.3,612.3,79.6,500,79.6z"/><path d="M322.5,290.6h108v412h-108V290.6z"/><path d="M561.6,290.6h107.9v412H561.6V290.6z"/></g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 969 B After Width: | Height: | Size: 969 B |
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 877 B After Width: | Height: | Size: 877 B |
|
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.3 KiB |
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"label": "lock",
|
||||
"action": "hyprlock &",
|
||||
"action": "loginctl lock-session",
|
||||
"text": "Lock",
|
||||
"keybind": "l"
|
||||
}
|
||||
@@ -24,7 +24,7 @@
|
||||
}
|
||||
{
|
||||
"label": "suspend",
|
||||
"action": "sleep 0.1 && systemctl suspend",
|
||||
"action": "systemctl suspend",
|
||||
"text": "Suspend",
|
||||
"keybind": "u"
|
||||
}
|
||||
@@ -1,11 +1,11 @@
|
||||
[[plugin.deps]]
|
||||
use = "yazi-rs/plugins:git"
|
||||
rev = "1962818"
|
||||
hash = "26db011a778f261d730d4f5f8bf24b3f"
|
||||
rev = "ac82af3"
|
||||
hash = "6849444b7c2df08eace83f3f86fb55a3"
|
||||
|
||||
[[plugin.deps]]
|
||||
use = "yazi-rs/plugins:smart-enter"
|
||||
rev = "1962818"
|
||||
rev = "ac82af3"
|
||||
hash = "187cc58ba7ac3befd49c342129e6f1b6"
|
||||
|
||||
[[plugin.deps]]
|
||||
@@ -20,8 +20,8 @@ hash = "771af2becc575a3f43d0542de823969d"
|
||||
|
||||
[[plugin.deps]]
|
||||
use = "llanosrocas/yaziline"
|
||||
rev = "d9cc2cb"
|
||||
hash = "b6073aadf2f9a1d5389a6d389f33f69c"
|
||||
rev = "cc0314c"
|
||||
hash = "b937c5c8e2d9fa314d4532489176814e"
|
||||
|
||||
[[plugin.deps]]
|
||||
use = "Rolv-Apneseth/starship"
|
||||
|
||||
@@ -25,14 +25,16 @@ And register it as fetchers in your `~/.config/yazi/yazi.toml`:
|
||||
|
||||
```toml
|
||||
[[plugin.prepend_fetchers]]
|
||||
id = "git"
|
||||
url = "*"
|
||||
run = "git"
|
||||
id = "git" # Remove if Yazi > v26.1.22
|
||||
url = "*"
|
||||
run = "git"
|
||||
group = "git"
|
||||
|
||||
[[plugin.prepend_fetchers]]
|
||||
id = "git"
|
||||
url = "*/"
|
||||
run = "git"
|
||||
id = "git" # Remove if Yazi > v26.1.22
|
||||
url = "*/"
|
||||
run = "git"
|
||||
group = "git"
|
||||
```
|
||||
|
||||
## Advanced
|
||||
|
||||
@@ -30,17 +30,15 @@ local function setup(_, options)
|
||||
color = options.color or nil,
|
||||
secondary_color = options.secondary_color or nil,
|
||||
default_files_color = options.default_files_color
|
||||
or th.which.separator_style:fg()
|
||||
or "darkgray",
|
||||
or th.which.separator_style:fg()
|
||||
or "darkgray",
|
||||
selected_files_color = options.selected_files_color
|
||||
or th.mgr.count_selected:bg()
|
||||
or "white",
|
||||
yanked_files_color = options.selected_files_color
|
||||
or th.mgr.count_copied:bg()
|
||||
or "green",
|
||||
cut_files_color = options.cut_files_color
|
||||
or th.mgr.count_cut:bg()
|
||||
or "red",
|
||||
or th.mgr.count_selected:bg()
|
||||
or "white",
|
||||
yanked_files_color = options.yanked_files_color
|
||||
or th.mgr.count_copied:bg()
|
||||
or "green",
|
||||
cut_files_color = options.cut_files_color or th.mgr.count_cut:bg() or "red",
|
||||
}
|
||||
|
||||
local current_separator_style = config.separator_styles
|
||||
@@ -55,10 +53,10 @@ local function setup(_, options)
|
||||
local style = self:style()
|
||||
return ui.Line({
|
||||
ui.Span(current_separator_style.separator_head)
|
||||
:fg(config.color or style.main:bg()),
|
||||
:fg(config.color or style.main:bg()),
|
||||
ui.Span(" " .. mode .. " ")
|
||||
:fg(th.which.mask:bg())
|
||||
:bg(config.color or style.main:bg()),
|
||||
:fg(th.which.mask:bg())
|
||||
:bg(config.color or style.main:bg()),
|
||||
})
|
||||
end
|
||||
|
||||
@@ -67,9 +65,14 @@ local function setup(_, options)
|
||||
local size = h and (h:size() or h.cha.len) or 0
|
||||
|
||||
local style = self:style()
|
||||
return ui.Span(current_separator_style.separator_close .. " " .. ya.readable_size(size) .. " ")
|
||||
:fg(config.color or style.main:bg())
|
||||
:bg(config.secondary_color or th.which.separator_style:fg())
|
||||
return ui.Span(
|
||||
current_separator_style.separator_close
|
||||
.. " "
|
||||
.. ya.readable_size(size)
|
||||
.. " "
|
||||
)
|
||||
:fg(config.color or style.main:bg())
|
||||
:bg(config.secondary_color or th.which.separator_style:fg())
|
||||
end
|
||||
|
||||
function Status:utf8_sub(str, start_char, end_char)
|
||||
@@ -90,8 +93,8 @@ local function setup(_, options)
|
||||
|
||||
if utf8.len(base_name) > max_length then
|
||||
base_name = self:utf8_sub(base_name, 1, config.filename_truncate_length)
|
||||
.. config.filename_truncate_separator
|
||||
.. self:utf8_sub(base_name, -config.filename_truncate_length)
|
||||
.. config.filename_truncate_separator
|
||||
.. self:utf8_sub(base_name, -config.filename_truncate_length)
|
||||
end
|
||||
|
||||
return base_name .. extension
|
||||
@@ -103,19 +106,18 @@ local function setup(_, options)
|
||||
if not h then
|
||||
return ui.Line({
|
||||
ui.Span(current_separator_style.separator_close .. " ")
|
||||
:fg(config.secondary_color or th.which.separator_style:fg()),
|
||||
ui.Span("Empty dir")
|
||||
:fg(config.color or style.main:bg()),
|
||||
:fg(config.secondary_color or th.which.separator_style:fg()),
|
||||
ui.Span("Empty dir"):fg(config.color or style.main:bg()),
|
||||
})
|
||||
end
|
||||
|
||||
local truncated_name = self:truncate_name(h.name, config.filename_max_length)
|
||||
local truncated_name =
|
||||
self:truncate_name(h.name, config.filename_max_length)
|
||||
|
||||
return ui.Line({
|
||||
ui.Span(current_separator_style.separator_close .. " ")
|
||||
:fg(config.secondary_color or th.which.separator_style:fg()),
|
||||
ui.Span(truncated_name)
|
||||
:fg(config.color or style.main:bg()),
|
||||
:fg(config.secondary_color or th.which.separator_style:fg()),
|
||||
ui.Span(truncated_name):fg(config.color or style.main:bg()),
|
||||
})
|
||||
end
|
||||
|
||||
@@ -124,28 +126,22 @@ local function setup(_, options)
|
||||
local files_selected = #cx.active.selected
|
||||
local files_cut = cx.yanked.is_cut
|
||||
|
||||
local selected_fg = files_selected > 0
|
||||
and config.selected_files_color
|
||||
or config.default_files_color
|
||||
local selected_fg = files_selected > 0 and config.selected_files_color
|
||||
or config.default_files_color
|
||||
local yanked_fg = files_yanked > 0
|
||||
and
|
||||
(files_cut
|
||||
and config.cut_files_color
|
||||
or config.yanked_files_color
|
||||
)
|
||||
or config.default_files_color
|
||||
and (files_cut and config.cut_files_color or config.yanked_files_color)
|
||||
or config.default_files_color
|
||||
|
||||
local yanked_text = files_yanked > 0
|
||||
and config.yank_symbol .. " " .. files_yanked
|
||||
or config.yank_symbol .. " 0"
|
||||
or config.yank_symbol .. " 0"
|
||||
|
||||
return ui.Line({
|
||||
ui.Span(" " .. current_separator_style.separator_close_thin .. " ")
|
||||
:fg(th.which.separator_style:fg()),
|
||||
:fg(th.which.separator_style:fg()),
|
||||
ui.Span(config.select_symbol .. " " .. files_selected .. " ")
|
||||
:fg(selected_fg),
|
||||
ui.Span(yanked_text .. " ")
|
||||
:fg(yanked_fg),
|
||||
:fg(selected_fg),
|
||||
ui.Span(yanked_text .. " "):fg(yanked_fg),
|
||||
})
|
||||
end
|
||||
|
||||
@@ -159,8 +155,12 @@ local function setup(_, options)
|
||||
local cha = hovered.cha
|
||||
local time = (cha.mtime or 0) // 1
|
||||
|
||||
return ui.Span(os.date("%Y-%m-%d %H:%M", time) .. " " .. current_separator_style.separator_open_thin .. " ")
|
||||
:fg(th.which.separator_style:fg())
|
||||
return ui.Span(
|
||||
os.date("%Y-%m-%d %H:%M", time)
|
||||
.. " "
|
||||
.. current_separator_style.separator_open_thin
|
||||
.. " "
|
||||
):fg(th.which.separator_style:fg())
|
||||
end
|
||||
|
||||
function Status:percent()
|
||||
@@ -182,13 +182,13 @@ local function setup(_, options)
|
||||
local style = self:style()
|
||||
return ui.Line({
|
||||
ui.Span(" " .. current_separator_style.separator_open)
|
||||
:fg(config.secondary_color or th.which.separator_style:fg()),
|
||||
:fg(config.secondary_color or th.which.separator_style:fg()),
|
||||
ui.Span(percent)
|
||||
:fg(config.color or style.main:bg())
|
||||
:bg(config.secondary_color or th.which.separator_style:fg()),
|
||||
:fg(config.color or style.main:bg())
|
||||
:bg(config.secondary_color or th.which.separator_style:fg()),
|
||||
ui.Span(current_separator_style.separator_open)
|
||||
:fg(config.color or style.main:bg())
|
||||
:bg(config.secondary_color or th.which.separator_style:fg()),
|
||||
:fg(config.color or style.main:bg())
|
||||
:bg(config.secondary_color or th.which.separator_style:fg()),
|
||||
})
|
||||
end
|
||||
|
||||
@@ -198,10 +198,13 @@ local function setup(_, options)
|
||||
|
||||
local style = self:style()
|
||||
return ui.Line({
|
||||
ui.Span(string.format(" %2d/%-2d ", math.min(cursor + 1, length), length))
|
||||
:fg(th.which.mask:bg())
|
||||
:bg(config.color or style.main:bg()),
|
||||
ui.Span(current_separator_style.separator_tail):fg(config.color or style.main:bg()),
|
||||
ui.Span(
|
||||
string.format(" %2d/%-2d ", math.min(cursor + 1, length), length)
|
||||
)
|
||||
:fg(th.which.mask:bg())
|
||||
:bg(config.color or style.main:bg()),
|
||||
ui.Span(current_separator_style.separator_tail)
|
||||
:fg(config.color or style.main:bg()),
|
||||
})
|
||||
end
|
||||
|
||||
|
||||
@@ -10,11 +10,11 @@ find_position = { fg = "#f5c2e7", bg = "reset", italic = true }
|
||||
marker_copied = { fg = "#a6e3a1", bg = "#a6e3a1" }
|
||||
marker_cut = { fg = "#f38ba8", bg = "#f38ba8" }
|
||||
marker_marked = { fg = "#94e2d5", bg = "#94e2d5" }
|
||||
marker_selected = { fg = "#f5c2e7", bg = "#f5c2e7" }
|
||||
marker_selected = { fg = "#89b4fa", bg = "#89b4fa" }
|
||||
|
||||
count_copied = { fg = "#1e1e2e", bg = "#a6e3a1" }
|
||||
count_cut = { fg = "#1e1e2e", bg = "#f38ba8" }
|
||||
count_selected = { fg = "#1e1e2e", bg = "#f5c2e7" }
|
||||
count_selected = { fg = "#1e1e2e", bg = "#89b4fa" }
|
||||
|
||||
border_symbol = "│"
|
||||
border_style = { fg = "#7f849c" }
|
||||
@@ -26,8 +26,8 @@ active = { fg = "#1e1e2e", bg = "#cdd6f4", bold = true }
|
||||
inactive = { fg = "#cdd6f4", bg = "#45475a" }
|
||||
|
||||
[mode]
|
||||
normal_main = { fg = "#1e1e2e", bg = "#f5c2e7", bold = true }
|
||||
normal_alt = { fg = "#f5c2e7", bg = "#313244"}
|
||||
normal_main = { fg = "#1e1e2e", bg = "#89b4fa", bold = true }
|
||||
normal_alt = { fg = "#89b4fa", bg = "#313244"}
|
||||
|
||||
select_main = { fg = "#1e1e2e", bg = "#a6e3a1", bold = true }
|
||||
select_alt = { fg = "#a6e3a1", bg = "#313244"}
|
||||
@@ -37,7 +37,7 @@ unset_alt = { fg = "#f2cdcd", bg = "#313244"}
|
||||
|
||||
[indicator]
|
||||
parent = { fg = "#1e1e2e", bg = "#cdd6f4" }
|
||||
current = { fg = "#1e1e2e", bg = "#f5c2e7" }
|
||||
current = { fg = "#1e1e2e", bg = "#89b4fa" }
|
||||
preview = { fg = "#1e1e2e", bg = "#cdd6f4" }
|
||||
|
||||
[status]
|
||||
@@ -55,29 +55,29 @@ perm_exec = { fg = "#a6e3a1" }
|
||||
perm_sep = { fg = "#7f849c" }
|
||||
|
||||
[input]
|
||||
border = { fg = "#f5c2e7" }
|
||||
border = { fg = "#89b4fa" }
|
||||
title = {}
|
||||
value = {}
|
||||
selected = { reversed = true }
|
||||
|
||||
[pick]
|
||||
border = { fg = "#f5c2e7" }
|
||||
border = { fg = "#89b4fa" }
|
||||
active = { fg = "#f5c2e7" }
|
||||
inactive = {}
|
||||
|
||||
[confirm]
|
||||
border = { fg = "#f5c2e7" }
|
||||
title = { fg = "#f5c2e7" }
|
||||
border = { fg = "#89b4fa" }
|
||||
title = { fg = "#89b4fa" }
|
||||
body = {}
|
||||
list = {}
|
||||
btn_yes = { reversed = true }
|
||||
btn_no = {}
|
||||
|
||||
[cmp]
|
||||
border = { fg = "#f5c2e7" }
|
||||
border = { fg = "#89b4fa" }
|
||||
|
||||
[tasks]
|
||||
border = { fg = "#f5c2e7" }
|
||||
border = { fg = "#89b4fa" }
|
||||
title = {}
|
||||
hovered = { fg = "#f5c2e7", bold = true }
|
||||
|
||||
@@ -126,13 +126,13 @@ rules = [
|
||||
{ url = "*/", is = "dummy", bg = "#f38ba8" },
|
||||
|
||||
# Fallback
|
||||
{ url = "*/", fg = "#f5c2e7" },
|
||||
{ url = "*/", fg = "#89b4fa" },
|
||||
]
|
||||
|
||||
[spot]
|
||||
border = { fg = "#f5c2e7" }
|
||||
title = { fg = "#f5c2e7" }
|
||||
tbl_cell = { fg = "#f5c2e7", reversed = true }
|
||||
border = { fg = "#89b4fa" }
|
||||
title = { fg = "#89b4fa" }
|
||||
tbl_cell = { fg = "#89b4fa", reversed = true }
|
||||
tbl_col = { bold = true }
|
||||
|
||||
[icon]
|
||||
|
||||
@@ -18,7 +18,7 @@ alt() {
|
||||
fi
|
||||
}
|
||||
|
||||
for item in "kitty" "wlogout"; do
|
||||
for item in "kitty" "wlogout" "ghostty"; do
|
||||
if [[ ! -L $HOME/.config/$item ]] && [[ -e $HOME/.config/$item ]]; then
|
||||
echo "Error: $HOME/.config/$item exists and is not a symlink." >&2
|
||||
exit 1
|
||||
@@ -0,0 +1,43 @@
|
||||
> 嗯, 用户想问的似乎是如何使用
|
||||
>
|
||||
> - `qemu-user-static`
|
||||
> - `qemu-user-static-binfmt`
|
||||
>
|
||||
> 通过
|
||||
>
|
||||
> ```bash
|
||||
> sudo systemd-nspawn -M {{ rootfs-name }}
|
||||
> ```
|
||||
>
|
||||
> 运行从
|
||||
>
|
||||
> ```bash
|
||||
> wget https://os.archlinuxarm.org/os/ArchLinuxARM-aarch64-latest.tar.gz
|
||||
> ```
|
||||
>
|
||||
> 下载且通过
|
||||
>
|
||||
> ```bash
|
||||
> sudo mkdir -p /var/lib/machines/{{ rootfs-name }} && \
|
||||
> sudo bsdtar -xpf ArchLinuxARM-aarch64-latest.tar.gz -C /var/lib/machines/{{ rootfs-name }}
|
||||
> ```
|
||||
>
|
||||
> 解压的 aarch64 架构的 archlinux rootfs. 但要不要提醒用户应该取消注释 `cat /etc/pacman.conf` 中的
|
||||
>
|
||||
> ```conf
|
||||
> [options]
|
||||
> #DisableSandboxFilesystem
|
||||
> #DisableSandboxSyscalls
|
||||
> ```
|
||||
>
|
||||
> 以禁用在 systemd-nspawn 中默认不可用的下载沙盒, 并且应该避免运行需要 setuid 的程序 (如 sudo), 因为 `/proc/sys/fs/binfmt_misc/qemu-aarch64` 中的 `flags` 缺失 `C` (Credentials) 标志, 导致可执行文件的 `s` 权限位被忽视? 不过如果真的需要 setuid 的话, 也可以通过
|
||||
>
|
||||
> ```bash
|
||||
> sudo cp /usr/lib/binfmt.d/qemu-aarch64-static.conf /etc/binfmt.d/
|
||||
> ```
|
||||
>
|
||||
> 复制一份并在末尾加上 C, 要不要一并告诉用户?
|
||||
>
|
||||
> 算了, 反正用户什么也不懂, 即使问题解决也只会原地消失, 一句感谢也不说.
|
||||
|
||||
_Baked for 27s._
|
||||