rofi steam game list... and lots of other stuff
This commit is contained in:
parent
741a5dfb18
commit
6af0cdbacf
|
@ -1,15 +1,56 @@
|
||||||
{ config, pkgs, lib, ... }:
|
{ config, pkgs, lib, ... }:
|
||||||
{
|
{
|
||||||
# TODO: theme (it's using fish variables...)
|
programs.fish =
|
||||||
programs.fish = {
|
let nom-compat = pkgs.runCommand "any-shell-nom-compat" {} ''
|
||||||
|
mkdir -p $out/bin
|
||||||
|
for cmd in $(echo nix nix-shell nix-build); do
|
||||||
|
echo '#! ${pkgs.bash}/bin/bash' > $out/bin/$cmd
|
||||||
|
echo -n 'PATH=`echo $PATH | tr ":" "\n" | grep -v "any-shell-nom-compat" | tr "\n" ":"` ' >> $out/bin/$cmd
|
||||||
|
cmd1=$(echo $cmd | sed 's/nix/nom/')
|
||||||
|
echo "$cmd1"' "$@"' >> $out/bin/$cmd
|
||||||
|
chmod +x $out/bin/$cmd
|
||||||
|
done
|
||||||
|
'';
|
||||||
|
in {
|
||||||
enable = true;
|
enable = true;
|
||||||
# not sure this is needed, but just in case
|
# not sure this is needed, but just in case
|
||||||
shellInit = ''
|
shellInit = ''
|
||||||
source /etc/fish/config.fish
|
source /etc/fish/config.fish
|
||||||
'';
|
'';
|
||||||
interactiveShellInit = ''
|
interactiveShellInit = ''
|
||||||
${pkgs.any-nix-shell}/bin/any-nix-shell fish --info-right | source
|
# ${pkgs.any-nix-shell}/bin/any-nix-shell fish | source
|
||||||
|
|
||||||
|
function nix-shell
|
||||||
|
${pkgs.any-nix-shell}/bin/.any-nix-shell-wrapper fish $argv
|
||||||
|
end
|
||||||
|
function nix
|
||||||
|
if test $argv[1] = shell
|
||||||
|
set argv[1] fish
|
||||||
|
${pkgs.any-nix-shell}/bin/.any-nix-wrapper $argv
|
||||||
|
else if test $argv[1] = develop
|
||||||
|
set argv[1] fish
|
||||||
|
command nix develop --command $argv
|
||||||
|
else
|
||||||
|
command nix $argv
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function nom-shell
|
||||||
|
PATH="${nom-compat}/bin:$PATH" ${pkgs.any-nix-shell}/bin/.any-nix-shell-wrapper fish $argv
|
||||||
|
end
|
||||||
|
function nom
|
||||||
|
if test $argv[1] = shell
|
||||||
|
set argv[1] fish
|
||||||
|
PATH="${nom-compat}/bin:$PATH" ${pkgs.any-nix-shell}/bin/.any-nix-wrapper $argv
|
||||||
|
else if test $argv[1] = develop
|
||||||
|
set argv[1] fish
|
||||||
|
${pkgs.nix-output-monitor}/bin/nom develop --command $argv
|
||||||
|
else
|
||||||
|
command nix $argv
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
export NOMCOMPAT=${nom-compat}
|
||||||
# for posix compatibility
|
# for posix compatibility
|
||||||
set -gx SHELL zsh
|
set -gx SHELL zsh
|
||||||
|
|
||||||
|
|
|
@ -56,12 +56,12 @@
|
||||||
# for preview
|
# for preview
|
||||||
exa bat
|
exa bat
|
||||||
ffmpeg ffmpegthumbnailer nsxiv imagemagick
|
ffmpeg ffmpegthumbnailer nsxiv imagemagick
|
||||||
libarchive unzip gnutar atool
|
libarchive atool
|
||||||
libreoffice poppler_utils fontpreview djvulibre
|
libreoffice poppler_utils fontpreview djvulibre
|
||||||
glow w3m
|
glow w3m
|
||||||
# for opening
|
# for opening
|
||||||
p7zip unrar-wrapper zathura mpv odt2txt
|
p7zip unrar-wrapper zathura odt2txt
|
||||||
];
|
] ++ lib.optionals (!config.programs.mpv.enable) [ mpv ];
|
||||||
plugins = {
|
plugins = {
|
||||||
src = pluginSrc;
|
src = pluginSrc;
|
||||||
mappings = {
|
mappings = {
|
||||||
|
@ -144,6 +144,6 @@
|
||||||
home.packages = with pkgs; [
|
home.packages = with pkgs; [
|
||||||
rclone sshfs fuse
|
rclone sshfs fuse
|
||||||
file jq python3Full killall
|
file jq python3Full killall
|
||||||
appimage-run comma
|
appimage-run comma nix-output-monitor
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,31 @@
|
||||||
{ config, pkgs, lib, ... }:
|
{ config, pkgs, lib, ... }:
|
||||||
{
|
{
|
||||||
imports = [ ./terminal.nix ];
|
imports = [ ./terminal.nix ];
|
||||||
|
i18n.inputMethod = let fcitx5-qt = pkgs.libsForQt5.fcitx5-qt; in {
|
||||||
|
enabled = "fcitx5";
|
||||||
|
fcitx5.addons = with pkgs; [ fcitx5-lua fcitx5-gtk fcitx5-mozc fcitx5-configtool fcitx5-qt ];
|
||||||
|
};
|
||||||
home.sessionVariables = {
|
home.sessionVariables = {
|
||||||
|
GTK_IM_MODULE = "fcitx";
|
||||||
|
QT_IM_MODULE = "fcitx";
|
||||||
|
XMODIFIERS = "@im=fcitx";
|
||||||
|
SDL_IM_MODULE = "fcitx";
|
||||||
|
XIM_SERVERS = "fcitx";
|
||||||
|
INPUT_METHOD = "fcitx";
|
||||||
|
SUDO_ASKPASS = pkgs.writeScript "sudo-askpass" ''
|
||||||
|
#! ${pkgs.bash}/bin/bash
|
||||||
|
${pkgs.libsecret}/bin/secret-tool lookup root password
|
||||||
|
'';
|
||||||
|
SDL_AUDIODRIVER = "pipewire,pulse,dsound";
|
||||||
|
# SDL 3
|
||||||
|
SDL_AUDIO_DRIVER = "pipewire,pulseaudio,dsound";
|
||||||
ALSOFT_CONF = "${config.xdg.configHome}/.config/alsoft.conf";
|
ALSOFT_CONF = "${config.xdg.configHome}/.config/alsoft.conf";
|
||||||
SDL_AUDIODRIVER = "pipewire";
|
# TODO: set to sdl3 compat when SDL3 releases
|
||||||
|
# this is for steam games, I set the launch options to:
|
||||||
|
# `SDL_DYNAMIC_API=$SDL2_DYNAMIC_API %command%`
|
||||||
|
# Steam itself doesn't work with SDL_DYNAMIC_API set, so it's
|
||||||
|
# a bad idea to set SDL_DYNAMIC_API globally
|
||||||
|
SDL2_DYNAMIC_API = "${pkgs.SDL2}/lib/libSDL2.so";
|
||||||
};
|
};
|
||||||
xdg.configFile."alsoft.conf".text = ''
|
xdg.configFile."alsoft.conf".text = ''
|
||||||
[general]
|
[general]
|
||||||
|
@ -189,10 +211,6 @@
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
i18n.inputMethod = let fcitx5-qt = pkgs.libsForQt5.fcitx5-qt; in {
|
|
||||||
enabled = "fcitx5";
|
|
||||||
fcitx5.addons = with pkgs; [ fcitx5-lua fcitx5-gtk fcitx5-mozc fcitx5-configtool fcitx5-qt ];
|
|
||||||
};
|
|
||||||
services.gammastep.enable = true;
|
services.gammastep.enable = true;
|
||||||
fonts.fontconfig.enable = true;
|
fonts.fontconfig.enable = true;
|
||||||
gtk = {
|
gtk = {
|
||||||
|
|
|
@ -80,7 +80,7 @@ commonConfig = {
|
||||||
inherit modifier;
|
inherit modifier;
|
||||||
startup = [
|
startup = [
|
||||||
{ command = builtins.toString (with pkgs; writeShellScript "init-wm" ''
|
{ command = builtins.toString (with pkgs; writeShellScript "init-wm" ''
|
||||||
${callPackage ./home-daemon.nix {}}/bin/dotfiles-home-daemon system76-scheduler&
|
${callPackage ../home-daemon {}}/bin/dotfiles-home-daemon system76-scheduler&
|
||||||
${gnome.zenity}/bin/zenity --password | (${keepassxc}/bin/keepassxc --pw-stdin ~/Nextcloud/keepass.kdbx&)
|
${gnome.zenity}/bin/zenity --password | (${keepassxc}/bin/keepassxc --pw-stdin ~/Nextcloud/keepass.kdbx&)
|
||||||
# nextcloud and nheko need secret service access
|
# nextcloud and nheko need secret service access
|
||||||
${nextcloud-client}/bin/nextcloud --background&
|
${nextcloud-client}/bin/nextcloud --background&
|
||||||
|
@ -166,16 +166,6 @@ in
|
||||||
imports = [ ./options.nix ./gui.nix ./waybar.nix ];
|
imports = [ ./options.nix ./gui.nix ./waybar.nix ];
|
||||||
home.sessionVariables = {
|
home.sessionVariables = {
|
||||||
_JAVA_AWT_WM_NONREPARENTING = "1";
|
_JAVA_AWT_WM_NONREPARENTING = "1";
|
||||||
GTK_IM_MODULE = "fcitx";
|
|
||||||
QT_IM_MODULE = "fcitx";
|
|
||||||
XMODIFIERS = "@im=fcitx";
|
|
||||||
SDL_IM_MODULE = "fcitx";
|
|
||||||
XIM_SERVERS = "fcitx";
|
|
||||||
INPUT_METHOD = "fcitx";
|
|
||||||
SUDO_ASKPASS = pkgs.writeScript "sudo-askpass" ''
|
|
||||||
#! ${pkgs.bash}/bin/bash
|
|
||||||
${pkgs.libsecret}/bin/secret-tool lookup root password
|
|
||||||
'';
|
|
||||||
};
|
};
|
||||||
xdg.configFile."xdg-desktop-portal-wlr/config".source = (pkgs.formats.ini {}).generate "xdg-desktop-portal-wlr.ini" {
|
xdg.configFile."xdg-desktop-portal-wlr/config".source = (pkgs.formats.ini {}).generate "xdg-desktop-portal-wlr.ini" {
|
||||||
screencast = {
|
screencast = {
|
||||||
|
@ -189,7 +179,7 @@ in
|
||||||
systemd.user.services = lib.mkIf config.wayland.windowManager.sway.enable {
|
systemd.user.services = lib.mkIf config.wayland.windowManager.sway.enable {
|
||||||
gammastep.Unit.ConditionEnvironment = "WAYLAND_DISPLAY";
|
gammastep.Unit.ConditionEnvironment = "WAYLAND_DISPLAY";
|
||||||
};
|
};
|
||||||
programs.mako = {
|
services.mako = {
|
||||||
enable = lib.mkDefault config.wayland.windowManager.sway.enable;
|
enable = lib.mkDefault config.wayland.windowManager.sway.enable;
|
||||||
# ms
|
# ms
|
||||||
defaultTimeout = 7500;
|
defaultTimeout = 7500;
|
||||||
|
@ -336,7 +326,9 @@ in
|
||||||
}; in commonConfig // swayConfig;
|
}; in commonConfig // swayConfig;
|
||||||
extraSessionCommands = ''
|
extraSessionCommands = ''
|
||||||
export WLR_RENDERER=vulkan
|
export WLR_RENDERER=vulkan
|
||||||
export SDL_VIDEODRIVER=wayland
|
export SDL_VIDEODRIVER=wayland,x11,kmsdrm,windows,directx
|
||||||
|
# SDL3
|
||||||
|
export SDL_VIDEO_DRIVER=wayland,x11,kmsdrm,windows
|
||||||
export QT_QPA_PLATFORM=wayland
|
export QT_QPA_PLATFORM=wayland
|
||||||
export QT_WAYLAND_DISABLE_WINDOWDECORATION=1
|
export QT_WAYLAND_DISABLE_WINDOWDECORATION=1
|
||||||
export QT_QPA_PLATFORMTHEME=gnome
|
export QT_QPA_PLATFORMTHEME=gnome
|
||||||
|
@ -345,12 +337,6 @@ in
|
||||||
export GTK_USE_PORTAL=1
|
export GTK_USE_PORTAL=1
|
||||||
export XDG_CURRENT_DESKTOP=sway
|
export XDG_CURRENT_DESKTOP=sway
|
||||||
export XDG_SESSION_DESKTOP=sway
|
export XDG_SESSION_DESKTOP=sway
|
||||||
# TODO: set to sdl3 compat when SDL3 releases
|
|
||||||
# this is for steam games, I set the launch options to:
|
|
||||||
# `SDL_DYNAMIC_API=$SDL2_DYNAMIC_API %command%`
|
|
||||||
# Steam itself doesn't work with SDL_DYNAMIC_API set, so it's
|
|
||||||
# a bad idea to set SDL_DYNAMIC_API globally
|
|
||||||
export SDL2_DYNAMIC_API=${pkgs.SDL2.out}/lib/libSDL2.so
|
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
services.swayidle = let swaylock-start = builtins.toString (with pkgs; writeScript "swaylock-start" ''
|
services.swayidle = let swaylock-start = builtins.toString (with pkgs; writeScript "swaylock-start" ''
|
||||||
|
@ -462,7 +448,7 @@ in
|
||||||
};
|
};
|
||||||
terminal = config.terminalBin;
|
terminal = config.terminalBin;
|
||||||
extraConfig = {
|
extraConfig = {
|
||||||
modi = [ "calc" "drun" "run" "ssh" ];
|
modi = [ "steam:${pkgs.callPackage ../rofi-steam-game-list {}}/bin/rofi-steam-game-list" "drun" "run" "ssh" ];
|
||||||
icon-theme = "hicolor";
|
icon-theme = "hicolor";
|
||||||
drun-match-fields = [ "name" "generic" "exec" "keywords" ];
|
drun-match-fields = [ "name" "generic" "exec" "keywords" ];
|
||||||
show-icons = true;
|
show-icons = true;
|
||||||
|
|
|
@ -19,13 +19,13 @@
|
||||||
];
|
];
|
||||||
# extraPython3Packages = pyPkgs: with pyPkgs; [ python-lsp-server ];
|
# extraPython3Packages = pyPkgs: with pyPkgs; [ python-lsp-server ];
|
||||||
extraConfig = ''
|
extraConfig = ''
|
||||||
autocmd BufReadPost * if @% !~# '\.git[\/\\]COMMIT_EDITMSG$' && line("'\"") > 1 && line("'\"") <= line("$") | exe "normal! g`\"" | endif
|
|
||||||
syntax on
|
syntax on
|
||||||
au FileType markdown set colorcolumn=73 textwidth=72
|
au FileType markdown set colorcolumn=73 textwidth=72
|
||||||
au FileType gitcommit set colorcolumn=73
|
au FileType gitcommit set colorcolumn=73
|
||||||
highlight NormalFloat guibg=NONE
|
highlight NormalFloat guibg=NONE
|
||||||
au BufReadPre * set foldmethod=syntax
|
au BufReadPre * set foldmethod=syntax
|
||||||
au BufReadPost * folddoc foldopen!
|
au BufReadPost * folddoc foldopen!
|
||||||
|
autocmd BufReadPost * if @% !~# '\.git[\/\\]COMMIT_EDITMSG$' && line("'\"") > 1 && line("'\"") <= line("$") | exe "normal! g`\"" | endif
|
||||||
'';
|
'';
|
||||||
viAlias = true;
|
viAlias = true;
|
||||||
vimAlias = true;
|
vimAlias = true;
|
||||||
|
@ -40,6 +40,36 @@
|
||||||
vim-svelte
|
vim-svelte
|
||||||
# TODO remove on next nvim update (0.8.3/0.9)
|
# TODO remove on next nvim update (0.8.3/0.9)
|
||||||
vim-nix
|
vim-nix
|
||||||
|
{ plugin = pkgs.vimUtils.buildVimPluginFrom2Nix {
|
||||||
|
pname = "vscode-nvim";
|
||||||
|
version = "2023-02-10";
|
||||||
|
src = pkgs.fetchFromGitHub {
|
||||||
|
owner = "Mofiqul";
|
||||||
|
repo = "vscode.nvim";
|
||||||
|
rev = "db9ee339b5556aa832ca58871fd18f9467a18520";
|
||||||
|
sha256 = "sha256-X2IgIjO5NNq7vJdl09hBY1TFqHlsfF1xfllKr4osILI=";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
config = lua ''
|
||||||
|
require("vscode").setup({
|
||||||
|
transparent = true,
|
||||||
|
color_overrides = {
|
||||||
|
vscGray = "#745b5f",
|
||||||
|
vscViolet = "#${config.colors.magenta}",
|
||||||
|
vscBlue = "#6ddfd8",
|
||||||
|
vscDarkBlue = "#${config.colors.blue}",
|
||||||
|
vscGreen = "#${config.colors.green}",
|
||||||
|
vscBlueGreen = "#73bf88",
|
||||||
|
vscLightGreen = "#6acf6e",
|
||||||
|
vscRed = "#${config.colors.red}",
|
||||||
|
vscOrange = "#e89666",
|
||||||
|
vscLightRed = "#e64e4e",
|
||||||
|
vscYellowOrange = "#e8b166",
|
||||||
|
vscYellow = "#${config.colors.yellow}",
|
||||||
|
vscPink = "#cf83c4",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
''; }
|
||||||
{ plugin = nvim-web-devicons;
|
{ plugin = nvim-web-devicons;
|
||||||
config = lua ''
|
config = lua ''
|
||||||
require'nvim-web-devicons'.setup {
|
require'nvim-web-devicons'.setup {
|
||||||
|
|
|
@ -8,11 +8,11 @@
|
||||||
"utils": "utils"
|
"utils": "utils"
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1676367705,
|
"lastModified": 1677783711,
|
||||||
"narHash": "sha256-un5UbRat9TwruyImtwUGcKF823rCEp4fQxnsaLFL7CM=",
|
"narHash": "sha256-eq5mOVk3gv5HITtLhPjKwi8bFnOaQplA3X0WFgHnmxE=",
|
||||||
"owner": "nix-community",
|
"owner": "nix-community",
|
||||||
"repo": "home-manager",
|
"repo": "home-manager",
|
||||||
"rev": "da72e6fc6b7dc0c3f94edbd310aae7cd95c678b5",
|
"rev": "b9e3a29864798d55ec1d6579ab97876bb1ee9664",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
@ -28,11 +28,11 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1676564857,
|
"lastModified": 1677773085,
|
||||||
"narHash": "sha256-E2O086asoR2sFhsEvPVCdneVYNoP1JbQ4B8OcIdpdPU=",
|
"narHash": "sha256-TtNq5ooEUvyHMwOnFr1nUIpqzslM3pPGmbZKe+7BU4w=",
|
||||||
"owner": "fufexan",
|
"owner": "fufexan",
|
||||||
"repo": "nix-gaming",
|
"repo": "nix-gaming",
|
||||||
"rev": "dbe7029d83ff8ab3db3e379c7a1fb65a309c5c54",
|
"rev": "d59c534258d8d9779a5497e5a6a0f4e9616365ce",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
@ -43,10 +43,10 @@
|
||||||
},
|
},
|
||||||
"nixpkgs": {
|
"nixpkgs": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1676795730,
|
"lastModified": 1677932085,
|
||||||
"narHash": "sha256-X69A9BdcPTySJJ7DqS4wc8b6eqGKi32jCSyaBsz4WB0=",
|
"narHash": "sha256-+AB4dYllWig8iO6vAiGGYl0NEgmMgGHpy9gzWJ3322g=",
|
||||||
"path": "/nix/store/wyanhqy905a9n7zy3syq5aiikd8y3ksl-source",
|
"path": "/nix/store/qilsyakhi0qmjq9iwxn49g3qbl1rp5m7-source",
|
||||||
"rev": "efc59894b1ba73cb745676616c56c780383d6788",
|
"rev": "3c5319ad3aa51551182ac82ea17ab1c6b0f0df89",
|
||||||
"type": "path"
|
"type": "path"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
@ -56,11 +56,11 @@
|
||||||
},
|
},
|
||||||
"nur": {
|
"nur": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1676785553,
|
"lastModified": 1678002043,
|
||||||
"narHash": "sha256-nJLp4LeU1MDfmyNkids+tIbpGx1tCwP4nI0gXOwKidg=",
|
"narHash": "sha256-CKAoPQaUA+kitq4ChzlM5O3oTGHuQnlSV4hNSI1Ht0g=",
|
||||||
"owner": "nix-community",
|
"owner": "nix-community",
|
||||||
"repo": "NUR",
|
"repo": "NUR",
|
||||||
"rev": "15ac68824a1d403aa0da7a92618b3ac379f3cf71",
|
"rev": "45ce037949e32a72bc65be6f20dc87fa73c5039d",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
|
|
@ -53,7 +53,7 @@
|
||||||
home.packages = with pkgs; [
|
home.packages = with pkgs; [
|
||||||
openrgb piper
|
openrgb piper
|
||||||
steam-run steam
|
steam-run steam
|
||||||
osu-lazer-bin
|
osu-lazer-bin taisei
|
||||||
easyeffects
|
easyeffects
|
||||||
# wineWowPackages.waylandFull
|
# wineWowPackages.waylandFull
|
||||||
winetricks
|
winetricks
|
||||||
|
|
1
home/rofi-steam-game-list/.gitignore
vendored
Normal file
1
home/rofi-steam-game-list/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
/target
|
225
home/rofi-steam-game-list/Cargo.lock
generated
Normal file
225
home/rofi-steam-game-list/Cargo.lock
generated
Normal file
|
@ -0,0 +1,225 @@
|
||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
version = 3
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "block-buffer"
|
||||||
|
version = "0.10.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "69cce20737498f97b993470a6e536b8523f0af7892a4f928cceb1ac5e52ebe7e"
|
||||||
|
dependencies = [
|
||||||
|
"generic-array",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cfg-if"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cpufeatures"
|
||||||
|
version = "0.2.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "28d997bd5e24a5928dd43e46dc529867e207907fe0b239c3477d924f7f2ca320"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crypto-common"
|
||||||
|
version = "0.1.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
|
||||||
|
dependencies = [
|
||||||
|
"generic-array",
|
||||||
|
"typenum",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "digest"
|
||||||
|
version = "0.10.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f"
|
||||||
|
dependencies = [
|
||||||
|
"block-buffer",
|
||||||
|
"crypto-common",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fork"
|
||||||
|
version = "0.1.20"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9788ce090af4bf8d6e8f43d3f7d12305c787456387bd2d88856fcda3aa1f0dca"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "generic-array"
|
||||||
|
version = "0.14.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bff49e947297f3312447abdca79f45f4738097cc82b06e72054d2223f601f1b9"
|
||||||
|
dependencies = [
|
||||||
|
"typenum",
|
||||||
|
"version_check",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "keyvalues-parser"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7d990301996c856ea07a84bc291e76f1273db52683663efc05c8d355976897e5"
|
||||||
|
dependencies = [
|
||||||
|
"pest",
|
||||||
|
"pest_derive",
|
||||||
|
"thiserror",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libc"
|
||||||
|
version = "0.2.139"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "once_cell"
|
||||||
|
version = "1.17.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pest"
|
||||||
|
version = "2.5.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8cbd939b234e95d72bc393d51788aec68aeeb5d51e748ca08ff3aad58cb722f7"
|
||||||
|
dependencies = [
|
||||||
|
"thiserror",
|
||||||
|
"ucd-trie",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pest_derive"
|
||||||
|
version = "2.5.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a81186863f3d0a27340815be8f2078dd8050b14cd71913db9fbda795e5f707d7"
|
||||||
|
dependencies = [
|
||||||
|
"pest",
|
||||||
|
"pest_generator",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pest_generator"
|
||||||
|
version = "2.5.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "75a1ef20bf3193c15ac345acb32e26b3dc3223aff4d77ae4fc5359567683796b"
|
||||||
|
dependencies = [
|
||||||
|
"pest",
|
||||||
|
"pest_meta",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pest_meta"
|
||||||
|
version = "2.5.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5e3b284b1f13a20dc5ebc90aff59a51b8d7137c221131b52a7260c08cbc1cc80"
|
||||||
|
dependencies = [
|
||||||
|
"once_cell",
|
||||||
|
"pest",
|
||||||
|
"sha2",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "proc-macro2"
|
||||||
|
version = "1.0.51"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5d727cae5b39d21da60fa540906919ad737832fe0b1c165da3a34d6548c849d6"
|
||||||
|
dependencies = [
|
||||||
|
"unicode-ident",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "quote"
|
||||||
|
version = "1.0.23"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rofi-steam-game-list"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"fork",
|
||||||
|
"keyvalues-parser",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sha2"
|
||||||
|
version = "0.10.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"cpufeatures",
|
||||||
|
"digest",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "syn"
|
||||||
|
version = "1.0.109"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"unicode-ident",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "thiserror"
|
||||||
|
version = "1.0.39"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a5ab016db510546d856297882807df8da66a16fb8c4101cb8b30054b0d5b2d9c"
|
||||||
|
dependencies = [
|
||||||
|
"thiserror-impl",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "thiserror-impl"
|
||||||
|
version = "1.0.39"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5420d42e90af0c38c3290abcca25b9b3bdf379fc9f55c528f53a269d9c9a267e"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "typenum"
|
||||||
|
version = "1.16.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ucd-trie"
|
||||||
|
version = "0.1.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9e79c4d996edb816c91e4308506774452e55e95c3c9de07b6729e17e15a5ef81"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-ident"
|
||||||
|
version = "1.0.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "version_check"
|
||||||
|
version = "0.9.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
10
home/rofi-steam-game-list/Cargo.toml
Normal file
10
home/rofi-steam-game-list/Cargo.toml
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
[package]
|
||||||
|
name = "rofi-steam-game-list"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
keyvalues-parser = "0.1"
|
||||||
|
fork = "0.1"
|
14
home/rofi-steam-game-list/default.nix
Normal file
14
home/rofi-steam-game-list/default.nix
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
{ lib, rustPlatform }:
|
||||||
|
rustPlatform.buildRustPackage {
|
||||||
|
pname = "rofi-steam-game-list";
|
||||||
|
version = "0.1";
|
||||||
|
|
||||||
|
src = ../rofi-steam-game-list;
|
||||||
|
|
||||||
|
cargoLock.lockFile = ../rofi-steam-game-list/Cargo.lock;
|
||||||
|
|
||||||
|
meta = with lib; {
|
||||||
|
description = "A program to list Steam games for Rofi";
|
||||||
|
license = licenses.bsd0;
|
||||||
|
};
|
||||||
|
}
|
510
home/rofi-steam-game-list/src/main.rs
Normal file
510
home/rofi-steam-game-list/src/main.rs
Normal file
|
@ -0,0 +1,510 @@
|
||||||
|
//! I tried to create a proper parser, but those abstractions turned out to be not-so-zero cost!
|
||||||
|
//! Here's a simple version instead
|
||||||
|
#![allow(clippy::similar_names)]
|
||||||
|
#![allow(clippy::cast_possible_truncation)]
|
||||||
|
#![allow(clippy::needless_pass_by_value)]
|
||||||
|
|
||||||
|
use fork::daemon;
|
||||||
|
use std::collections::{HashMap, HashSet};
|
||||||
|
use std::io::{self, prelude::*};
|
||||||
|
use std::sync::mpsc;
|
||||||
|
use std::time::{Duration, SystemTime};
|
||||||
|
|
||||||
|
fn read_file(p: impl AsRef<std::path::Path>) -> io::Result<Vec<u8>> {
|
||||||
|
let p = p.as_ref().to_owned();
|
||||||
|
let mut vec = Vec::new();
|
||||||
|
let mut file = std::fs::File::open(p)?;
|
||||||
|
file.read_to_end(&mut vec)?;
|
||||||
|
Ok(vec)
|
||||||
|
}
|
||||||
|
fn read_file_s(p: impl AsRef<std::path::Path>) -> io::Result<String> {
|
||||||
|
let p = p.as_ref().to_owned();
|
||||||
|
let mut s = String::new();
|
||||||
|
let mut file = std::fs::File::open(p)?;
|
||||||
|
std::io::Read::read_to_string(&mut file, &mut s)?;
|
||||||
|
Ok(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_file(p: impl AsRef<std::path::Path>, data: Vec<u8>) -> io::Result<()> {
|
||||||
|
let p = p.as_ref().to_owned();
|
||||||
|
let mut file = std::fs::File::create(p)?;
|
||||||
|
std::io::Write::write_all(&mut file, &data)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub struct AppInfoEntry {
|
||||||
|
pub app_id: u32,
|
||||||
|
pub info_state: u32,
|
||||||
|
pub last_updated: u32,
|
||||||
|
pub pics_token: u64,
|
||||||
|
pub text_vdf_sha1: [u8; 20],
|
||||||
|
pub change_number: u32,
|
||||||
|
pub info: HashMap<Vec<u8>, Value>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub struct AppInfo {
|
||||||
|
pub magic: u32,
|
||||||
|
pub universe: u32,
|
||||||
|
pub entries: Vec<AppInfoEntry>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub enum Value {
|
||||||
|
Map(HashMap<Vec<u8>, Value>),
|
||||||
|
String(Vec<u8>),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::missing_const_for_fn)]
|
||||||
|
impl Value {
|
||||||
|
fn into_map(self) -> Option<HashMap<Vec<u8>, Self>> {
|
||||||
|
if let Self::Map(map) = self {
|
||||||
|
Some(map)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn into_string(self) -> Option<Vec<u8>> {
|
||||||
|
if let Self::String(s) = self {
|
||||||
|
Some(s)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read_map(reader: &mut impl io::Read) -> io::Result<HashMap<Vec<u8>, Value>> {
|
||||||
|
let mut ret = HashMap::new();
|
||||||
|
let mut buf = [0u8];
|
||||||
|
let mut buf2 = [0u8; 2];
|
||||||
|
let mut buf4 = [0u8; 4];
|
||||||
|
let mut buf8 = [0u8; 8];
|
||||||
|
loop {
|
||||||
|
reader.read_exact(&mut buf)?;
|
||||||
|
let kind = buf[0];
|
||||||
|
if kind == 8 || kind == 11 {
|
||||||
|
break Ok(ret);
|
||||||
|
}
|
||||||
|
let mut key = vec![];
|
||||||
|
loop {
|
||||||
|
reader.read_exact(&mut buf)?;
|
||||||
|
if buf[0] == 0 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
key.push(buf[0]);
|
||||||
|
}
|
||||||
|
#[allow(clippy::match_same_arms)]
|
||||||
|
match kind {
|
||||||
|
0 => {
|
||||||
|
ret.insert(key, Value::Map(read_map(reader)?));
|
||||||
|
}
|
||||||
|
1 => {
|
||||||
|
let mut s = vec![];
|
||||||
|
loop {
|
||||||
|
reader.read_exact(&mut buf)?;
|
||||||
|
if buf[0] == 0 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
s.push(buf[0]);
|
||||||
|
}
|
||||||
|
ret.insert(key, Value::String(s));
|
||||||
|
}
|
||||||
|
2 => {
|
||||||
|
reader.read_exact(&mut buf4)?;
|
||||||
|
// ret.insert(key, Value::I32(i32::from_le_bytes(buf4)))?;
|
||||||
|
}
|
||||||
|
3 => {
|
||||||
|
reader.read_exact(&mut buf4)?;
|
||||||
|
// ret.insert(key, Value::F32(f32::from_le_bytes(buf4)))?;
|
||||||
|
}
|
||||||
|
4 => {
|
||||||
|
reader.read_exact(&mut buf4)?;
|
||||||
|
// ret.insert(key, Value::Pointer(i32::from_le_bytes(buf4)))?;
|
||||||
|
}
|
||||||
|
5 => {
|
||||||
|
let mut s = vec![0u16; 2];
|
||||||
|
loop {
|
||||||
|
reader.read_exact(&mut buf2)?;
|
||||||
|
if buf2 == [0u8, 0u8] {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
s.extend_from_slice(&[u16::from_le_bytes(buf2)]);
|
||||||
|
}
|
||||||
|
// utf-8 is used instead of utf-16 here
|
||||||
|
// ret.insert(key, Value::WideString(s))?;
|
||||||
|
}
|
||||||
|
7 => {
|
||||||
|
reader.read_exact(&mut buf8)?;
|
||||||
|
// ret.insert(key, Value::U64(u64::from_le_bytes(buf8)))?;
|
||||||
|
}
|
||||||
|
10 => {
|
||||||
|
reader.read_exact(&mut buf8)?;
|
||||||
|
// ret.insert(key, Value::I64(i64::from_le_bytes(buf8)))?;
|
||||||
|
}
|
||||||
|
n => panic!("invalid vdf data type: {n}"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read_app_info(reader: &mut impl io::Read) -> io::Result<AppInfo> {
|
||||||
|
let mut buf4 = [0u8; 4];
|
||||||
|
// let mut buf8 = [0u8; 8];
|
||||||
|
// let mut buf20 = [0u8; 20];
|
||||||
|
let mut buf64 = [0u8; 64];
|
||||||
|
reader.read_exact(&mut buf4)?;
|
||||||
|
assert_eq!(buf4, [0x28, 0x44, 0x56, 0x07]);
|
||||||
|
reader.read_exact(&mut buf4)?;
|
||||||
|
assert_eq!(u32::from_le_bytes(buf4), 1);
|
||||||
|
let mut ret = AppInfo {
|
||||||
|
magic: 0x0756_4428,
|
||||||
|
universe: 1,
|
||||||
|
entries: vec![],
|
||||||
|
};
|
||||||
|
loop {
|
||||||
|
reader.read_exact(&mut buf4)?;
|
||||||
|
let app_id = u32::from_le_bytes(buf4);
|
||||||
|
if app_id == 0 {
|
||||||
|
break Ok(ret);
|
||||||
|
}
|
||||||
|
let mut entry = AppInfoEntry {
|
||||||
|
app_id,
|
||||||
|
info_state: 0,
|
||||||
|
last_updated: 0,
|
||||||
|
pics_token: 0,
|
||||||
|
text_vdf_sha1: [0u8; 20],
|
||||||
|
change_number: 0,
|
||||||
|
info: HashMap::new(),
|
||||||
|
};
|
||||||
|
reader.read_exact(&mut buf64[..4 * 3 + 8 + 20 + 4 + 20])?;
|
||||||
|
// reader.read_exact(&mut buf4)?;
|
||||||
|
// size
|
||||||
|
// reader.read_exact(&mut buf4)?;
|
||||||
|
// entry.info_state = u32::from_le_bytes(buf4);
|
||||||
|
// reader.read_exact(&mut buf4)?;
|
||||||
|
// entry.last_updated = u32::from_le_bytes(buf4);
|
||||||
|
// reader.read_exact(&mut buf8)?;
|
||||||
|
// entry.pics_token = u64::from_le_bytes(buf8);
|
||||||
|
// reader.read_exact(&mut buf20)?;
|
||||||
|
// entry.text_vdf_sha1 = buf20;
|
||||||
|
// reader.read_exact(&mut buf4)?;
|
||||||
|
// entry.change_number = u32::from_le_bytes(buf4);
|
||||||
|
// reader.read_exact(&mut buf20)?;
|
||||||
|
// bin sha1
|
||||||
|
entry.info = read_map(reader)?;
|
||||||
|
ret.entries.push(entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn home() -> String {
|
||||||
|
std::env::var("HOME").unwrap()
|
||||||
|
}
|
||||||
|
fn xdg_home() -> String {
|
||||||
|
std::env::var("XDG_DATA_HOME").unwrap_or_else(|_| home() + "/.local/share")
|
||||||
|
}
|
||||||
|
fn xdg_cache() -> String {
|
||||||
|
std::env::var("XDG_CACHE_HOME").unwrap_or_else(|_| home() + "/.cache")
|
||||||
|
}
|
||||||
|
fn cache_dir() -> String {
|
||||||
|
let dir = xdg_cache() + "/rofi-steam-game-list";
|
||||||
|
let _ = std::fs::create_dir_all(&dir);
|
||||||
|
dir
|
||||||
|
}
|
||||||
|
fn history_dir() -> String {
|
||||||
|
let dir = xdg_home() + "/rofi-steam-game-list";
|
||||||
|
let _ = std::fs::create_dir_all(&dir);
|
||||||
|
dir
|
||||||
|
}
|
||||||
|
fn history(k: &str) -> HashMap<u32, u32> {
|
||||||
|
let dir = history_dir();
|
||||||
|
let mut ret = HashMap::new();
|
||||||
|
let Ok(data) = read_file(dir + "/history_" + k) else {
|
||||||
|
return ret;
|
||||||
|
};
|
||||||
|
if data.len() < 8 {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
let count = u32::from_le_bytes(data[4..8].try_into().unwrap());
|
||||||
|
let data = &mut &data[8..];
|
||||||
|
let mut buf4 = [0u8; 4];
|
||||||
|
for _ in 0..count {
|
||||||
|
if std::io::Read::read_exact(data, &mut buf4).is_err() {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
let k = u32::from_le_bytes(buf4);
|
||||||
|
if std::io::Read::read_exact(data, &mut buf4).is_err() {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
let v = u32::from_le_bytes(buf4);
|
||||||
|
ret.insert(k, v);
|
||||||
|
}
|
||||||
|
ret
|
||||||
|
}
|
||||||
|
fn write_history(m: &HashMap<u32, u32>, k: &str) {
|
||||||
|
let dir = history_dir();
|
||||||
|
let mut data = vec![];
|
||||||
|
data.extend_from_slice(&[0; 4]);
|
||||||
|
data.extend_from_slice(&(m.len() as u32).to_le_bytes());
|
||||||
|
for (k, v) in m.iter() {
|
||||||
|
data.extend_from_slice(&k.to_le_bytes());
|
||||||
|
data.extend_from_slice(&v.to_le_bytes());
|
||||||
|
}
|
||||||
|
let _ = write_file(dir + "/history_" + k, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read_time(s: String) -> io::Result<SystemTime> {
|
||||||
|
std::fs::metadata(s + "/Steam/appcache/appinfo.vdf")?.modified()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read_appinfo(target_type: String, s: String) -> io::Result<(SystemTime, Vec<(u32, String)>)> {
|
||||||
|
let time = read_time(s.clone())?;
|
||||||
|
let vec = read_file(s + "/Steam/appcache/appinfo.vdf")?;
|
||||||
|
let data = read_app_info(&mut &vec[..])?;
|
||||||
|
let mut ret = Vec::new();
|
||||||
|
for mut info in data.entries {
|
||||||
|
if let Some(mut x) = info
|
||||||
|
.info
|
||||||
|
.remove(&b"appinfo"[..])
|
||||||
|
.and_then(Value::into_map)
|
||||||
|
.and_then(|mut x| x.remove(&b"common"[..]))
|
||||||
|
.and_then(Value::into_map)
|
||||||
|
{
|
||||||
|
if let Some(mut t) = x
|
||||||
|
.remove(&b"type"[..])
|
||||||
|
.and_then(Value::into_string)
|
||||||
|
.and_then(|x| String::from_utf8(x).ok())
|
||||||
|
{
|
||||||
|
if let Some(n) = x
|
||||||
|
.remove(&b"name"[..])
|
||||||
|
.and_then(Value::into_string)
|
||||||
|
.and_then(|x| String::from_utf8(x).ok())
|
||||||
|
{
|
||||||
|
t.make_ascii_lowercase();
|
||||||
|
if t == target_type {
|
||||||
|
ret.push((info.app_id, n));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok((time, ret))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn list_appids(s: &str) -> HashSet<u32> {
|
||||||
|
let Ok(data) = read_file_s(s.to_owned() + "/Steam/steamapps/libraryfolders.vdf") else {
|
||||||
|
return HashSet::new();
|
||||||
|
};
|
||||||
|
let ret = keyvalues_parser::Vdf::parse(&data)
|
||||||
|
.unwrap()
|
||||||
|
.value
|
||||||
|
.get_obj()
|
||||||
|
.unwrap()
|
||||||
|
.values()
|
||||||
|
.flat_map(|x| {
|
||||||
|
x.iter().flat_map(|x| {
|
||||||
|
x.get_obj().unwrap().get("apps").into_iter().flat_map(|x| {
|
||||||
|
x.iter().flat_map(|x| {
|
||||||
|
x.get_obj()
|
||||||
|
.unwrap()
|
||||||
|
.keys()
|
||||||
|
.filter_map(|x| x.parse::<u32>().ok())
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.collect::<HashSet<u32>>();
|
||||||
|
ret
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cache_time(k: &str) -> std::io::Result<SystemTime> {
|
||||||
|
let path = cache_dir() + "/type_" + k;
|
||||||
|
let mut file = std::fs::File::open(path)?;
|
||||||
|
let mut data = Vec::new();
|
||||||
|
file.read_to_end(&mut data)?;
|
||||||
|
if data.len() >= 12 {
|
||||||
|
let (_, data) = data.split_at(4);
|
||||||
|
let (first, _data) = data.split_at(8);
|
||||||
|
let time = SystemTime::UNIX_EPOCH
|
||||||
|
+ Duration::from_millis(u64::from_le_bytes(first.try_into().unwrap()));
|
||||||
|
Ok(time)
|
||||||
|
} else {
|
||||||
|
Err(io::Error::from(io::ErrorKind::Other))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read_cache(k: &str) -> io::Result<(SystemTime, Vec<(u32, String)>)> {
|
||||||
|
let path = cache_dir() + "/type_" + k;
|
||||||
|
let mut file = std::fs::File::open(path)?;
|
||||||
|
let mut data = Vec::new();
|
||||||
|
file.read_to_end(&mut data)?;
|
||||||
|
if data.len() >= 16 {
|
||||||
|
let (_, data) = data.split_at(4);
|
||||||
|
let (first, data) = data.split_at(8);
|
||||||
|
let time = SystemTime::UNIX_EPOCH
|
||||||
|
+ Duration::from_millis(u64::from_le_bytes(first.try_into().unwrap()));
|
||||||
|
let (first, data) = data.split_at(4);
|
||||||
|
let count = u32::from_le_bytes(first.try_into().unwrap());
|
||||||
|
let data = &mut &data[..];
|
||||||
|
let mut buf4 = [0u8; 4];
|
||||||
|
let mut buf1 = [0u8; 1];
|
||||||
|
let mut ret = Vec::with_capacity(count as usize);
|
||||||
|
for _ in 0..count {
|
||||||
|
std::io::Read::read_exact(data, &mut buf4)?;
|
||||||
|
std::io::Read::read_exact(data, &mut buf1)?;
|
||||||
|
let len = if buf1[0] == 255 {
|
||||||
|
std::io::Read::read_exact(data, &mut buf1)?;
|
||||||
|
255 + buf1[0] as usize
|
||||||
|
} else {
|
||||||
|
buf1[0] as usize
|
||||||
|
};
|
||||||
|
let mut buf = vec![0; len];
|
||||||
|
std::io::Read::read_exact(data, &mut buf)?;
|
||||||
|
if let Ok(s) = String::from_utf8(buf) {
|
||||||
|
ret.push((u32::from_le_bytes(buf4), s));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok((time, ret))
|
||||||
|
} else {
|
||||||
|
Err(std::io::Error::new(
|
||||||
|
std::io::ErrorKind::Other,
|
||||||
|
"invalid app id cache format",
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_cache(k: &str, time: SystemTime, ids: &[(u32, String)]) {
|
||||||
|
let mut data = Vec::new();
|
||||||
|
data.extend_from_slice(&[0; 4]);
|
||||||
|
data.extend_from_slice(
|
||||||
|
&(time
|
||||||
|
.duration_since(SystemTime::UNIX_EPOCH)
|
||||||
|
.unwrap()
|
||||||
|
.as_millis() as u64)
|
||||||
|
.to_le_bytes(),
|
||||||
|
);
|
||||||
|
data.extend_from_slice(&(ids.len() as u32).to_le_bytes());
|
||||||
|
for (id, s) in ids {
|
||||||
|
if s.len() > u8::MAX as usize + u8::MAX as usize {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
data.extend_from_slice(&id.to_le_bytes());
|
||||||
|
if s.len() > u8::MAX as usize {
|
||||||
|
data.extend_from_slice(&255u8.to_le_bytes());
|
||||||
|
data.extend_from_slice(&((s.len() - u8::MAX as usize) as u8).to_le_bytes());
|
||||||
|
} else {
|
||||||
|
data.extend_from_slice(&(s.len() as u8).to_le_bytes());
|
||||||
|
}
|
||||||
|
data.extend_from_slice(s.as_bytes());
|
||||||
|
}
|
||||||
|
let path = cache_dir() + "/type_" + k;
|
||||||
|
if let Ok(mut file) = std::fs::File::create(path) {
|
||||||
|
let _ = file.write_all(&data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct PendingFut;
|
||||||
|
impl std::future::Future for PendingFut {
|
||||||
|
type Output = ();
|
||||||
|
fn poll(self: std::pin::Pin<&mut Self>, _: &mut std::task::Context<'_>) -> std::task::Poll<()> {
|
||||||
|
std::task::Poll::Pending
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let target_type = std::env::args().nth(1).map_or_else(
|
||||||
|
|| "game".to_owned(),
|
||||||
|
|mut x| {
|
||||||
|
x.make_ascii_lowercase();
|
||||||
|
x
|
||||||
|
},
|
||||||
|
);
|
||||||
|
if let Ok(appid) = std::env::var("ROFI_INFO") {
|
||||||
|
let _ = daemon(true, false);
|
||||||
|
let mut cmd = std::process::Command::new("xdg-open")
|
||||||
|
.arg(&format!("steam://rungameid/{appid}"))
|
||||||
|
.spawn()
|
||||||
|
.unwrap();
|
||||||
|
if let Ok(x) = appid.parse::<u32>() {
|
||||||
|
let mut history = history(&target_type);
|
||||||
|
history.entry(x).and_modify(|curr| *curr += 1).or_insert(1);
|
||||||
|
write_history(&history, &target_type);
|
||||||
|
}
|
||||||
|
let _ = cmd.wait();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* Flow1: read app info -> print app info -> write cache
|
||||||
|
* Flow2: read cache -> print cache -> check app info mod time -> write cache
|
||||||
|
* */
|
||||||
|
let xdg_home = xdg_home();
|
||||||
|
let xdg_home2 = xdg_home.clone();
|
||||||
|
let xdg_home3 = xdg_home;
|
||||||
|
let target_type2 = target_type.clone();
|
||||||
|
let target_type3 = target_type.clone();
|
||||||
|
let target_type4 = target_type.clone();
|
||||||
|
let a = std::thread::spawn(move || history(&target_type3));
|
||||||
|
let (tx0, rx0) = mpsc::channel();
|
||||||
|
let (tx2, rx2) = mpsc::channel();
|
||||||
|
let b = std::thread::spawn(move || {
|
||||||
|
let tx1 = tx0.clone();
|
||||||
|
std::thread::spawn(move || {
|
||||||
|
tx0.send(
|
||||||
|
read_appinfo(target_type2, crate::xdg_home()).map_or_else(|_| {
|
||||||
|
let _ = tx2.send(None);
|
||||||
|
None
|
||||||
|
}, |info| {
|
||||||
|
let _ = tx2.send(Some(info.clone()));
|
||||||
|
Some((info, false))
|
||||||
|
})
|
||||||
|
)
|
||||||
|
});
|
||||||
|
std::thread::spawn(move || tx1.send(read_cache(&target_type4).ok().map(|x| (x, true))));
|
||||||
|
#[allow(clippy::same_functions_in_if_condition)]
|
||||||
|
if let Ok(Some(x)) = rx0.recv() {
|
||||||
|
x
|
||||||
|
} else if let Ok(Some(x)) = rx0.recv() {
|
||||||
|
x
|
||||||
|
} else {
|
||||||
|
panic!()
|
||||||
|
}
|
||||||
|
});
|
||||||
|
let c = std::thread::spawn(move || list_appids(&xdg_home2));
|
||||||
|
let history = a.join().unwrap();
|
||||||
|
let ((time, app_info), is_cache) = b.join().unwrap();
|
||||||
|
let installed_games = c.join().unwrap();
|
||||||
|
|
||||||
|
let mut app_info_2 = app_info
|
||||||
|
.iter()
|
||||||
|
.filter_map(|x| {
|
||||||
|
if installed_games.contains(&x.0) {
|
||||||
|
Some(x.clone())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
app_info_2.sort_by_key(|x| u32::MAX - history.get(&x.0).unwrap_or(&0));
|
||||||
|
for (app_id, n) in &app_info_2 {
|
||||||
|
let icon = format!("{xdg_home3}/Steam/appcache/librarycache/{app_id}_icon.jpg");
|
||||||
|
print!("{n}\0info\x1f{app_id}");
|
||||||
|
if std::fs::metadata(&icon).is_ok() {
|
||||||
|
print!("\x1ficon\x1f{icon}");
|
||||||
|
}
|
||||||
|
println!();
|
||||||
|
}
|
||||||
|
let _ = daemon(true, false);
|
||||||
|
if is_cache {
|
||||||
|
if read_time(xdg_home3).unwrap() <= time {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if let Some((time, app_info)) = rx2.recv().unwrap() {
|
||||||
|
write_cache(&target_type, time, &app_info);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if let Ok(ctime) = cache_time(&target_type) {
|
||||||
|
if time <= ctime {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
write_cache(&target_type, time, &app_info);
|
||||||
|
}
|
||||||
|
}
|
|
@ -94,13 +94,11 @@
|
||||||
"vfio"
|
"vfio"
|
||||||
"vfio_iommu_type1"
|
"vfio_iommu_type1"
|
||||||
"vfio_pci"
|
"vfio_pci"
|
||||||
"vfio_virqfd"
|
|
||||||
] else []);
|
] else []);
|
||||||
initrd.availableKernelModules = lib.mkIf (!cfg.passGpuAtBoot) [
|
initrd.availableKernelModules = lib.mkIf (!cfg.passGpuAtBoot) [
|
||||||
"vfio"
|
"vfio"
|
||||||
"vfio_iommu_type1"
|
"vfio_iommu_type1"
|
||||||
"vfio_pci"
|
"vfio_pci"
|
||||||
"vfio_virqfd"
|
|
||||||
];
|
];
|
||||||
extraModulePackages =
|
extraModulePackages =
|
||||||
with config.boot.kernelPackages;
|
with config.boot.kernelPackages;
|
||||||
|
@ -118,8 +116,7 @@
|
||||||
];
|
];
|
||||||
kernelModules = [
|
kernelModules = [
|
||||||
"vhost-net"
|
"vhost-net"
|
||||||
] ++ (if cfg.passGpuAtBoot then [] else [ "vfio_virqfd" ])
|
] ++ (if enableIvshmem then [ "kvmfr" ] else []);
|
||||||
++ (if enableIvshmem then [ "kvmfr" ] else []);
|
|
||||||
};
|
};
|
||||||
services.udev.extraRules = lib.mkIf enableIvshmem
|
services.udev.extraRules = lib.mkIf enableIvshmem
|
||||||
(lib.concatStringsSep
|
(lib.concatStringsSep
|
||||||
|
|
|
@ -52,11 +52,11 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1676564857,
|
"lastModified": 1677773085,
|
||||||
"narHash": "sha256-E2O086asoR2sFhsEvPVCdneVYNoP1JbQ4B8OcIdpdPU=",
|
"narHash": "sha256-TtNq5ooEUvyHMwOnFr1nUIpqzslM3pPGmbZKe+7BU4w=",
|
||||||
"owner": "fufexan",
|
"owner": "fufexan",
|
||||||
"repo": "nix-gaming",
|
"repo": "nix-gaming",
|
||||||
"rev": "dbe7029d83ff8ab3db3e379c7a1fb65a309c5c54",
|
"rev": "d59c534258d8d9779a5497e5a6a0f4e9616365ce",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
@ -67,11 +67,11 @@
|
||||||
},
|
},
|
||||||
"nixos-hardware": {
|
"nixos-hardware": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1676775543,
|
"lastModified": 1677949148,
|
||||||
"narHash": "sha256-VI0e60l94RY9Sc90OwDZpOf/nyLy41n2ULK6I6YkoP8=",
|
"narHash": "sha256-dEdcn+UYs8TUK3VTNCQk9TsJapJLEq50A4q7eC3/PTU=",
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"repo": "nixos-hardware",
|
"repo": "nixos-hardware",
|
||||||
"rev": "525177a78023e1363bee482f520d4f2471ada03a",
|
"rev": "d63e86cbed3d399c4162594943bd8c1d8392e550",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
@ -82,15 +82,16 @@
|
||||||
},
|
},
|
||||||
"nixpkgs": {
|
"nixpkgs": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1676795730,
|
"lastModified": 1677932085,
|
||||||
"narHash": "sha256-X69A9BdcPTySJJ7DqS4wc8b6eqGKi32jCSyaBsz4WB0=",
|
"narHash": "sha256-+AB4dYllWig8iO6vAiGGYl0NEgmMgGHpy9gzWJ3322g=",
|
||||||
"owner": "nixos",
|
"owner": "nixos",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "efc59894b1ba73cb745676616c56c780383d6788",
|
"rev": "3c5319ad3aa51551182ac82ea17ab1c6b0f0df89",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
"owner": "nixos",
|
"owner": "nixos",
|
||||||
|
"ref": "nixos-unstable",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
|
@ -113,11 +114,11 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1676773870,
|
"lastModified": 1677983714,
|
||||||
"narHash": "sha256-RhG7QmA14xih1lv6SB2WDVER4fbJ1cLwr0ntCpIjKbQ=",
|
"narHash": "sha256-2A5uDpF0vN4w9tvo5N+918bK0yRYfg4FdNZ/qccgH6s=",
|
||||||
"owner": "oxalica",
|
"owner": "oxalica",
|
||||||
"repo": "rust-overlay",
|
"repo": "rust-overlay",
|
||||||
"rev": "a6fa42390d46ef1326fbe98288b65d3b586870da",
|
"rev": "1a9f6285d441ff438a6a1422dc3fde109d8615bf",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
|
|
@ -2,8 +2,7 @@
|
||||||
description = "NixOS configuration";
|
description = "NixOS configuration";
|
||||||
|
|
||||||
inputs = {
|
inputs = {
|
||||||
# nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
|
nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
|
||||||
nixpkgs.url = "github:nixos/nixpkgs";
|
|
||||||
utils.url = "github:gytis-ivaskevicius/flake-utils-plus";
|
utils.url = "github:gytis-ivaskevicius/flake-utils-plus";
|
||||||
nixos-hardware.url = "github:NixOS/nixos-hardware";
|
nixos-hardware.url = "github:NixOS/nixos-hardware";
|
||||||
impermanence.url = "github:nix-community/impermanence";
|
impermanence.url = "github:nix-community/impermanence";
|
||||||
|
|
|
@ -43,6 +43,7 @@ in {
|
||||||
# resume_offset = $(btrfs inspect-internal map-swapfile -r path/to/swapfile)
|
# resume_offset = $(btrfs inspect-internal map-swapfile -r path/to/swapfile)
|
||||||
"resume_offset=533760"
|
"resume_offset=533760"
|
||||||
"fbcon=font:TER16x32"
|
"fbcon=font:TER16x32"
|
||||||
|
"consoleblank=60"
|
||||||
];
|
];
|
||||||
cleanTmpDir = true;
|
cleanTmpDir = true;
|
||||||
loader = {
|
loader = {
|
||||||
|
|
Loading…
Reference in a new issue