commit 4aac54bff6080c88de0a936e5579bd420f24f9d8 Author: gibbyDev Date: Fri Jul 10 20:07:29 2026 -0400 I am batman diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..786a53a --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +.vscode + +hosts/desktop/ +hosts/laptop/ +hosts/yoga/ diff --git a/.p10k.zsh b/.p10k.zsh new file mode 100644 index 0000000..3c220ca --- /dev/null +++ b/.p10k.zsh @@ -0,0 +1,1721 @@ + +# Generated by Powerlevel10k configuration wizard on 2026-01-21 at 16:37 EST. +# Based on romkatv/powerlevel10k/config/p10k-lean-8colors.zsh. +# Wizard options: nerdfont-v3 + powerline, small icons, unicode, lean_8colors, 12h time, +# 2 lines, disconnected, no frame, compact, few icons, concise, transient_prompt, +# instant_prompt=verbose. +# Type `p10k configure` to generate another config. +# +# Config for Powerlevel10k with 8-color lean prompt style. Type `p10k configure` to generate +# your own config based on it. +# +# Tip: Looking for a nice color? Here's a one-liner to print colormap. +# +# for i in {0..255}; do print -Pn "%K{$i} %k%F{$i}${(l:3::0:)i}%f " ${${(M)$((i%6)):#3}:+$'\n'}; done + +# Temporarily change options. +'builtin' 'local' '-a' 'p10k_config_opts' +[[ ! -o 'aliases' ]] || p10k_config_opts+=('aliases') +[[ ! -o 'sh_glob' ]] || p10k_config_opts+=('sh_glob') +[[ ! -o 'no_brace_expand' ]] || p10k_config_opts+=('no_brace_expand') +'builtin' 'setopt' 'no_aliases' 'no_sh_glob' 'brace_expand' + +() { + emulate -L zsh -o extended_glob + + # Unset all configuration options. This allows you to apply configuration changes without + # restarting zsh. Edit ~/.p10k.zsh and type `source ~/.p10k.zsh`. + unset -m '(POWERLEVEL9K_*|DEFAULT_USER)~POWERLEVEL9K_GITSTATUS_DIR' + + # Zsh >= 5.1 is required. + [[ $ZSH_VERSION == (5.<1->*|<6->.*) ]] || return + + # The list of segments shown on the left. Fill it with the most important segments. + typeset -g POWERLEVEL9K_LEFT_PROMPT_ELEMENTS=( + # =========================[ Line #1 ]========================= + # os_icon # os identifier + dir # current directory + vcs # git status + # =========================[ Line #2 ]========================= + newline # \n + prompt_char # prompt symbol + ) + + # The list of segments shown on the right. Fill it with less important segments. + # Right prompt on the last prompt line (where you are typing your commands) gets + # automatically hidden when the input line reaches it. Right prompt above the + # last prompt line gets hidden if it would overlap with left prompt. + typeset -g POWERLEVEL9K_RIGHT_PROMPT_ELEMENTS=( + # =========================[ Line #1 ]========================= + status # exit code of the last command + command_execution_time # duration of the last command + background_jobs # presence of background jobs + direnv # direnv status (https://direnv.net/) + asdf # asdf version manager (https://github.com/asdf-vm/asdf) + virtualenv # python virtual environment (https://docs.python.org/3/library/venv.html) + anaconda # conda environment (https://conda.io/) + pyenv # python environment (https://github.com/pyenv/pyenv) + goenv # go environment (https://github.com/syndbg/goenv) + nodenv # node.js version from nodenv (https://github.com/nodenv/nodenv) + nvm # node.js version from nvm (https://github.com/nvm-sh/nvm) + nodeenv # node.js environment (https://github.com/ekalinin/nodeenv) + # node_version # node.js version + # go_version # go version (https://golang.org) + # rust_version # rustc version (https://www.rust-lang.org) + # dotnet_version # .NET version (https://dotnet.microsoft.com) + # php_version # php version (https://www.php.net/) + # laravel_version # laravel php framework version (https://laravel.com/) + # java_version # java version (https://www.java.com/) + # package # name@version from package.json (https://docs.npmjs.com/files/package.json) + rbenv # ruby version from rbenv (https://github.com/rbenv/rbenv) + rvm # ruby version from rvm (https://rvm.io) + fvm # flutter version management (https://github.com/leoafarias/fvm) + luaenv # lua version from luaenv (https://github.com/cehoffman/luaenv) + jenv # java version from jenv (https://github.com/jenv/jenv) + plenv # perl version from plenv (https://github.com/tokuhirom/plenv) + perlbrew # perl version from perlbrew (https://github.com/gugod/App-perlbrew) + phpenv # php version from phpenv (https://github.com/phpenv/phpenv) + scalaenv # scala version from scalaenv (https://github.com/scalaenv/scalaenv) + haskell_stack # haskell version from stack (https://haskellstack.org/) + kubecontext # current kubernetes context (https://kubernetes.io/) + terraform # terraform workspace (https://www.terraform.io) + # terraform_version # terraform version (https://www.terraform.io) + aws # aws profile (https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-profiles.html) + aws_eb_env # aws elastic beanstalk environment (https://aws.amazon.com/elasticbeanstalk/) + azure # azure account name (https://docs.microsoft.com/en-us/cli/azure) + gcloud # google cloud cli account and project (https://cloud.google.com/) + google_app_cred # google application credentials (https://cloud.google.com/docs/authentication/production) + toolbox # toolbox name (https://github.com/containers/toolbox) + context # user@hostname + nordvpn # nordvpn connection status, linux only (https://nordvpn.com/) + ranger # ranger shell (https://github.com/ranger/ranger) + yazi # yazi shell (https://github.com/sxyazi/yazi) + nnn # nnn shell (https://github.com/jarun/nnn) + lf # lf shell (https://github.com/gokcehan/lf) + xplr # xplr shell (https://github.com/sayanarijit/xplr) + vim_shell # vim shell indicator (:sh) + midnight_commander # midnight commander shell (https://midnight-commander.org/) + nix_shell # nix shell (https://nixos.org/nixos/nix-pills/developing-with-nix-shell.html) + chezmoi_shell # chezmoi shell (https://www.chezmoi.io/) + # vpn_ip # virtual private network indicator + # load # CPU load + # disk_usage # disk usage + # ram # free RAM + # swap # used swap + todo # todo items (https://github.com/todotxt/todo.txt-cli) + timewarrior # timewarrior tracking status (https://timewarrior.net/) + taskwarrior # taskwarrior task count (https://taskwarrior.org/) + per_directory_history # Oh My Zsh per-directory-history local/global indicator + # cpu_arch # CPU architecture + time # current time + # =========================[ Line #2 ]========================= + newline # \n + # ip # ip address and bandwidth usage for a specified network interface + # public_ip # public IP address + # proxy # system-wide http/https/ftp proxy + # battery # internal battery + # wifi # wifi speed + # example # example user-defined segment (see prompt_example function below) + ) + + # Defines character set used by powerlevel10k. It's best to let `p10k configure` set it for you. + typeset -g POWERLEVEL9K_MODE=nerdfont-v3 + # When set to `moderate`, some icons will have an extra space after them. This is meant to avoid + # icon overlap when using non-monospace fonts. When set to `none`, spaces are not added. + typeset -g POWERLEVEL9K_ICON_PADDING=none + + # Basic style options that define the overall look of your prompt. You probably don't want to + # change them. + typeset -g POWERLEVEL9K_BACKGROUND= # transparent background + typeset -g POWERLEVEL9K_{LEFT,RIGHT}_{LEFT,RIGHT}_WHITESPACE= # no surrounding whitespace + typeset -g POWERLEVEL9K_{LEFT,RIGHT}_SUBSEGMENT_SEPARATOR=' ' # separate segments with a space + typeset -g POWERLEVEL9K_{LEFT,RIGHT}_SEGMENT_SEPARATOR= # no end-of-line symbol + + # When set to true, icons appear before content on both sides of the prompt. When set + # to false, icons go after content. If empty or not set, icons go before content in the left + # prompt and after content in the right prompt. + # + # You can also override it for a specific segment: + # + # POWERLEVEL9K_STATUS_ICON_BEFORE_CONTENT=false + # + # Or for a specific segment in specific state: + # + # POWERLEVEL9K_DIR_NOT_WRITABLE_ICON_BEFORE_CONTENT=false + typeset -g POWERLEVEL9K_ICON_BEFORE_CONTENT=true + + # Add an empty line before each prompt. + typeset -g POWERLEVEL9K_PROMPT_ADD_NEWLINE=false + + # Connect left prompt lines with these symbols. + typeset -g POWERLEVEL9K_MULTILINE_FIRST_PROMPT_PREFIX= + typeset -g POWERLEVEL9K_MULTILINE_NEWLINE_PROMPT_PREFIX= + typeset -g POWERLEVEL9K_MULTILINE_LAST_PROMPT_PREFIX= + # Connect right prompt lines with these symbols. + typeset -g POWERLEVEL9K_MULTILINE_FIRST_PROMPT_SUFFIX= + typeset -g POWERLEVEL9K_MULTILINE_NEWLINE_PROMPT_SUFFIX= + typeset -g POWERLEVEL9K_MULTILINE_LAST_PROMPT_SUFFIX= + + # The left end of left prompt. + typeset -g POWERLEVEL9K_LEFT_PROMPT_FIRST_SEGMENT_START_SYMBOL= + # The right end of right prompt. + typeset -g POWERLEVEL9K_RIGHT_PROMPT_LAST_SEGMENT_END_SYMBOL= + + # Ruler, a.k.a. the horizontal line before each prompt. If you set it to true, you'll + # probably want to set POWERLEVEL9K_PROMPT_ADD_NEWLINE=false above and + # POWERLEVEL9K_MULTILINE_FIRST_PROMPT_GAP_CHAR=' ' below. + typeset -g POWERLEVEL9K_SHOW_RULER=false + typeset -g POWERLEVEL9K_RULER_CHAR='─' # reasonable alternative: '·' + typeset -g POWERLEVEL9K_RULER_FOREGROUND=7 + + # Filler between left and right prompt on the first prompt line. You can set it to '·' or '─' + # to make it easier to see the alignment between left and right prompt and to separate prompt + # from command output. It serves the same purpose as ruler (see above) without increasing + # the number of prompt lines. You'll probably want to set POWERLEVEL9K_SHOW_RULER=false + # if using this. You might also like POWERLEVEL9K_PROMPT_ADD_NEWLINE=false for more compact + # prompt. + typeset -g POWERLEVEL9K_MULTILINE_FIRST_PROMPT_GAP_CHAR=' ' + if [[ $POWERLEVEL9K_MULTILINE_FIRST_PROMPT_GAP_CHAR != ' ' ]]; then + # The color of the filler. + typeset -g POWERLEVEL9K_MULTILINE_FIRST_PROMPT_GAP_FOREGROUND=7 + # Add a space between the end of left prompt and the filler. + typeset -g POWERLEVEL9K_LEFT_PROMPT_LAST_SEGMENT_END_SYMBOL=' ' + # Add a space between the filler and the start of right prompt. + typeset -g POWERLEVEL9K_RIGHT_PROMPT_FIRST_SEGMENT_START_SYMBOL=' ' + # Start filler from the edge of the screen if there are no left segments on the first line. + typeset -g POWERLEVEL9K_EMPTY_LINE_LEFT_PROMPT_FIRST_SEGMENT_END_SYMBOL='%{%}' + # End filler on the edge of the screen if there are no right segments on the first line. + typeset -g POWERLEVEL9K_EMPTY_LINE_RIGHT_PROMPT_FIRST_SEGMENT_START_SYMBOL='%{%}' + fi + + #################################[ os_icon: os identifier ]################################## + # OS identifier color. + typeset -g POWERLEVEL9K_OS_ICON_FOREGROUND= + # Custom icon. + # typeset -g POWERLEVEL9K_OS_ICON_CONTENT_EXPANSION='⭐' + + ################################[ prompt_char: prompt symbol ]################################ + # Green prompt symbol if the last command succeeded. + typeset -g POWERLEVEL9K_PROMPT_CHAR_OK_{VIINS,VICMD,VIVIS,VIOWR}_FOREGROUND=2 + # Red prompt symbol if the last command failed. + typeset -g POWERLEVEL9K_PROMPT_CHAR_ERROR_{VIINS,VICMD,VIVIS,VIOWR}_FOREGROUND=1 + # Default prompt symbol. + typeset -g POWERLEVEL9K_PROMPT_CHAR_{OK,ERROR}_VIINS_CONTENT_EXPANSION='❯' + # Prompt symbol in command vi mode. + typeset -g POWERLEVEL9K_PROMPT_CHAR_{OK,ERROR}_VICMD_CONTENT_EXPANSION='❮' + # Prompt symbol in visual vi mode. + typeset -g POWERLEVEL9K_PROMPT_CHAR_{OK,ERROR}_VIVIS_CONTENT_EXPANSION='V' + # Prompt symbol in overwrite vi mode. + typeset -g POWERLEVEL9K_PROMPT_CHAR_{OK,ERROR}_VIOWR_CONTENT_EXPANSION='▶' + typeset -g POWERLEVEL9K_PROMPT_CHAR_OVERWRITE_STATE=true + # No line terminator if prompt_char is the last segment. + typeset -g POWERLEVEL9K_PROMPT_CHAR_LEFT_PROMPT_LAST_SEGMENT_END_SYMBOL='' + # No line introducer if prompt_char is the first segment. + typeset -g POWERLEVEL9K_PROMPT_CHAR_LEFT_PROMPT_FIRST_SEGMENT_START_SYMBOL= + + ##################################[ dir: current directory ]################################## + # Default current directory color. + typeset -g POWERLEVEL9K_DIR_FOREGROUND=4 + # If directory is too long, shorten some of its segments to the shortest possible unique + # prefix. The shortened directory can be tab-completed to the original. + typeset -g POWERLEVEL9K_SHORTEN_STRATEGY=truncate_to_unique + # Replace removed segment suffixes with this symbol. + typeset -g POWERLEVEL9K_SHORTEN_DELIMITER= + # Color of the shortened directory segments. + typeset -g POWERLEVEL9K_DIR_SHORTENED_FOREGROUND=4 + # Color of the anchor directory segments. Anchor segments are never shortened. The first + # segment is always an anchor. + typeset -g POWERLEVEL9K_DIR_ANCHOR_FOREGROUND=4 + # Set to true to display anchor directory segments in bold. + typeset -g POWERLEVEL9K_DIR_ANCHOR_BOLD=false + # Don't shorten directories that contain any of these files. They are anchors. + local anchor_files=( + .bzr + .citc + .git + .hg + .node-version + .python-version + .go-version + .ruby-version + .lua-version + .java-version + .perl-version + .php-version + .tool-versions + .mise.toml + .shorten_folder_marker + .svn + .terraform + CVS + Cargo.toml + composer.json + go.mod + package.json + stack.yaml + ) + typeset -g POWERLEVEL9K_SHORTEN_FOLDER_MARKER="(${(j:|:)anchor_files})" + # If set to "first" ("last"), remove everything before the first (last) subdirectory that contains + # files matching $POWERLEVEL9K_SHORTEN_FOLDER_MARKER. For example, when the current directory is + # /foo/bar/git_repo/nested_git_repo/baz, prompt will display git_repo/nested_git_repo/baz (first) + # or nested_git_repo/baz (last). This assumes that git_repo and nested_git_repo contain markers + # and other directories don't. + # + # Optionally, "first" and "last" can be followed by ":" where is an integer. + # This moves the truncation point to the right (positive offset) or to the left (negative offset) + # relative to the marker. Plain "first" and "last" are equivalent to "first:0" and "last:0" + # respectively. + typeset -g POWERLEVEL9K_DIR_TRUNCATE_BEFORE_MARKER=false + # Don't shorten this many last directory segments. They are anchors. + typeset -g POWERLEVEL9K_SHORTEN_DIR_LENGTH=1 + # Shorten directory if it's longer than this even if there is space for it. The value can + # be either absolute (e.g., '80') or a percentage of terminal width (e.g, '50%'). If empty, + # directory will be shortened only when prompt doesn't fit or when other parameters demand it + # (see POWERLEVEL9K_DIR_MIN_COMMAND_COLUMNS and POWERLEVEL9K_DIR_MIN_COMMAND_COLUMNS_PCT below). + # If set to `0`, directory will always be shortened to its minimum length. + typeset -g POWERLEVEL9K_DIR_MAX_LENGTH=80 + # When `dir` segment is on the last prompt line, try to shorten it enough to leave at least this + # many columns for typing commands. + typeset -g POWERLEVEL9K_DIR_MIN_COMMAND_COLUMNS=40 + # When `dir` segment is on the last prompt line, try to shorten it enough to leave at least + # COLUMNS * POWERLEVEL9K_DIR_MIN_COMMAND_COLUMNS_PCT * 0.01 columns for typing commands. + typeset -g POWERLEVEL9K_DIR_MIN_COMMAND_COLUMNS_PCT=50 + # If set to true, embed a hyperlink into the directory. Useful for quickly + # opening a directory in the file manager simply by clicking the link. + # Can also be handy when the directory is shortened, as it allows you to see + # the full directory that was used in previous commands. + typeset -g POWERLEVEL9K_DIR_HYPERLINK=false + + # Enable special styling for non-writable and non-existent directories. See POWERLEVEL9K_LOCK_ICON + # and POWERLEVEL9K_DIR_CLASSES below. + typeset -g POWERLEVEL9K_DIR_SHOW_WRITABLE=v3 + + # The default icon shown next to non-writable and non-existent directories when + # POWERLEVEL9K_DIR_SHOW_WRITABLE is set to v3. + # typeset -g POWERLEVEL9K_LOCK_ICON='⭐' + + # POWERLEVEL9K_DIR_CLASSES allows you to specify custom icons and colors for different + # directories. It must be an array with 3 * N elements. Each triplet consists of: + # + # 1. A pattern against which the current directory ($PWD) is matched. Matching is done with + # extended_glob option enabled. + # 2. Directory class for the purpose of styling. + # 3. An empty string. + # + # Triplets are tried in order. The first triplet whose pattern matches $PWD wins. + # + # If POWERLEVEL9K_DIR_SHOW_WRITABLE is set to v3, non-writable and non-existent directories + # acquire class suffix _NOT_WRITABLE and NON_EXISTENT respectively. + # + # For example, given these settings: + # + # typeset -g POWERLEVEL9K_DIR_CLASSES=( + # '~/work(|/*)' WORK '' + # '~(|/*)' HOME '' + # '*' DEFAULT '') + # + # Whenever the current directory is ~/work or a subdirectory of ~/work, it gets styled with one + # of the following classes depending on its writability and existence: WORK, WORK_NOT_WRITABLE or + # WORK_NON_EXISTENT. + # + # Simply assigning classes to directories doesn't have any visible effects. It merely gives you an + # option to define custom colors and icons for different directory classes. + # + # # Styling for WORK. + # typeset -g POWERLEVEL9K_DIR_WORK_VISUAL_IDENTIFIER_EXPANSION='⭐' + # typeset -g POWERLEVEL9K_DIR_WORK_FOREGROUND=4 + # typeset -g POWERLEVEL9K_DIR_WORK_SHORTENED_FOREGROUND=4 + # typeset -g POWERLEVEL9K_DIR_WORK_ANCHOR_FOREGROUND=4 + # + # # Styling for WORK_NOT_WRITABLE. + # typeset -g POWERLEVEL9K_DIR_WORK_NOT_WRITABLE_VISUAL_IDENTIFIER_EXPANSION='⭐' + # typeset -g POWERLEVEL9K_DIR_WORK_NOT_WRITABLE_FOREGROUND=4 + # typeset -g POWERLEVEL9K_DIR_WORK_NOT_WRITABLE_SHORTENED_FOREGROUND=4 + # typeset -g POWERLEVEL9K_DIR_WORK_NOT_WRITABLE_ANCHOR_FOREGROUND=4# + # + # Styling for WORK_NON_EXISTENT. + # typeset -g POWERLEVEL9K_DIR_WORK_NON_EXISTENT_VISUAL_IDENTIFIER_EXPANSION='⭐' + # typeset -g POWERLEVEL9K_DIR_WORK_NON_EXISTENT_FOREGROUND=4 + # typeset -g POWERLEVEL9K_DIR_WORK_NON_EXISTENT_SHORTENED_FOREGROUND=4 + # typeset -g POWERLEVEL9K_DIR_WORK_NON_EXISTENT_ANCHOR_FOREGROUND=4 + # + # If a styling parameter isn't explicitly defined for some class, it falls back to the classless + # parameter. For example, if POWERLEVEL9K_DIR_WORK_NOT_WRITABLE_FOREGROUND is not set, it falls + # back to POWERLEVEL9K_DIR_FOREGROUND. + # + typeset -g POWERLEVEL9K_DIR_CLASSES=() + + # Custom prefix. + # typeset -g POWERLEVEL9K_DIR_PREFIX='%fin ' + + #####################################[ vcs: git status ]###################################### + # Branch icon. Set this parameter to '\UE0A0 ' for the popular Powerline branch icon. + typeset -g POWERLEVEL9K_VCS_BRANCH_ICON= + + # Untracked files icon. It's really a question mark, your font isn't broken. + # Change the value of this parameter to show a different icon. + typeset -g POWERLEVEL9K_VCS_UNTRACKED_ICON='?' + + # Formatter for Git status. + # + # Example output: master wip ⇣42⇡42 *42 merge ~42 +42 !42 ?42. + # + # You can edit the function to customize how Git status looks. + # + # VCS_STATUS_* parameters are set by gitstatus plugin. See reference: + # https://github.com/romkatv/gitstatus/blob/master/gitstatus.plugin.zsh. + function my_git_formatter() { + emulate -L zsh + + if [[ -n $P9K_CONTENT ]]; then + # If P9K_CONTENT is not empty, use it. It's either "loading" or from vcs_info (not from + # gitstatus plugin). VCS_STATUS_* parameters are not available in this case. + typeset -g my_git_format=$P9K_CONTENT + return + fi + + if (( $1 )); then + # Styling for up-to-date Git status. + local meta='%f' # default foreground + local clean='%2F' # green foreground + local modified='%3F' # yellow foreground + local untracked='%4F' # blue foreground + local conflicted='%1F' # red foreground + else + # Styling for incomplete and stale Git status. + local meta='%f' # default foreground + local clean='%f' # default foreground + local modified='%f' # default foreground + local untracked='%f' # default foreground + local conflicted='%f' # default foreground + fi + + local res + + if [[ -n $VCS_STATUS_LOCAL_BRANCH ]]; then + local branch=${(V)VCS_STATUS_LOCAL_BRANCH} + # If local branch name is at most 32 characters long, show it in full. + # Otherwise show the first 12 … the last 12. + # Tip: To always show local branch name in full without truncation, delete the next line. + (( $#branch > 32 )) && branch[13,-13]="…" # <-- this line + res+="${clean}${(g::)POWERLEVEL9K_VCS_BRANCH_ICON}${branch//\%/%%}" + fi + + if [[ -n $VCS_STATUS_TAG + # Show tag only if not on a branch. + # Tip: To always show tag, delete the next line. + && -z $VCS_STATUS_LOCAL_BRANCH # <-- this line + ]]; then + local tag=${(V)VCS_STATUS_TAG} + # If tag name is at most 32 characters long, show it in full. + # Otherwise show the first 12 … the last 12. + # Tip: To always show tag name in full without truncation, delete the next line. + (( $#tag > 32 )) && tag[13,-13]="…" # <-- this line + res+="${meta}#${clean}${tag//\%/%%}" + fi + + # Display the current Git commit if there is no branch and no tag. + # Tip: To always display the current Git commit, delete the next line. + [[ -z $VCS_STATUS_LOCAL_BRANCH && -z $VCS_STATUS_TAG ]] && # <-- this line + res+="${meta}@${clean}${VCS_STATUS_COMMIT[1,8]}" + + # Show tracking branch name if it differs from local branch. + if [[ -n ${VCS_STATUS_REMOTE_BRANCH:#$VCS_STATUS_LOCAL_BRANCH} ]]; then + res+="${meta}:${clean}${(V)VCS_STATUS_REMOTE_BRANCH//\%/%%}" + fi + + # Display "wip" if the latest commit's summary contains "wip" or "WIP". + if [[ $VCS_STATUS_COMMIT_SUMMARY == (|*[^[:alnum:]])(wip|WIP)(|[^[:alnum:]]*) ]]; then + res+=" ${modified}wip" + fi + + if (( VCS_STATUS_COMMITS_AHEAD || VCS_STATUS_COMMITS_BEHIND )); then + # ⇣42 if behind the remote. + (( VCS_STATUS_COMMITS_BEHIND )) && res+=" ${clean}⇣${VCS_STATUS_COMMITS_BEHIND}" + # ⇡42 if ahead of the remote; no leading space if also behind the remote: ⇣42⇡42. + (( VCS_STATUS_COMMITS_AHEAD && !VCS_STATUS_COMMITS_BEHIND )) && res+=" " + (( VCS_STATUS_COMMITS_AHEAD )) && res+="${clean}⇡${VCS_STATUS_COMMITS_AHEAD}" + elif [[ -n $VCS_STATUS_REMOTE_BRANCH ]]; then + # Tip: Uncomment the next line to display '=' if up to date with the remote. + # res+=" ${clean}=" + fi + + # ⇠42 if behind the push remote. + (( VCS_STATUS_PUSH_COMMITS_BEHIND )) && res+=" ${clean}⇠${VCS_STATUS_PUSH_COMMITS_BEHIND}" + (( VCS_STATUS_PUSH_COMMITS_AHEAD && !VCS_STATUS_PUSH_COMMITS_BEHIND )) && res+=" " + # ⇢42 if ahead of the push remote; no leading space if also behind: ⇠42⇢42. + (( VCS_STATUS_PUSH_COMMITS_AHEAD )) && res+="${clean}⇢${VCS_STATUS_PUSH_COMMITS_AHEAD}" + # *42 if have stashes. + (( VCS_STATUS_STASHES )) && res+=" ${clean}*${VCS_STATUS_STASHES}" + # 'merge' if the repo is in an unusual state. + [[ -n $VCS_STATUS_ACTION ]] && res+=" ${conflicted}${VCS_STATUS_ACTION}" + # ~42 if have merge conflicts. + (( VCS_STATUS_NUM_CONFLICTED )) && res+=" ${conflicted}~${VCS_STATUS_NUM_CONFLICTED}" + # +42 if have staged changes. + (( VCS_STATUS_NUM_STAGED )) && res+=" ${modified}+${VCS_STATUS_NUM_STAGED}" + # !42 if have unstaged changes. + (( VCS_STATUS_NUM_UNSTAGED )) && res+=" ${modified}!${VCS_STATUS_NUM_UNSTAGED}" + # ?42 if have untracked files. It's really a question mark, your font isn't broken. + # See POWERLEVEL9K_VCS_UNTRACKED_ICON above if you want to use a different icon. + # Remove the next line if you don't want to see untracked files at all. + (( VCS_STATUS_NUM_UNTRACKED )) && res+=" ${untracked}${(g::)POWERLEVEL9K_VCS_UNTRACKED_ICON}${VCS_STATUS_NUM_UNTRACKED}" + # "─" if the number of unstaged files is unknown. This can happen due to + # POWERLEVEL9K_VCS_MAX_INDEX_SIZE_DIRTY (see below) being set to a non-negative number lower + # than the number of files in the Git index, or due to bash.showDirtyState being set to false + # in the repository config. The number of staged and untracked files may also be unknown + # in this case. + (( VCS_STATUS_HAS_UNSTAGED == -1 )) && res+=" ${modified}─" + + typeset -g my_git_format=$res + } + functions -M my_git_formatter 2>/dev/null + + # Don't count the number of unstaged, untracked and conflicted files in Git repositories with + # more than this many files in the index. Negative value means infinity. + # + # If you are working in Git repositories with tens of millions of files and seeing performance + # sagging, try setting POWERLEVEL9K_VCS_MAX_INDEX_SIZE_DIRTY to a number lower than the output + # of `git ls-files | wc -l`. Alternatively, add `bash.showDirtyState = false` to the repository's + # config: `git config bash.showDirtyState false`. + typeset -g POWERLEVEL9K_VCS_MAX_INDEX_SIZE_DIRTY=-1 + + # Don't show Git status in prompt for repositories whose workdir matches this pattern. + # For example, if set to '~', the Git repository at $HOME/.git will be ignored. + # Multiple patterns can be combined with '|': '~(|/foo)|/bar/baz/*'. + typeset -g POWERLEVEL9K_VCS_DISABLED_WORKDIR_PATTERN='~' + + # Disable the default Git status formatting. + typeset -g POWERLEVEL9K_VCS_DISABLE_GITSTATUS_FORMATTING=true + # Install our own Git status formatter. + typeset -g POWERLEVEL9K_VCS_CONTENT_EXPANSION='${$((my_git_formatter(1)))+${my_git_format}}' + typeset -g POWERLEVEL9K_VCS_LOADING_CONTENT_EXPANSION='${$((my_git_formatter(0)))+${my_git_format}}' + # Enable counters for staged, unstaged, etc. + typeset -g POWERLEVEL9K_VCS_{STAGED,UNSTAGED,UNTRACKED,CONFLICTED,COMMITS_AHEAD,COMMITS_BEHIND}_MAX_NUM=-1 + + # Icon color. + typeset -g POWERLEVEL9K_VCS_VISUAL_IDENTIFIER_COLOR=2 + typeset -g POWERLEVEL9K_VCS_LOADING_VISUAL_IDENTIFIER_COLOR= + # Custom icon. + typeset -g POWERLEVEL9K_VCS_VISUAL_IDENTIFIER_EXPANSION= + # Custom prefix. + # typeset -g POWERLEVEL9K_VCS_PREFIX='%fon ' + + # Show status of repositories of these types. You can add svn and/or hg if you are + # using them. If you do, your prompt may become slow even when your current directory + # isn't in an svn or hg repository. + typeset -g POWERLEVEL9K_VCS_BACKENDS=(git) + + # These settings are used for repositories other than Git or when gitstatusd fails and + # Powerlevel10k has to fall back to using vcs_info. + typeset -g POWERLEVEL9K_VCS_CLEAN_FOREGROUND=2 + typeset -g POWERLEVEL9K_VCS_UNTRACKED_FOREGROUND=2 + typeset -g POWERLEVEL9K_VCS_MODIFIED_FOREGROUND=3 + + ##########################[ status: exit code of the last command ]########################### + # Enable OK_PIPE, ERROR_PIPE and ERROR_SIGNAL status states to allow us to enable, disable and + # style them independently from the regular OK and ERROR state. + typeset -g POWERLEVEL9K_STATUS_EXTENDED_STATES=true + + # Status on success. No content, just an icon. No need to show it if prompt_char is enabled as + # it will signify success by turning green. + typeset -g POWERLEVEL9K_STATUS_OK=false + typeset -g POWERLEVEL9K_STATUS_OK_FOREGROUND=2 + typeset -g POWERLEVEL9K_STATUS_OK_VISUAL_IDENTIFIER_EXPANSION='✔' + + # Status when some part of a pipe command fails but the overall exit status is zero. It may look + # like this: 1|0. + typeset -g POWERLEVEL9K_STATUS_OK_PIPE=true + typeset -g POWERLEVEL9K_STATUS_OK_PIPE_FOREGROUND=2 + typeset -g POWERLEVEL9K_STATUS_OK_PIPE_VISUAL_IDENTIFIER_EXPANSION='✔' + + # Status when it's just an error code (e.g., '1'). No need to show it if prompt_char is enabled as + # it will signify error by turning red. + typeset -g POWERLEVEL9K_STATUS_ERROR=false + typeset -g POWERLEVEL9K_STATUS_ERROR_FOREGROUND=1 + typeset -g POWERLEVEL9K_STATUS_ERROR_VISUAL_IDENTIFIER_EXPANSION='✘' + + # Status when the last command was terminated by a signal. + typeset -g POWERLEVEL9K_STATUS_ERROR_SIGNAL=true + typeset -g POWERLEVEL9K_STATUS_ERROR_SIGNAL_FOREGROUND=1 + # Use terse signal names: "INT" instead of "SIGINT(2)". + typeset -g POWERLEVEL9K_STATUS_VERBOSE_SIGNAME=false + typeset -g POWERLEVEL9K_STATUS_ERROR_SIGNAL_VISUAL_IDENTIFIER_EXPANSION='✘' + + # Status when some part of a pipe command fails and the overall exit status is also non-zero. + # It may look like this: 1|0. + typeset -g POWERLEVEL9K_STATUS_ERROR_PIPE=true + typeset -g POWERLEVEL9K_STATUS_ERROR_PIPE_FOREGROUND=1 + typeset -g POWERLEVEL9K_STATUS_ERROR_PIPE_VISUAL_IDENTIFIER_EXPANSION='✘' + + ###################[ command_execution_time: duration of the last command ]################### + # Show duration of the last command if takes at least this many seconds. + typeset -g POWERLEVEL9K_COMMAND_EXECUTION_TIME_THRESHOLD=3 + # Show this many fractional digits. Zero means round to seconds. + typeset -g POWERLEVEL9K_COMMAND_EXECUTION_TIME_PRECISION=0 + # Execution time color. + typeset -g POWERLEVEL9K_COMMAND_EXECUTION_TIME_FOREGROUND=3 + # Duration format: 1d 2h 3m 4s. + typeset -g POWERLEVEL9K_COMMAND_EXECUTION_TIME_FORMAT='d h m s' + # Custom icon. + typeset -g POWERLEVEL9K_COMMAND_EXECUTION_TIME_VISUAL_IDENTIFIER_EXPANSION= + # Custom prefix. + # typeset -g POWERLEVEL9K_COMMAND_EXECUTION_TIME_PREFIX='%ftook ' + + #######################[ background_jobs: presence of background jobs ]####################### + # Don't show the number of background jobs. + typeset -g POWERLEVEL9K_BACKGROUND_JOBS_VERBOSE=false + # Background jobs color. + typeset -g POWERLEVEL9K_BACKGROUND_JOBS_FOREGROUND=1 + # Custom icon. + # typeset -g POWERLEVEL9K_BACKGROUND_JOBS_VISUAL_IDENTIFIER_EXPANSION='⭐' + + #######################[ direnv: direnv status (https://direnv.net/) ]######################## + # Direnv color. + typeset -g POWERLEVEL9K_DIRENV_FOREGROUND=3 + # Custom icon. + # typeset -g POWERLEVEL9K_DIRENV_VISUAL_IDENTIFIER_EXPANSION='⭐' + + ###############[ asdf: asdf version manager (https://github.com/asdf-vm/asdf) ]############### + # Default asdf color. Only used to display tools for which there is no color override (see below). + # Tip: Override this parameter for ${TOOL} with POWERLEVEL9K_ASDF_${TOOL}_FOREGROUND. + typeset -g POWERLEVEL9K_ASDF_FOREGROUND=6 + + # There are four parameters that can be used to hide asdf tools. Each parameter describes + # conditions under which a tool gets hidden. Parameters can hide tools but not unhide them. If at + # least one parameter decides to hide a tool, that tool gets hidden. If no parameter decides to + # hide a tool, it gets shown. + # + # Special note on the difference between POWERLEVEL9K_ASDF_SOURCES and + # POWERLEVEL9K_ASDF_PROMPT_ALWAYS_SHOW. Consider the effect of the following commands: + # + # asdf local python 3.8.1 + # asdf global python 3.8.1 + # + # After running both commands the current python version is 3.8.1 and its source is "local" as + # it takes precedence over "global". If POWERLEVEL9K_ASDF_PROMPT_ALWAYS_SHOW is set to false, + # it'll hide python version in this case because 3.8.1 is the same as the global version. + # POWERLEVEL9K_ASDF_SOURCES will hide python version only if the value of this parameter doesn't + # contain "local". + + # Hide tool versions that don't come from one of these sources. + # + # Available sources: + # + # - shell `asdf current` says "set by ASDF_${TOOL}_VERSION environment variable" + # - local `asdf current` says "set by /some/not/home/directory/file" + # - global `asdf current` says "set by /home/username/file" + # + # Note: If this parameter is set to (shell local global), it won't hide tools. + # Tip: Override this parameter for ${TOOL} with POWERLEVEL9K_ASDF_${TOOL}_SOURCES. + typeset -g POWERLEVEL9K_ASDF_SOURCES=(shell local global) + + # If set to false, hide tool versions that are the same as global. + # + # Note: The name of this parameter doesn't reflect its meaning at all. + # Note: If this parameter is set to true, it won't hide tools. + # Tip: Override this parameter for ${TOOL} with POWERLEVEL9K_ASDF_${TOOL}_PROMPT_ALWAYS_SHOW. + typeset -g POWERLEVEL9K_ASDF_PROMPT_ALWAYS_SHOW=false + + # If set to false, hide tool versions that are equal to "system". + # + # Note: If this parameter is set to true, it won't hide tools. + # Tip: Override this parameter for ${TOOL} with POWERLEVEL9K_ASDF_${TOOL}_SHOW_SYSTEM. + typeset -g POWERLEVEL9K_ASDF_SHOW_SYSTEM=true + + # If set to non-empty value, hide tools unless there is a file matching the specified file pattern + # in the current directory, or its parent directory, or its grandparent directory, and so on. + # + # Note: If this parameter is set to empty value, it won't hide tools. + # Note: SHOW_ON_UPGLOB isn't specific to asdf. It works with all prompt segments. + # Tip: Override this parameter for ${TOOL} with POWERLEVEL9K_ASDF_${TOOL}_SHOW_ON_UPGLOB. + # + # Example: Hide nodejs version when there is no package.json and no *.js files in the current + # directory, in `..`, in `../..` and so on. + # + # typeset -g POWERLEVEL9K_ASDF_NODEJS_SHOW_ON_UPGLOB='*.js|package.json' + typeset -g POWERLEVEL9K_ASDF_SHOW_ON_UPGLOB= + + # Ruby version from asdf. + typeset -g POWERLEVEL9K_ASDF_RUBY_FOREGROUND=1 + # typeset -g POWERLEVEL9K_ASDF_RUBY_VISUAL_IDENTIFIER_EXPANSION='⭐' + # typeset -g POWERLEVEL9K_ASDF_RUBY_SHOW_ON_UPGLOB='*.foo|*.bar' + + # Python version from asdf. + typeset -g POWERLEVEL9K_ASDF_PYTHON_FOREGROUND=6 + # typeset -g POWERLEVEL9K_ASDF_PYTHON_VISUAL_IDENTIFIER_EXPANSION='⭐' + # typeset -g POWERLEVEL9K_ASDF_PYTHON_SHOW_ON_UPGLOB='*.foo|*.bar' + + # Go version from asdf. + typeset -g POWERLEVEL9K_ASDF_GOLANG_FOREGROUND=6 + # typeset -g POWERLEVEL9K_ASDF_GOLANG_VISUAL_IDENTIFIER_EXPANSION='⭐' + # typeset -g POWERLEVEL9K_ASDF_GOLANG_SHOW_ON_UPGLOB='*.foo|*.bar' + + # Node.js version from asdf. + typeset -g POWERLEVEL9K_ASDF_NODEJS_FOREGROUND=2 + # typeset -g POWERLEVEL9K_ASDF_NODEJS_VISUAL_IDENTIFIER_EXPANSION='⭐' + # typeset -g POWERLEVEL9K_ASDF_NODEJS_SHOW_ON_UPGLOB='*.foo|*.bar' + + # Rust version from asdf. + typeset -g POWERLEVEL9K_ASDF_RUST_FOREGROUND=4 + # typeset -g POWERLEVEL9K_ASDF_RUST_VISUAL_IDENTIFIER_EXPANSION='⭐' + # typeset -g POWERLEVEL9K_ASDF_RUST_SHOW_ON_UPGLOB='*.foo|*.bar' + + # .NET Core version from asdf. + typeset -g POWERLEVEL9K_ASDF_DOTNET_CORE_FOREGROUND=5 + # typeset -g POWERLEVEL9K_ASDF_DOTNET_CORE_VISUAL_IDENTIFIER_EXPANSION='⭐' + # typeset -g POWERLEVEL9K_ASDF_DOTNET_CORE_SHOW_ON_UPGLOB='*.foo|*.bar' + + # Flutter version from asdf. + typeset -g POWERLEVEL9K_ASDF_FLUTTER_FOREGROUND=4 + # typeset -g POWERLEVEL9K_ASDF_FLUTTER_VISUAL_IDENTIFIER_EXPANSION='⭐' + # typeset -g POWERLEVEL9K_ASDF_FLUTTER_SHOW_ON_UPGLOB='*.foo|*.bar' + + # Lua version from asdf. + typeset -g POWERLEVEL9K_ASDF_LUA_FOREGROUND=4 + # typeset -g POWERLEVEL9K_ASDF_LUA_VISUAL_IDENTIFIER_EXPANSION='⭐' + # typeset -g POWERLEVEL9K_ASDF_LUA_SHOW_ON_UPGLOB='*.foo|*.bar' + + # Java version from asdf. + typeset -g POWERLEVEL9K_ASDF_JAVA_FOREGROUND=4 + # typeset -g POWERLEVEL9K_ASDF_JAVA_VISUAL_IDENTIFIER_EXPANSION='⭐' + # typeset -g POWERLEVEL9K_ASDF_JAVA_SHOW_ON_UPGLOB='*.foo|*.bar' + + # Perl version from asdf. + typeset -g POWERLEVEL9K_ASDF_PERL_FOREGROUND=6 + # typeset -g POWERLEVEL9K_ASDF_PERL_VISUAL_IDENTIFIER_EXPANSION='⭐' + # typeset -g POWERLEVEL9K_ASDF_PERL_SHOW_ON_UPGLOB='*.foo|*.bar' + + # Erlang version from asdf. + typeset -g POWERLEVEL9K_ASDF_ERLANG_FOREGROUND=1 + # typeset -g POWERLEVEL9K_ASDF_ERLANG_VISUAL_IDENTIFIER_EXPANSION='⭐' + # typeset -g POWERLEVEL9K_ASDF_ERLANG_SHOW_ON_UPGLOB='*.foo|*.bar' + + # Elixir version from asdf. + typeset -g POWERLEVEL9K_ASDF_ELIXIR_FOREGROUND=5 + # typeset -g POWERLEVEL9K_ASDF_ELIXIR_VISUAL_IDENTIFIER_EXPANSION='⭐' + # typeset -g POWERLEVEL9K_ASDF_ELIXIR_SHOW_ON_UPGLOB='*.foo|*.bar' + + # Postgres version from asdf. + typeset -g POWERLEVEL9K_ASDF_POSTGRES_FOREGROUND=6 + # typeset -g POWERLEVEL9K_ASDF_POSTGRES_VISUAL_IDENTIFIER_EXPANSION='⭐' + # typeset -g POWERLEVEL9K_ASDF_POSTGRES_SHOW_ON_UPGLOB='*.foo|*.bar' + + # PHP version from asdf. + typeset -g POWERLEVEL9K_ASDF_PHP_FOREGROUND=5 + # typeset -g POWERLEVEL9K_ASDF_PHP_VISUAL_IDENTIFIER_EXPANSION='⭐' + # typeset -g POWERLEVEL9K_ASDF_PHP_SHOW_ON_UPGLOB='*.foo|*.bar' + + # Haskell version from asdf. + typeset -g POWERLEVEL9K_ASDF_HASKELL_FOREGROUND=3 + # typeset -g POWERLEVEL9K_ASDF_HASKELL_VISUAL_IDENTIFIER_EXPANSION='⭐' + # typeset -g POWERLEVEL9K_ASDF_HASKELL_SHOW_ON_UPGLOB='*.foo|*.bar' + + # Julia version from asdf. + typeset -g POWERLEVEL9K_ASDF_JULIA_FOREGROUND=2 + # typeset -g POWERLEVEL9K_ASDF_JULIA_VISUAL_IDENTIFIER_EXPANSION='⭐' + # typeset -g POWERLEVEL9K_ASDF_JULIA_SHOW_ON_UPGLOB='*.foo|*.bar' + + ##########[ nordvpn: nordvpn connection status, linux only (https://nordvpn.com/) ]########### + # NordVPN connection indicator color. + typeset -g POWERLEVEL9K_NORDVPN_FOREGROUND=6 + # Hide NordVPN connection indicator when not connected. + typeset -g POWERLEVEL9K_NORDVPN_{DISCONNECTED,CONNECTING,DISCONNECTING}_CONTENT_EXPANSION= + typeset -g POWERLEVEL9K_NORDVPN_{DISCONNECTED,CONNECTING,DISCONNECTING}_VISUAL_IDENTIFIER_EXPANSION= + # Custom icon. + # typeset -g POWERLEVEL9K_NORDVPN_VISUAL_IDENTIFIER_EXPANSION='⭐' + + #################[ ranger: ranger shell (https://github.com/ranger/ranger) ]################## + # Ranger shell color. + typeset -g POWERLEVEL9K_RANGER_FOREGROUND=3 + # Custom icon. + # typeset -g POWERLEVEL9K_RANGER_VISUAL_IDENTIFIER_EXPANSION='⭐' + + ####################[ yazi: yazi shell (https://github.com/sxyazi/yazi) ]##################### + # Yazi shell color. + typeset -g POWERLEVEL9K_YAZI_FOREGROUND=3 + # Custom icon. + # typeset -g POWERLEVEL9K_YAZI_VISUAL_IDENTIFIER_EXPANSION='⭐' + + ######################[ nnn: nnn shell (https://github.com/jarun/nnn) ]####################### + # Nnn shell color. + typeset -g POWERLEVEL9K_NNN_FOREGROUND=3 + # Custom icon. + # typeset -g POWERLEVEL9K_NNN_VISUAL_IDENTIFIER_EXPANSION='⭐' + + ######################[ lf: lf shell (https://github.com/gokcehan/lf) ]####################### + # lf shell color. + typeset -g POWERLEVEL9K_LF_FOREGROUND=3 + # Custom icon. + # typeset -g POWERLEVEL9K_LF_VISUAL_IDENTIFIER_EXPANSION='⭐' + + ##################[ xplr: xplr shell (https://github.com/sayanarijit/xplr) ]################## + # xplr shell color. + typeset -g POWERLEVEL9K_XPLR_FOREGROUND=3 + # Custom icon. + # typeset -g POWERLEVEL9K_XPLR_VISUAL_IDENTIFIER_EXPANSION='⭐' + + ###########################[ vim_shell: vim shell indicator (:sh) ]########################### + # Vim shell indicator color. + typeset -g POWERLEVEL9K_VIM_SHELL_FOREGROUND=3 + # Custom icon. + # typeset -g POWERLEVEL9K_VIM_SHELL_VISUAL_IDENTIFIER_EXPANSION='⭐' + + ######[ midnight_commander: midnight commander shell (https://midnight-commander.org/) ]###### + # Midnight Commander shell color. + typeset -g POWERLEVEL9K_MIDNIGHT_COMMANDER_FOREGROUND=3 + # Custom icon. + # typeset -g POWERLEVEL9K_MIDNIGHT_COMMANDER_VISUAL_IDENTIFIER_EXPANSION='⭐' + + #[ nix_shell: nix shell (https://nixos.org/nixos/nix-pills/developing-with-nix-shell.html) ]## + # Nix shell color. + typeset -g POWERLEVEL9K_NIX_SHELL_FOREGROUND=4 + + # Display the icon of nix_shell if PATH contains a subdirectory of /nix/store. + # typeset -g POWERLEVEL9K_NIX_SHELL_INFER_FROM_PATH=false + + # Tip: If you want to see just the icon without "pure" and "impure", uncomment the next line. + # typeset -g POWERLEVEL9K_NIX_SHELL_CONTENT_EXPANSION= + + # Custom icon. + # typeset -g POWERLEVEL9K_NIX_SHELL_VISUAL_IDENTIFIER_EXPANSION='⭐' + + ##################[ chezmoi_shell: chezmoi shell (https://www.chezmoi.io/) ]################## + # chezmoi shell color. + typeset -g POWERLEVEL9K_CHEZMOI_SHELL_FOREGROUND=4 + # Custom icon. + # typeset -g POWERLEVEL9K_CHEZMOI_SHELL_VISUAL_IDENTIFIER_EXPANSION='⭐' + + ##################################[ disk_usage: disk usage ]################################## + # Colors for different levels of disk usage. + typeset -g POWERLEVEL9K_DISK_USAGE_NORMAL_FOREGROUND=2 + typeset -g POWERLEVEL9K_DISK_USAGE_WARNING_FOREGROUND=3 + typeset -g POWERLEVEL9K_DISK_USAGE_CRITICAL_FOREGROUND=1 + # Thresholds for different levels of disk usage (percentage points). + typeset -g POWERLEVEL9K_DISK_USAGE_WARNING_LEVEL=90 + typeset -g POWERLEVEL9K_DISK_USAGE_CRITICAL_LEVEL=95 + # If set to true, hide disk usage when below $POWERLEVEL9K_DISK_USAGE_WARNING_LEVEL percent. + typeset -g POWERLEVEL9K_DISK_USAGE_ONLY_WARNING=false + # Custom icon. + # typeset -g POWERLEVEL9K_DISK_USAGE_VISUAL_IDENTIFIER_EXPANSION='⭐' + + ######################################[ ram: free RAM ]####################################### + # RAM color. + typeset -g POWERLEVEL9K_RAM_FOREGROUND=2 + # Custom icon. + # typeset -g POWERLEVEL9K_RAM_VISUAL_IDENTIFIER_EXPANSION='⭐' + + #####################################[ swap: used swap ]###################################### + # Swap color. + typeset -g POWERLEVEL9K_SWAP_FOREGROUND=3 + # Custom icon. + # typeset -g POWERLEVEL9K_SWAP_VISUAL_IDENTIFIER_EXPANSION='⭐' + + ######################################[ load: CPU load ]###################################### + # Show average CPU load over this many last minutes. Valid values are 1, 5 and 15. + typeset -g POWERLEVEL9K_LOAD_WHICH=5 + # Load color when load is under 50%. + typeset -g POWERLEVEL9K_LOAD_NORMAL_FOREGROUND=2 + # Load color when load is between 50% and 70%. + typeset -g POWERLEVEL9K_LOAD_WARNING_FOREGROUND=3 + # Load color when load is over 70%. + typeset -g POWERLEVEL9K_LOAD_CRITICAL_FOREGROUND=1 + # Custom icon. + # typeset -g POWERLEVEL9K_LOAD_VISUAL_IDENTIFIER_EXPANSION='⭐' + + ################[ todo: todo items (https://github.com/todotxt/todo.txt-cli) ]################ + # Todo color. + typeset -g POWERLEVEL9K_TODO_FOREGROUND=4 + # Hide todo when the total number of tasks is zero. + typeset -g POWERLEVEL9K_TODO_HIDE_ZERO_TOTAL=true + # Hide todo when the number of tasks after filtering is zero. + typeset -g POWERLEVEL9K_TODO_HIDE_ZERO_FILTERED=false + + # Todo format. The following parameters are available within the expansion. + # + # - P9K_TODO_TOTAL_TASK_COUNT The total number of tasks. + # - P9K_TODO_FILTERED_TASK_COUNT The number of tasks after filtering. + # + # These variables correspond to the last line of the output of `todo.sh -p ls`: + # + # TODO: 24 of 42 tasks shown + # + # Here 24 is P9K_TODO_FILTERED_TASK_COUNT and 42 is P9K_TODO_TOTAL_TASK_COUNT. + # + # typeset -g POWERLEVEL9K_TODO_CONTENT_EXPANSION='$P9K_TODO_FILTERED_TASK_COUNT' + + # Custom icon. + # typeset -g POWERLEVEL9K_TODO_VISUAL_IDENTIFIER_EXPANSION='⭐' + + ###########[ timewarrior: timewarrior tracking status (https://timewarrior.net/) ]############ + # Timewarrior color. + typeset -g POWERLEVEL9K_TIMEWARRIOR_FOREGROUND=4 + # If the tracked task is longer than 24 characters, truncate and append "…". + # Tip: To always display tasks without truncation, delete the following parameter. + # Tip: To hide task names and display just the icon when time tracking is enabled, set the + # value of the following parameter to "". + typeset -g POWERLEVEL9K_TIMEWARRIOR_CONTENT_EXPANSION='${P9K_CONTENT:0:24}${${P9K_CONTENT:24}:+…}' + + # Custom icon. + # typeset -g POWERLEVEL9K_TIMEWARRIOR_VISUAL_IDENTIFIER_EXPANSION='⭐' + + ##############[ taskwarrior: taskwarrior task count (https://taskwarrior.org/) ]############## + # Taskwarrior color. + typeset -g POWERLEVEL9K_TASKWARRIOR_FOREGROUND=6 + + # Taskwarrior segment format. The following parameters are available within the expansion. + # + # - P9K_TASKWARRIOR_PENDING_COUNT The number of pending tasks: `task +PENDING count`. + # - P9K_TASKWARRIOR_OVERDUE_COUNT The number of overdue tasks: `task +OVERDUE count`. + # + # Zero values are represented as empty parameters. + # + # The default format: + # + # '${P9K_TASKWARRIOR_OVERDUE_COUNT:+"!$P9K_TASKWARRIOR_OVERDUE_COUNT/"}$P9K_TASKWARRIOR_PENDING_COUNT' + # + # typeset -g POWERLEVEL9K_TASKWARRIOR_CONTENT_EXPANSION='$P9K_TASKWARRIOR_PENDING_COUNT' + + # Custom icon. + # typeset -g POWERLEVEL9K_TASKWARRIOR_VISUAL_IDENTIFIER_EXPANSION='⭐' + + ######[ per_directory_history: Oh My Zsh per-directory-history local/global indicator ]####### + # Color when using local/global history. + typeset -g POWERLEVEL9K_PER_DIRECTORY_HISTORY_LOCAL_FOREGROUND=5 + typeset -g POWERLEVEL9K_PER_DIRECTORY_HISTORY_GLOBAL_FOREGROUND=3 + + # Tip: Uncomment the next two lines to hide "local"/"global" text and leave just the icon. + # typeset -g POWERLEVEL9K_PER_DIRECTORY_HISTORY_LOCAL_CONTENT_EXPANSION='' + # typeset -g POWERLEVEL9K_PER_DIRECTORY_HISTORY_GLOBAL_CONTENT_EXPANSION='' + + # Custom icon. + # typeset -g POWERLEVEL9K_PER_DIRECTORY_HISTORY_LOCAL_VISUAL_IDENTIFIER_EXPANSION='⭐' + # typeset -g POWERLEVEL9K_PER_DIRECTORY_HISTORY_GLOBAL_VISUAL_IDENTIFIER_EXPANSION='⭐' + + ################################[ cpu_arch: CPU architecture ]################################ + # CPU architecture color. + typeset -g POWERLEVEL9K_CPU_ARCH_FOREGROUND=3 + + # Hide the segment when on a specific CPU architecture. + # typeset -g POWERLEVEL9K_CPU_ARCH_X86_64_CONTENT_EXPANSION= + # typeset -g POWERLEVEL9K_CPU_ARCH_X86_64_VISUAL_IDENTIFIER_EXPANSION= + + # Custom icon. + # typeset -g POWERLEVEL9K_CPU_ARCH_VISUAL_IDENTIFIER_EXPANSION='⭐' + + ##################################[ context: user@hostname ]################################## + # Context color when running with privileges. + typeset -g POWERLEVEL9K_CONTEXT_ROOT_FOREGROUND=1 + # Context color in SSH without privileges. + typeset -g POWERLEVEL9K_CONTEXT_{REMOTE,REMOTE_SUDO}_FOREGROUND=7 + # Default context color (no privileges, no SSH). + typeset -g POWERLEVEL9K_CONTEXT_FOREGROUND=7 + + # Context format when running with privileges: bold user@hostname. + typeset -g POWERLEVEL9K_CONTEXT_ROOT_TEMPLATE='%B%n@%m' + # Context format when in SSH without privileges: user@hostname. + typeset -g POWERLEVEL9K_CONTEXT_{REMOTE,REMOTE_SUDO}_TEMPLATE='%n@%m' + # Default context format (no privileges, no SSH): user@hostname. + typeset -g POWERLEVEL9K_CONTEXT_TEMPLATE='%n@%m' + + # Don't show context unless running with privileges or in SSH. + # Tip: Remove the next line to always show context. + typeset -g POWERLEVEL9K_CONTEXT_{DEFAULT,SUDO}_{CONTENT,VISUAL_IDENTIFIER}_EXPANSION= + + # Custom icon. + # typeset -g POWERLEVEL9K_CONTEXT_VISUAL_IDENTIFIER_EXPANSION='⭐' + # Custom prefix. + # typeset -g POWERLEVEL9K_CONTEXT_PREFIX='%fwith ' + + ###[ virtualenv: python virtual environment (https://docs.python.org/3/library/venv.html) ]### + # Python virtual environment color. + typeset -g POWERLEVEL9K_VIRTUALENV_FOREGROUND=6 + # Don't show Python version next to the virtual environment name. + typeset -g POWERLEVEL9K_VIRTUALENV_SHOW_PYTHON_VERSION=false + # If set to "false", won't show virtualenv if pyenv is already shown. + # If set to "if-different", won't show virtualenv if it's the same as pyenv. + typeset -g POWERLEVEL9K_VIRTUALENV_SHOW_WITH_PYENV=false + # Separate environment name from Python version only with a space. + typeset -g POWERLEVEL9K_VIRTUALENV_{LEFT,RIGHT}_DELIMITER= + # Custom icon. + # typeset -g POWERLEVEL9K_VIRTUALENV_VISUAL_IDENTIFIER_EXPANSION='⭐' + + #####################[ anaconda: conda environment (https://conda.io/) ]###################### + # Anaconda environment color. + typeset -g POWERLEVEL9K_ANACONDA_FOREGROUND=6 + + # Anaconda segment format. The following parameters are available within the expansion. + # + # - CONDA_PREFIX Absolute path to the active Anaconda/Miniconda environment. + # - CONDA_DEFAULT_ENV Name of the active Anaconda/Miniconda environment. + # - CONDA_PROMPT_MODIFIER Configurable prompt modifier (see below). + # - P9K_ANACONDA_PYTHON_VERSION Current python version (python --version). + # + # CONDA_PROMPT_MODIFIER can be configured with the following command: + # + # conda config --set env_prompt '({default_env}) ' + # + # The last argument is a Python format string that can use the following variables: + # + # - prefix The same as CONDA_PREFIX. + # - default_env The same as CONDA_DEFAULT_ENV. + # - name The last segment of CONDA_PREFIX. + # - stacked_env Comma-separated list of names in the environment stack. The first element is + # always the same as default_env. + # + # Note: '({default_env}) ' is the default value of env_prompt. + # + # The default value of POWERLEVEL9K_ANACONDA_CONTENT_EXPANSION expands to $CONDA_PROMPT_MODIFIER + # without the surrounding parentheses, or to the last path component of CONDA_PREFIX if the former + # is empty. + typeset -g POWERLEVEL9K_ANACONDA_CONTENT_EXPANSION='${${${${CONDA_PROMPT_MODIFIER#\(}% }%\)}:-${CONDA_PREFIX:t}}' + + # Custom icon. + # typeset -g POWERLEVEL9K_ANACONDA_VISUAL_IDENTIFIER_EXPANSION='⭐' + + ################[ pyenv: python environment (https://github.com/pyenv/pyenv) ]################ + # Pyenv color. + typeset -g POWERLEVEL9K_PYENV_FOREGROUND=6 + # Hide python version if it doesn't come from one of these sources. + typeset -g POWERLEVEL9K_PYENV_SOURCES=(shell local global) + # If set to false, hide python version if it's the same as global: + # $(pyenv version-name) == $(pyenv global). + typeset -g POWERLEVEL9K_PYENV_PROMPT_ALWAYS_SHOW=false + # If set to false, hide python version if it's equal to "system". + typeset -g POWERLEVEL9K_PYENV_SHOW_SYSTEM=true + + # Pyenv segment format. The following parameters are available within the expansion. + # + # - P9K_CONTENT Current pyenv environment (pyenv version-name). + # - P9K_PYENV_PYTHON_VERSION Current python version (python --version). + # + # The default format has the following logic: + # + # 1. Display just "$P9K_CONTENT" if it's equal to "$P9K_PYENV_PYTHON_VERSION" or + # starts with "$P9K_PYENV_PYTHON_VERSION/". + # 2. Otherwise display "$P9K_CONTENT $P9K_PYENV_PYTHON_VERSION". + typeset -g POWERLEVEL9K_PYENV_CONTENT_EXPANSION='${P9K_CONTENT}${${P9K_CONTENT:#$P9K_PYENV_PYTHON_VERSION(|/*)}:+ $P9K_PYENV_PYTHON_VERSION}' + + # Custom icon. + # typeset -g POWERLEVEL9K_PYENV_VISUAL_IDENTIFIER_EXPANSION='⭐' + + ################[ goenv: go environment (https://github.com/syndbg/goenv) ]################ + # Goenv color. + typeset -g POWERLEVEL9K_GOENV_FOREGROUND=6 + # Hide go version if it doesn't come from one of these sources. + typeset -g POWERLEVEL9K_GOENV_SOURCES=(shell local global) + # If set to false, hide go version if it's the same as global: + # $(goenv version-name) == $(goenv global). + typeset -g POWERLEVEL9K_GOENV_PROMPT_ALWAYS_SHOW=false + # If set to false, hide go version if it's equal to "system". + typeset -g POWERLEVEL9K_GOENV_SHOW_SYSTEM=true + # Custom icon. + # typeset -g POWERLEVEL9K_GOENV_VISUAL_IDENTIFIER_EXPANSION='⭐' + + ##########[ nodenv: node.js version from nodenv (https://github.com/nodenv/nodenv) ]########## + # Nodenv color. + typeset -g POWERLEVEL9K_NODENV_FOREGROUND=2 + # Hide node version if it doesn't come from one of these sources. + typeset -g POWERLEVEL9K_NODENV_SOURCES=(shell local global) + # If set to false, hide node version if it's the same as global: + # $(nodenv version-name) == $(nodenv global). + typeset -g POWERLEVEL9K_NODENV_PROMPT_ALWAYS_SHOW=false + # If set to false, hide node version if it's equal to "system". + typeset -g POWERLEVEL9K_NODENV_SHOW_SYSTEM=true + # Custom icon. + # typeset -g POWERLEVEL9K_NODENV_VISUAL_IDENTIFIER_EXPANSION='⭐' + + ##############[ nvm: node.js version from nvm (https://github.com/nvm-sh/nvm) ]############### + # Nvm color. + typeset -g POWERLEVEL9K_NVM_FOREGROUND=2 + # If set to false, hide node version if it's the same as default: + # $(nvm version current) == $(nvm version default). + typeset -g POWERLEVEL9K_NVM_PROMPT_ALWAYS_SHOW=false + # If set to false, hide node version if it's equal to "system". + typeset -g POWERLEVEL9K_NVM_SHOW_SYSTEM=true + # Custom icon. + # typeset -g POWERLEVEL9K_NVM_VISUAL_IDENTIFIER_EXPANSION='⭐' + + ############[ nodeenv: node.js environment (https://github.com/ekalinin/nodeenv) ]############ + # Nodeenv color. + typeset -g POWERLEVEL9K_NODEENV_FOREGROUND=2 + # Don't show Node version next to the environment name. + typeset -g POWERLEVEL9K_NODEENV_SHOW_NODE_VERSION=false + # Separate environment name from Node version only with a space. + typeset -g POWERLEVEL9K_NODEENV_{LEFT,RIGHT}_DELIMITER= + # Custom icon. + # typeset -g POWERLEVEL9K_NODEENV_VISUAL_IDENTIFIER_EXPANSION='⭐' + + ##############################[ node_version: node.js version ]############################### + # Node version color. + typeset -g POWERLEVEL9K_NODE_VERSION_FOREGROUND=2 + # Show node version only when in a directory tree containing package.json. + typeset -g POWERLEVEL9K_NODE_VERSION_PROJECT_ONLY=true + # Custom icon. + # typeset -g POWERLEVEL9K_NODE_VERSION_VISUAL_IDENTIFIER_EXPANSION='⭐' + + #######################[ go_version: go version (https://golang.org) ]######################## + # Go version color. + typeset -g POWERLEVEL9K_GO_VERSION_FOREGROUND=6 + # Show go version only when in a go project subdirectory. + typeset -g POWERLEVEL9K_GO_VERSION_PROJECT_ONLY=true + # Custom icon. + # typeset -g POWERLEVEL9K_GO_VERSION_VISUAL_IDENTIFIER_EXPANSION='⭐' + + #################[ rust_version: rustc version (https://www.rust-lang.org) ]################## + # Rust version color. + typeset -g POWERLEVEL9K_RUST_VERSION_FOREGROUND=4 + # Show rust version only when in a rust project subdirectory. + typeset -g POWERLEVEL9K_RUST_VERSION_PROJECT_ONLY=true + # Custom icon. + # typeset -g POWERLEVEL9K_RUST_VERSION_VISUAL_IDENTIFIER_EXPANSION='⭐' + + ###############[ dotnet_version: .NET version (https://dotnet.microsoft.com) ]################ + # .NET version color. + typeset -g POWERLEVEL9K_DOTNET_VERSION_FOREGROUND=5 + # Show .NET version only when in a .NET project subdirectory. + typeset -g POWERLEVEL9K_DOTNET_VERSION_PROJECT_ONLY=true + # Custom icon. + # typeset -g POWERLEVEL9K_DOTNET_VERSION_VISUAL_IDENTIFIER_EXPANSION='⭐' + + #####################[ php_version: php version (https://www.php.net/) ]###################### + # PHP version color. + typeset -g POWERLEVEL9K_PHP_VERSION_FOREGROUND=5 + # Show PHP version only when in a PHP project subdirectory. + typeset -g POWERLEVEL9K_PHP_VERSION_PROJECT_ONLY=true + # Custom icon. + # typeset -g POWERLEVEL9K_PHP_VERSION_VISUAL_IDENTIFIER_EXPANSION='⭐' + + ##########[ laravel_version: laravel php framework version (https://laravel.com/) ]########### + # Laravel version color. + typeset -g POWERLEVEL9K_LARAVEL_VERSION_FOREGROUND=1 + # Custom icon. + # typeset -g POWERLEVEL9K_LARAVEL_VERSION_VISUAL_IDENTIFIER_EXPANSION='⭐' + + ####################[ java_version: java version (https://www.java.com/) ]#################### + # Java version color. + typeset -g POWERLEVEL9K_JAVA_VERSION_FOREGROUND=4 + # Show java version only when in a java project subdirectory. + typeset -g POWERLEVEL9K_JAVA_VERSION_PROJECT_ONLY=true + # Show brief version. + typeset -g POWERLEVEL9K_JAVA_VERSION_FULL=false + # Custom icon. + # typeset -g POWERLEVEL9K_JAVA_VERSION_VISUAL_IDENTIFIER_EXPANSION='⭐' + + ###[ package: name@version from package.json (https://docs.npmjs.com/files/package.json) ]#### + # Package color. + typeset -g POWERLEVEL9K_PACKAGE_FOREGROUND=6 + # Package format. The following parameters are available within the expansion. + # + # - P9K_PACKAGE_NAME The value of `name` field in package.json. + # - P9K_PACKAGE_VERSION The value of `version` field in package.json. + # + # typeset -g POWERLEVEL9K_PACKAGE_CONTENT_EXPANSION='${P9K_PACKAGE_NAME//\%/%%}@${P9K_PACKAGE_VERSION//\%/%%}' + # Custom icon. + # typeset -g POWERLEVEL9K_PACKAGE_VISUAL_IDENTIFIER_EXPANSION='⭐' + + #############[ rbenv: ruby version from rbenv (https://github.com/rbenv/rbenv) ]############## + # Rbenv color. + typeset -g POWERLEVEL9K_RBENV_FOREGROUND=1 + # Hide ruby version if it doesn't come from one of these sources. + typeset -g POWERLEVEL9K_RBENV_SOURCES=(shell local global) + # If set to false, hide ruby version if it's the same as global: + # $(rbenv version-name) == $(rbenv global). + typeset -g POWERLEVEL9K_RBENV_PROMPT_ALWAYS_SHOW=false + # If set to false, hide ruby version if it's equal to "system". + typeset -g POWERLEVEL9K_RBENV_SHOW_SYSTEM=true + # Custom icon. + # typeset -g POWERLEVEL9K_RBENV_VISUAL_IDENTIFIER_EXPANSION='⭐' + + #######################[ rvm: ruby version from rvm (https://rvm.io) ]######################## + # Rvm color. + typeset -g POWERLEVEL9K_RVM_FOREGROUND=1 + # Don't show @gemset at the end. + typeset -g POWERLEVEL9K_RVM_SHOW_GEMSET=false + # Don't show ruby- at the front. + typeset -g POWERLEVEL9K_RVM_SHOW_PREFIX=false + # Custom icon. + # typeset -g POWERLEVEL9K_RVM_VISUAL_IDENTIFIER_EXPANSION='⭐' + + ###########[ fvm: flutter version management (https://github.com/leoafarias/fvm) ]############ + # Fvm color. + typeset -g POWERLEVEL9K_FVM_FOREGROUND=4 + # Custom icon. + # typeset -g POWERLEVEL9K_FVM_VISUAL_IDENTIFIER_EXPANSION='⭐' + + ##########[ luaenv: lua version from luaenv (https://github.com/cehoffman/luaenv) ]########### + # Lua color. + typeset -g POWERLEVEL9K_LUAENV_FOREGROUND=4 + # Hide lua version if it doesn't come from one of these sources. + typeset -g POWERLEVEL9K_LUAENV_SOURCES=(shell local global) + # If set to false, hide lua version if it's the same as global: + # $(luaenv version-name) == $(luaenv global). + typeset -g POWERLEVEL9K_LUAENV_PROMPT_ALWAYS_SHOW=false + # If set to false, hide lua version if it's equal to "system". + typeset -g POWERLEVEL9K_LUAENV_SHOW_SYSTEM=true + # Custom icon. + # typeset -g POWERLEVEL9K_LUAENV_VISUAL_IDENTIFIER_EXPANSION='⭐' + + ###############[ jenv: java version from jenv (https://github.com/jenv/jenv) ]################ + # Java color. + typeset -g POWERLEVEL9K_JENV_FOREGROUND=4 + # Hide java version if it doesn't come from one of these sources. + typeset -g POWERLEVEL9K_JENV_SOURCES=(shell local global) + # If set to false, hide java version if it's the same as global: + # $(jenv version-name) == $(jenv global). + typeset -g POWERLEVEL9K_JENV_PROMPT_ALWAYS_SHOW=false + # If set to false, hide java version if it's equal to "system". + typeset -g POWERLEVEL9K_JENV_SHOW_SYSTEM=true + # Custom icon. + # typeset -g POWERLEVEL9K_JENV_VISUAL_IDENTIFIER_EXPANSION='⭐' + + ###########[ plenv: perl version from plenv (https://github.com/tokuhirom/plenv) ]############ + # Perl color. + typeset -g POWERLEVEL9K_PLENV_FOREGROUND=6 + # Hide perl version if it doesn't come from one of these sources. + typeset -g POWERLEVEL9K_PLENV_SOURCES=(shell local global) + # If set to false, hide perl version if it's the same as global: + # $(plenv version-name) == $(plenv global). + typeset -g POWERLEVEL9K_PLENV_PROMPT_ALWAYS_SHOW=false + # If set to false, hide perl version if it's equal to "system". + typeset -g POWERLEVEL9K_PLENV_SHOW_SYSTEM=true + # Custom icon. + # typeset -g POWERLEVEL9K_PLENV_VISUAL_IDENTIFIER_EXPANSION='⭐' + + ###########[ perlbrew: perl version from perlbrew (https://github.com/gugod/App-perlbrew) ]############ + # Perlbrew color. + typeset -g POWERLEVEL9K_PERLBREW_FOREGROUND=67 + # Show perlbrew version only when in a perl project subdirectory. + typeset -g POWERLEVEL9K_PERLBREW_PROJECT_ONLY=true + # Don't show "perl-" at the front. + typeset -g POWERLEVEL9K_PERLBREW_SHOW_PREFIX=false + # Custom icon. + # typeset -g POWERLEVEL9K_PERLBREW_VISUAL_IDENTIFIER_EXPANSION='⭐' + + ############[ phpenv: php version from phpenv (https://github.com/phpenv/phpenv) ]############ + # PHP color. + typeset -g POWERLEVEL9K_PHPENV_FOREGROUND=5 + # Hide php version if it doesn't come from one of these sources. + typeset -g POWERLEVEL9K_PHPENV_SOURCES=(shell local global) + # If set to false, hide php version if it's the same as global: + # $(phpenv version-name) == $(phpenv global). + typeset -g POWERLEVEL9K_PHPENV_PROMPT_ALWAYS_SHOW=false + # If set to false, hide php version if it's equal to "system". + typeset -g POWERLEVEL9K_PHPENV_SHOW_SYSTEM=true + # Custom icon. + # typeset -g POWERLEVEL9K_PHPENV_VISUAL_IDENTIFIER_EXPANSION='⭐' + + #######[ scalaenv: scala version from scalaenv (https://github.com/scalaenv/scalaenv) ]####### + # Scala color. + typeset -g POWERLEVEL9K_SCALAENV_FOREGROUND=1 + # Hide scala version if it doesn't come from one of these sources. + typeset -g POWERLEVEL9K_SCALAENV_SOURCES=(shell local global) + # If set to false, hide scala version if it's the same as global: + # $(scalaenv version-name) == $(scalaenv global). + typeset -g POWERLEVEL9K_SCALAENV_PROMPT_ALWAYS_SHOW=false + # If set to false, hide scala version if it's equal to "system". + typeset -g POWERLEVEL9K_SCALAENV_SHOW_SYSTEM=true + # Custom icon. + # typeset -g POWERLEVEL9K_SCALAENV_VISUAL_IDENTIFIER_EXPANSION='⭐' + + ##########[ haskell_stack: haskell version from stack (https://haskellstack.org/) ]########### + # Haskell color. + typeset -g POWERLEVEL9K_HASKELL_STACK_FOREGROUND=3 + # Hide haskell version if it doesn't come from one of these sources. + # + # shell: version is set by STACK_YAML + # local: version is set by stack.yaml up the directory tree + # global: version is set by the implicit global project (~/.stack/global-project/stack.yaml) + typeset -g POWERLEVEL9K_HASKELL_STACK_SOURCES=(shell local) + # If set to false, hide haskell version if it's the same as in the implicit global project. + typeset -g POWERLEVEL9K_HASKELL_STACK_ALWAYS_SHOW=true + # Custom icon. + # typeset -g POWERLEVEL9K_HASKELL_STACK_VISUAL_IDENTIFIER_EXPANSION='⭐' + + #############[ kubecontext: current kubernetes context (https://kubernetes.io/) ]############# + # Show kubecontext only when the command you are typing invokes one of these tools. + # Tip: Remove the next line to always show kubecontext. + typeset -g POWERLEVEL9K_KUBECONTEXT_SHOW_ON_COMMAND='kubectl|helm|kubens|kubectx|oc|istioctl|kogito|k9s|helmfile|flux|fluxctl|stern|kubeseal|skaffold|kubent|kubecolor|cmctl|sparkctl' + + # Kubernetes context classes for the purpose of using different colors, icons and expansions with + # different contexts. + # + # POWERLEVEL9K_KUBECONTEXT_CLASSES is an array with even number of elements. The first element + # in each pair defines a pattern against which the current kubernetes context gets matched. + # More specifically, it's P9K_CONTENT prior to the application of context expansion (see below) + # that gets matched. If you unset all POWERLEVEL9K_KUBECONTEXT_*CONTENT_EXPANSION parameters, + # you'll see this value in your prompt. The second element of each pair in + # POWERLEVEL9K_KUBECONTEXT_CLASSES defines the context class. Patterns are tried in order. The + # first match wins. + # + # For example, given these settings: + # + # typeset -g POWERLEVEL9K_KUBECONTEXT_CLASSES=( + # '*prod*' PROD + # '*test*' TEST + # '*' DEFAULT) + # + # If your current kubernetes context is "deathray-testing/default", its class is TEST + # because "deathray-testing/default" doesn't match the pattern '*prod*' but does match '*test*'. + # + # You can define different colors, icons and content expansions for different classes: + # + # typeset -g POWERLEVEL9K_KUBECONTEXT_TEST_FOREGROUND=3 + # typeset -g POWERLEVEL9K_KUBECONTEXT_TEST_VISUAL_IDENTIFIER_EXPANSION='⭐' + # typeset -g POWERLEVEL9K_KUBECONTEXT_TEST_CONTENT_EXPANSION='> ${P9K_CONTENT} <' + typeset -g POWERLEVEL9K_KUBECONTEXT_CLASSES=( + # '*prod*' PROD # These values are examples that are unlikely + # '*test*' TEST # to match your needs. Customize them as needed. + '*' DEFAULT) + typeset -g POWERLEVEL9K_KUBECONTEXT_DEFAULT_FOREGROUND=5 + # typeset -g POWERLEVEL9K_KUBECONTEXT_DEFAULT_VISUAL_IDENTIFIER_EXPANSION='⭐' + + # Use POWERLEVEL9K_KUBECONTEXT_CONTENT_EXPANSION to specify the content displayed by kubecontext + # segment. Parameter expansions are very flexible and fast, too. See reference: + # http://zsh.sourceforge.net/Doc/Release/Expansion.html#Parameter-Expansion. + # + # Within the expansion the following parameters are always available: + # + # - P9K_CONTENT The content that would've been displayed if there was no content + # expansion defined. + # - P9K_KUBECONTEXT_NAME The current context's name. Corresponds to column NAME in the + # output of `kubectl config get-contexts`. + # - P9K_KUBECONTEXT_CLUSTER The current context's cluster. Corresponds to column CLUSTER in the + # output of `kubectl config get-contexts`. + # - P9K_KUBECONTEXT_NAMESPACE The current context's namespace. Corresponds to column NAMESPACE + # in the output of `kubectl config get-contexts`. If there is no + # namespace, the parameter is set to "default". + # - P9K_KUBECONTEXT_USER The current context's user. Corresponds to column AUTHINFO in the + # output of `kubectl config get-contexts`. + # + # If the context points to Google Kubernetes Engine (GKE) or Elastic Kubernetes Service (EKS), + # the following extra parameters are available: + # + # - P9K_KUBECONTEXT_CLOUD_NAME Either "gke" or "eks". + # - P9K_KUBECONTEXT_CLOUD_ACCOUNT Account/project ID. + # - P9K_KUBECONTEXT_CLOUD_ZONE Availability zone. + # - P9K_KUBECONTEXT_CLOUD_CLUSTER Cluster. + # + # P9K_KUBECONTEXT_CLOUD_* parameters are derived from P9K_KUBECONTEXT_CLUSTER. For example, + # if P9K_KUBECONTEXT_CLUSTER is "gke_my-account_us-east1-a_my-cluster-01": + # + # - P9K_KUBECONTEXT_CLOUD_NAME=gke + # - P9K_KUBECONTEXT_CLOUD_ACCOUNT=my-account + # - P9K_KUBECONTEXT_CLOUD_ZONE=us-east1-a + # - P9K_KUBECONTEXT_CLOUD_CLUSTER=my-cluster-01 + # + # If P9K_KUBECONTEXT_CLUSTER is "arn:aws:eks:us-east-1:123456789012:cluster/my-cluster-01": + # + # - P9K_KUBECONTEXT_CLOUD_NAME=eks + # - P9K_KUBECONTEXT_CLOUD_ACCOUNT=123456789012 + # - P9K_KUBECONTEXT_CLOUD_ZONE=us-east-1 + # - P9K_KUBECONTEXT_CLOUD_CLUSTER=my-cluster-01 + typeset -g POWERLEVEL9K_KUBECONTEXT_DEFAULT_CONTENT_EXPANSION= + # Show P9K_KUBECONTEXT_CLOUD_CLUSTER if it's not empty and fall back to P9K_KUBECONTEXT_NAME. + POWERLEVEL9K_KUBECONTEXT_DEFAULT_CONTENT_EXPANSION+='${P9K_KUBECONTEXT_CLOUD_CLUSTER:-${P9K_KUBECONTEXT_NAME}}' + # Append the current context's namespace if it's not "default". + POWERLEVEL9K_KUBECONTEXT_DEFAULT_CONTENT_EXPANSION+='${${:-/$P9K_KUBECONTEXT_NAMESPACE}:#/default}' + + # Custom prefix. + # typeset -g POWERLEVEL9K_KUBECONTEXT_PREFIX='%fat ' + + ################[ terraform: terraform workspace (https://www.terraform.io) ]################# + # Don't show terraform workspace if it's literally "default". + typeset -g POWERLEVEL9K_TERRAFORM_SHOW_DEFAULT=false + # POWERLEVEL9K_TERRAFORM_CLASSES is an array with even number of elements. The first element + # in each pair defines a pattern against which the current terraform workspace gets matched. + # More specifically, it's P9K_CONTENT prior to the application of context expansion (see below) + # that gets matched. If you unset all POWERLEVEL9K_TERRAFORM_*CONTENT_EXPANSION parameters, + # you'll see this value in your prompt. The second element of each pair in + # POWERLEVEL9K_TERRAFORM_CLASSES defines the workspace class. Patterns are tried in order. The + # first match wins. + # + # For example, given these settings: + # + # typeset -g POWERLEVEL9K_TERRAFORM_CLASSES=( + # '*prod*' PROD + # '*test*' TEST + # '*' OTHER) + # + # If your current terraform workspace is "project_test", its class is TEST because "project_test" + # doesn't match the pattern '*prod*' but does match '*test*'. + # + # You can define different colors, icons and content expansions for different classes: + # + # typeset -g POWERLEVEL9K_TERRAFORM_TEST_FOREGROUND=2 + # typeset -g POWERLEVEL9K_TERRAFORM_TEST_VISUAL_IDENTIFIER_EXPANSION='⭐' + # typeset -g POWERLEVEL9K_TERRAFORM_TEST_CONTENT_EXPANSION='> ${P9K_CONTENT} <' + typeset -g POWERLEVEL9K_TERRAFORM_CLASSES=( + # '*prod*' PROD # These values are examples that are unlikely + # '*test*' TEST # to match your needs. Customize them as needed. + '*' OTHER) + typeset -g POWERLEVEL9K_TERRAFORM_OTHER_FOREGROUND=4 + # typeset -g POWERLEVEL9K_TERRAFORM_OTHER_VISUAL_IDENTIFIER_EXPANSION='⭐' + + #############[ terraform_version: terraform version (https://www.terraform.io) ]############## + # Terraform version color. + typeset -g POWERLEVEL9K_TERRAFORM_VERSION_FOREGROUND=4 + # Custom icon. + # typeset -g POWERLEVEL9K_TERRAFORM_VERSION_VISUAL_IDENTIFIER_EXPANSION='⭐' + + #[ aws: aws profile (https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-profiles.html) ]# + # Show aws only when the command you are typing invokes one of these tools. + # Tip: Remove the next line to always show aws. + typeset -g POWERLEVEL9K_AWS_SHOW_ON_COMMAND='aws|awless|cdk|terraform|pulumi|terragrunt' + + # POWERLEVEL9K_AWS_CLASSES is an array with even number of elements. The first element + # in each pair defines a pattern against which the current AWS profile gets matched. + # More specifically, it's P9K_CONTENT prior to the application of context expansion (see below) + # that gets matched. If you unset all POWERLEVEL9K_AWS_*CONTENT_EXPANSION parameters, + # you'll see this value in your prompt. The second element of each pair in + # POWERLEVEL9K_AWS_CLASSES defines the profile class. Patterns are tried in order. The + # first match wins. + # + # For example, given these settings: + # + # typeset -g POWERLEVEL9K_AWS_CLASSES=( + # '*prod*' PROD + # '*test*' TEST + # '*' DEFAULT) + # + # If your current AWS profile is "company_test", its class is TEST + # because "company_test" doesn't match the pattern '*prod*' but does match '*test*'. + # + # You can define different colors, icons and content expansions for different classes: + # + # typeset -g POWERLEVEL9K_AWS_TEST_FOREGROUND=2 + # typeset -g POWERLEVEL9K_AWS_TEST_VISUAL_IDENTIFIER_EXPANSION='⭐' + # typeset -g POWERLEVEL9K_AWS_TEST_CONTENT_EXPANSION='> ${P9K_CONTENT} <' + typeset -g POWERLEVEL9K_AWS_CLASSES=( + # '*prod*' PROD # These values are examples that are unlikely + # '*test*' TEST # to match your needs. Customize them as needed. + '*' DEFAULT) + typeset -g POWERLEVEL9K_AWS_DEFAULT_FOREGROUND=3 + # typeset -g POWERLEVEL9K_AWS_DEFAULT_VISUAL_IDENTIFIER_EXPANSION='⭐' + + # AWS segment format. The following parameters are available within the expansion. + # + # - P9K_AWS_PROFILE The name of the current AWS profile. + # - P9K_AWS_REGION The region associated with the current AWS profile. + typeset -g POWERLEVEL9K_AWS_CONTENT_EXPANSION='${P9K_AWS_PROFILE//\%/%%}${P9K_AWS_REGION:+ ${P9K_AWS_REGION//\%/%%}}' + + #[ aws_eb_env: aws elastic beanstalk environment (https://aws.amazon.com/elasticbeanstalk/) ]# + # AWS Elastic Beanstalk environment color. + typeset -g POWERLEVEL9K_AWS_EB_ENV_FOREGROUND=2 + # Custom icon. + # typeset -g POWERLEVEL9K_AWS_EB_ENV_VISUAL_IDENTIFIER_EXPANSION='⭐' + + ##########[ azure: azure account name (https://docs.microsoft.com/en-us/cli/azure) ]########## + # Show azure only when the command you are typing invokes one of these tools. + # Tip: Remove the next line to always show azure. + typeset -g POWERLEVEL9K_AZURE_SHOW_ON_COMMAND='az|terraform|pulumi|terragrunt' + + # POWERLEVEL9K_AZURE_CLASSES is an array with even number of elements. The first element + # in each pair defines a pattern against which the current azure account name gets matched. + # More specifically, it's P9K_CONTENT prior to the application of context expansion (see below) + # that gets matched. If you unset all POWERLEVEL9K_AZURE_*CONTENT_EXPANSION parameters, + # you'll see this value in your prompt. The second element of each pair in + # POWERLEVEL9K_AZURE_CLASSES defines the account class. Patterns are tried in order. The + # first match wins. + # + # For example, given these settings: + # + # typeset -g POWERLEVEL9K_AZURE_CLASSES=( + # '*prod*' PROD + # '*test*' TEST + # '*' OTHER) + # + # If your current azure account is "company_test", its class is TEST because "company_test" + # doesn't match the pattern '*prod*' but does match '*test*'. + # + # You can define different colors, icons and content expansions for different classes: + # + # typeset -g POWERLEVEL9K_AZURE_TEST_FOREGROUND=2 + # typeset -g POWERLEVEL9K_AZURE_TEST_VISUAL_IDENTIFIER_EXPANSION='⭐' + # typeset -g POWERLEVEL9K_AZURE_TEST_CONTENT_EXPANSION='> ${P9K_CONTENT} <' + typeset -g POWERLEVEL9K_AZURE_CLASSES=( + # '*prod*' PROD # These values are examples that are unlikely + # '*test*' TEST # to match your needs. Customize them as needed. + '*' OTHER) + + # Azure account name color. + typeset -g POWERLEVEL9K_AZURE_OTHER_FOREGROUND=4 + # Custom icon. + # typeset -g POWERLEVEL9K_AZURE_OTHER_VISUAL_IDENTIFIER_EXPANSION='⭐' + + ##########[ gcloud: google cloud account and project (https://cloud.google.com/) ]########### + # Show gcloud only when the command you are typing invokes one of these tools. + # Tip: Remove the next line to always show gcloud. + typeset -g POWERLEVEL9K_GCLOUD_SHOW_ON_COMMAND='gcloud|gcs|gsutil' + # Google cloud color. + typeset -g POWERLEVEL9K_GCLOUD_FOREGROUND=4 + + # Google cloud format. Change the value of POWERLEVEL9K_GCLOUD_PARTIAL_CONTENT_EXPANSION and/or + # POWERLEVEL9K_GCLOUD_COMPLETE_CONTENT_EXPANSION if the default is too verbose or not informative + # enough. You can use the following parameters in the expansions. Each of them corresponds to the + # output of `gcloud` tool. + # + # Parameter | Source + # -------------------------|-------------------------------------------------------------------- + # P9K_GCLOUD_CONFIGURATION | gcloud config configurations list --format='value(name)' + # P9K_GCLOUD_ACCOUNT | gcloud config get-value account + # P9K_GCLOUD_PROJECT_ID | gcloud config get-value project + # P9K_GCLOUD_PROJECT_NAME | gcloud projects describe $P9K_GCLOUD_PROJECT_ID --format='value(name)' + # + # Note: ${VARIABLE//\%/%%} expands to ${VARIABLE} with all occurrences of '%' replaced with '%%'. + # + # Obtaining project name requires sending a request to Google servers. This can take a long time + # and even fail. When project name is unknown, P9K_GCLOUD_PROJECT_NAME is not set and gcloud + # prompt segment is in state PARTIAL. When project name gets known, P9K_GCLOUD_PROJECT_NAME gets + # set and gcloud prompt segment transitions to state COMPLETE. + # + # You can customize the format, icon and colors of gcloud segment separately for states PARTIAL + # and COMPLETE. You can also hide gcloud in state PARTIAL by setting + # POWERLEVEL9K_GCLOUD_PARTIAL_VISUAL_IDENTIFIER_EXPANSION and + # POWERLEVEL9K_GCLOUD_PARTIAL_CONTENT_EXPANSION to empty. + typeset -g POWERLEVEL9K_GCLOUD_PARTIAL_CONTENT_EXPANSION='${P9K_GCLOUD_PROJECT_ID//\%/%%}' + typeset -g POWERLEVEL9K_GCLOUD_COMPLETE_CONTENT_EXPANSION='${P9K_GCLOUD_PROJECT_NAME//\%/%%}' + + # Send a request to Google (by means of `gcloud projects describe ...`) to obtain project name + # this often. Negative value disables periodic polling. In this mode project name is retrieved + # only when the current configuration, account or project id changes. + typeset -g POWERLEVEL9K_GCLOUD_REFRESH_PROJECT_NAME_SECONDS=60 + + # Custom icon. + # typeset -g POWERLEVEL9K_GCLOUD_VISUAL_IDENTIFIER_EXPANSION='⭐' + + #[ google_app_cred: google application credentials (https://cloud.google.com/docs/authentication/production) ]# + # Show google_app_cred only when the command you are typing invokes one of these tools. + # Tip: Remove the next line to always show google_app_cred. + typeset -g POWERLEVEL9K_GOOGLE_APP_CRED_SHOW_ON_COMMAND='terraform|pulumi|terragrunt' + + # Google application credentials classes for the purpose of using different colors, icons and + # expansions with different credentials. + # + # POWERLEVEL9K_GOOGLE_APP_CRED_CLASSES is an array with even number of elements. The first + # element in each pair defines a pattern against which the current kubernetes context gets + # matched. More specifically, it's P9K_CONTENT prior to the application of context expansion + # (see below) that gets matched. If you unset all POWERLEVEL9K_GOOGLE_APP_CRED_*CONTENT_EXPANSION + # parameters, you'll see this value in your prompt. The second element of each pair in + # POWERLEVEL9K_GOOGLE_APP_CRED_CLASSES defines the context class. Patterns are tried in order. + # The first match wins. + # + # For example, given these settings: + # + # typeset -g POWERLEVEL9K_GOOGLE_APP_CRED_CLASSES=( + # '*:*prod*:*' PROD + # '*:*test*:*' TEST + # '*' DEFAULT) + # + # If your current Google application credentials is "service_account deathray-testing x@y.com", + # its class is TEST because it doesn't match the pattern '* *prod* *' but does match '* *test* *'. + # + # You can define different colors, icons and content expansions for different classes: + # + # typeset -g POWERLEVEL9K_GOOGLE_APP_CRED_TEST_FOREGROUND=3 + # typeset -g POWERLEVEL9K_GOOGLE_APP_CRED_TEST_VISUAL_IDENTIFIER_EXPANSION='⭐' + # typeset -g POWERLEVEL9K_GOOGLE_APP_CRED_TEST_CONTENT_EXPANSION='$P9K_GOOGLE_APP_CRED_PROJECT_ID' + typeset -g POWERLEVEL9K_GOOGLE_APP_CRED_CLASSES=( + # '*:*prod*:*' PROD # These values are examples that are unlikely + # '*:*test*:*' TEST # to match your needs. Customize them as needed. + '*' DEFAULT) + typeset -g POWERLEVEL9K_GOOGLE_APP_CRED_DEFAULT_FOREGROUND=5 + # typeset -g POWERLEVEL9K_GOOGLE_APP_CRED_DEFAULT_VISUAL_IDENTIFIER_EXPANSION='⭐' + + # Use POWERLEVEL9K_GOOGLE_APP_CRED_CONTENT_EXPANSION to specify the content displayed by + # google_app_cred segment. Parameter expansions are very flexible and fast, too. See reference: + # http://zsh.sourceforge.net/Doc/Release/Expansion.html#Parameter-Expansion. + # + # You can use the following parameters in the expansion. Each of them corresponds to one of the + # fields in the JSON file pointed to by GOOGLE_APPLICATION_CREDENTIALS. + # + # Parameter | JSON key file field + # ---------------------------------+--------------- + # P9K_GOOGLE_APP_CRED_TYPE | type + # P9K_GOOGLE_APP_CRED_PROJECT_ID | project_id + # P9K_GOOGLE_APP_CRED_CLIENT_EMAIL | client_email + # + # Note: ${VARIABLE//\%/%%} expands to ${VARIABLE} with all occurrences of '%' replaced by '%%'. + typeset -g POWERLEVEL9K_GOOGLE_APP_CRED_DEFAULT_CONTENT_EXPANSION='${P9K_GOOGLE_APP_CRED_PROJECT_ID//\%/%%}' + + ##############[ toolbox: toolbox name (https://github.com/containers/toolbox) ]############### + # Toolbox color. + typeset -g POWERLEVEL9K_TOOLBOX_FOREGROUND=3 + # Don't display the name of the toolbox if it matches fedora-toolbox-*. + typeset -g POWERLEVEL9K_TOOLBOX_CONTENT_EXPANSION='${P9K_TOOLBOX_NAME:#fedora-toolbox-*}' + # Custom icon. + # typeset -g POWERLEVEL9K_TOOLBOX_VISUAL_IDENTIFIER_EXPANSION='⭐' + # Custom prefix. + # typeset -g POWERLEVEL9K_TOOLBOX_PREFIX='%fin ' + + ###############################[ public_ip: public IP address ]############################### + # Public IP color. + typeset -g POWERLEVEL9K_PUBLIC_IP_FOREGROUND=6 + # Custom icon. + # typeset -g POWERLEVEL9K_PUBLIC_IP_VISUAL_IDENTIFIER_EXPANSION='⭐' + + ########################[ vpn_ip: virtual private network indicator ]######################### + # VPN IP color. + typeset -g POWERLEVEL9K_VPN_IP_FOREGROUND=3 + # When on VPN, show just an icon without the IP address. + # Tip: To display the private IP address when on VPN, remove the next line. + typeset -g POWERLEVEL9K_VPN_IP_CONTENT_EXPANSION= + # Regular expression for the VPN network interface. Run `ifconfig` or `ip -4 a show` while on VPN + # to see the name of the interface. + typeset -g POWERLEVEL9K_VPN_IP_INTERFACE='(gpd|wg|(.*tun)|tailscale)[0-9]*|(zt.*)' + # If set to true, show one segment per matching network interface. If set to false, show only + # one segment corresponding to the first matching network interface. + # Tip: If you set it to true, you'll probably want to unset POWERLEVEL9K_VPN_IP_CONTENT_EXPANSION. + typeset -g POWERLEVEL9K_VPN_IP_SHOW_ALL=false + # Custom icon. + # typeset -g POWERLEVEL9K_VPN_IP_VISUAL_IDENTIFIER_EXPANSION='⭐' + + ###########[ ip: ip address and bandwidth usage for a specified network interface ]########### + # IP color. + typeset -g POWERLEVEL9K_IP_FOREGROUND=4 + # The following parameters are accessible within the expansion: + # + # Parameter | Meaning + # ----------------------+------------------------------------------- + # P9K_IP_IP | IP address + # P9K_IP_INTERFACE | network interface + # P9K_IP_RX_BYTES | total number of bytes received + # P9K_IP_TX_BYTES | total number of bytes sent + # P9K_IP_RX_BYTES_DELTA | number of bytes received since last prompt + # P9K_IP_TX_BYTES_DELTA | number of bytes sent since last prompt + # P9K_IP_RX_RATE | receive rate (since last prompt) + # P9K_IP_TX_RATE | send rate (since last prompt) + typeset -g POWERLEVEL9K_IP_CONTENT_EXPANSION='$P9K_IP_IP${P9K_IP_RX_RATE:+ %2F⇣$P9K_IP_RX_RATE}${P9K_IP_TX_RATE:+ %3F⇡$P9K_IP_TX_RATE}' + # Show information for the first network interface whose name matches this regular expression. + # Run `ifconfig` or `ip -4 a show` to see the names of all network interfaces. + typeset -g POWERLEVEL9K_IP_INTERFACE='[ew].*' + # Custom icon. + # typeset -g POWERLEVEL9K_IP_VISUAL_IDENTIFIER_EXPANSION='⭐' + + #########################[ proxy: system-wide http/https/ftp proxy ]########################## + # Proxy color. + typeset -g POWERLEVEL9K_PROXY_FOREGROUND=2 + # Custom icon. + # typeset -g POWERLEVEL9K_PROXY_VISUAL_IDENTIFIER_EXPANSION='⭐' + + ################################[ battery: internal battery ]################################# + # Show battery in red when it's below this level and not connected to power supply. + typeset -g POWERLEVEL9K_BATTERY_LOW_THRESHOLD=20 + typeset -g POWERLEVEL9K_BATTERY_LOW_FOREGROUND=1 + # Show battery in green when it's charging or fully charged. + typeset -g POWERLEVEL9K_BATTERY_{CHARGING,CHARGED}_FOREGROUND=2 + # Show battery in yellow when it's discharging. + typeset -g POWERLEVEL9K_BATTERY_DISCONNECTED_FOREGROUND=3 + # Battery pictograms going from low to high level of charge. + typeset -g POWERLEVEL9K_BATTERY_STAGES='\UF008E\UF007A\UF007B\UF007C\UF007D\UF007E\UF007F\UF0080\UF0081\UF0082\UF0079' + # Don't show the remaining time to charge/discharge. + typeset -g POWERLEVEL9K_BATTERY_VERBOSE=false + + #####################################[ wifi: wifi speed ]##################################### + # WiFi color. + typeset -g POWERLEVEL9K_WIFI_FOREGROUND=4 + # Custom icon. + # typeset -g POWERLEVEL9K_WIFI_VISUAL_IDENTIFIER_EXPANSION='⭐' + + # Use different colors and icons depending on signal strength ($P9K_WIFI_BARS). + # + # # Wifi colors and icons for different signal strength levels (low to high). + # typeset -g my_wifi_fg=(4 4 4 4 4) # <-- change these values + # typeset -g my_wifi_icon=('WiFi' 'WiFi' 'WiFi' 'WiFi' 'WiFi') # <-- change these values + # + # typeset -g POWERLEVEL9K_WIFI_CONTENT_EXPANSION='%F{${my_wifi_fg[P9K_WIFI_BARS+1]}}$P9K_WIFI_LAST_TX_RATE Mbps' + # typeset -g POWERLEVEL9K_WIFI_VISUAL_IDENTIFIER_EXPANSION='%F{${my_wifi_fg[P9K_WIFI_BARS+1]}}${my_wifi_icon[P9K_WIFI_BARS+1]}' + # + # The following parameters are accessible within the expansions: + # + # Parameter | Meaning + # ----------------------+--------------- + # P9K_WIFI_SSID | service set identifier, a.k.a. network name + # P9K_WIFI_LINK_AUTH | authentication protocol such as "wpa2-psk" or "none"; empty if unknown + # P9K_WIFI_LAST_TX_RATE | wireless transmit rate in megabits per second + # P9K_WIFI_RSSI | signal strength in dBm, from -120 to 0 + # P9K_WIFI_NOISE | noise in dBm, from -120 to 0 + # P9K_WIFI_BARS | signal strength in bars, from 0 to 4 (derived from P9K_WIFI_RSSI and P9K_WIFI_NOISE) + + ####################################[ time: current time ]#################################### + # Current time color. + typeset -g POWERLEVEL9K_TIME_FOREGROUND=6 + # Format for the current time: 09:51:02. See `man 3 strftime`. + typeset -g POWERLEVEL9K_TIME_FORMAT='%D{%I:%M:%S %p}' + # If set to true, time will update when you hit enter. This way prompts for the past + # commands will contain the start times of their commands as opposed to the default + # behavior where they contain the end times of their preceding commands. + typeset -g POWERLEVEL9K_TIME_UPDATE_ON_COMMAND=false + # Custom icon. + typeset -g POWERLEVEL9K_TIME_VISUAL_IDENTIFIER_EXPANSION= + # Custom prefix. + # typeset -g POWERLEVEL9K_TIME_PREFIX='%fat ' + + # Example of a user-defined prompt segment. Function prompt_example will be called on every + # prompt if `example` prompt segment is added to POWERLEVEL9K_LEFT_PROMPT_ELEMENTS or + # POWERLEVEL9K_RIGHT_PROMPT_ELEMENTS. It displays an icon and green text greeting the user. + # + # Type `p10k help segment` for documentation and a more sophisticated example. + function prompt_example() { + p10k segment -f 2 -i '⭐' -t 'hello, %n' + } + + # User-defined prompt segments may optionally provide an instant_prompt_* function. Its job + # is to generate the prompt segment for display in instant prompt. See + # https://github.com/romkatv/powerlevel10k#instant-prompt. + # + # Powerlevel10k will call instant_prompt_* at the same time as the regular prompt_* function + # and will record all `p10k segment` calls it makes. When displaying instant prompt, Powerlevel10k + # will replay these calls without actually calling instant_prompt_*. It is imperative that + # instant_prompt_* always makes the same `p10k segment` calls regardless of environment. If this + # rule is not observed, the content of instant prompt will be incorrect. + # + # Usually, you should either not define instant_prompt_* or simply call prompt_* from it. If + # instant_prompt_* is not defined for a segment, the segment won't be shown in instant prompt. + function instant_prompt_example() { + # Since prompt_example always makes the same `p10k segment` calls, we can call it from + # instant_prompt_example. This will give us the same `example` prompt segment in the instant + # and regular prompts. + prompt_example + } + + # User-defined prompt segments can be customized the same way as built-in segments. + # typeset -g POWERLEVEL9K_EXAMPLE_FOREGROUND=208 + # typeset -g POWERLEVEL9K_EXAMPLE_VISUAL_IDENTIFIER_EXPANSION='⭐' + + # Transient prompt works similarly to the builtin transient_rprompt option. It trims down prompt + # when accepting a command line. Supported values: + # + # - off: Don't change prompt when accepting a command line. + # - always: Trim down prompt when accepting a command line. + # - same-dir: Trim down prompt when accepting a command line unless this is the first command + # typed after changing current working directory. + typeset -g POWERLEVEL9K_TRANSIENT_PROMPT=always + + # Instant prompt mode. + # + # - off: Disable instant prompt. Choose this if you've tried instant prompt and found + # it incompatible with your zsh configuration files. + # - quiet: Enable instant prompt and don't print warnings when detecting console output + # during zsh initialization. Choose this if you've read and understood + # https://github.com/romkatv/powerlevel10k#instant-prompt. + # - verbose: Enable instant prompt and print a warning when detecting console output during + # zsh initialization. Choose this if you've never tried instant prompt, haven't + # seen the warning, or if you are unsure what this all means. + typeset -g POWERLEVEL9K_INSTANT_PROMPT=verbose + + # Hot reload allows you to change POWERLEVEL9K options after Powerlevel10k has been initialized. + # For example, you can type POWERLEVEL9K_BACKGROUND=red and see your prompt turn red. Hot reload + # can slow down prompt by 1-2 milliseconds, so it's better to keep it turned off unless you + # really need it. + typeset -g POWERLEVEL9K_DISABLE_HOT_RELOAD=true + + # If p10k is already loaded, reload configuration. + # This works even with POWERLEVEL9K_DISABLE_HOT_RELOAD=true. + (( ! $+functions[p10k] )) || p10k reload +} + +# Tell `p10k configure` which file it should overwrite. +typeset -g POWERLEVEL9K_CONFIG_FILE=${${(%):-%x}:a} + +(( ${#p10k_config_opts} )) && setopt ${p10k_config_opts[@]} +'builtin' 'unset' 'p10k_config_opts' diff --git a/README.md b/README.md new file mode 100644 index 0000000..3b83bda --- /dev/null +++ b/README.md @@ -0,0 +1,145 @@ +# 🖥️ ParanaOS + + +

+ Screenshot 1 + Screenshot 2 + Screenshot 3 + Screenshot 4 + Screenshot 5 + Screenshot 6 + Screenshot 7 + Screenshot 8 + Screenshot 9 + Screenshot 10 +

+ +--- + +## Overview + +Welcome to my personal dotfiles repo! This setup uses [Nix Flakes](https://nixos.wiki/wiki/Flakes), modular shell/configuration management, and lightweight scripts to make my Linux environment highly reproducible, beautiful, and easy to customize. + +**Features:** +- 🎨 Powerlevel10k Zsh theme +- 🐚 Modular configs for shell, editor, and more +- ⚡ Automated install with Nix +- 🖼️ Wallpapers for a custom look +- 🛠️ Utility scripts +- 🔒 Host-specific overrides + +--- + +## Screenshots + +
+Click to expand all screenshots + +

+ Screenshot 1 + Screenshot 2 + Screenshot 3 + Screenshot 4 + Screenshot 5 + Screenshot 6 + Screenshot 7 + Screenshot 8 + Screenshot 9 + Screenshot 10 +

+
+ +--- + +## Installation & Setup + +### Prerequisites +- **Linux machine** (tested with Arch, Ubuntu; works on most distros) +- **[Nix](https://nixos.org/download.html)** package manager (see https://nixos.org for install instructions) +- Optionally: [Home Manager](https://nix-community.github.io/home-manager/) for full home directory integration + +### Step 1: Clone the repository + +```sh +git clone https://github.com/gibbyDev/.dotfiles>.git ~/.dotfiles +cd ~/.dotfiles +``` + +### Step 2: Install dependencies with Nix Flakes + +If you don’t have flakes enabled, run: + +```sh +nix --experimental-features 'nix-command flakes' flake show +``` + +Run the installer to rebuild system and home manager modules: + +```sh +chmod +x install.sh +./install.sh +``` + +Replace `` with your hostname as defined in the `hosts/` directory. + +### Step 3: Extras and Customization +- Edit (or override) configs in `modules/` for shell, editor, etc. +- Change wallpapers by replacing files in `wallpapers/` +- Update host-specific settings in `hosts/` +- Zsh theme: `.p10k.zsh` config for Powerlevel10k is included +- Additional scripts can be run or extended from `scripts/` + +--- + +## Directory Structure + +```text +. +├── flake.lock +├── flake.nix +├── hosts +│   └── template/ +├── imgs +├── modules +│   ├── code/ +│   ├── default.nix +│   ├── dolphin/ +│   ├── fastfetch/ +│   ├── firefox/ +│   ├── hyprland/ +│   ├── kitty/ +│   ├── misc/ +│   ├── nvim/ +│   ├── opencode/ +│   ├── rofi/ +│   ├── tmux/ +│   ├── virtualization/ +│   ├── waybar/ +│   ├── wlogout/ +│   └── yazi/ +├── .p10k.zsh +├── README.md +├── scripts +└── wallpapers +``` + +--- + +## FAQ & Troubleshooting +- **How do I update everything?** + - Pull latest: `git pull` + - Re-run the Nix install process +- **Where do I put overrides for my machine?** + - Add files to the `hosts/` directory named after your hostname. +- **How do I contribute or fork?** + - Make your edits, then push to your fork or PR as needed! + +--- + +## License +MIT (or specify your own preferred license) + +## Credits +Big thanks to the Nix, Home Manager, and Powerlevel10k communities! + +--- diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..66b3e2f --- /dev/null +++ b/flake.lock @@ -0,0 +1,173 @@ +{ + "nodes": { + "crane": { + "locked": { + "lastModified": 1766194365, + "narHash": "sha256-4AFsUZ0kl6MXSm4BaQgItD0VGlEKR3iq7gIaL7TjBvc=", + "owner": "ipetkov", + "repo": "crane", + "rev": "7d8ec2c71771937ab99790b45e6d9b93d15d9379", + "type": "github" + }, + "original": { + "owner": "ipetkov", + "repo": "crane", + "type": "github" + } + }, + "flake-parts": { + "inputs": { + "nixpkgs-lib": [ + "nur", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1733312601, + "narHash": "sha256-4pDvzqnegAfRkPwO3wmwBhVi/Sye1mzps0zHWYnP88c=", + "owner": "hercules-ci", + "repo": "flake-parts", + "rev": "205b12d8b7cd4802fbcb8e8ef6a0f1408781a4f9", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "flake-parts", + "type": "github" + } + }, + "home-manager": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1772218752, + "narHash": "sha256-G8nArvOTZXU8DRvrzAdz3Elcj6kA/vMtvY9mrGLATtA=", + "owner": "nix-community", + "repo": "home-manager", + "rev": "f3a30376bb9eb2f6f61816be7d6ed954b6d2a3b9", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "home-manager", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1771848320, + "narHash": "sha256-0MAd+0mun3K/Ns8JATeHT1sX28faLII5hVLq0L3BdZU=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "2fc6539b481e1d2569f25f8799236694180c0993", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs-stable": { + "locked": { + "lastModified": 1751274312, + "narHash": "sha256-/bVBlRpECLVzjV19t5KMdMFWSwKLtb5RyXdjz3LJT+g=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "50ab793786d9de88ee30ec4e4c24fb4236fc2674", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-24.11", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_2": { + "locked": { + "lastModified": 1771848320, + "narHash": "sha256-0MAd+0mun3K/Ns8JATeHT1sX28faLII5hVLq0L3BdZU=", + "owner": "nixos", + "repo": "nixpkgs", + "rev": "2fc6539b481e1d2569f25f8799236694180c0993", + "type": "github" + }, + "original": { + "owner": "nixos", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_3": { + "locked": { + "lastModified": 1766309749, + "narHash": "sha256-3xY8CZ4rSnQ0NqGhMKAy5vgC+2IVK0NoVEzDoOh4DA4=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "a6531044f6d0bef691ea18d4d4ce44d0daa6e816", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nur": { + "inputs": { + "flake-parts": "flake-parts", + "nixpkgs": "nixpkgs_2" + }, + "locked": { + "lastModified": 1772306319, + "narHash": "sha256-ZcE3mTo1ThKx8KfW/deQxDhswNso/g0kbPWsfIkbsg8=", + "owner": "nix-community", + "repo": "NUR", + "rev": "2ad742d56b58e3cf5f8b300dc92ced2488ef3420", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "NUR", + "type": "github" + } + }, + "root": { + "inputs": { + "home-manager": "home-manager", + "nixpkgs": "nixpkgs", + "nixpkgs-stable": "nixpkgs-stable", + "nur": "nur", + "stash": "stash" + } + }, + "stash": { + "inputs": { + "crane": "crane", + "nixpkgs": "nixpkgs_3" + }, + "locked": { + "lastModified": 1772183710, + "narHash": "sha256-ojaPFnfWFRUi4Nc69T+ObdZ3Bxf62T3bv49qqV+wgHw=", + "owner": "NotAShelf", + "repo": "stash", + "rev": "181edcefb1fb38bbd1ca306e91ba493bcf4014d9", + "type": "github" + }, + "original": { + "owner": "NotAShelf", + "repo": "stash", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..d806c99 --- /dev/null +++ b/flake.nix @@ -0,0 +1,236 @@ +{ + description = "ParanaOS by GibbyDev"; + + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; + nixpkgs-stable.url = "github:NixOS/nixpkgs/nixos-24.11"; + home-manager.url = "github:nix-community/home-manager"; + home-manager.inputs.nixpkgs.follows = "nixpkgs"; + nur.url = "github:nix-community/NUR"; + stash.url = "github:NotAShelf/stash"; + }; + + outputs = { self, nixpkgs, nixpkgs-stable, home-manager, nur, ... }@inputs: + let + lib = nixpkgs.lib; + system = "x86_64-linux"; + + customOverlays = builtins.attrValues (import ./overlays) ++ [ +# Override kdenlive with stable version to work around ffmpeg shaderc issue + (final: prev: { + kdenlive = let + stable = import nixpkgs-stable { + inherit system; + config.allowUnfree = true; + }; + in stable.kdenlive; + }) + ]; + + pkgs = import nixpkgs { + inherit system; + overlays = customOverlays ++ [ nur.overlays.default ]; + config.allowUnfree = true; + }; + + src = lib.cleanSourceWith { + src = ./.; + filter = path: type: + let baseName = lib.baseNameOf path; + in baseName != ".git" + && baseName != ".direnv" + && baseName != "result"; + }; + + hostDirs = lib.filter (h: h != "template") (builtins.attrNames (builtins.readDir ./hosts)); + + mkHost = host: + lib.nixosSystem { + inherit system; + + specialArgs = { + inherit inputs src; + }; + + modules = [ + ./hosts/${host}/configuration.nix + + { + nixpkgs.overlays = customOverlays; + } + + home-manager.nixosModules.home-manager + { + home-manager.useGlobalPkgs = true; + home-manager.useUserPackages = true; + home-manager.extraSpecialArgs = { inherit inputs src; }; + } + ]; + }; + + in + { + nixosConfigurations = + builtins.listToAttrs ( + map (host: { + name = host; + value = mkHost host; + }) hostDirs + ); + + devShells.${system} = { + + golang = pkgs.mkShell { + name = "golang-shell"; + +# ----------------------- +# Packages +# ----------------------- + buildInputs = with pkgs; [ + go # Golang compiler & tooling + git # for cloning repos + curl # fetch templates/examples + gnumake # optional, for builds + bash # shell utilities + ]; + +# ----------------------- +# Shell setup +# ----------------------- + shellHook = '' + echo "" + echo "🚀 Golang dev shell ready" + +# Ensure GOPATH/bin is in PATH + export GOPATH=$HOME/go + export PATH=$GOPATH/bin:$PATH + +# Go modules enabled + export GO111MODULE=on + +# Preinstall templ if missing + if [ ! -x "$GOPATH/bin/templ" ]; then + echo "Installing Templ..." + mkdir -p $GOPATH/src/github.com/evanw/templ + cd $GOPATH/src/github.com/evanw + git clone https://github.com/evanw/templ.git + cd templ + go install ./... + cd - + fi + + echo "Go version: $(go version)" + echo "Templ location: $(command -v templ || echo 'not found')" + echo "HTMX is front-end only: include in HTML" + ''; + }; + + +# ----------------------- +# Jetzig dev shell +# ----------------------- + jetzig = pkgs.mkShell { + name = "jetzig-shell"; + + buildInputs = with pkgs; [ + zig + git + gnumake + pkg-config + openssl + ]; + + shellHook = '' + echo "" + echo "🚀 Jetzig dev shell ready" + + export JETZIG_HOME=$HOME/.jetzig + export ZIG_GLOBAL_CACHE_DIR=$HOME/.cache/zig + export PATH=$JETZIG_HOME/zig-out/bin:$PATH + +# Clone if missing + if [ ! -d "$JETZIG_HOME" ]; then + echo "Cloning Jetzig into $JETZIG_HOME ..." + git clone https://github.com/jetzig-framework/jetzig $JETZIG_HOME + fi + +# Build if not built yet + if [ ! -f "$JETZIG_HOME/zig-out/bin/jetzig" ]; then + echo "Building Jetzig..." + cd $JETZIG_HOME + zig build -Doptimize=ReleaseSafe + cd - + fi + + echo "jetzig location: $(command -v jetzig || echo 'not found')" + ''; + }; + +# ----------------------- +# MERN dev shell +# ----------------------- + mern = pkgs.mkShell { + name = "mern-shell"; + + buildInputs = with pkgs; [ + nodejs + yarn + mongodb-tools + git + curl + openssl + gnumake + ]; + + shellHook = '' + echo "" + echo "🚀 MERN dev shell ready" + +# Local node_modules bin + export PATH=$(pwd)/node_modules/.bin:$PATH + +# Default MongoDB URL + export MONGO_URL="mongodb://localhost:27017" + + echo "Node.js version: $(node -v)" + echo "npm version: $(npm -v)" + echo "MongoDB tools available: $(which mongo || echo 'not found')" + ''; + }; + +# ----------------------- +# Flutter dev shell +# ----------------------- + flutter = pkgs.mkShell { + name = "flutter-shell"; + + buildInputs = with pkgs; [ + flutter + dart + android-tools + jdk21 + kotlin + gradle + ]; + + shellHook = '' + echo "" + echo "🚀 Flutter dev shell ready" + echo "" + + export ANDROID_HOME="$HOME/Android/Sdk" + export ANDROID_SDK_ROOT="$HOME/Android/Sdk" + + echo "Flutter version: $(flutter --version)" + echo "Dart version: $(dart --version)" + echo "Android tools: adb, fastboot available" + echo "" + echo "Next steps:" + echo " • flutter doctor (check setup)" + echo " • flutter create my_app" + echo " • cd my_app && flutter run" + ''; + }; + }; + }; +} diff --git a/hosts/nixos/configuration.nix b/hosts/nixos/configuration.nix new file mode 100644 index 0000000..daffbf7 --- /dev/null +++ b/hosts/nixos/configuration.nix @@ -0,0 +1,201 @@ +{ config, pkgs, inputs, lib, ... }: + +{ + imports = [ + ./hardware-configuration.nix # Include hardware scan results. + ]; + + boot.loader.grub = { + enable = true; + efiSupport = true; + device = "nodev"; + useOSProber = true; + }; + + boot.loader.efi.canTouchEfiVariables = true; + networking = { + hostName = "nixos"; + networkmanager.enable = true; # Enable NetworkManager + nameservers = ["192.168.1.2"]; + }; + + time.timeZone = "America/Detroit"; + + i18n = { + defaultLocale = "en_US.UTF-8"; + extraLocaleSettings = { + LC_ADDRESS = "en_US.UTF-8"; + LC_IDENTIFICATION = "en_US.UTF-8"; + LC_MEASUREMENT = "en_US.UTF-8"; + LC_MONETARY = "en_US.UTF-8"; + LC_NAME = "en_US.UTF-8"; + LC_NUMERIC = "en_US.UTF-8"; + LC_PAPER = "en_US.UTF-8"; + LC_TELEPHONE = "en_US.UTF-8"; + LC_TIME = "en_US.UTF-8"; + }; + }; + + programs.zsh.enable = true; + + users.users.cody = { + isNormalUser = true; + description = "cody"; + extraGroups = [ "wheel" "networkmanager" "libvirtd" "kvm" "qemu" "docker" ]; + packages = with pkgs; [ ]; + shell = pkgs.zsh; + }; + + home-manager.users.cody = import ./home.nix; + + nixpkgs.overlays = [ + inputs.nur.overlays.default + ]; + + nixpkgs.config.android_sdk.accept_license = true; + + services = { + xserver = { + enable = true; + xkb.layout = "us"; + displayManager.lightdm = { + enable = true; + }; + }; + + tailscale.enable = true; + + displayManager.defaultSession = "hyprland"; + + pipewire = { + enable = true; + alsa.enable = true; + alsa.support32Bit = true; + pulse.enable = true; + jack.enable = true; + }; + + resolved.enable = false; + + blueman.enable = true; + }; + + + + hardware.bluetooth = { + enable = true; + powerOnBoot = true; + }; + + virtualisation = { + libvirtd.enable = true; # Enables libvirt daemon and KVM support + docker.enable = true; # Enable this only if you want Docker + }; + + programs.virt-manager.enable = true; + + programs.hyprland.enable = true; + + boot.kernelModules = [ + "kvm" + "kvm-intel" + "v4l2loopback" + ]; + + fonts = { + fontconfig.enable = true; + fontconfig.defaultFonts.monospace = [ "Meslo LG M Regular Nerd Font Complete Mono" ]; + packages = with pkgs; [ + nerd-fonts.meslo-lg + nerd-fonts.jetbrains-mono + nerd-fonts.agave + font-awesome + powerline-fonts + powerline-symbols + ]; + }; + + environment.systemPackages = with pkgs; [ + vim + lastpass-cli + wget + git + docker + xhost + docker-compose + gnumake42 + go + cmake + gcc + gdb + networkmanagerapplet + kdenlive + postman + pywalfox-native + vlc + xcolor + adb-sync + wl-clipboard + cliphist + wtype + nwg-look + tailscale + libsForQt5.qt5.qtgraphicaleffects + linuxPackages.v4l2loopback # Kernel module for virtual webcam + alsa-utils # Audio support + v4l-utils # Video4Linux tools + pipewire + libsForQt5.qt5.qtmultimedia + qemu + libvirt + virt-manager + bridge-utils # For networking support + dnsmasq # DHCP for VM networking + ebtables # NAT support for VMs + grim + nload + htop + atop + iftop + slurp + grimblast + swappy + dunst + jq + moreutils + hyprland + libnotify + coreutils + hyprshade + unityhub + pkg-config + mkinitcpio-nfs-utils + xorg.libX11 + xorg.libXcursor + xorg.libXrandr + xorg.libXinerama + xorg.libXi + mesa + libGL + alsa-lib + adwaita-icon-theme + papirus-icon-theme + bibata-cursors + blueman + chromium + + bind + iproute2 + iputils + traceroute + mtr + tcpdump + ]; + + # Miscellaneous Settings + nixpkgs.config.allowUnfree = true; + nix.settings.experimental-features = [ "nix-command" "flakes" ]; + + # System State Version + system.stateVersion = "25.11"; +} diff --git a/hosts/nixos/hardware-configuration.nix b/hosts/nixos/hardware-configuration.nix new file mode 100644 index 0000000..f263e61 --- /dev/null +++ b/hosts/nixos/hardware-configuration.nix @@ -0,0 +1,31 @@ +# Do not modify this file! It was generated by ‘nixos-generate-config’ +# and may be overwritten by future invocations. Please make changes +# to /etc/nixos/configuration.nix instead. +{ config, lib, pkgs, modulesPath, ... }: + +{ + imports = + [ (modulesPath + "/installer/scan/not-detected.nix") + ]; + + boot.initrd.availableKernelModules = [ "xhci_pci" "thunderbolt" "nvme" "rtsx_pci_sdmmc" ]; + boot.initrd.kernelModules = [ ]; + boot.kernelModules = [ "kvm-intel" ]; + boot.extraModulePackages = [ ]; + + fileSystems."/" = + { device = "/dev/disk/by-uuid/7f7c0193-c0bc-47ad-9be3-0d48d83e489a"; + fsType = "ext4"; + }; + + fileSystems."/boot" = + { device = "/dev/disk/by-uuid/E646-95CD"; + fsType = "vfat"; + options = [ "fmask=0077" "dmask=0077" ]; + }; + + swapDevices = [ ]; + + nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; + hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware; +} diff --git a/hosts/nixos/home.nix b/hosts/nixos/home.nix new file mode 100644 index 0000000..524eef8 --- /dev/null +++ b/hosts/nixos/home.nix @@ -0,0 +1,100 @@ +{ config, pkgs, lib, ... }: + +{ + imports = [ + ../../modules + ]; + + home.username = "cody"; + home.homeDirectory = "/home/cody"; + home.stateVersion = "24.11"; + + nixpkgs.config.allowUnfree = true; + + home.packages = with pkgs; [ + kitty + screenkey + docker + tree + ffmpeg + tilt + unzip + gimp + ripgrep + fzf + lsd + lazygit + opencode + neofetch + fastfetch + tree + git + nodejs_22 + zig + tailwindcss + templ + imagemagick + go-blueprint + protobuf + air + pywal + bat + # go_1_24 + # go-tools + # Protocol buffers + # protobuf + # Go protoc plugins + # protoc-gen-go + # protoc-gen-go-grpc + cava + w3m + nwg-displays + (writeShellScriptBin "protoc-gen-go" '' + export PATH=$HOME/.go/bin:$PATH + go install google.golang.org/protobuf/cmd/protoc-gen-go@latest + '') + + (writeShellScriptBin "protoc-gen-go-grpc" '' + export PATH=$HOME/.go/bin:$PATH + go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest + '') + ]; + + modules.android = { + enable = false; + enableEmulator = false; + apiLevel = 34; + enableFlutterSupport = false; + }; + + home.sessionVariables = { + SHELL = "${pkgs.zsh}/bin/zsh"; + }; + + programs.dircolors.enable = true; + + home.file.".p10k.zsh".source = ../../.p10k.zsh; + + home.activation.copyScripts = + lib.hm.dag.entryAfter [ "writeBoundary" ] '' + mkdir -p ~/.local/share/bin + rm -rf ~/.local/share/bin/* + cp -r ${../../scripts}/* ~/.local/share/bin/ + chmod +x ~/.local/share/bin/* + if [ -x ~/.local/share/bin/tmux-session-manager.sh ] && [ ! -e ~/.local/share/bin/tmux-session-manager ]; then + ln -s ~/.local/share/bin/tmux-session-manager.sh ~/.local/share/bin/tmux-session-manager + fi + ''; + + home.activation.setupFirefoxCalendarProfile = + lib.hm.dag.entryAfter [ "writeBoundary" ] '' + bash ~/.local/share/bin/setup-firefox-calendar-profile.sh + ''; + + home.activation.copyWallpapers = + lib.hm.dag.entryAfter [ "writeBoundary" ] '' + mkdir -p ~/Pictures/wallpapers + rm -rf ~/Pictures/wallpapers/* + cp -r ${../../wallpapers}/* ~/Pictures/wallpapers/ + ''; +} diff --git a/hosts/nixos/sddm-theme.nix b/hosts/nixos/sddm-theme.nix new file mode 100644 index 0000000..96333f0 --- /dev/null +++ b/hosts/nixos/sddm-theme.nix @@ -0,0 +1,16 @@ +{ pkgs }: + +pkgs.stdenv.mkDerivation { + name = "sddm-theme"; + src = pkgs.fetchFromGitHub { + owner = "MarianArlt"; + repo = "sddm-sugar-dark"; + rev = "ceb2c455663429be03ba62d9f898c571650ef7fe"; + sha256 = "0153z1kylbhc9d12nxy9vpn0spxgrhgy36wy37pk6ysq7akaqlvy"; + }; + installPhase = '' + mkdir -p $out + cp -R ./* $out/ + ''; +} + diff --git a/hosts/template/configuration.nix b/hosts/template/configuration.nix new file mode 100644 index 0000000..f2093a1 --- /dev/null +++ b/hosts/template/configuration.nix @@ -0,0 +1,188 @@ +{ config, pkgs, inputs, lib, ... }: + +{ + imports = [ ./hardware-configuration.nix ]; # Include hardware scan results. + + boot.loader.grub = { + enable = true; + efiSupport = true; + device = "nodev"; + useOSProber = true; + }; + + boot.loader.efi.canTouchEfiVariables = true; + networking = { + hostName = "REPLACE_HOST"; + networkmanager.enable = true; # Enable NetworkManager + }; + + time.timeZone = "America/Detroit"; + + i18n = { + defaultLocale = "en_US.UTF-8"; + extraLocaleSettings = { + LC_ADDRESS = "en_US.UTF-8"; + LC_IDENTIFICATION = "en_US.UTF-8"; + LC_MEASUREMENT = "en_US.UTF-8"; + LC_MONETARY = "en_US.UTF-8"; + LC_NAME = "en_US.UTF-8"; + LC_NUMERIC = "en_US.UTF-8"; + LC_PAPER = "en_US.UTF-8"; + LC_TELEPHONE = "en_US.UTF-8"; + LC_TIME = "en_US.UTF-8"; + }; + }; + + programs.zsh.enable = true; + + users.users.REPLACE_USER = { + isNormalUser = true; + description = "REPLACE_USER"; + extraGroups = [ "wheel" "networkmanager" "libvirtd" "kvm" "qemu" "docker" ]; + packages = with pkgs; [ ]; + shell = pkgs.zsh; + }; + + home-manager.users.REPLACE_USER = import ./home.nix; + + nixpkgs.overlays = [ + inputs.nur.overlays.default + ]; + + services = { + xserver = { + enable = true; + xkb.layout = "us"; + displayManager.sddm.enable = true; + displayManager.defaultSession = "hyprland"; + }; + + displayManager.sddm = { + enable = true; + wayland.enable = true; # important for Hyprland + theme = "sddm-sugar-dark"; + }; + + pipewire = { + enable = true; + alsa.enable = true; + alsa.support32Bit = true; + pulse.enable = true; + jack.enable = true; + }; + }; + + virtualisation = { + libvirtd.enable = true; # Enables libvirt daemon and KVM support + docker.enable = true; # Enable this only if you want Docker + }; + + programs.virt-manager.enable = true; + + programs.hyprland.enable = true; + + boot.kernelModules = [ + "kvm" + "kvm-intel" + "v4l2loopback" + ]; + + fonts = { + fontconfig.enable = true; + fontconfig.defaultFonts.monospace = [ "Meslo LG M Regular Nerd Font Complete Mono" ]; + packages = with pkgs; [ + nerd-fonts.meslo-lg + nerd-fonts.jetbrains-mono + nerd-fonts.agave + font-awesome + powerline-fonts + powerline-symbols + ]; + }; + + environment.systemPackages = with pkgs; [ + vim + lastpass-cli + wget + git + docker + xhost + docker-compose + gnumake42 + go + cmake + gcc + gdb + networkmanagerapplet + pywalfox-native + # droidcam +# kdenlive + vlc + xcolor + adb-sync + wl-clipboard + stash + nwg-look + libsForQt5.qt5.qtgraphicaleffects + linuxPackages.v4l2loopback # Kernel module for virtual webcam + alsa-utils # Audio support + v4l-utils # Video4Linux tools + pipewire + qemu + libvirt + virt-manager + bridge-utils # For networking support + dnsmasq # DHCP for VM networking + ebtables # NAT support for VMs + grim + slurp + grimblast + swappy + dunst + jq + moreutils + hyprland + libnotify + coreutils + hyprshade + unityhub + pkg-config + xorg.libX11 + xorg.libXcursor + xorg.libXrandr + xorg.libXinerama + xorg.libXi + mesa + libGL + alsa-lib + (pkgs.stdenv.mkDerivation { + pname = "sugar-candy-sddm-theme"; + version = "latest"; + src = pkgs.fetchFromGitHub { + owner = "MarianArlt"; + repo = "sddm-sugar-dark"; + rev = "master"; + sha256 = "0153z1kylbhc9d12nxy9vpn0spxgrhgy36wy37pk6ysq7akaqlvy"; + }; + installPhase = '' + mkdir -p $out/share/sddm/themes/sddm-sugar-dark + cp -r * $out/share/sddm/themes/sddm-sugar-dark + ''; + }) + + ]; + + # Optional: Specify the SDDM theme configuration + # environment.etc."sddm.conf".text = lib.mkForce '' + # [Theme] + # Current=sddm-sugar-dark + # ''; + # + # Miscellaneous Settings + nixpkgs.config.allowUnfree = true; + nix.settings.experimental-features = [ "nix-command" "flakes" ]; + + # System State Version + system.stateVersion = "25.11"; +} + diff --git a/hosts/template/hardware-configuration.nix b/hosts/template/hardware-configuration.nix new file mode 100644 index 0000000..3fb614b --- /dev/null +++ b/hosts/template/hardware-configuration.nix @@ -0,0 +1,34 @@ +# Do not modify this file! It was generated by ‘nixos-generate-config’ +# and may be overwritten by future invocations. Please make changes +# to /etc/nixos/configuration.nix instead. +{ config, lib, pkgs, modulesPath, ... }: + +{ + imports = + [ + (modulesPath + "/installer/scan/not-detected.nix") + ]; + + boot.initrd.availableKernelModules = [ "xhci_pci" "nvme" "usb_storage" "sd_mod" ]; + boot.initrd.kernelModules = [ ]; + boot.kernelModules = [ "kvm-intel" ]; + boot.extraModulePackages = [ ]; + + fileSystems."/" = + { + device = "/dev/disk/by-uuid/4555c094-debf-45c7-a330-b6f5d0a1e64f"; + fsType = "ext4"; + }; + + fileSystems."/boot" = + { + device = "/dev/disk/by-uuid/A7D4-AE37"; + fsType = "vfat"; + options = [ "fmask=0077" "dmask=0077" ]; + }; + + swapDevices = [ ]; + + nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; + hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware; +} diff --git a/hosts/template/home.nix b/hosts/template/home.nix new file mode 100644 index 0000000..8a46115 --- /dev/null +++ b/hosts/template/home.nix @@ -0,0 +1,88 @@ +{ config, pkgs, lib, ... }: + +{ + imports = [ + ../../modules + ]; + + home.username = "REPLACE_USER"; + home.homeDirectory = "/home/REPLACE_USER"; + home.stateVersion = "24.11"; + + nixpkgs.config.allowUnfree = true; + + home.packages = with pkgs; [ + kitty + screenkey + docker + tree + ffmpeg + tilt + unzip + gimp + ripgrep + fzf + lsd + lazygit + opencode + neofetch + fastfetch + tree + git + nodejs_22 + zig + tailwindcss + templ + imagemagick + go-blueprint + protobuf + air + pywal + bat + cava + w3m + nwg-displays + (writeShellScriptBin "protoc-gen-go" '' + export PATH=$HOME/.go/bin:$PATH + go install google.golang.org/protobuf/cmd/protoc-gen-go@latest + '') + + (writeShellScriptBin "protoc-gen-go-grpc" '' + export PATH=$HOME/.go/bin:$PATH + go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest + '') + ]; + + home.sessionVariables = { + SHELL = "${pkgs.zsh}/bin/zsh"; + }; + + programs.dircolors.enable = true; + + home.file.".p10k.zsh".source = ../../.p10k.zsh; + + home.activation.copyScripts = + lib.hm.dag.entryAfter [ "writeBoundary" ] '' + mkdir -p ~/.local/share/bin + rm -rf ~/.local/share/bin/* + cp -r ${../../scripts}/* ~/.local/share/bin/ + chmod +x ~/.local/share/bin/* + if [ -x ~/.local/share/bin/tmux-session-manager.sh ] && [ ! -e ~/.local/share/bin/tmux-session-manager ]; then + ln -s ~/.local/share/bin/tmux-session-manager.sh ~/.local/share/bin/tmux-session-manager + fi + ''; + + home.activation.copyWallpapers = + lib.hm.dag.entryAfter [ "writeBoundary" ] '' + mkdir -p ~/Pictures/wallpapers + rm -rf ~/Pictures/wallpapers/* + cp -r ${../../wallpapers}/* ~/Pictures/wallpapers/ + ''; + + home.file.".config/lsd/colors.yaml".text = '' + date: "white" + user: "white" + group: "white" + # ...any other preferences + ''; +} diff --git a/hosts/template/sddm-theme.nix b/hosts/template/sddm-theme.nix new file mode 100644 index 0000000..eaa6644 --- /dev/null +++ b/hosts/template/sddm-theme.nix @@ -0,0 +1,14 @@ +pkgs.stdenv.mkDerivation { + name = "sddm-theme"; + src = pkgs.fetchFromGitHub { + owner = "MarianArlt"; + repo = "sddm-sugar-dark"; + rev = "ceb2c455663429be03ba62d9f898c571650ef7fe"; + sha256 = "0153z1kylbhc9d12nxy9vpn0spxgrhgy36wy37pk6ysq7akaqlvy"; + }; + installPhase = '' + mkdir -p $out + cp -R ./* $out/ + ''; +} + diff --git a/imgs/260204_17h43m19s_screenshot.png b/imgs/260204_17h43m19s_screenshot.png new file mode 100644 index 0000000..fe283eb Binary files /dev/null and b/imgs/260204_17h43m19s_screenshot.png differ diff --git a/imgs/260204_17h44m14s_screenshot.png b/imgs/260204_17h44m14s_screenshot.png new file mode 100644 index 0000000..9a3f862 Binary files /dev/null and b/imgs/260204_17h44m14s_screenshot.png differ diff --git a/imgs/260204_17h44m50s_screenshot.png b/imgs/260204_17h44m50s_screenshot.png new file mode 100644 index 0000000..80c74fd Binary files /dev/null and b/imgs/260204_17h44m50s_screenshot.png differ diff --git a/imgs/260204_17h47m38s_screenshot.png b/imgs/260204_17h47m38s_screenshot.png new file mode 100644 index 0000000..af295ec Binary files /dev/null and b/imgs/260204_17h47m38s_screenshot.png differ diff --git a/imgs/260204_17h48m01s_screenshot.png b/imgs/260204_17h48m01s_screenshot.png new file mode 100644 index 0000000..7ca0419 Binary files /dev/null and b/imgs/260204_17h48m01s_screenshot.png differ diff --git a/imgs/260204_17h49m57s_screenshot.png b/imgs/260204_17h49m57s_screenshot.png new file mode 100644 index 0000000..47fffd1 Binary files /dev/null and b/imgs/260204_17h49m57s_screenshot.png differ diff --git a/imgs/260204_17h50m12s_screenshot.png b/imgs/260204_17h50m12s_screenshot.png new file mode 100644 index 0000000..2b0aa0f Binary files /dev/null and b/imgs/260204_17h50m12s_screenshot.png differ diff --git a/imgs/260204_17h50m28s_screenshot.png b/imgs/260204_17h50m28s_screenshot.png new file mode 100644 index 0000000..afe6c56 Binary files /dev/null and b/imgs/260204_17h50m28s_screenshot.png differ diff --git a/imgs/260204_17h50m45s_screenshot.png b/imgs/260204_17h50m45s_screenshot.png new file mode 100644 index 0000000..0382965 Binary files /dev/null and b/imgs/260204_17h50m45s_screenshot.png differ diff --git a/imgs/260204_17h52m05s_screenshot.png b/imgs/260204_17h52m05s_screenshot.png new file mode 100644 index 0000000..3459409 Binary files /dev/null and b/imgs/260204_17h52m05s_screenshot.png differ diff --git a/install.sh b/install.sh new file mode 100755 index 0000000..b2a9f4d --- /dev/null +++ b/install.sh @@ -0,0 +1,56 @@ +#!/usr/bin/env bash +set -e + +DOTFILES="$HOME/.dotfiles" + +if [ ! -d "$DOTFILES" ]; then + echo "❌ .dotfiles not found at $DOTFILES" + exit 1 +fi + +echo "🔍 Detecting hostname..." +host=$(hostname) +echo "✔ Hostname detected: $host" +echo "" + +read -rp "👤 Enter your username: " username +if [ -z "$username" ]; then + echo "❌ Username cannot be empty." + exit 1 +fi + +HOST_DIR="$DOTFILES/hosts/$host" + +if [ -d "$HOST_DIR" ]; then + echo "❌ Host '$host' already exists." + exit 1 +fi + +echo "📁 Creating host directory..." +mkdir -p "$HOST_DIR" + +echo "📋 Copying template..." +cp -r "$DOTFILES/hosts/template/"* "$HOST_DIR" + +echo "✏️ Replacing placeholders..." + +sed -i "s/REPLACE_HOST/$host/g" \ + "$HOST_DIR/configuration.nix" + +sed -i "s/REPLACE_USER/$username/g" \ + "$HOST_DIR/configuration.nix" + +sed -i "s/REPLACE_USER/$username/g" \ + "$HOST_DIR/home.nix" + +echo "🖥 Generating hardware configuration..." +sudo nixos-generate-config \ + --show-hardware-config > "$HOST_DIR/hardware-configuration.nix" + +echo "" +echo "🚀 Building system..." +sudo nixos-rebuild switch --flake "$DOTFILES#$host" + +echo "" +echo "✅ Installation complete!" + diff --git a/modules/android/README.md b/modules/android/README.md new file mode 100644 index 0000000..36f1252 --- /dev/null +++ b/modules/android/README.md @@ -0,0 +1,271 @@ +# Android Development Module for NixOS + +This module provides Android development environment setup using NixOS-specific approaches that respect the immutable filesystem while maintaining full functionality. + +## Features + +- **Android Studio Full** - Includes FHS environment for compatibility +- **androidenv** - Declarative Android SDK management (reproducible) +- **Android Emulator** - Optimized for NixOS with GPU acceleration +- **Flutter SDK** - Optional Dart and Flutter support +- **Build Tools** - Gradle, Maven, Kotlin, Java +- **Additional Tools** - scrcpy for device screen sharing, APK signing utilities + +## Configuration + +Add to your `home.nix`: + +```nix +modules.android = { + enable = true; + enableEmulator = true; + apiLevel = 34; + enableFlutterSupport = true; +}; +``` + +## Configuration Options + +- **enable** - Master switch for the module +- **enableEmulator** - Include Android emulator (default: true) +- **apiLevel** - Default Android API level (default: 34) +- **enableFlutterSupport** - Install Flutter SDK (default: true) + +## Why This Approach is Better for NixOS + +### Problem with Standard Android Tools on NixOS + +NixOS uses an immutable filesystem and unique file structure that standard Android tools struggle with: +- Expected `/system`, `/data`, `/cache` paths don't exist +- SDK expects mutable `/opt` directories +- Dynamic library linking issues + +### Solution: NixOS-Specific Tools + +**android-studio-full** - The recommended approach for NixOS +- Provides FHS (Filesystem Hierarchy Standard) environment +- Works out-of-the-box with proper file hierarchy +- Pre-configured with SDK, emulator, and build tools +- Manages mutable state in `~/.android` directory +- No immutability conflicts + +## Initial Setup + +After applying the module: + +```bash +# Accept Android licenses +android-setup + +# Or manually +yes | sdkmanager --licenses + +# Create and start emulator +android-emulator + +# Verify Flutter setup +flutter doctor +``` + +## Usage + +### Launch Emulator + +```bash +# Default emulator (flutter-dev, API 34) +android-emulator + +# Custom name +android-emulator my-device + +# Custom name and API level +android-emulator my-device 33 +``` + +### Launch Android Studio + +```bash +android-studio +``` + +### Flutter Development + +```bash +# Create new project +flutter create my_app + +# Run on emulator +cd my_app +flutter run + +# Run with verbose output +flutter run -v +``` + +### Physical Device Development + +```bash +# Check connected devices +adb devices + +# Screen sharing (requires scrcpy) +scrcpy + +# View logs +adb logcat +``` + +## Available API Levels + +The module includes these Android API levels by default: +- API 28 (Android 9) +- API 31 (Android 12) +- API 33 (Android 13) +- API 34 (Android 14) +- API 35 (Android 15) + +To use a specific API level: + +```bash +android-emulator test-device 31 +android-emulator latest 35 +``` + +## Build Tools + +Included by default: +- Gradle (build system) +- Maven (alternative build system) +- Kotlin compiler +- Java JDK (11 and 21) +- CMake, Ninja, GNU Make + +## Hyprland Keybind + +The module includes a Hyprland keybind: + +``` +SUPER + ALT + A → Launch Android emulator +``` + +Edit `modules/hyprland/config.nix` to customize. + +## Troubleshooting + +### "avdmanager: command not found" + +Ensure the module is properly enabled and rebuilt: + +```bash +home-manager switch --flake .#cody@nixos +``` + +Then source environment: + +```bash +exec $SHELL +``` + +### Emulator won't start + +Check that the system image is available: + +```bash +avdmanager list all +``` + +If the API level isn't listed, it may not be in the androidenv configuration. Edit the module to add it. + +### Flutter doctor shows issues + +```bash +flutter doctor --verbose + +# Accept licenses +yes | flutter doctor --android-licenses + +# Clean cache +flutter clean +rm -rf pubspec.lock +flutter pub get +``` + +### Physical device not detected + +```bash +# Check ADB sees the device +adb devices + +# Reload udev rules if you added a new device +sudo udevadm control --reload-rules +sudo udevadm trigger + +# Ensure user is in correct group +groups # Check for adbusers +``` + +## Environment Variables + +Automatically configured: + +```bash +ANDROID_HOME # Points to androidenv SDK +ANDROID_SDK_ROOT # Points to androidenv SDK +ANDROID_USER_HOME # $HOME/.android +JAVA_HOME # JDK path +ANDROID_JAVA_HOME # JDK for Android tools +``` + +## Nix-Specific Notes + +**android-studio-full** provides: +- Complete Android SDK with tools +- Emulator with hardware acceleration +- System images for multiple API levels +- Proper FHS environment for compatibility with standard Android tools + +The module automatically configures: +- `ANDROID_HOME` environment variable +- `ANDROID_SDK_ROOT` for SDK location +- `JAVA_HOME` for Java toolchain +- All necessary PATH entries + +### Adding More API Levels + +Android Studio's SDK Manager handles API level management. After installation: + +1. Open Android Studio +2. Go to SDK Manager (Tools → SDK Manager) +3. Select additional API levels and download system images +4. Use `android-emulator my-device 31` for the new level + +## Advanced: Manual SDK Management + +If you prefer not to use Android Studio, you can manage the SDK manually using `android-tools`: + +```bash +# List available SDK components +sdkmanager --list + +# Install specific SDK component +sdkmanager "system-images;android-34;google_apis;x86_64" + +# Create AVD +avdmanager create avd --name test --package "system-images;android-34;google_apis;x86_64" +``` + +## Additional Resources + +- [NixOS Android Environment](https://search.nixos.org/packages?channel=unstable&query=androidenv) +- [Android Studio on NixOS](https://github.com/NixOS/nixpkgs/blob/master/pkgs/applications/editors/android-studio) +- [Android Developer Docs](https://developer.android.com/) +- [Flutter Documentation](https://flutter.dev/docs) + +## Module Implementation Details + +The module uses: +- `android-studio-full` for complete Android SDK with FHS environment +- `android-tools` for command-line utilities +- Standard Nix packages for build tools (Gradle, Maven, CMake) +- Environment variable configuration for automatic tool discovery +- Helper scripts for emulator management diff --git a/modules/android/default.nix b/modules/android/default.nix new file mode 100644 index 0000000..3629cbb --- /dev/null +++ b/modules/android/default.nix @@ -0,0 +1,210 @@ +{ config, pkgs, lib, ... }: + +let + cfg = config.modules.android; +in +{ + options.modules.android = { + enable = lib.mkEnableOption "Android development environment with emulator support"; + + enableEmulator = lib.mkOption { + type = lib.types.bool; + default = true; + description = "Enable Android emulator for testing Flutter and Android apps"; + }; + + apiLevel = lib.mkOption { + type = lib.types.int; + default = 34; + description = "Default Android API level for the emulator"; + }; + + enableFlutterSupport = lib.mkOption { + type = lib.types.bool; + default = true; + description = "Enable Flutter SDK and related tools"; + }; + }; + + config = lib.mkIf cfg.enable { + home.packages = with pkgs; [ + # Android Studio Full with FHS environment (recommended for NixOS) + # This includes SDK, emulator, and all necessary tools + android-studio-full + + # Core Android command-line tools + android-tools + + # Build and compilation tools + gradle + maven + ninja + cmake + gnumake + pkg-config + + # Java/Kotlin development + jdk + jdk21 + kotlin + + # Flutter SDK for app development + (if cfg.enableFlutterSupport then flutter else null) + + # Flutter Version Manager + (if cfg.enableFlutterSupport then fvm else null) + + # Additional Android tools + scrcpy # Screen sharing for Android devices + apksigner # Sign APKs + ]; + + # Environment variables for Android development + home.sessionVariables = lib.mkIf cfg.enable { + ANDROID_HOME = "$HOME/.android"; + ANDROID_SDK_ROOT = "$HOME/Android/Sdk"; + ANDROID_USER_HOME = "$HOME/.android"; + JAVA_HOME = "${pkgs.jdk}/lib/openjdk"; + # For Flutter development + ANDROID_JAVA_HOME = "${pkgs.jdk}"; + }; + + # Create a script to launch the Android emulator + # Note: This works with the NixOS androidenv setup + home.file.".local/share/bin/android-emulator" = lib.mkIf cfg.enableEmulator { + executable = true; + text = '' + #!/usr/bin/env bash + # Android Emulator launcher script for NixOS + # Uses android-studio-full's built-in tools + + set -e + + EMULATOR_NAME="''${1:-flutter-dev}" + API_LEVEL="''${2:-${toString cfg.apiLevel}}" + + echo "Starting Android Emulator: $EMULATOR_NAME (API $API_LEVEL)" + + # Check if AVD exists, if not create it + if ! grep -q "^[^#]*name=$EMULATOR_NAME" ~/.android/avd/devices.txt 2>/dev/null; then + echo "Creating AVD: $EMULATOR_NAME..." + + # Try using avdmanager from Android Studio + if command -v avdmanager &> /dev/null; then + echo "no" | avdmanager create avd \ + --name "$EMULATOR_NAME" \ + --package "system-images;android-$API_LEVEL;google_apis;x86_64" \ + --device "pixel_6" \ + --force 2>&1 || { + echo "Error: Could not create AVD" + echo "Try running: android-studio to set up SDK from the IDE" + exit 1 + } + else + echo "Error: avdmanager not found" + echo "Please open Android Studio and complete the SDK setup:" + echo " android-studio" + echo "" + echo "Then use SDK Manager to download system images for API $API_LEVEL" + exit 1 + fi + fi + + # Launch emulator with optimizations for NixOS + emulator -avd "$EMULATOR_NAME" \ + -memory 2048 \ + -partition-size 4096 \ + -dns-server 8.8.8.8 \ + -no-snapshot-load \ + -no-snapshot-save \ + -gpu auto \ + -no-boot-anim \ + & + + EMULATOR_PID=$! + echo "Emulator starting in background (PID: $EMULATOR_PID)" + echo "Waiting for boot..." + + # Wait for emulator to boot + for i in {1..90}; do + if adb shell getprop sys.boot_completed 2>/dev/null | grep -q "1"; then + echo "✓ Emulator fully booted!" + exit 0 + fi + echo -n "." + sleep 2 + done + + echo "" + echo "⚠ Timeout waiting for emulator to boot" + exit 1 + ''; + }; + + # Create a setup script to initialize Android environment on first use + home.file.".local/share/bin/android-setup" = lib.mkIf cfg.enable { + executable = true; + text = '' + #!/usr/bin/env bash + # One-time setup script for Android development on NixOS + + echo "Setting up Android development environment..." + echo "" + + # Check if sdkmanager is available + if ! command -v sdkmanager &> /dev/null; then + echo "Warning: sdkmanager not found in PATH" + echo "This is normal on NixOS. You'll need to use Android Studio to manage SDKs." + echo "" + echo "Opening Android Studio for SDK setup..." + android-studio & + echo "" + echo "In Android Studio:" + echo " 1. Go to Tools → SDK Manager" + echo " 2. Select API levels you want to download" + echo " 3. Click 'Apply' and 'OK'" + echo " 4. Close Android Studio when done" + exit 0 + fi + + # Accept Android licenses + echo "Accepting Android licenses..." + yes | sdkmanager --licenses 2>&1 | tail -10 + + echo "" + echo "✓ Android environment setup complete!" + echo "" + echo "Next steps:" + echo " 1. Run: android-emulator (to create and start emulator)" + echo " 2. For Flutter: flutter doctor" + echo " 3. For Android Studio: android-studio" + echo "" + ''; + }; + + # Optional: Add udev rules for Android devices + # This allows debugging on physical devices without root + home.file.".config/udev/rules.d/51-android.rules" = lib.mkIf cfg.enable { + text = '' + # Android debug bridge - allows USB debugging without sudo + SUBSYSTEM=="usb", ATTR{idVendor}=="0bb4", MODE="0666", GROUP="adbusers" + SUBSYSTEM=="usb", ATTR{idVendor}=="0e79", MODE="0666", GROUP="adbusers" + SUBSYSTEM=="usb", ATTR{idVendor}=="0502", MODE="0666", GROUP="adbusers" + SUBSYSTEM=="usb", ATTR{idVendor}=="0b05", MODE="0666", GROUP="adbusers" + SUBSYSTEM=="usb", ATTR{idVendor}=="413c", MODE="0666", GROUP="adbusers" + SUBSYSTEM=="usb", ATTR{idVendor}=="0489", MODE="0666", GROUP="adbusers" + SUBSYSTEM=="usb", ATTR{idVendor}=="091e", MODE="0666", GROUP="adbusers" + SUBSYSTEM=="usb", ATTR{idVendor}=="18d1", MODE="0666", GROUP="adbusers" + SUBSYSTEM=="usb", ATTR{idVendor}=="0d4d", MODE="0666", GROUP="adbusers" + SUBSYSTEM=="usb", ATTR{idVendor}=="05c6", MODE="0666", GROUP="adbusers" + SUBSYSTEM=="usb", ATTR{idVendor}=="04e8", MODE="0666", GROUP="adbusers" + SUBSYSTEM=="usb", ATTR{idVendor}=="04da", MODE="0666", GROUP="adbusers" + SUBSYSTEM=="usb", ATTR{idVendor}=="04b7", MODE="0666", GROUP="adbusers" + SUBSYSTEM=="usb", ATTR{idVendor}=="04b8", MODE="0666", GROUP="adbusers" + SUBSYSTEM=="usb", ATTR{idVendor}=="04b9", MODE="0666", GROUP="adbusers" + SUBSYSTEM=="usb", ATTR{idVendor}=="0bed", MODE="0666", GROUP="adbusers" + SUBSYSTEM=="usb", ATTR{idVendor}=="1d4d", MODE="0666", GROUP="adbusers" + ''; + }; + }; +} diff --git a/modules/code/code.nix b/modules/code/code.nix new file mode 100644 index 0000000..55ac6e4 --- /dev/null +++ b/modules/code/code.nix @@ -0,0 +1,52 @@ +{ config, pkgs, lib, ... }: + +{ + programs.vscode = { + enable = true; + + # Use the unwrapped package to avoid extension issues + package = pkgs.vscode; + + profiles.default = { + extensions = with pkgs.vscode-extensions; [ + github.copilot + vscodevim.vim + esbenp.prettier-vscode + ms-azuretools.vscode-docker + ]; + + userSettings = { + ## Editor + "editor.fontFamily" = "Fira Code"; + "editor.fontLigatures" = true; + "editor.formatOnSave" = true; + "editor.minimap.enabled" = false; + "editor.tabSize" = 4; + + ## Files + "files.autoSave" = "afterDelay"; + + ## Vim + "vim.useSystemClipboard" = true; + ## Line numbers + "editor.lineNumbers" = "relative"; + + ## Vim polish + "vim.smartRelativeLine" = true; # absolute number on current line + "vim.hlsearch" = true; # highlight search matches + + ## UI + "workbench.sideBar.location" = "right"; + "workbench.colorTheme" = "Pywal"; + + ## Copilot + "github.copilot.enable" = { + "*" = true; + "plaintext" = false; + "markdown" = true; + }; + "github.copilot.nextEditSuggestions.enabled" = true; + }; + }; + }; +} diff --git a/modules/code/default.nix b/modules/code/default.nix new file mode 100644 index 0000000..efbb157 --- /dev/null +++ b/modules/code/default.nix @@ -0,0 +1,4 @@ +{ inputs, ... }: +{ + imports = [ (import ./code.nix) ]; +} diff --git a/modules/default.nix b/modules/default.nix new file mode 100644 index 0000000..5312e16 --- /dev/null +++ b/modules/default.nix @@ -0,0 +1,20 @@ +{ + imports = [ + ./kitty + ./hyprland + ./firefox + ./rofi + ./tmux + ./misc + ./swaync + # ./opencode + ./waybar + ./wlogout + ./yazi + ./nvim + ./posting + ./code + ./fastfetch + ./android + ]; +} diff --git a/modules/dolphin/default.nix b/modules/dolphin/default.nix new file mode 100644 index 0000000..6a28839 --- /dev/null +++ b/modules/dolphin/default.nix @@ -0,0 +1,5 @@ +{ + imports = [ + ./dolphin.nix + ]; +} diff --git a/modules/dolphin/dolphin.nix b/modules/dolphin/dolphin.nix new file mode 100644 index 0000000..d6f471c --- /dev/null +++ b/modules/dolphin/dolphin.nix @@ -0,0 +1,10 @@ +{ config, pkgs, ... }: + +{ + home.packages = with pkgs; [ + dolphin + ffmpegthumbs # Enables video thumbnails in Dolphin + ] ++ (pkgs.lib.optionals (pkgs ? kio-extras) [ pkgs.kio-extras ]); + +} + diff --git a/modules/fastfetch/default.nix b/modules/fastfetch/default.nix new file mode 100644 index 0000000..241fd61 --- /dev/null +++ b/modules/fastfetch/default.nix @@ -0,0 +1,5 @@ +{ + imports = [ + ./fastfetch.nix + ]; +} diff --git a/modules/fastfetch/fastfetch.nix b/modules/fastfetch/fastfetch.nix new file mode 100644 index 0000000..17cdf9b --- /dev/null +++ b/modules/fastfetch/fastfetch.nix @@ -0,0 +1,131 @@ +{ + programs.fastfetch = { + enable = true; + + settings = { + display = { + color = { + keys = "35"; + output = "95"; + }; + separator = " ➜ "; + }; + + logo = { + source = ./me.png; + type = "kitty-direct"; + height = 12; + width = 30; + padding = { + top = 2; + left = 2; + }; + }; + + modules = [ + "break" + { + type = "os"; + key = "OS - GibbyDev's OS"; + keyColor = "31"; + } + { + type = "kernel"; + key = " ├  "; + keyColor = "31"; + } + { + type = "packages"; + key = " ├ 󰏖 "; + keyColor = "31"; + } + { + type = "shell"; + key = " └  "; + keyColor = "31"; + } + "break" + { + type = "wm"; + key = "WM "; + keyColor = "32"; + } + { + type = "wmtheme"; + key = " ├ 󰉼 "; + keyColor = "32"; + } + { + type = "icons"; + key = " ├ 󰀻 "; + keyColor = "32"; + } + { + type = "cursor"; + key = " ├  "; + keyColor = "32"; + } + { + type = "terminal"; + key = " ├  "; + keyColor = "32"; + } + { + type = "terminalfont"; + key = " └  "; + keyColor = "32"; + } + "break" + { + type = "host"; + format = "{5} {1} Type {2}"; + key = "PC "; + keyColor = "33"; + } + { + type = "cpu"; + format = "{1} ({3}) @ {7} GHz"; + key = " ├  "; + keyColor = "33"; + } + { + type = "gpu"; + format = "{1} {2} @ {12} GHz"; + key = " ├ 󰢮 "; + keyColor = "33"; + } + { + type = "memory"; + key = " ├  "; + keyColor = "33"; + } + { + type = "disk"; + key = " ├ 󰋊 "; + keyColor = "33"; + } + { + type = "monitor"; + key = " ├  "; + keyColor = "33"; + } + { + type = "player"; + key = " ├ 󰥠 "; + keyColor = "33"; + } + { + type = "media"; + key = " └ 󰝚 "; + keyColor = "33"; + } + "break" + { + type = "uptime"; + key = " Uptime "; + } + ]; + }; + }; +} + diff --git a/modules/fastfetch/me.png b/modules/fastfetch/me.png new file mode 100644 index 0000000..de20513 Binary files /dev/null and b/modules/fastfetch/me.png differ diff --git a/modules/fastfetch/nixos.png b/modules/fastfetch/nixos.png new file mode 100644 index 0000000..571410a Binary files /dev/null and b/modules/fastfetch/nixos.png differ diff --git a/modules/firefox/default.nix b/modules/firefox/default.nix new file mode 100644 index 0000000..0b8d308 --- /dev/null +++ b/modules/firefox/default.nix @@ -0,0 +1,4 @@ +{ inputs, ... }: +{ + imports = [ (import ./firefox.nix) ]; +} diff --git a/modules/firefox/firefox.nix b/modules/firefox/firefox.nix new file mode 100644 index 0000000..17abd6e --- /dev/null +++ b/modules/firefox/firefox.nix @@ -0,0 +1,991 @@ +{ config, pkgs, lib, ... }: + +let + firefoxAddons = pkgs.nur.repos.rycee.firefox-addons; +in +{ + programs.firefox = { + enable = true; + + profiles.default = { + bookmarks = { + force = true; + settings = [ + { + name = "Toolbar"; + toolbar = true; + bookmarks = [ + { + name = "Dev"; + bookmarks = [ + { name = "GitHub"; url = "https://github.com/gibbyDev"; } + { name = "ChatGPT"; url = "https://chatgpt.com"; } + { name = "Hostinger"; url = "https://hostinger.com"; } + { name = "UpWork"; url = "https://www.upwork.com/nx/find-work/best-matches"; } + { name = "Servers"; bookmarks = [ { name = "8080"; url = "http://localhost:8080"; } { name = "3000"; url = "http://localhost:3000"; } { name = "5000"; url = "http://localhost:5000"; } ]; } + ]; + } + { + name = "Personal"; + bookmarks = [ + { name = "Dropbox"; url = "https://www.dropbox.com/home"; } + { name = "Betterhelp"; url = "https://www.betterhelp.com/"; } + ]; + } + + { + name = "Mail"; + bookmarks = [ + { name = "ProtonMail"; url = "https://protonmail.com"; } + { name = "Gmail"; url = "https://gmail.com"; } + ]; + } + + { + name = "Social"; + bookmarks = [ + { name = "LinkedIn"; url = "https://linkedin.com"; } + { name = "YouTube"; url = "https://youtube.com"; } + { name = "YouTube Studio"; url = "https://studio.youtube.com/channel/UCrWyV9qsJOPCF2af1gYzDeQ"; } + ]; + } + + + # You can still mix in loose bookmarks if you want + { name = "Search"; url = "https://duckduckgo.com"; } + ]; + } + ]; + }; + + # ------------------------------ + # ⚙️ Firefox preferences + # ------------------------------ + settings = { + "places.favicons.enabled" = true; + "privacy.donottrackheader.enabled" = true; + "network.trr.mode" = 2; + "toolkit.legacyUserProfileCustomizations.stylesheets" = true; + }; + + # ------------------------------ + # 🧩 Extensions + # ------------------------------ + extensions.packages = with firefoxAddons; [ + pywalfox + vimium + ublock-origin + sponsorblock + darkreader + tridactyl + youtube-shorts-block + ]; + userChrome = '' + /* =================================================================== + LATIN ACCENT - FIREFOX TRANSPARENT THEME + Made with cariño by Acercandr0 + =================================================================== */ + + :root { + /* 🎯 Core Transparency */ + --tabpanel-background-color: transparent !important; + --chrome-content-separator-color: transparent !important; + --toolbar-bgcolor: transparent !important; + + /* 🌈 Adaptive Color System */ + --accent-color: color-mix(in srgb, AccentColor 100%, transparent) !important; + --accent-color-subtle: color-mix(in srgb, AccentColor 30%, transparent) !important; + + /* 💻 Opacity System */ + --inactive-opacity: 0.3 !important; + --hover-opacity: 1 !important; + --semi-opacity: 0.7 !important; + + /* ⚡ Animation System */ + --transition-smooth: all 0.3s cubic-bezier(0.4, 0, 0.2, 1) !important; + --transition-bounce: all 0.45s cubic-bezier(0.65, -0.50, 0.260, 1.50) !important; + --transition-quick: all 0.15s ease-out !important; + + /* 📐 Layout Constants */ + --border-radius: 5px; + --border-radius-large: 7px; + + /* 🔍 Outline & Border System */ + --border-outline-width: 1px; + + /* 🎨 Adaptive Interface Colors - Light/Dark aware */ + --base-bg: light-dark(rgb(245, 245, 245), rgb(20, 20, 20)); + --panel-bg: color-mix(in srgb, var(--accent-color) 1%, var(--base-bg) 99%) !important; + --panel-border: var(--accent-color) !important; + --panel-text: light-dark(rgb(40, 40, 40), white) !important; + --hover-bg: light-dark(rgba(0, 0, 0, 0.08), rgba(255, 255, 255, 0.08)) !important; + + /* 🔍 Focus System */ + --focus-outline-color: var(--accent-color) !important; + --focus-outline-width: var(--border-outline-width) !important; + --toolbarbutton-icon-fill-attention: var(--accent-color) !important; + + /* 📋 Dropdown Styling */ + --arrowpanel-background: var(--panel-bg) !important; + --arrowpanel-border-color: var(--panel-border) !important; + --arrowpanel-color: var(--panel-text) !important; + --urlbar-open-background: var(--panel-bg) !important; + --urlbar-open-color: var(--panel-text) !important; + + /* 🚫 Button Background Override */ + --toolbarbutton-hover-background: transparent !important; + --toolbarbutton-active-background: transparent !important; + } + + /* =========================== + 🧹 GLOBAL RESETS + =========================== */ + *, + #content, + #content > *, + #main-window, + #browser, + #appcontent, + #browserContainer, + #tabbrowser-tabpanels, + #tabbrowser-tabbox, + #tabbrowser-arrowscrollbox, + .tabbrowser-tabs, + .webRenderCompositor, + .browserContainer, + .browserStack, + #webrtcIndicator, + #navigator-toolbox, + #TabsToolbar, + #PersonalToolbar { + box-shadow: none !important; + filter: none !important; + } + + /* =========================== + 📑 TAB SYSTEM + =========================== */ + + #navigator-toolbox, + #TabsToolbar, + #nav-bar { + border: none !important; + } + + /* Tab Layout */ + .titlebar-spacer[type="pre-tabs"] { + width: 1px !important; + } + + /* Mimized window tab spacing */ + #main-window[sizemode="maximized"] #TabsToolbar { + padding-left: 2px !important; + } + + #main-window[sizemode="maximized"] .tabbrowser-tabs { + margin-left: 0 !important; + } + + /* Post-tabs spacer - Windows */ + @supports not (-moz-bool-pref: "widget.macos.titlebar-blend") { + .titlebar-spacer[type="post-tabs"] { + width: 40px !important; + } + } + + /* Pre-tabs spacer - macOS */ + @supports (-moz-bool-pref: "widget.macos.titlebar-blend") { + .titlebar-spacer[type="pre-tabs"] { + width: 80px !important; + } + + .titlebar-spacer[type="post-tabs"] { + width: 1px !important; + } + } + + /* Base Tab Styling */ + .tabbrowser-tab { + transition: var(--transition-smooth) !important; + position: relative; + } + + /* Active Tab */ + .tabbrowser-tab[selected="true"] .tab-background { + border: var(--border-outline-width) solid var(--accent-color) !important; + background: transparent !important; + border-radius: var(--border-radius) !important; + animation: tabActivate 0.3s ease-out; + } + + /* Inactive Tabs */ + .tabbrowser-tab:not([selected]) .tab-icon-image, + .tabbrowser-tab:not([selected]) .tab-label, + #tabs-newtab-button { + opacity: var(--inactive-opacity) !important; + transition: var(--transition-smooth) !important; + } + + /* Tab Hover Effects */ + .tabbrowser-tab:hover .tab-text, + .tabbrowser-tab:hover .tab-icon-image, + #tabs-newtab-button:hover { + opacity: var(--hover-opacity) !important; + } + + /* Tab Close Button */ + .tabbrowser-tab .tab-close-button { + opacity: 0 !important; + visibility: hidden !important; + transform: scale(0.8) rotate(30deg) !important; + transition: var(--transition-bounce) !important; + } + + .tabbrowser-tab:hover .tab-close-button { + opacity: var(--semi-opacity) !important; + visibility: visible !important; + transform: scale(1) rotate(0deg) !important; + } + + .tabbrowser-tab .tab-close-button:hover { + opacity: var(--hover-opacity) !important; + transform: scale(1.1) !important; + } + + /* =========================== + 🏷️ TAB GROUPS STYLING + =========================== */ + + /* Hide original underline */ + .tab-group-line { + display: none !important; + } + + /* Hide label underline */ + .tab-group-label-container { + #tabbrowser-tabs:is([orient="horizontal"], [orient="vertical"]:not([expanded])) tab-group:not([collapsed]) > &::after { + display: none !important; + } + } + + /* Group outline */ + tab-group:not([collapsed]) .tabbrowser-tab .tab-background { + outline: var(--border-outline-width) solid var(--tab-group-color) !important; + outline-offset: -1px !important; + } + + /* Inactive tabs inside group */ + tab-group:not([collapsed]) .tabbrowser-tab:not([selected]) .tab-background { + outline: var(--border-outline-width) solid color-mix(in srgb, var(--tab-group-color) 30%, transparent) !important; + outline-offset: -1px !important; + } + + /* Active group tab */ + tab-group:not([collapsed]) .tabbrowser-tab[selected="true"] .tab-background { + border: none !important; + outline: var(--border-outline-width) solid var(--tab-group-color) !important; + outline-offset: -1px !important; + } + + /* 🏷️ Label text - inactive/closed state */ + .tab-group-label { + text-transform: uppercase !important; + font-weight: 500 !important; + letter-spacing: 0.5px !important; + color: light-dark(#666666, #cccccc) !important; + background-color: transparent !important; + transition: var(--transition-smooth) !important; + outline: var(--border-outline-width) solid var(--tab-group-color) !important; + outline-offset: -1px !important; + padding: 8px !important; + border-radius: var(--border-radius) !important; + } + + /* 🌟 Label hover effect */ + .tab-group-label-container:hover .tab-group-label { + color: light-dark(#333333, white) !important; + background-color: color-mix(in srgb, var(--tab-group-color) 35%, light-dark(white, black)) !important; + outline: var(--border-outline-width) solid var(--tab-group-color) !important; + outline-offset: -1px !important; + } + + + /* =========================== + 📊 AUDIO TAB INDICATORS + =========================== */ + + /* 🔊 Sound playing (not muted) */ + .tab-audio-button[soundplaying]:not([muted]) { + background-image: url("chrome://global/skin/media/audio.svg") !important; + background-repeat: no-repeat !important; + background-position: center !important; + background-size: contain !important; + -moz-context-properties: fill, stroke !important; + fill: currentColor !important; + opacity: 0.6 !important; + background-color: transparent !important; + border: none !important; + padding: 0 !important; + padding-right: 4px !important; + margin-inline-start: 4px !important; + width: 10px !important; + height: 10px !important; + display: block !important; + transform-origin: center; + } + + /* 🔇 Muted tab */ + .tab-audio-button[muted] { + background-image: url("chrome://global/skin/media/audio-muted.svg") !important; + background-repeat: no-repeat !important; + background-position: center !important; + background-size: contain !important; + -moz-context-properties: fill, stroke !important; + fill: var(--accent-color) !important; + opacity: 0.8 !important; + background-color: transparent !important; + border: none !important; + padding: 0 !important; + padding-right: 4px !important; + margin-inline-start: 4px !important; + width: 10px !important; + height: 10px !important; + display: block !important; + } + + /* =========================== + 🔍 URL BAR SYSTEM + =========================== */ + + /* Closed State - Force transparent background */ + #urlbar:not([open]) #urlbar-background, + #urlbar:not([open]) .urlbar-background, + #searchbar:not([open]), + #urlbar[breakout][breakout-extend]:not([open]) > #urlbar-background { + background: transparent !important; + background-color: transparent !important; + background-clip: border-box !important; + } + + /* Open State - Updated selectors for new Firefox versions */ + #urlbar[open] > #urlbar-background, + #urlbar[breakout][breakout-extend][open] > #urlbar-background, + #urlbar[open] .urlbar-background { + background: var(--urlbar-open-background) !important; + background-color: var(--panel-bg) !important; + background-clip: border-box !important; + color: var(--urlbar-open-color) !important; + border: var(--border-outline-width) solid var(--accent-color) !important; + border-radius: var(--border-radius-large) !important; + margin: 1px !important; + animation: urlbarExpand 0.3s cubic-bezier(0.68, -0.55, 0.265, 1.55); + box-shadow: none !important; + } + + /* Fix for urlbar input container when closed */ + #urlbar:not([open]) #urlbar-input-container { + background: transparent !important; + background-color: transparent !important; + } + + /* Search Results - always transparent background, panel shows behind */ + #urlbar-results, + #urlbar-results .urlbarView, + #urlbar-results .urlbarView-body, + #urlbar-results .urlbarView-row { + background: transparent !important; + } + + /* Search Results Container */ + #urlbar[open] #urlbar-results, + #urlbar[open] #urlbar-results .urlbarView, + #urlbar[breakout][breakout-extend][open] #urlbar-results { + background: transparent !important; + } + + #urlbar[open] #urlbar-results .urlbarView-body { + background: transparent !important; + } + + /* Search Result Items */ + #urlbar-results .urlbarView-row { + transition: var(--transition-quick) !important; + border-radius: var(--border-radius) !important; + margin-right: 8px !important; + } + + #urlbar-results .urlbarView-row:hover { + background: var(--hover-bg) !important; + transform: translateX(4px); + margin-right: 8px !important; + } + + #urlbar-searchmode-switcher { + background-color: transparent !important; + } + + /* URL Input Styling */ + .urlbar-input-box { + display: flex !important; + justify-content: center !important; + } + + .urlbar-input { + text-align: center !important; + transition: var(--transition-smooth) !important; + } + + #urlbar[focused] .urlbar-input { + transform: scale(1.02); + } + + /* =========================== + 📚 BOOKMARKS BAR + =========================== */ + + /* Personal Toolbar (Bookmarks Bar) */ + #PersonalToolbar { + background: transparent !important; + border: none !important; + padding: 2px 5px !important; + } + + /* Bookmark Items Container */ + #PlacesToolbarItems { + display: flex !important; + align-items: center !important; + gap: 2px !important; + } + + /* Individual Bookmark Items */ + .bookmark-item { + background: transparent !important; + border: none !important; + border-radius: var(--border-radius) !important; + opacity: var(--inactive-opacity) !important; + transition: var(--transition-smooth) !important; + padding: 4px 8px !important; + margin: 0 1px !important; + min-height: 24px !important; + max-height: 24px !important; + display: flex !important; + align-items: center !important; + justify-content: center !important; + white-space: nowrap !important; + overflow: hidden !important; + text-overflow: ellipsis !important; + transform-origin: center !important; + flex-shrink: 0 !important; + } + + /* Bookmark Icons */ + .bookmark-item .toolbarbutton-icon { + width: 16px !important; + height: 16px !important; + margin-right: 4px !important; + flex-shrink: 0 !important; + } + + /* Bookmark Text */ + .bookmark-item .toolbarbutton-text { + font-size: 12px !important; + max-width: 120px !important; + overflow: hidden !important; + text-overflow: ellipsis !important; + white-space: nowrap !important; + } + + /* Bookmark Hover - Only opacity and subtle effects */ + .bookmark-item:hover { + opacity: var(--hover-opacity) !important; + background: var(--hover-bg) !important; + transform: none !important; + } + + /* Bookmark Icon Color on Hover */ + .bookmark-item:hover .toolbarbutton-icon { + fill: var(--accent-color) !important; + } + + /* Bookmarks Chevron Button */ + #PlacesChevron { + background: transparent !important; + border: none !important; + opacity: var(--inactive-opacity) !important; + transition: var(--transition-smooth) !important; + min-width: 20px !important; + max-width: 20px !important; + margin-left: 5px !important; + } + + #PlacesChevron:hover { + opacity: var(--hover-opacity) !important; + background: var(--hover-bg) !important; + transform: none !important; + } + + /* =========================== + 🎛️ REFINED BUTTON SYSTEM + =========================== */ + + /* 🔧 COMPREHENSIVE BUTTON SELECTOR - keeping normal behavior for urlbar buttons */ + toolbarbutton:not(.bookmark-item):not([id*="identity"]):not([id*="tracking"]):not([id*="star"]):not([id*="picture"]):not([id*="reader"]), + .toolbarbutton-1:not(.bookmark-item):not([id*="identity"]):not([id*="tracking"]):not([id*="star"]):not([id*="picture"]):not([id*="reader"]), + #back-button, + #forward-button, + #reload-button, + #stop-button, + #home-button, + #library-button, + #fxa-toolbar-menu-button, + #unified-extensions-button, + #downloads-button, + #bookmarks-menu-button, + #history-panelmenu, + #appMenu-button, + #PanelUI-menu-button, + #sidebar-switcher-target toolbarbutton, + #sidebar-box .sidebar-placesTree toolbarbutton, + .sidebar-placesTreechildren toolbarbutton, + #sidebar-header .sidebar-close-button, + #sidebar-header toolbarbutton, + .sidebar-panel toolbarbutton, + #sidebar toolbarbutton, + #context-navigation toolbarbutton, + #context-sep-navigation + toolbarbutton, + .unified-extensions-item-action-button, + .panel-subview-footer-button, + toolbarpaletteitem > toolbarbutton, + .chromeclass-toolbar-additional toolbarbutton, + #addon-bar toolbarbutton, + .tabs-newtab-button, + #new-tab-button, + .tab-close-button, + .close-button, + .button-background { + background: transparent !important; + opacity: var(--inactive-opacity) !important; + transition: var(--transition-smooth) !important; + border-radius: var(--border-radius) !important; + position: relative; + overflow: hidden; + border: none !important; + box-shadow: none !important; + } + + /* Keep urlbar buttons with their normal transparent behavior */ + #urlbar-container toolbarbutton, + #urlbar toolbarbutton, + #identity-permission-box, + #identity-icon-box, + #tracking-protection-icon-container, + #star-button-box, + #picture-in-picture-button, + #reader-mode-button, + #pageAction-urlbar-_testpilot-containers, + #pageAction-panel-bookmark, + #pageAction-panel-copyURL, + #pageAction-panel-emailLink, + #pageAction-panel-pinTab, + #pageAction-panel-sendToDevice, + #page-action-buttons > toolbarbutton, + .urlbar-page-action { + background: transparent !important; + opacity: var(--inactive-opacity) !important; + transition: var(--transition-smooth) !important; + border-radius: var(--border-radius) !important; + border: none !important; + box-shadow: none !important; + } + + /* 🚫 FORCE NO BACKGROUNDS */ + #navigator-toolbox toolbarbutton:not(.bookmark-item), + #navigator-toolbox .toolbarbutton-1:not(.bookmark-item), + #nav-bar > * > toolbarbutton:not(.bookmark-item), + #nav-bar > toolbarbutton:not(.bookmark-item), + #nav-bar toolbarbutton:not(.bookmark-item), + #nav-bar .toolbarbutton-1:not(.bookmark-item), + #back-button, + #forward-button, + #reload-button, + #stop-button, + #home-button, + #library-button, + #fxa-toolbar-menu-button, + #unified-extensions-button, + #downloads-button, + #bookmarks-menu-button, + #history-panelmenu, + #appMenu-button, + #PanelUI-menu-button, + #sidebar-switcher-target toolbarbutton, + .toolbarbutton-1:not(.bookmark-item), + .button-background { + background-color: transparent !important; + background-image: none !important; + background: transparent !important; + } + + #navigator-toolbox toolbarbutton:not(.bookmark-item):hover, + #navigator-toolbox .toolbarbutton-1:not(.bookmark-item):hover, + #nav-bar > * > toolbarbutton:not(.bookmark-item):hover, + #nav-bar > toolbarbutton:not(.bookmark-item):hover, + #nav-bar toolbarbutton:not(.bookmark-item):hover, + #nav-bar .toolbarbutton-1:not(.bookmark-item):hover, + #back-button:hover, + #forward-button:hover, + #reload-button:hover, + #stop-button:hover, + #home-button:hover, + #library-button:hover, + #fxa-toolbar-menu-button:hover, + #unified-extensions-button:hover, + #downloads-button:hover, + #bookmarks-menu-button:hover, + #history-panelmenu:hover, + #appMenu-button:hover, + #PanelUI-menu-button:hover, + #sidebar-switcher-target toolbarbutton:hover, + .toolbarbutton-1:not(.bookmark-item):hover, + .toolbarbutton-1:not(.bookmark-item):hover:active, + .button-background:hover { + background-color: transparent !important; + background-image: none !important; + background: transparent !important; + } + + /* 🎯 REFINED HOVER EFFECTS - subtle scale only */ + toolbarbutton:not(.bookmark-item):not([id*="identity"]):not([id*="tracking"]):not([id*="star"]):not([id*="picture"]):not([id*="reader"]):hover, + .toolbarbutton-1:not(.bookmark-item):not([id*="identity"]):not([id*="tracking"]):not([id*="star"]):not([id*="picture"]):not([id*="reader"]):hover, + #nav-bar toolbarbutton:not(.bookmark-item):hover, + #nav-bar-customization-target > toolbarbutton:not(.bookmark-item):hover, + #back-button:hover, + #forward-button:hover, + #reload-button:hover, + #stop-button:hover, + #home-button:hover, + #library-button:hover, + #fxa-toolbar-menu-button:hover, + #unified-extensions-button:hover, + #downloads-button:hover, + #bookmarks-menu-button:hover, + #history-panelmenu:hover, + #appMenu-button:hover, + #PanelUI-menu-button:hover, + #sidebar-switcher-target toolbarbutton:hover, + #sidebar-box .sidebar-placesTree toolbarbutton:hover, + .sidebar-placesTreechildren toolbarbutton:hover, + #sidebar-header .sidebar-close-button:hover, + #sidebar-header toolbarbutton:hover, + .sidebar-panel toolbarbutton:hover, + #sidebar toolbarbutton:hover, + #context-navigation toolbarbutton:hover, + #context-sep-navigation + toolbarbutton:hover, + .unified-extensions-item-action-button:hover, + .panel-subview-footer-button:hover, + toolbarpaletteitem > toolbarbutton:hover, + .chromeclass-toolbar-additional toolbarbutton:hover, + #addon-bar toolbarbutton:hover, + .tabs-newtab-button:hover, + #new-tab-button:hover, + .tab-close-button:hover, + .close-button:hover, + .button-background:hover { + opacity: var(--hover-opacity) !important; + transform: scale(1.05) !important; + } + + /* Keep urlbar buttons transparent on hover */ + #urlbar-container toolbarbutton:hover, + #urlbar toolbarbutton:hover, + #identity-permission-box:hover, + #identity-icon-box:hover, + #tracking-protection-icon-container:hover, + #star-button-box:hover, + #picture-in-picture-button:hover, + #reader-mode-button:hover, + .urlbar-page-action:hover { + opacity: var(--hover-opacity) !important; + background: transparent !important; + transform: scale(1.05) !important; + } + + /* 🎨 ICON COLOR CHANGE ON HOVER */ + toolbarbutton:not(.bookmark-item):hover image, + .toolbarbutton-1:not(.bookmark-item):hover image, + #nav-bar toolbarbutton:not(.bookmark-item):hover image, + #urlbar toolbarbutton:hover image, + #urlbar #identity-icon-box:hover image, + #urlbar #identity-permission-box:hover image, + #urlbar #tracking-protection-icon-container:hover image, + #urlbar #star-button-box:hover image, + #urlbar #picture-in-picture-button:hover image, + #urlbar #reader-mode-button:hover image, + .urlbar-page-action:hover image, + #sidebar toolbarbutton:hover image, + toolbarpaletteitem > toolbarbutton:hover image, + .panel-subview-footer-button:hover image { + fill: var(--accent-color) !important; + filter: none !important; + } + + .button-background:hover { + & img { + fill: var(--accent-color) !important; + } + } + + /* 🌟 SPECIAL STATES */ + toolbarbutton[checked="true"]:not(.bookmark-item), + toolbarbutton[open="true"]:not(.bookmark-item), + .toolbarbutton-1[checked="true"]:not(.bookmark-item), + .toolbarbutton-1[open="true"]:not(.bookmark-item), + #downloads-button[attention="true"], + #library-button[attention="true"] { + opacity: var(--hover-opacity) !important; + background: var(--accent-color-subtle) !important; + } + + /* =========================== + 🎭 ELEMENT VISIBILITY + =========================== */ + + #identity-icon-box label { + display: none !important; + } + + #sidebar-tools-and-extensions-splitter { + display: none !important; + } + + #forward-button[disabled="true"] { + display: none !important; + } + + toolbarbutton[label="Bookmarks toolbar items"] { + display: none !important; + } + + /* =========================== + 🎮 WINDOW CONTROLS + =========================== */ + + /* Normal Window */ + #main-window:not([tabsintitlebar]) .titlebar-buttonbox toolbarbutton, + #main-window[tabsintitlebar]:not([sizemode="maximized"]) .titlebar-buttonbox toolbarbutton { + opacity: var(--semi-opacity) !important; + transform: scale(0.9) !important; + transition: var(--transition-smooth) !important; + fill: currentColor !important; + color: inherit !important; + } + + /* Hover - Normal Window - subtle scaling */ + #main-window:not([tabsintitlebar]) .titlebar-buttonbox toolbarbutton:hover, + #main-window[tabsintitlebar]:not([sizemode="maximized"]) .titlebar-buttonbox toolbarbutton:hover { + opacity: var(--hover-opacity) !important; + transform: scale(1.05) !important; + color: var(--accent-color) !important; + } + + /* Maximized Window */ + #main-window[tabsintitlebar][sizemode="maximized"] .titlebar-buttonbox toolbarbutton, + .titlebar-buttonbox toolbarbutton { + opacity: var(--hover-opacity) !important; + transform: scale(0.9) !important; + transition: var(--transition-smooth) !important; + fill: currentColor !important; + color: inherit !important; + } + + /* Hover - Maximized Window - subtle scaling */ + .titlebar-buttonbox toolbarbutton:hover { + transform: scale(1.05) !important; + color: var(--accent-color) !important; + } + + /* =========================== + ✨ ANIMATIONS & KEYFRAMES + =========================== */ + + /* URL Bar Expand Animation */ + @keyframes urlbarExpand { + 0% { + opacity: 0; + transform: scale(0.95) translateY(-5px); + } + 70% { + transform: scale(1.02) translateY(0); + } + 100% { + opacity: 1; + transform: scale(1) translateY(0); + } + } + + /* Tab Activation Animation */ + @keyframes tabActivate { + 0% { + transform: scale(0.98); + opacity: 0.8; + } + 50% { + transform: scale(1.02); + } + 100% { + transform: scale(1); + opacity: 1; + } + } + + /* Dropdown Slide Animation */ + #urlbar-results { + animation: slideDown 0.4s cubic-bezier(0.68, -0.55, 0.265, 1.55) !important; + } + + @keyframes slideDown { + 0% { + opacity: 0; + transform: translateY(-15px) scale(0.95); + } + 60% { + transform: translateY(2px) scale(1.01); + } + 100% { + opacity: 1; + transform: translateY(0) scale(1); + } + } + + /* Loading Indicator */ + .tab-throbber { + transition: var(--transition-smooth) !important; + } + + .tab-throbber[busy] { + animation: pulse 1.5s ease-in-out infinite; + } + + @keyframes pulse { + 0%, 100% { opacity: 1; } + 50% { opacity: 0.6; } + } + + /* Button Press Animation */ + @keyframes buttonPress { + 0% { transform: scale(1); } + 50% { transform: scale(0.95); } + 100% { transform: scale(1.05); } + } + + /* Bookmark Button Animation */ + toolbarbutton:not(.bookmark-item):active, + .toolbarbutton-1:not(.bookmark-item):active { + animation: buttonPress 0.15s ease-out !important; + } + ''; + userContent = '' + /* =================================================================== + LATIN ACCENT - FIREFOX TRANSPARENT THEME + Made with cariño by Acercandr0 + =================================================================== */ + + @-moz-document url("about:home"), url("about:newtab"), url("about:blank") { + html, + body, + #root, + .outer-wrapper, + main, + .discovery-stream, + .ds-layout, + .sections-list, + .top-sites, + .search-wrapper { + background: transparent !important; + background-color: transparent !important; + background-image: none !important; + box-shadow: none !important; + filter: none !important; + border: none !important; + } + + /* =========================== + 🎯 TOP SITES + =========================== */ + + /* Remove ALL backgrounds from top sites */ + .top-sites .top-site-outer, + .top-sites .top-site-inner, + .top-site-outer .tile, + .tile, + .shortcuts-refresh .top-sites-list .top-site-outer .tile, + .shortcuts-refresh .top-sites-list:not(.dnd-active) .top-site-outer:is(.active, :focus, :hover) .tile { + background: transparent !important; + background-color: transparent !important; + background-image: none !important; + box-shadow: none !important; + border: none !important; + } + + /* Only opacity changes on hover */ + .top-sites .top-site-outer { + opacity: 0.3 !important; + transition: opacity 0.3s ease !important; + } + + .top-sites .top-site-outer:hover { + opacity: 1 !important; + } + + /* Force transparent background for topsites section */ + .top-sites { + --newtab-background-color-secondary: transparent !important; + } + + /* =========================== + 🛠️ CUSTOMIZE MENU FIX + =========================== */ + + /* Restore proper background for customize menu */ + .customize-menu, + .customize-menu.customize-animate-enter-done { + background: var(--newtab-background-color) !important; + background-color: var(--newtab-background-color) !important; + } + + /* Ensure customize menu has proper styling */ + .customize-menu { + box-shadow: none !important; + border: none !important; + border-radius: 0px !important; + } + + /* Fix text visibility in customize menu */ + .customize-menu .section-title, + .customize-menu .section-disclaimer, + .customize-menu .personalize-button, + .customize-menu label, + .customize-menu input, + .customize-menu button { + color: var(--newtab-text-primary-color) !important } + } + + /* =========================== + 🎭 HIDE ELEMENTS + =========================== */ + + /* Recent Activity */ + .body-wrapper.on .section-title, + .body-wrapper.on .sections-list .section:last-of-type, + .body-wrapper.on .topics { + display: none !important; + } + + /* Search bar */ + .search-wrapper .search-inner-wrapper { + display: none !important; + } + ''; + }; + }; +} diff --git a/modules/hyprland/config.nix b/modules/hyprland/config.nix new file mode 100644 index 0000000..265aa55 --- /dev/null +++ b/modules/hyprland/config.nix @@ -0,0 +1,236 @@ +{ config, pkgs, ... }: { + + wayland.windowManager.hyprland = { + settings = { + monitor = [ ",preferred,auto,auto" ]; + + exec-once = [ + "${pkgs.swww}/bin/swww-daemon &" + "networkmanagerapplet --indicator &" + "$HOME/.local/share/bin/set-wallpaper.sh &" + "${pkgs.procps}/bin/pkill -f '/bin/stash watch' || true" + "${pkgs.pyprland}/bin/pypr &" + ]; + + env = [ + "PATH,$PATH:$HOME/.local/share/bin" + ]; + + input = { + kb_layout = "us,us"; + kb_variant = ",dvorak"; + kb_options = "grp:alt_shift_toggle"; + follow_mouse = 1; + sensitivity = 0; + force_no_accel = 1; + numlock_by_default = true; + touchpad.natural_scroll = false; + }; + + device = [ + { + name = "epic mouse V1"; + sensitivity = -0.5; + } + ]; + + dwindle = { + pseudotile = true; + preserve_split = true; + single_window_aspect_ratio = "1 1"; + }; + + master.new_status = "master"; + + general = { + gaps_in = 2; + gaps_out = 4; + border_size = 2; + }; + + decoration = { + rounding = 0; + blur = { + enabled = true; + size = 6; + passes = 4; + }; + }; + + animations = { + enabled = true; + bezier = [ + "myBezier, 0.05, 0.9, 0.1, 1.05" + "dropdownCurve, 0.34, 1.56, 0.64, 1" + ]; + animation = [ + "windows, 1, 3, myBezier" + "border, 1, 10, default" + "fade, 1, 10, default" + "workspaces, 1, 2, default" + "windowsMove, 1, 2, dropdownCurve" + ]; + }; + + misc = { + vrr = 0; + disable_hyprland_logo = true; + disable_splash_rendering = true; + force_default_wallpaper = 0; + }; + + xwayland.force_zero_scaling = true; + + bindm = [ + # "SUPER, mouse_down, exec, $HOME/.local/share/bin/switch-workspace.sh down" + # "SUPER, mouse_up, exec, $HOME/.local/share/bin/switch-workspace.sh up" + "SUPER, mouse:272, movewindow" + "SUPER, Z, movewindow" + "SUPER, X, resizewindow" + ]; + + bind = [ + "SUPER, Q, exec, $HOME/.local/share/bin/dontkillsteam.sh" + "ALT, F4, exec, $HOME/.local/share/bin/dontkillsteam.sh" + "SUPER, Delete, exit" + "SUPER, W, togglefloating" + "SUPER, G, togglegroup" + "ALT, Return, fullscreen" + "SUPER, L, exec, hyprlock" + "SUPER+SHIFT, F, exec, $HOME/.local/share/bin/windowpin.sh" + "SUPER, Backspace, exec, wlogout" + "SUPER+CTRL+ALT, Backspace, exec, $HOME/.local/share/bin/center-window.sh" + + "SUPER, T, exec, kitty" + "SUPER, return, exec, kitty" + "SUPER, E, exec, kitty -e yazi" + "SUPER, C, exec, kitty -e nvim" + "SUPER, F, exec, firefox" + "SUPER+ALT, T, exec, pypr toggle term" + + + "SUPER, A, exec, pkill -x rofi || $HOME/.local/share/bin/rofilaunch.sh d" + "SUPER, Tab, exec, pkill -x rofi || $HOME/.local/share/bin/rofilaunch.sh w" + "SUPER+SHIFT, E, exec, pkill -x rofi || $HOME/.local/share/bin/rofilaunch.sh f" + + "SUPER, V, exec, $HOME/.dotfiles/scripts/cliphist-paste.sh" + "CTRL SHIFT, ESCAPE, exec, kitty -e btop -t" + + "SUPER, B, exec, sh -c 'systemctl --user is-active waybar && systemctl --user stop waybar || systemctl --user start waybar'" + + "SUPER, K, exec, $HOME/.local/share/bin/keybinds_hint.sh" + + "SUPER+ALT, A, exec, android-emulator" + + "SUPER, N, exec, swaync-client -t" + + ", F10, exec, $HOME/.local/share/bin/volumecontrol.sh -o m" + ", F11, exec, $HOME/.local/share/bin/volumecontrol.sh -o d" + ", F12, exec, $HOME/.local/share/bin/volumecontrol.sh -o i" + + ", XF86AudioMute, exec, $HOME/.local/share/bin/volumecontrol.sh -o m" + ", XF86AudioLowerVolume, exec, $HOME/.local/share/bin/volumecontrol.sh -o d" + ", XF86AudioRaiseVolume, exec, $HOME/.local/share/bin/volumecontrol.sh -o i" + ", XF86AudioPlay, exec, playerctl play-pause" + ", XF86AudioNext, exec, playerctl next" + ", XF86AudioPrev, exec, playerctl previous" + + ", XF86MonBrightnessUp, exec, $HOME/.local/share/bin/brightnesscontrol.sh i" + ", XF86MonBrightnessDown, exec, $HOME/.local/share/bin/brightnesscontrol.sh d" + + "SUPER, P, exec, $HOME/.local/share/bin/screenshot.sh s" + "SUPER+CTRL, P, exec, $HOME/.local/share/bin/screenshot.sh sf" + "SUPER+ALT, P, exec, $HOME/.local/share/bin/screenshot.sh m" + ", Print, exec, $HOME/.local/share/bin/screenshot.sh p" + + "SUPER+ALT, G, exec, $HOME/.local/share/bin/gamemode.sh" + "SUPER+ALT, Right, exec, $HOME/.local/share/bin/set-wallpaper.sh next" + "SUPER+ALT, Left, exec, $HOME/.local/share/bin/set-wallpaper.sh prev" + "SUPER+SHIFT, W, exec, $HOME/.local/share/bin/set-wallpaper.sh rofi" + + "SUPER, Left, movefocus, l" + "SUPER, Right, movefocus, r" + "SUPER, Up, movefocus, u" + "SUPER, Down, movefocus, d" + "ALT, , movefocus, d" + + "SUPER+Ctrl, Down, workspace, empty" + + "SUPER+Shift, Right, resizeactive, 30 0" + "SUPER+Shift, Left, resizeactive, -30 0" + "SUPER+Shift, Up, resizeactive, 0 -30" + "SUPER+Shift, Down, resizeactive, 0 30" + "SUPER+Shift, minus, resizeactive, -30% -30%" + "SUPER+Shift, equal, resizeactive, 30% 30%" + + + "SUPER+SHIFT+CTRL, left, exec, $HOME/.local/share/bin/move-floating.sh l" + "SUPER+SHIFT+CTRL, right, exec, $HOME/.local/share/bin/move-floating.sh r" + "SUPER+SHIFT+CTRL, up, exec, $HOME/.local/share/bin/move-floating.sh u" + "SUPER+SHIFT+CTRL, down, exec, $HOME/.local/share/bin/move-floating.sh d" + + "SUPER, 1, workspace, 1" + "SUPER, 2, workspace, 2" + "SUPER, 3, workspace, 3" + "SUPER, 4, workspace, 4" + "SUPER, 5, workspace, 5" + "SUPER, 6, workspace, 6" + "SUPER, 7, workspace, 7" + "SUPER, 8, workspace, 8" + "SUPER, 9, workspace, 9" + "SUPER, 0, workspace, 10" + + "SUPER+SHIFT, 1, movetoworkspace, 1" + "SUPER+SHIFT, 2, movetoworkspace, 2" + "SUPER+SHIFT, 3, movetoworkspace, 3" + "SUPER+SHIFT, 4, movetoworkspace, 4" + "SUPER+SHIFT, 5, movetoworkspace, 5" + "SUPER+SHIFT, 6, movetoworkspace, 6" + "SUPER+SHIFT, 7, movetoworkspace, 7" + "SUPER+SHIFT, 8, movetoworkspace, 8" + "SUPER+SHIFT, 9, movetoworkspace, 9" + "SUPER+SHIFT, 0, movetoworkspace, 10" + + "SUPER+Alt, S, movetoworkspacesilent, special" + "SUPER, S, togglespecialworkspace" + + "SUPER, J, togglesplit" + + "SUPER+Alt, 1, movetoworkspacesilent, 1" + "SUPER+Alt, 2, movetoworkspacesilent, 2" + "SUPER+Alt, 3, movetoworkspacesilent, 3" + "SUPER+Alt, 4, movetoworkspacesilent, 4" + "SUPER+Alt, 5, movetoworkspacesilent, 5" + "SUPER+Alt, 6, movetoworkspacesilent, 6" + "SUPER+Alt, 7, movetoworkspacesilent, 7" + "SUPER+Alt, 8, movetoworkspacesilent, 8" + "SUPER+Alt, 9, movetoworkspacesilent, 9" + "SUPER+Alt, 0, movetoworkspacesilent, 10" + ]; + }; + + extraConfig = '' + source = ~/.cache/wal/colors-hyprland.conf + + general { + col.active_border = $color4 + col.inactive_border = $color8 + } + ''; + }; + systemd.user.services.cliphist-watcher = { + Unit = { + Description = "Wayland clipboard watcher for cliphist"; + PartOf = [ "hyprland-session.target" ]; + After = [ "hyprland-session.target" ]; + }; + + Service = { + ExecStart = "/run/current-system/sw/bin/wl-paste --watch /run/current-system/sw/bin/cliphist store"; + Restart = "always"; + RestartSec = 1; + }; + + Install.WantedBy = [ "hyprland-session.target" ]; + }; +} diff --git a/modules/hyprland/default.nix b/modules/hyprland/default.nix new file mode 100644 index 0000000..de20476 --- /dev/null +++ b/modules/hyprland/default.nix @@ -0,0 +1,10 @@ +{ inputs, ... }: +{ + imports = [ + ./hyprland.nix + ./hyprlock.nix + # ./hypridle.nix + ./config.nix + ./pyprland.nix + ]; +} diff --git a/modules/hyprland/hypridle.nix b/modules/hyprland/hypridle.nix new file mode 100644 index 0000000..fe70347 --- /dev/null +++ b/modules/hyprland/hypridle.nix @@ -0,0 +1,26 @@ +{...}: { + services = { + hypridle = { + enable = true; + systemdTarget = "hyprland-session.target"; + settings = { + general = { + after_sleep_cmd = "hyprctl dispatch dpms on"; + ignore_dbus_inhibit = false; + lock_cmd = "hyprlock"; + }; + listener = [ + { + timeout = 900; + on-timeout = "hyprlock"; + } + { + timeout = 1200; + on-timeout = "hyprctl dispatch dpms off"; + on-resume = "hyprctl dispatch dpms on"; + } + ]; + }; + }; + }; +} diff --git a/modules/hyprland/hyprland.nix b/modules/hyprland/hyprland.nix new file mode 100644 index 0000000..97510e6 --- /dev/null +++ b/modules/hyprland/hyprland.nix @@ -0,0 +1,23 @@ +{ inputs, pkgs, ... }: +{ + home.packages = with pkgs; [ + swww + # hyprpicker + # wofi + ]; + systemd.user.targets.hyprland-session.Unit.Wants = [ "xdg-desktop-autostart.target" ]; + wayland.windowManager.hyprland = { + enable = true; + xwayland = { + enable = true; + # hidpi = true; + }; + # enableNvidiaPatches = false; + # systemd.enable = true; + }; + wayland.windowManager.hyprland.extraConfig = '' + source = ~/.config/hypr/monitors.conf + source = ~/.config/hypr/workspaces.conf + ''; + +} diff --git a/modules/hyprland/hyprlock.nix b/modules/hyprland/hyprlock.nix new file mode 100644 index 0000000..8570002 --- /dev/null +++ b/modules/hyprland/hyprlock.nix @@ -0,0 +1,71 @@ +{ + config, + lib, + ... +}: { + programs.hyprlock = { + enable = true; + settings = { + general = { + disable_loading_bar = true; + grace = 10; + hide_cursor = true; + no_fade_in = false; + }; + background = [ + { + # Wallpaper path will be managed by set-wallpaper.sh script + # which symlinks the current wallpaper to this location + path = "$HOME/.cache/hyprlock_wallpaper"; + blur_passes = 3; + blur_size = 3; + } + ]; + image = [ + { + path = "$HOME/.dotfiles/modules/fastfetch/me.png"; + size = 150; + border_size = 4; + # Border color will use color4 from pywal + border_color = "rgb(142, 115, 113)"; + rounding = -1; # Negative means circle + position = "0, 200"; + halign = "center"; + valign = "center"; + } + ]; + label = [ + { + # Media player information + monitor = ""; + text = "cmd[update:1000] $HOME/.local/share/bin/media-player-info.sh"; + text_align = "center"; + font_size = 12; + font_family = "Monospace"; + position = "0, 100"; + halign = "center"; + valign = "center"; + color = "rgb(205, 188, 187)"; + } + ]; + input-field = [ + { + size = "200, 50"; + position = "0, -80"; + monitor = ""; + dots_center = true; + fade_on_empty = false; + # Foreground color from pywal + font_color = "rgb(205, 188, 187)"; + # Color2 from pywal for inner color + inner_color = "rgb(118, 96, 95)"; + # Background from pywal for outer color + outer_color = "rgb(10, 10, 10)"; + outline_thickness = 5; + placeholder_text = "Password..."; + shadow_passes = 2; + } + ]; + }; + }; +} diff --git a/modules/hyprland/pyprland.nix b/modules/hyprland/pyprland.nix new file mode 100644 index 0000000..88b6c0a --- /dev/null +++ b/modules/hyprland/pyprland.nix @@ -0,0 +1,17 @@ +{pkgs, ...}: { + home.packages = with pkgs; [pyprland]; + + home.file.".config/hypr/pyprland.toml".text = '' + [pyprland] +plugins = ["scratchpads"] + +[scratchpads.term] +animation = "fromTop" +command = "kitty --class floating-term" +class = "floating-term" +size = "60% 60%" +position = "center" +on_open = "move cursor 0 0" +lazy = true + ''; +} diff --git a/modules/kitty/default.nix b/modules/kitty/default.nix new file mode 100644 index 0000000..b49cf93 --- /dev/null +++ b/modules/kitty/default.nix @@ -0,0 +1,4 @@ +{ inputs, ... }: +{ + imports = [ (import ./kitty.nix) ]; +} diff --git a/modules/kitty/kitty.nix b/modules/kitty/kitty.nix new file mode 100644 index 0000000..8715d28 --- /dev/null +++ b/modules/kitty/kitty.nix @@ -0,0 +1,54 @@ +{ pkgs, ... }: + +{ + programs.kitty = { + enable = true; + + font = { + name = "JetBrainsMono Nerd Font"; + size = 12; + }; + + settings = { + confirm_os_window_close = 0; + window_padding_width = 10; + scrollback_lines = 10000; + enable_audio_bell = false; + mouse_hide_wait = 60; + + tab_title_template = "{index}"; + active_tab_font_style = "normal"; + inactive_tab_font_style = "normal"; + + tab_bar_style = "powerline"; + tab_powerline_style = "round"; + + active_tab_foreground = "#1e1e2e"; + active_tab_background = "#cba6f7"; + inactive_tab_foreground = "#bac2de"; + inactive_tab_background = "#313244"; + }; + + keybindings = { + "alt+1" = "goto_tab 1"; + "alt+2" = "goto_tab 2"; + "alt+3" = "goto_tab 3"; + "alt+4" = "goto_tab 4"; + "ctrl+v" = "paste_from_clipboard"; + + "ctrl+shift+left" = "no_op"; + "ctrl+shift+right" = "no_op"; + }; + + extraConfig = '' + export QT_QPA_PLATFORMTHEME=qt5ct + export QT_STYLE_OVERRIDE=kvantum + + mouse_map right press ungrabbed paste_from_clipboard + mouse_map right press grabbed paste_from_clipboard + + # Load pywal colors if they exist + include ~/.cache/wal/colors-kitty.conf + ''; + }; +} diff --git a/modules/lightdm/aqua-theme.nix b/modules/lightdm/aqua-theme.nix new file mode 100644 index 0000000..00746dd --- /dev/null +++ b/modules/lightdm/aqua-theme.nix @@ -0,0 +1,45 @@ +{ pkgs, lib, config, ... }: + +let + aqua-theme = pkgs.stdenv.mkDerivation { + pname = "aqua-lightdm-webkit-theme"; + version = "1.0"; + + src = pkgs.fetchzip { + url = "https://github.com/paysonwallach/aqua-lightdm-webkit-theme/archive/master.zip"; + sha256 = "sha256-+nn2JN+l/SF6fNH/caT/JIptHilRdwLZ7FlFMD68VxA="; + stripRoot = true; + }; + + installPhase = '' + mkdir -p $out/share/lightdm-webkit/themes/aqua + cp -r . $out/share/lightdm-webkit/themes/aqua/ + ''; + + meta = with pkgs.lib; { + description = "macOS-inspired LightDM Webkit greeter theme"; + homepage = "https://github.com/paysonwallach/aqua-lightdm-webkit-theme"; + platforms = platforms.linux; + }; + }; +in +{ + config = lib.mkIf config.services.xserver.displayManager.lightdm.enable { + # Install the aqua theme (for future webkit greeter use) + environment.systemPackages = [ + aqua-theme + ]; + + # Create symlink for theme to be accessible to lightdm + system.activationScripts.aqua-lightdm-theme = { + text = '' + mkdir -p /usr/share/lightdm-webkit/themes + if [ -L /usr/share/lightdm-webkit/themes/aqua ]; then + rm /usr/share/lightdm-webkit/themes/aqua + fi + ln -sf ${aqua-theme}/share/lightdm-webkit/themes/aqua /usr/share/lightdm-webkit/themes/aqua + ''; + deps = []; + }; + }; +} diff --git a/modules/lightdm/default.nix b/modules/lightdm/default.nix new file mode 100644 index 0000000..a3503c9 --- /dev/null +++ b/modules/lightdm/default.nix @@ -0,0 +1,6 @@ +{ ... }: +{ + imports = [ + ./aqua-theme.nix + ]; +} diff --git a/modules/misc/btop.nix b/modules/misc/btop.nix new file mode 100644 index 0000000..46383ac --- /dev/null +++ b/modules/misc/btop.nix @@ -0,0 +1,14 @@ +{ config, pkgs, ... }: + +{ + programs.btop = { + enable = true; + settings = { + # color_theme = "gruvbox-dark"; # You can change this to any other theme + theme_background = false; + vim_keys = true; + # You can add more settings from: https://github.com/aristocratos/btop#configuration + }; + }; +} + diff --git a/modules/misc/default.nix b/modules/misc/default.nix new file mode 100644 index 0000000..4e617ef --- /dev/null +++ b/modules/misc/default.nix @@ -0,0 +1,17 @@ +{ + imports = [ +# ./discord.nix + ./git.nix + ./gtk.nix + ./btop.nix + ./pipewire.nix + ./pywal.nix + ./obsidian.nix + ./obs-studio.nix + ./dunst.nix + # ./sddm.nix + ./spotify.nix + ./zsh.nix + ./zoxide.nix + ]; +} diff --git a/modules/misc/discord.nix b/modules/misc/discord.nix new file mode 100644 index 0000000..249e944 --- /dev/null +++ b/modules/misc/discord.nix @@ -0,0 +1,8 @@ +{ pkgs, ... }: +{ + home.packages = with pkgs; [ + (discord.override { + withVencord = true; + }) + ]; +} diff --git a/modules/misc/dunst.nix b/modules/misc/dunst.nix new file mode 100644 index 0000000..fda40f1 --- /dev/null +++ b/modules/misc/dunst.nix @@ -0,0 +1,58 @@ +{ config, pkgs, lib, ... }: + +{ + home.packages = with pkgs; [ + dunst + jq + ]; + + home.file.".config/dunst/dunstrc".text = '' + #!/usr/bin/env sh + WAL_COLORS="$HOME/.cache/wal/colors.json" + + if [ -f "$WAL_COLORS" ]; then + BG=$(jq -r '.special.background' "$WAL_COLORS") + FG=$(jq -r '.special.foreground' "$WAL_COLORS") + LOW=$(jq -r '.colors.color2' "$WAL_COLORS") + NORMAL=$(jq -r '.colors.color1' "$WAL_COLORS") + CRITICAL=$(jq -r '.colors.color3' "$WAL_COLORS") + else + BG="#0f1016" + FG="#c6c3da" + LOW="#6F6C91" + NORMAL="#6B6691" + CRITICAL="#877AB1" + fi + + cat < "$HOME/.config/dunst/dunstrc" + [global] + font = Monospace 10 + geometry = "300x50-10+50" + timeouts = { low = 1000, normal = 1500, critical = 3000 } + frame_color = "$NORMAL" + background = "$BG" + foreground = "$FG" + separator_height = 2 + padding = 8 + transparency = 10 + sort = newest + ignore_new_urgency = false + + [urgency_low] + background = "$BG" + foreground = "$FG" + frame_color = "$LOW" + + [urgency_normal] + background = "$BG" + foreground = "$FG" + frame_color = "$NORMAL" + + [urgency_critical] + background = "$BG" + foreground = "$FG" + frame_color = "$CRITICAL" + EOL + ''; +} + diff --git a/modules/misc/git.nix b/modules/misc/git.nix new file mode 100644 index 0000000..ba97f7f --- /dev/null +++ b/modules/misc/git.nix @@ -0,0 +1,21 @@ +{ pkgs, ... }: { + programs.git = { + enable = true; + + settings = { + user.name = "gibbyDev"; + user.email = "gibbyDEV@protonmail.com"; + init.defaultBranch = "main"; + credential.helper = "store"; + }; + }; + + home.packages = [ + pkgs.gh + pkgs.git-lfs + pkgs.copilot-cli + pkgs.noto-fonts + pkgs.noto-fonts-color-emoji # renamed + ]; +} + diff --git a/modules/misc/gtk.nix b/modules/misc/gtk.nix new file mode 100644 index 0000000..c24db54 --- /dev/null +++ b/modules/misc/gtk.nix @@ -0,0 +1,60 @@ +{ config, pkgs, lib, ... }: + +let + cacheDir = config.xdg.cacheHome; + isValidUser = config.home.username != "cody"; +in +{ + fonts.fontconfig.enable = true; + + home.packages = with pkgs; [ + nerd-fonts.jetbrains-mono + twemoji-color-font + noto-fonts-color-emoji + ]; + + gtk = { + enable = true; + + font = { + name = "JetBrainsMono Nerd Font"; + size = 11; + }; + + theme = { + name = "Adwaita-dark"; + package = pkgs.gnome-themes-extra; + }; + + iconTheme = { + name = "Papirus-Dark"; + package = pkgs.papirus-icon-theme; + }; + + cursorTheme = { + name = "Bibata-Modern-Classic"; + package = pkgs.bibata-cursors; + size = 16; + }; + + gtk3.extraCss = lib.mkIf isValidUser '' + @import url("file://${cacheDir}/wal/colors.css"); + ''; + + gtk4.extraCss = lib.mkIf isValidUser '' + @import url("file://${cacheDir}/wal/colors.css"); + ''; + }; + + qt = { + enable = true; + platformTheme.name = "gtk"; + style.name = "adwaita-dark"; + }; + + home.pointerCursor = { + name = "Bibata-Modern-Classic"; + package = pkgs.bibata-cursors; + size = 16; + }; +} diff --git a/modules/misc/obs-studio.nix b/modules/misc/obs-studio.nix new file mode 100644 index 0000000..c9e2db2 --- /dev/null +++ b/modules/misc/obs-studio.nix @@ -0,0 +1,35 @@ +{ pkgs, config, ... }: { + programs.obs-studio = { + enable = true; + #enableVirtualCamera = true; + plugins = with pkgs.obs-studio-plugins; [ + wlrobs + obs-pipewire-audio-capture + obs-vkcapture + obs-source-clone + obs-move-transition + obs-composite-blur + obs-backgroundremoval + ]; + }; + + # Create Videos directory for OBS recordings + home.file."Videos/.keep".text = ""; + + # Configure OBS to use ~/Videos for recordings + home.file.".config/obs-studio/basic/profiles/Untitled/basic.ini" = { + text = '' + [Output] + FilePath=${config.home.homeDirectory}/Videos + FilenameFormatting=%CCYY-%MM-%DD %HH-%mm-%SS + ''; + }; + + # Also set the global OBS settings to use Videos directory + home.file.".config/obs-studio/global.ini" = { + text = '' + [General] + RecordPath=${config.home.homeDirectory}/Videos + ''; + }; +} diff --git a/modules/misc/obsidian.nix b/modules/misc/obsidian.nix new file mode 100644 index 0000000..2259e7d --- /dev/null +++ b/modules/misc/obsidian.nix @@ -0,0 +1,33 @@ +{ config, lib, pkgs, ... }: + +{ + home.packages = with pkgs; [ obsidian ]; + + # NOTE: vault is at ~/Documents/Notebook + # Commented out symlink due to pure eval restrictions + # home.file.".config/obsidian" = { + # source = config.lib.file.mkOutOfStoreSymlink "${config.home.homeDirectory}/Documents/Notebook"; + # }; + +# systemd.user.services.obsidian-git-sync = { +# Unit = { +# Description = "Auto-commit and push Obsidian Vault"; +# After = [ "network-online.target" ]; +# }; + +# Service = { +# ExecStart = pkgs.writeShellScript "obsidian-git-sync" '' +# cd ${vaultPath} +# if [ -n "$(git status --porcelain)" ]; then +# git add . +# git commit -m "Auto-sync: $(date)" +# git push origin main +# fi +# ''; +# Restart = "always"; +# }; + +# Install = { WantedBy = [ "default.target" ]; }; +# }; +} + diff --git a/modules/misc/pipewire.nix b/modules/misc/pipewire.nix new file mode 100644 index 0000000..ff41237 --- /dev/null +++ b/modules/misc/pipewire.nix @@ -0,0 +1,29 @@ +{ config, lib, pkgs, ... }: + +{ + # Enable PipeWire +# services.pipewire = { +# enable = true; +# audio.enable = true; +# alsa = { +# enable = true; +# support32Bit = true; +# }; +# pulse.enable = true; +# jack.enable = true; +# }; + + # Enable real-time scheduling for better audio performance +# security.rtkit.enable = true; + + # Disable PulseAudio (ensure it's removed if previously enabled) +# hardware.pulseaudio.enable = false; + + # Optional: Install `pavucontrol` for a GUI to manage audio + home.packages = with pkgs; [ + pavucontrol + helvum # For managing audio routing visually + qpwgraph # Graph-based PipeWire manager + ]; +} + diff --git a/modules/misc/pywal.nix b/modules/misc/pywal.nix new file mode 100644 index 0000000..e74efee --- /dev/null +++ b/modules/misc/pywal.nix @@ -0,0 +1,38 @@ +{ config, pkgs, lib, ... }: + +{ + config = lib.mkIf config.programs.pywal.enable { + home.sessionVariables = { + PYWAL_CACHE_DIR = "${config.xdg.cacheHome}/wal"; + }; + + home.file.".config/waybar/colors.css".source = + "${config.xdg.cacheHome}/wal/colors-waybar.css"; + + home.file.".config/rofi/colors.rasi".text = '' + * { + background: #''${palette.background}; + foreground: #''${palette.foreground}; + normal-background: #''${palette.background}; + normal-foreground: #''${palette.foreground}; + alternate-normal-background: #''${palette.background}; + alternate-normal-foreground: #''${palette.foreground}; + selected-normal-background: #''${palette.color7}; + selected-normal-foreground: #''${palette.background}; + active-background: #''${palette.background}; + active-foreground: #''${palette.color2}; + alternate-active-background: #''${palette.background}; + alternate-active-foreground: #''${palette.color2}; + selected-active-background: #''${palette.color2}; + selected-active-foreground: #''${palette.background}; + urgent-background: #''${palette.color1}; + urgent-foreground: #''${palette.background}; + alternate-urgent-background: #''${palette.background}; + alternate-urgent-foreground: #''${palette.color1}; + selected-urgent-background: #''${palette.color1}; + selected-urgent-foreground: #''${palette.background}; + } + ''; + }; +} + diff --git a/modules/misc/sddm.nix b/modules/misc/sddm.nix new file mode 100644 index 0000000..907025b --- /dev/null +++ b/modules/misc/sddm.nix @@ -0,0 +1,10 @@ +{ config, pkgs, lib, ... }: + +{ + # SDDM configuration has been migrated to LightDM + # This file is kept for reference only +} + + + + diff --git a/modules/misc/spotify.nix b/modules/misc/spotify.nix new file mode 100644 index 0000000..25c3236 --- /dev/null +++ b/modules/misc/spotify.nix @@ -0,0 +1,11 @@ +{ pkgs, ... }: + +{ + home.packages = [ + pkgs.spotify + ]; + + # Prevent Spotify from launching on startup by removing its autostart entry +# xdg.configFile."autostart/spotify.desktop".force = false; +} + diff --git a/modules/misc/thunar.nix b/modules/misc/thunar.nix new file mode 100644 index 0000000..a9add73 --- /dev/null +++ b/modules/misc/thunar.nix @@ -0,0 +1,24 @@ +{ config, pkgs, ... }: + +{ + # Enable Thunar via Home Manager + programs.thunar = { + enable = true; + + # Enable thumbnails for supported file types + enableThumbnailing = true; + + # Set Thunar as the default file manager + defaultFileManager = true; + + # Enable the Thunar custom actions (e.g., opening a terminal in the current directory) + customActions = [ + { + } + ]; + + # Optional: Customize the icon theme for Thunar + iconTheme = "Papirus-Dark"; # Adjust as needed based on your icon theme + }; +} + diff --git a/modules/misc/zoxide.nix b/modules/misc/zoxide.nix new file mode 100644 index 0000000..153d85c --- /dev/null +++ b/modules/misc/zoxide.nix @@ -0,0 +1,12 @@ +_: { + programs = { + zoxide = { + enable = true; + enableZshIntegration = true; + enableBashIntegration = true; + options = [ + "--cmd cd" + ]; + }; + }; +} diff --git a/modules/misc/zsh.nix b/modules/misc/zsh.nix new file mode 100644 index 0000000..27bcb40 --- /dev/null +++ b/modules/misc/zsh.nix @@ -0,0 +1,68 @@ +{ config, pkgs, lib, ... }: + +{ + programs.zsh = { + enable = true; + enableCompletion = true; + + syntaxHighlighting.enable = true; + autosuggestion.enable = true; + + initContent = '' + # Powerlevel10k + source ${pkgs.zsh-powerlevel10k}/share/zsh-powerlevel10k/powerlevel10k.zsh-theme + [[ -f ~/.p10k.zsh ]] && source ~/.p10k.zsh + ''; + + shellAliases = { + # Defaults – hosts may override + ls = lib.mkDefault "lsd --color=auto"; + ll = lib.mkDefault "lsd -lah --color=auto"; + ".." = lib.mkDefault "cd ../"; + v = lib.mkDefault "nvim ."; + c = lib.mkDefault "clear"; + z = lib.mkDefault "zoxide"; + op = lib.mkDefault "opencode ."; + ff = lib.mkDefault "fastfetch"; + gs = lib.mkDefault "git status"; + gc = lib.mkDefault "git commit -m"; + gp = lib.mkDefault "git push -u origin"; + tsm = lib.mkDefault "tmux-session-manager"; + # rgi = lib.mkDefault '' + # rg --color=always --line-number --no-heading --smart-case . | + # fzf --ansi --delimiter : \ + # --preview "bat --style=full --color=always --highlight-line {2} {1}" \ + # --preview-window "~4,+{2}+4/3,<80(up)" + # ''; + rgi = lib.mkDefault '' + rg --color=always --line-number --no-heading --smart-case . | + fzf --ansi --delimiter : \ + --preview "bat --style=full --color=always --highlight-line {2} {1}" \ + --preview-window "~4,+{2}+4/3,<80(up)" \ + --bind "enter:become(nvim +{2} {1})" + ''; + hmr = lib.mkDefault "sudo nixos-rebuild switch --flake .#$(hostname)"; + snr = lib.mkDefault "sudo nixos-rebuild switch --flake ."; + ncg = "nix-collect-garbage --delete-old && sudo nix-collect-garbage -d && sudo /run/current-system/bin/switch-to-configuration boot"; + reload = lib.mkDefault "exec zsh"; + }; + }; + + ################################ + # Fonts (for p10k icons) + ################################ + fonts.fontconfig.enable = true; + + ################################ + # Packages + ################################ + home.packages = with pkgs; [ + nerd-fonts.fira-code + nerd-fonts.hack + nerd-fonts.jetbrains-mono + + zsh-powerlevel10k + zsh-autosuggestions + zsh-syntax-highlighting + ]; +} diff --git a/modules/nvim/default.nix b/modules/nvim/default.nix new file mode 100644 index 0000000..7c0e9ea --- /dev/null +++ b/modules/nvim/default.nix @@ -0,0 +1,5 @@ +{ + imports = [ + ./nvim.nix + ]; +} diff --git a/modules/nvim/nvim.nix b/modules/nvim/nvim.nix new file mode 100644 index 0000000..f1a4b8f --- /dev/null +++ b/modules/nvim/nvim.nix @@ -0,0 +1,26 @@ +{ config, pkgs, ... }: + +let + nvimConfigDir = "${config.home.homeDirectory}/.config/nvim"; + nvimGitRepo = "https://github.com/gibbyDev/nvim.git"; # Change this + git = "${pkgs.git}/bin/git"; +in +{ + home.activation.cloneNvimConfig = config.lib.dag.entryAfter [ "writeBoundary" ] '' + if [ ! -d "${nvimConfigDir}/.git" ]; then + echo "Cloning Neovim config..." + ${git} clone --depth=1 ${nvimGitRepo} ${nvimConfigDir} + else + echo "Neovim config already exists, pulling latest changes..." + ${git} -C ${nvimConfigDir} pull + fi + ''; + + programs.neovim = { + enable = true; + defaultEditor = true; + package = pkgs.neovim-unwrapped; + extraPackages = with pkgs; [ wl-clipboard xclip xsel ]; + }; +} + diff --git a/modules/opencode/default.nix b/modules/opencode/default.nix new file mode 100644 index 0000000..beace21 --- /dev/null +++ b/modules/opencode/default.nix @@ -0,0 +1,5 @@ +{ + imports = [ + ./opencode.nix + ]; +} diff --git a/modules/opencode/opencode.nix b/modules/opencode/opencode.nix new file mode 100644 index 0000000..6c649b2 --- /dev/null +++ b/modules/opencode/opencode.nix @@ -0,0 +1,19 @@ +{ config, lib, pkgs, ... }: + +let + cfg = config.programs.opencode; +in +{ + config = lib.mkIf cfg.enable { + home.packages = [ pkgs.gh ]; + + xdg.configFile."opencode/config.toml".text = '' + [ai] + provider = "github-copilot" + + [ai.github] + auth = "gh" + ''; + }; +} + diff --git a/modules/posting/default.nix b/modules/posting/default.nix new file mode 100644 index 0000000..e780110 --- /dev/null +++ b/modules/posting/default.nix @@ -0,0 +1,5 @@ +{ + imports = [ + ./posting.nix + ]; +} diff --git a/modules/posting/posting.nix b/modules/posting/posting.nix new file mode 100644 index 0000000..fdf76dd --- /dev/null +++ b/modules/posting/posting.nix @@ -0,0 +1,148 @@ +{ config, pkgs, lib, ... }: + +let + # Script to generate posting theme from pywal colors + generate-posting-theme = pkgs.writeShellScriptBin "generate-posting-theme" '' + #!/bin/bash + + # Get pywal colors + WAL_COLORS="''${XDG_CACHE_HOME:-$HOME/.cache}/wal/colors" + + if [ ! -f "$WAL_COLORS" ]; then + echo "Error: pywal colors file not found at $WAL_COLORS" + exit 1 + fi + + # Read colors from wal + mapfile -t COLORS < "$WAL_COLORS" + + # Extract colors (wal provides 16 colors) + BG="''${COLORS[0]}" # background + FG_DARK="''${COLORS[8]}" # dark foreground + COLOR1="''${COLORS[1]}" # red + COLOR2="''${COLORS[2]}" # green + COLOR3="''${COLORS[3]}" # yellow + COLOR4="''${COLORS[4]}" # blue + COLOR5="''${COLORS[5]}" # magenta + COLOR6="''${COLORS[6]}" # cyan + COLOR7="''${COLORS[7]}" # white + + POSTING_THEME_DIR="''${XDG_DATA_HOME:-$HOME/.local/share}/posting/themes" + mkdir -p "$POSTING_THEME_DIR" + + # Generate theme from pywal colors with proper variable substitution + cat > "$POSTING_THEME_DIR/pywal.yaml" </dev/null || echo "balanced") + + if [ "$current_mode" = "powersave" ]; then + # Switch to performance mode + echo "performance" > "$power_mode_file" + echo "Performance Mode" + else + # Switch to powersave mode + echo "powersave" > "$power_mode_file" + echo "Power Saving Mode" + fi + ''; + + walColors = "${config.xdg.cacheHome}/wal/colors-waybar.css"; + isValidUser = config.home.username == "cody"; +in +{ + home.packages = with pkgs; [ + swaynotificationcenter + nerd-fonts.jetbrains-mono + playerctl + pamixer + brightnessctl + blueman + networkmanager + libnotify + grimblast + swappy + ]; + + services.swaync = { + enable = true; + settings = { + "$schema" = "/etc/xdg/swaync/configSchema.json"; + positionX = "right"; + positionY = "top"; + cssPriority = "user"; + control-center-margin-top = 10; + control-center-margin-bottom = 10; + control-center-margin-right = 10; + control-center-margin-left = 0; + notification-icon-size = 64; + notification-body-image-height = 100; + notification-body-image-width = 200; + timeout = 6; + timeout-low = 3; + timeout-critical = 0; + fit-to-screen = false; + control-center-width = 400; + control-center-height = 740; + notification-window-width = 375; + keyboard-shortcuts = true; + image-visibility = "when-available"; + transition-time = 200; + hide-on-clear = false; + hide-on-action = true; + script-fail-notify = true; + widgets = [ + "title" + "dnd" + "menubar#desktop" + "volume" + "mpris" + "notifications" + "buttons-grid" + ]; + widget-config = { + title = { + text = " Quick settings"; + clear-all-button = true; + button-text = ""; + }; + "menubar#desktop" = { + "backlight" = { + label = " 󰃟 "; + }; + "menu#screenshot" = { + label = "󰄀 Screenshot"; + position = "left"; + actions = [ + { + label = "Whole screen"; + command = "sh -c 'swaync-client -cp; sleep 1; ${pkgs.grimblast}/bin/grimblast copysave output \"/tmp/screenshot.png\"; ${pkgs.swappy}/bin/swappy -f \"/tmp/screenshot.png\"'"; + } + { + label = "Whole window / Select region"; + command = "sh -c 'swaync-client -cp; ${pkgs.grimblast}/bin/grimblast copysave area \"/tmp/screenshot.png\"; ${pkgs.swappy}/bin/swappy -f \"/tmp/screenshot.png\"'"; + } + ]; + }; + "menu#power" = { + label = " Power Menu"; + position = "left"; + actions = [ + { + label = " Shut down"; + command = "systemctl poweroff"; + } + { + label = " Reboot"; + command = "systemctl reboot"; + } + { + label = "󰤄 Suspend"; + command = "systemctl suspend"; + } + { + label = " Logout"; + command = "hyprctl dispatch exit 0"; + } + { + label = " Lock"; + command = "hyprlock"; + } + ]; + }; + }; + volume = { + label = ""; + expand-button-label = ""; + collapse-button-label = ""; + show-per-app = true; + show-per-app-icon = true; + show-per-app-label = true; + }; + dnd = { + text = " Do Not Disturb"; + }; + mpris = { + image-size = 96; + image-radius = 4; + }; + notifications = { + text = "Notifications"; + clear-all-button = true; + button-text = " Clear"; + }; + "buttons-grid" = { + actions = [ + { + label = "󰝟"; + type = "toggle"; + command = "${pkgs.pamixer}/bin/pamixer -t"; + update-command = "sh -c '${pkgs.pamixer}/bin/pamixer --get-mute | grep -q true && echo true || echo false'"; + } + { + label = "󰍭"; + type = "toggle"; + command = "${pkgs.pamixer}/bin/pamixer --default-source -t"; + update-command = "sh -c '${pkgs.pamixer}/bin/pamixer --get-mute --default-source | grep true && echo true || echo false'"; + } + { + label = ""; + type = "toggle"; + command = "blueman-manager"; + update-command = "sh -c 'bluetoothctl show | grep -q \"Powered: yes\" && echo true || echo false'"; + } + { + label = "󰤨"; + type = "toggle"; + command = "sh -c '[ \"$SWAYNC_TOGGLE_STATE\" = true ] && ${pkgs.networkmanager}/bin/nmcli radio wifi on || ${pkgs.networkmanager}/bin/nmcli radio wifi off'"; + update-command = "sh -c '${pkgs.networkmanager}/bin/nmcli radio wifi | grep -q enabled && echo true || echo false'"; + } + { + label = "🎮"; + type = "toggle"; + command = "${gamemode}/bin/gamemode"; + update-command = "hyprctl getoption animations:enabled | grep -q 'int: 1' && echo false || echo true"; + } + { + label = "󰤄"; + type = "toggle"; + command = "sh -c '${pkgs.procps}/bin/pgrep -x hyprsunset >/dev/null && ${pkgs.procps}/bin/pkill hyprsunset || nohup ${pkgs.hyprsunset}/bin/hyprsunset --temperature 3500 > /tmp/hyprsunset_output.log 2>&1 &'"; + update-command = "sh -c 'pgrep -x hyprsunset >/dev/null && echo true || echo false'"; + } + { + label = "☕"; + command = "systemctl --user is-active --quiet hypridle.service && systemctl --user stop hypridle.service || systemctl --user start hypridle.service"; + type = "toggle"; + update-command = "pgrep -x hypridle > /dev/null && echo false || echo true"; + } + { + label = ""; + type = "toggle"; + command = "${togglepowermode}/bin/togglepowermode"; + update-command = "test -f \"$HOME/.config/hypr/power_mode\" && grep -q \"^powersave$\" \"$HOME/.config/hypr/power_mode\" && echo true || echo false"; + } + ]; + }; + }; + scripts = { + example-script = { + exec = "echo 'Do something...'"; + urgency = "Normal"; + }; + }; + notification-visibility = { + spotify = { + state = "enabled"; + urgency = "Low"; + app-name = "Spotify"; + }; + youtube-music = { + state = "enabled"; + urgency = "Low"; + app-name = "com.github.th_ch.youtube_music"; + }; + }; + }; + style = lib.mkIf isValidUser '' + @import url("file://${walColors}"); + + @define-color shadow rgba(0, 0, 0, 0.25); + + * { + font-family: "JetBrainsMono NFM SemiBold", monospace; + border-radius: 4px; + } + + .notification { + background: @background; + color: @foreground; + border: 1px solid @color4; + border-radius: 4px; + margin: 6px 0; + } + + .notification-action { + border: 2px solid; + border-top: none; + } + + .close-button { + background: transparent; + color: transparent; + } + + .summary { + color: @foreground; + font-size: 16px; + background: transparent; + text-shadow: none; + } + + .time { + color: @color7; + font-size: 16px; + background: transparent; + text-shadow: none; + margin-right: 18px; + } + + .body { + background: transparent; + font-size: 15px; + font-weight: 500; + color: @color7; + text-shadow: none; + } + + .top-action-title { + color: @foreground; + text-shadow: none; + } + + .control-center { + background: @background; + border-radius: 4px; + border: 1px solid @color4; + } + + .control-center .notification-row:focus, + .control-center .notification-row:hover { + opacity: 1; + border-radius: 4px; + } + + .notification-row { + outline: none; + margin: 0; + padding: 0; + background: transparent; + border: none; + } + + .notification-group { + background: transparent; + border: none; + } + + .widget-title { + margin: 0px; + background: transparent; + border-radius: 4px; + border-bottom: none; + } + + .widget-title > label { + margin: 18px 10px; + font-size: 20px; + font-weight: 500; + } + + .widget-title > button { + font-weight: 700; + padding: 7px 3px; + margin-right: 10px; + background: transparent; + color: @foreground; + border: none; + border-radius: 4px; + } + + .widget-title > button:hover { + background: @color2; + } + + .widget-label { + margin: 0px; + padding: 0px; + min-height: 5px; + background: alpha(@background, 0.80); + border-radius: 0px 0px 4px 4px; + border-top: none; + } + + .widget-label > label { + font-size: 15px; + font-weight: 400; + } + + .widget-menubar { + background: transparent; + border-radius: 4px; + border-top: none; + border-bottom: none; + } + + .widget-menubar > box > box { + margin: 5px 5px 5px 5px; + min-height: 40px; + border-radius: 4px; + background: transparent; + } + + .widget-menubar > box > box > button { + background: alpha(@background, 0.80); + min-width: 185px; + min-height: 50px; + margin-right: 25px; + font-size: 14px; + padding: 5px; + } + + .widget-menubar > box > box > button:nth-child(2) { + margin-right: 0px; + padding-top: 5px; + } + + .widget-menubar button:hover { + background: @color2; + box-shadow: none; + } + + .widget-menubar > box > revealer > box { + margin: 5px 10px 5px 10px; + background: alpha(@background, 0.80); + border-radius: 4px; + } + + .widget-menubar > box > revealer > box > button { + background: transparent; + min-height: 50px; + padding: 0px; + margin: 5px; + } + + .widget-buttons-grid { + background: transparent; + border-top: none; + border-bottom: none; + font-size: 14px; + font-weight: 500; + margin: 0px; + padding: 0px; + border-radius: 0px; + } + + .widget-buttons-grid > flowbox > flowboxchild { + background: @background; + border-radius: 4px; + min-height: 40px; + min-width: 85px; + margin: 5px; + padding: 0px; + } + + .widget-buttons-grid > flowbox > flowboxchild > button { + background: transparent; + border-radius: 4px; + margin: 0px; + border: none; + box-shadow: none; + } + + .widget-buttons-grid > flowbox > flowboxchild > button:hover { + background: @color2; + } + + .widget-mpris { + padding: 8px; + border-radius: 8px; + padding-bottom: 15px; + margin-bottom: 0px; + background: alpha(@color1, 0.25); + border: 1px solid @color4; + } + + .widget-mpris > box > button, + .widget-mpris-player, + .widget-mpris-album-art { + box-shadow: none; + margin: 10px 0 0 0; + padding: 5px 10px; + border-radius: 8px; + } + + .widget-mpris button { + background: alpha(@color2, 0.5); + color: @foreground; + border: none; + border-radius: 4px; + } + + .widget-mpris button:hover { + background: @color2; + } + + .widget-backlight, + .widget-volume { + background: transparent; + border-top: none; + border-bottom: none; + font-size: 13px; + font-weight: 600; + border-radius: 0px; + margin: 0px; + padding: 0px; + } + + .widget-volume > box { + background: alpha(@background, 0.80); + border-radius: 4px; + margin: 5px 10px 5px 10px; + min-height: 50px; + } + + .widget-volume > box > label { + min-width: 50px; + padding: 0px; + } + + .widget-volume > box > button { + min-width: 50px; + box-shadow: none; + padding: 0px; + } + + .widget-volume > box > button:hover { + background: @color2; + } + + .widget-volume > revealer > list { + background: alpha(@background, 0.80); + border-radius: 4px; + margin-top: 5px; + padding: 0px; + } + + .widget-volume > revealer > list > row { + padding-left: 10px; + min-height: 40px; + background: transparent; + } + + .widget-volume > revealer > list > row:hover { + background: transparent; + box-shadow: none; + border-radius: 4px; + } + + .widget-backlight > scale { + background: alpha(@background, 0.80); + border-radius: 0px 4px 4px 0px; + margin: 5px 10px 5px 0px; + padding: 0px 10px 0px 0px; + min-height: 50px; + } + + .widget-backlight > label { + background: @color2; + margin: 5px 0px 5px 10px; + border-radius: 4px 0px 0px 4px; + padding: 0px; + min-height: 50px; + min-width: 50px; + } + + .widget-dnd { + margin: 6px 10px; + padding: 0 12px; + font-size: 1.2rem; + } + + .widget-dnd > switch { + background: alpha(@background, 0.80); + font-size: initial; + border-radius: 8px; + box-shadow: none; + padding: 2px; + } + + .widget-dnd > switch:hover { + background: alpha(@color2, 0.80); + } + + .widget-dnd > switch:checked { + background: @color2; + } + + .widget-dnd > switch:checked:hover { + background: alpha(@color2, 0.80); + } + + .widget-dnd > switch slider { + background: alpha(@color2, 0.80); + border-radius: 6px; + } + + .toggle:checked { + background: @color2; + } + + .toggle:checked:hover { + background: alpha(@color2, 0.75); + } + + scale trough { + border-radius: 4px; + background: @color2; + } + + scale slider { + background: @color2; + } + + scrollbar, + scrollbar * { + all: unset; + min-width: 0px; + min-height: 0px; + } + + scrollbar slider { + background: transparent; + } + + scrollbar.vertical, + scrollbar.horizontal { + background: transparent; + } + ''; + }; +} diff --git a/modules/tmux/default.nix b/modules/tmux/default.nix new file mode 100644 index 0000000..b12ca71 --- /dev/null +++ b/modules/tmux/default.nix @@ -0,0 +1,5 @@ +{ + imports = [ + ./tmux.nix + ]; +} diff --git a/modules/tmux/tmux.nix b/modules/tmux/tmux.nix new file mode 100644 index 0000000..56d9d23 --- /dev/null +++ b/modules/tmux/tmux.nix @@ -0,0 +1,104 @@ +{ pkgs, ... }: + +{ + programs.tmux = { + enable = true; + terminal = "screen-256color"; # Ensures proper color support + shell = "${pkgs.zsh}/bin/zsh"; # Forces tmux to use Zsh by default + clock24 = true; + + plugins = with pkgs.tmuxPlugins; [ + vim-tmux-navigator + { + plugin = rose-pine; + extraConfig = '' + set -g @rose_pine_variant 'main' + set -g @rose_pine_host 'on' + set -g @rose_pine_user 'on' + set -g @rose_pine_directory 'on' + set -g @rose_pine_date_time '%a %b %d %H:%M:%S %Y' + set -g @rose_pine_left_separator ' > ' + set -g @rose_pine_right_separator ' < ' + set -g @rose_pine_field_separator ' | ' + set -g @rose_pine_window_separator ' - ' + set -g @rose_pine_window_status_separator " " + set -g @rose_pine_hostname_icon '󰒋' + set -g @rose_pine_date_time_icon '󰃰' + ''; + } + { + plugin = resurrect; + extraConfig = '' + # Resurrect Configuration - Save/restore tmux sessions with all details + set -g @resurrect-strategy-nvim 'session' + set -g @resurrect-strategy-vim 'session' + set -g @resurrect-strategy-pane 'bash' + set -g @resurrect-capture-pane-contents 'on' + set -g @resurrect-processes 'nvim vim ssh "~zsh" "~bash" opencode ranger fzf' + set -g @resurrect-dir '$HOME/.local/share/tmux/resurrect' + # Save command history in panes + set -g @resurrect-save-shell-history 'on' + ''; + } + { + plugin = continuum; + extraConfig = '' + # Continuum Configuration - Automatically save and restore sessions + set -g @continuum-restore 'on' + set -g @continuum-save-interval '5' # Save every 5 minutes for better persistence + set -g @continuum-boot 'on' # Start tmux automatically on boot + set -g @continuum-boot-options 'new-session -d -s main' # Create default session on boot + ''; + } + ]; + +extraConfig = '' + # Basic terminal setup + set -g default-terminal "screen-256color" + set-option -ga terminal-overrides ",xterm-256color:Tc" + set-option -g default-command "zsh -l" + setw -g mode-keys vi + set -g base-index 1 + set -g pane-base-index 1 + set -g status-position top + set -g status-style "bg=default" + + # Pane navigation + bind-key h select-pane -L + bind-key j select-pane -D + bind-key k select-pane -U + bind-key l select-pane -R + bind-key % split-window -h -c "#{pane_current_path}" + bind-key '"' split-window -v -c "#{pane_current_path}" + bind-key c new-window -c "#{pane_current_path}" + + # Prefix key + set -g prefix C-s + bind C-s send-prefix + + # Session management keybindings + bind-key n new-session -d # Create new session + bind-key C-n new-session # Create and attach new session + bind-key C-l list-sessions # List all sessions + bind-key C-d kill-session # Delete current session + + # Enable mouse and scrollback + set -g mouse on + setw -g history-limit 10000 + + # Automatic system clipboard copy for selections + bind -T copy-mode-vi y send -X copy-pipe-and-cancel "wl-copy" + bind -T copy-mode-vi Enter send -X copy-pipe-and-cancel "wl-copy" + + # Create resurrect directory if it doesn't exist + run-shell 'mkdir -p ~/.local/share/tmux/resurrect' + + # Pywal support - Load AFTER plugins so colors override rose-pine + if-shell "test -f ~/.cache/wal/colors-tmux.sh" \ + "source-file ~/.cache/wal/colors-tmux.sh" + # Watch for updates + run-shell "while inotifywait -e close_write ~/.cache/wal/colors-tmux.sh 2>/dev/null; do tmux source-file ~/.cache/wal/colors-tmux.sh; done &" +''; + }; +} + diff --git a/modules/virtualization/blackarch.nix b/modules/virtualization/blackarch.nix new file mode 100644 index 0000000..d393df4 --- /dev/null +++ b/modules/virtualization/blackarch.nix @@ -0,0 +1,21 @@ +{ pkgs, ... }: + +let + blackarchISO = "https://blackarch.org/blackarch-linux-live-2023.12.01-x86_64.iso"; # Change URL if outdated + vmStorage = "/var/lib/libvirt/images/blackarch.qcow2"; # Change this path if needed +in +pkgs.stdenv.mkDerivation { + name = "blackarch-vm"; + buildInputs = [ pkgs.qemu ]; + + unpackPhase = "true"; # No unpacking needed + + installPhase = '' + echo "Creating BlackArch VM disk..." + qemu-img create -f qcow2 ${vmStorage} 50G + echo "BlackArch VM disk created at ${vmStorage}" + ''; + + meta.description = "BlackArch Linux VM installation"; +} + diff --git a/modules/virtualization/default.nix b/modules/virtualization/default.nix new file mode 100644 index 0000000..e867944 --- /dev/null +++ b/modules/virtualization/default.nix @@ -0,0 +1,6 @@ +{ + imports = [ + ./vm.nix + ./blackarch.nix + ]; +} diff --git a/modules/virtualization/vm.nix b/modules/virtualization/vm.nix new file mode 100644 index 0000000..ad73dbf --- /dev/null +++ b/modules/virtualization/vm.nix @@ -0,0 +1,37 @@ +{ config, pkgs, ... }: + +{ + environment.systemPackages = with pkgs; [ + qemu + libvirt + uefi-run + lxc + swtpm + bottles + dosfstools + virt-manager + virt-viewer + dnsmasq + bridge-utils + ebtables + iptables + ]; + + virtualisation = { + libvirtd = { + enable = true; + qemu.runAsRoot = false; + }; + }; + + users.groups.libvirtd.members = [ "cody" ]; # Replace "cody" with your username + + systemd.services.libvirtd.wantedBy = [ "multi-user.target" ]; + + networking.firewall.allowedTCPPorts = [ 5900 ]; # VNC for VM access + + services.udev.packages = [ pkgs.qemu_kvm ]; + + nixpkgs.config.allowUnfree = true; +} + diff --git a/modules/waybar/default.nix b/modules/waybar/default.nix new file mode 100644 index 0000000..9b8b240 --- /dev/null +++ b/modules/waybar/default.nix @@ -0,0 +1,6 @@ +{ ... }: +{ + imports = [ (import ./waybar.nix) ] + ++ [ (import ./settings.nix) ] + ++ [ (import ./style.nix) ]; +} diff --git a/modules/waybar/settings.nix b/modules/waybar/settings.nix new file mode 100644 index 0000000..56fb499 --- /dev/null +++ b/modules/waybar/settings.nix @@ -0,0 +1,244 @@ +{ ... }: +{ + programs.waybar.settings.mainBar = { + position= "top"; + layer= "top"; + height= 30; + margin-top= 4; + margin-bottom= 0; + margin-left= 4; + margin-right= 4; + + modules-left= [ + "custom/icon" + "custom/separator" + "custom/separator" + "custom/separator" + "custom/separator" + "clock" + "custom/separator" + "custom/swaync" + ]; + + modules-center= [ + "hyprland/workspaces" + ]; + + modules-right= [ + #"hyprland/window" + "custom/cava_mviz" + "network" + "pulseaudio#audio" + "pulseaudio#mic" + "battery" + "custom/power" + "custom/separator" + ]; + + "hyprland/window" = { + format = "{}"; + exec = "hyprctl activewindow | grep class | awk '{print $2}'"; + separate-outputs = true; + max-length = 35; + }; + + # clock= { + # calendar = { + # format = { today = "{}"; }; + # }; + # # format = " {:%H:%M}"; + # format = "{:%H:%M}"; + # tooltip= "true"; + # tooltip-format= "{:%Y %B}\n{calendar}"; + # format-alt= " {:%d/%m}"; + # }; + # + clock = { + format = "{:%H:%M}"; + tooltip = true; + tooltip-format = "{:%Y %B}\n{calendar}"; + on-click = "$HOME/.local/share/bin/open-calendar-floating.sh"; + }; + + "hyprland/workspaces" = { + format = "{icon}"; + + format-icons = { + active = ""; # filled circle + default = ""; # empty circle + }; + + persistent-workspaces = { + "*" = 2; # always show exactly 3 workspaces + }; + + sort-by-number = true; + + on-scroll-up = "hyprctl dispatch workspace e-1"; + on-scroll-down = "hyprctl dispatch workspace e+1"; + on-click = "activate"; +}; + + memory= { + format= " {}%"; + interval= 2; + }; + + cpu= { + format= " {usage}%"; + format-alt= " {avg_frequency} GHz"; + interval= 2; + }; + + + network = { + format-wifi = "  "; + format-ethernet = ""; + tooltip-format = "Connected to {essid} {ifname} via {gwaddr}"; + format-linked = "{ifname} (No IP)"; + format-disconnected = " "; + on-click = "bash $HOME/.dotfiles/scripts/rofi-network.sh"; + + }; + + # network = { + # format-wifi = " "; + # format-ethernet = ""; + # tooltip-format = "Connected to {essid} {ifname} via {gwaddr}"; + # format-linked = "{ifname} (No IP)"; + # format-disconnected = " "; + # }; + # + backlight = { + format = "{icon} {percent}%"; + format-icons = [ + "" + "" + "" + "" + "" + "" + "" + "" + "" + ]; + interval = 2; + }; + + "custom/right-arr" = { + format = "  "; + }; + + battery = { + format = "{icon} {capacity}% "; + format-alt = "{icon} {time}"; + format-charging = " {capacity}% "; + format-icons = [" " " " " " " "]; + + }; + + tray= { + icon-size= 20; + spacing= 8; + }; + +"pulseaudio#audio" = { + format = "{format_source}"; + format-source = "  {volume} "; + format-source-muted = " 󰸈 {volume} "; + on-click = "wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle"; + on-scroll-up = "wpctl set-volume @DEFAULT_AUDIO_SINK@ -1%"; + on-scroll-down = "wpctl set-volume @DEFAULT_AUDIO_SINK@ +1%"; + scroll-step = 5; + tooltip = false; + }; + + "pulseaudio#mic" = { + format = "{format_source}"; + format-source = "  {volume} "; + format-source-muted = "  {volume} "; + on-click = "wpctl set-mute @DEFAULT_AUDIO_SOURCE@ toggle"; + on-scroll-up = "wpctl set-volume @DEFAULT_AUDIO_SOURCE@ -1%"; + on-scroll-down = "wpctl set-volume @DEFAULT_AUDIO_SOURCE@ +1%"; + scroll-step = 5; + tooltip = true; + }; + + "pulseaudio/slider" = { + min = 0; + max = 100; + orientation = "horizontal"; + }; + +# pulseaudio= { + # format= "{icon} {volume} {format_source}"; + # format-source = "  {volume} "; + # format-source-muted = "  "; + # format-bluetooth = " ᛒ {volume} "; + # format-bluetooth-muted = " "; + # format-muted= " {format_source}"; + # format-icons= { + # default= ["" "" ""]; + # }; + # scroll-step= 5; + # + # }; + # + + "custom/cava_mviz" = { + exec = "~/.local/share/bin/waybar-cava.sh"; + format = " {} "; + tooltip = false; + }; + + "custom/swaync" = { + tooltip = true; + "tooltip-format" = "Left Click: Launch Notification Center\nRight Click: Do not Disturb"; + format = " {icon} "; + "format-icons" = { + notification = ""; + none = ""; + "dnd-notification" = ""; + "dnd-none" = ""; + "inhibited-notification" = ""; + "inhibited-none" = ""; + "dnd-inhibited-notification" = ""; + "dnd-inhibited-none" = ""; + }; + "return-type" = "json"; + "exec-if" = "which swaync-client"; + exec = "swaync-client -swb"; + "on-click" = "systemctl --user start swaync.service; swaync-client -t"; + "on-click-right" = "systemctl --user start swaync.service; swaync-client -d"; + escape = true; + }; + + + "custom/icon"= { + format= ""; + on-click= "sh -c 'rofi -show drun -theme fullscreen-grid &'"; + tooltip= "App Launcher"; + }; + + "custom/separtor" = { + format = " "; + }; + + "custom/browser" = { + format = " "; + }; + + "custom/window-icon" = { + # to be added + }; + + "custom/power" = { + format = " "; + tooltip = "Power menu"; + on-click = "sh -c 'wlogout &'"; + }; + + }; +} + + diff --git a/modules/waybar/style.nix b/modules/waybar/style.nix new file mode 100644 index 0000000..42e17fc --- /dev/null +++ b/modules/waybar/style.nix @@ -0,0 +1,183 @@ +{ ... }: +let custom = { + font = "JetBrainsMono Nerd Font"; + font_size = "14px"; + font_weight = "bold"; + }; +in +{ + programs.waybar.style = '' + + @import url("colors-waybar.css"); /* Dynamically generated by pywal */ + + * { + padding: 0; + margin: 0; + font-family: ${custom.font}; + font-size: ${custom.font_size}; + font-weight: ${custom.font_weight}; + } + + window#waybar { + background-color: transparent; + } + + .modules-left { + background-color: @color0; + opacity: 0.9; + border-radius: 4px; + padding-right: 8px; + padding-left: 15px; + } + + .modules-center { + background-color: @color0; + border-radius: 4px; + opacity: 0.9; + padding-right: 10px; + padding-left: 10px; + } + + .modules-right { + background-color: @color0; + border-radius: 4px; + opacity: 0.9; + padding-right: 15px; + padding-left: 15px; + } + + #custom-icon { + font-size: 24px; + color: @color4; + padding-right: 10px; + margin-right: 5px; + } + + #cpu, + #memory, + #temperature { + font-size: 14px; + background: @color0; + margin-top: 5px; + margin-bottom: 5px; + } + + #cpu { + color: #8ec07c; + padding: 0px 10px 0px 12px; + border-radius: 5px 0px 0px 5px; + } + + #memory { + color: #000000; + padding: 0px 10px 0px 0px; + } + + #temperature { + color: #000000; + padding: 0px 12px 0px 0px; + border-radius: 0px 5px 5px 0px; + } + + #window { + margin-right: 10px; + margin-left: 10px; + color: #000000; + } + + #workspaces button:nth-child(1) label { + color: @color4; + margin: 0px 8px; + } + + #workspaces button:nth-child(2) label { + color: @color5; + margin: 0px 8px; + } + + #workspaces button:nth-child(3) label { + color: @color6; + margin: 0px 8px; + } + + #workspaces button:nth-child(4) label { + color: @color7; + margin: 0px 8px; + } + + #workspaces button:nth-child(5) label { + color: @color8; + margin: 0px 8px; + } + + #workspaces button:nth-child(6) label { + color: @color8; + margin: 0px 8px; + } + + #battery { + color: @color8; + margin: 0px 10px 0px 0px; + } + + #pulseaudio, + #backlight { + font-size: 14px; + background: @color0; + margin-top: 5px; + margin-bottom: 5px; + color: @color4; + padding: 0px 10px 0px 10px; + border-radius: 5px 0px 0px 5px; + } + + #pulseaudio { + color: @color5; + padding: 0px 10px 0px 0px; + border-radius: 0px 5px 5px 0px; + } + + #custom-swaync { + color: @color7; + } + + #custom-cava_mviz { + color: @color8; + } + + #custom-right-arr { + color: @color4; + } + + #custom-power { + color: @color7 + } + + #network { + color: @color4; + margin-right: 10px; + } + + #custom-dot { + color: @color5; + padding-left: 10px; + padding-right: 10px; + } + + #custom-dot-alt { + color: #a5adcb; + padding-left: 10px; + padding-right: 10px; + } + + #clock { + padding-left: 10px; + color: @color4; + background-color: @color0; + padding-right: 10px; + margin-top: 5px; + margin-bottom: 5px; + border-radius: 5px; + } + ''; +} diff --git a/modules/waybar/waybar.nix b/modules/waybar/waybar.nix new file mode 100644 index 0000000..c50e873 --- /dev/null +++ b/modules/waybar/waybar.nix @@ -0,0 +1,9 @@ +{ pkgs, ... }: +{ + programs.waybar = { + enable = true; + }; + programs.waybar.package = pkgs.waybar.overrideAttrs (oa: { + mesonFlags = (oa.mesonFlags or [ ]) ++ [ "-Dexperimental=true" ]; + }); +} diff --git a/modules/wlogout/default.nix b/modules/wlogout/default.nix new file mode 100644 index 0000000..d7a0c9a --- /dev/null +++ b/modules/wlogout/default.nix @@ -0,0 +1,6 @@ +{ + imports = [ + ./wlogout.nix + ]; +} + diff --git a/modules/wlogout/icons/hibernate.png b/modules/wlogout/icons/hibernate.png new file mode 100644 index 0000000..bf2b001 Binary files /dev/null and b/modules/wlogout/icons/hibernate.png differ diff --git a/modules/wlogout/icons/lock.png b/modules/wlogout/icons/lock.png new file mode 100644 index 0000000..da59b10 Binary files /dev/null and b/modules/wlogout/icons/lock.png differ diff --git a/modules/wlogout/icons/logout.png b/modules/wlogout/icons/logout.png new file mode 100644 index 0000000..8a25922 Binary files /dev/null and b/modules/wlogout/icons/logout.png differ diff --git a/modules/wlogout/icons/reboot.png b/modules/wlogout/icons/reboot.png new file mode 100644 index 0000000..e5fd221 Binary files /dev/null and b/modules/wlogout/icons/reboot.png differ diff --git a/modules/wlogout/icons/shutdown.png b/modules/wlogout/icons/shutdown.png new file mode 100644 index 0000000..663ca03 Binary files /dev/null and b/modules/wlogout/icons/shutdown.png differ diff --git a/modules/wlogout/icons/suspend.png b/modules/wlogout/icons/suspend.png new file mode 100644 index 0000000..af099b9 Binary files /dev/null and b/modules/wlogout/icons/suspend.png differ diff --git a/modules/wlogout/wlogout.nix b/modules/wlogout/wlogout.nix new file mode 100644 index 0000000..20c82fc --- /dev/null +++ b/modules/wlogout/wlogout.nix @@ -0,0 +1,112 @@ +{ config, lib, ... }: { + programs.wlogout = { + enable = true; + layout = [ + { + label = "shutdown"; + action = "sleep 1; systemctl poweroff"; + text = "Shutdown"; + keybind = "s"; + } + { + label = "reboot"; + action = "sleep 1; systemctl reboot"; + text = "Reboot"; + keybind = "r"; + } + { + label = "logout"; + action = "sleep 1; hyprctl dispatch exit"; + text = "Exit"; + keybind = "e"; + } + { + label = "suspend"; + action = "sleep 1; systemctl suspend"; + text = "Suspend"; + keybind = "u"; + } + { + label = "lock"; + action = "sleep 1; hyprlock"; + text = "Lock"; + keybind = "l"; + } + { + label = "hibernate"; + action = "sleep 1; systemctl hibernate"; + text = "Hibernate"; + keybind = "h"; + } + ]; + style = '' + @import url("./colors-waybar.css"); + + * { + font-family: "JetBrainsMono NF", FontAwesome, sans-serif; + background-image: none; + transition: 20ms; + } + window { + background-color: alpha(@background, 0.9); + } + button { + color: @foreground; + font-size: 20px; + background-repeat: no-repeat; + background-position: center; + background-size: 15%; + border-style: solid; + background-color: alpha(@background, 0.3); + border: 3px solid @foreground; + box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19); + } + button:focus, + button:active, + button:hover { + color: @color2; + background-color: alpha(@background, 0.5); + border: 3px solid @color2; + } + #logout { + margin: 10px; + border-radius: 20px; + background-image: image(url("icons/logout.png")); + } + #suspend { + margin: 10px; + border-radius: 20px; + background-image: image(url("icons/suspend.png")); + } + #shutdown { + margin: 10px; + border-radius: 20px; + background-image: image(url("icons/shutdown.png")); + } + #reboot { + margin: 10px; + border-radius: 20px; + background-image: image(url("icons/reboot.png")); + } + #lock { + margin: 10px; + border-radius: 20px; + background-image: image(url("icons/lock.png")); + } + #hibernate { + margin: 10px; + border-radius: 20px; + background-image: image(url("icons/hibernate.png")); + } + ''; + }; + + home.file.".config/wlogout/icons" = { + source = ./icons; + recursive = true; + }; + + # Note: colors.css is managed by set-wallpaper.sh script which copies from pywal cache + # It cannot be managed by home-manager due to pure evaluation restrictions +} + diff --git a/modules/yazi/default.nix b/modules/yazi/default.nix new file mode 100644 index 0000000..9364039 --- /dev/null +++ b/modules/yazi/default.nix @@ -0,0 +1,30 @@ +{pkgs, ...}: let + settings = import ./yazi.nix; + keymap = import ./keymap.nix; + theme = import ./theme.nix; +in { + programs.yazi = { + enable = true; + enableZshIntegration = true; + enableBashIntegration = true; + enableFishIntegration = true; + shellWrapperName = "yy"; + settings = settings; + keymap = keymap; + theme = theme; + plugins = { + lazygit = pkgs.yaziPlugins.lazygit; + full-border = pkgs.yaziPlugins.full-border; + git = pkgs.yaziPlugins.git; + smart-enter = pkgs.yaziPlugins.smart-enter; + }; + + initLua = '' + require("full-border"):setup() + require("git"):setup() + require("smart-enter"):setup { + open_multi = true, + } + ''; + }; +} diff --git a/modules/yazi/keymap.nix b/modules/yazi/keymap.nix new file mode 100644 index 0000000..c8e2561 --- /dev/null +++ b/modules/yazi/keymap.nix @@ -0,0 +1,1201 @@ +{ + mgr = { + keymap = [ + { + on = ""; + run = "escape"; + desc = "Exit visual mode, clear selected, or cancel search"; + } + { + on = ""; + run = "escape"; + desc = "Exit visual mode, clear selected, or cancel search"; + } + { + on = "q"; + run = "quit"; + desc = "Quit the process"; + } + { + on = "Q"; + run = "quit --no-cwd-file"; + desc = "Quit the process without outputting cwd-file"; + } + { + on = ""; + run = "close"; + desc = "Close the current tab, or quit if it's last"; + } + { + on = ""; + run = "suspend"; + desc = "Suspend the process"; + } + { + on = "k"; + run = "arrow -1"; + desc = "Move cursor up"; + } + { + on = "j"; + run = "arrow 1"; + desc = "Move cursor down"; + } + { + on = ""; + run = "arrow -1"; + desc = "Move cursor up"; + } + { + on = ""; + run = "arrow 1"; + desc = "Move cursor down"; + } + { + on = ""; + run = "arrow -50%"; + desc = "Move cursor up half page"; + } + { + on = ""; + run = "arrow 50%"; + desc = "Move cursor down half page"; + } + { + on = ""; + run = "arrow -100%"; + desc = "Move cursor up one page"; + } + { + on = ""; + run = "arrow 100%"; + desc = "Move cursor down one page"; + } + { + on = ""; + run = "arrow -50%"; + desc = "Move cursor up half page"; + } + { + on = ""; + run = "arrow 50%"; + desc = "Move cursor down half page"; + } + { + on = ""; + run = "arrow -100%"; + desc = "Move cursor up one page"; + } + { + on = ""; + run = "arrow 100%"; + desc = "Move cursor down one page"; + } + { + on = ["g" "g"]; + run = "arrow top"; + desc = "Move cursor to the top"; + } + { + on = "G"; + run = "arrow bot"; + desc = "Move cursor to the bottom"; + } + { + on = "h"; + run = "leave"; + desc = "Go back to the parent directory"; + } + { + on = "l"; + run = "enter"; + desc = "Enter the child directory"; + } + { + on = ""; + run = "leave"; + desc = "Go back to the parent directory"; + } + { + on = ""; + run = "enter"; + desc = "Enter the child directory"; + } + { + on = "H"; + run = "back"; + desc = "Go back to the previous directory"; + } + { + on = "L"; + run = "forward"; + desc = "Go forward to the next directory"; + } + { + on = ""; + run = ["toggle" "arrow 1"]; + desc = "Toggle the current selection state"; + } + { + on = ""; + run = "toggle_all --state=on"; + desc = "Select all files"; + } + { + on = ""; + run = "toggle_all"; + desc = "Invert selection of all files"; + } + { + on = "v"; + run = "visual_mode"; + desc = "Enter visual mode (selection mode)"; + } + { + on = "V"; + run = "visual_mode --unset"; + desc = "Enter visual mode (unset mode)"; + } + { + on = "K"; + run = "seek -5"; + desc = "Seek up 5 units in the preview"; + } + { + on = "J"; + run = "seek 5"; + desc = "Seek down 5 units in the preview"; + } + { + on = ""; + run = "spot"; + desc = "Spot hovered file"; + } + { + on = "o"; + run = "open"; + desc = "Open selected files"; + } + { + on = "O"; + run = "open --interactive"; + desc = "Open selected files interactively"; + } + { + on = ""; + run = "open"; + desc = "Open selected files"; + } + { + on = ""; + run = "open --interactive"; + desc = "Open selected files interactively"; + } + { + on = "y"; + run = "yank"; + desc = "Yank selected files (copy)"; + } + { + on = "x"; + run = "yank --cut"; + desc = "Yank selected files (cut)"; + } + { + on = "p"; + run = "paste"; + desc = "Paste yanked files"; + } + { + on = "P"; + run = "paste --force"; + desc = "Paste yanked files (overwrite if the destination exists)"; + } + { + on = "-"; + run = "link"; + desc = "Symlink the absolute path of yanked files"; + } + { + on = "_"; + run = "link --relative"; + desc = "Symlink the relative path of yanked files"; + } + { + on = ""; + run = "hardlink"; + desc = "Hardlink yanked files"; + } + { + on = "Y"; + run = "unyank"; + desc = "Cancel the yank status"; + } + { + on = "X"; + run = "unyank"; + desc = "Cancel the yank status"; + } + { + on = "d"; + run = "remove"; + desc = "Trash selected files"; + } + { + on = "D"; + run = "remove --permanently"; + desc = "Permanently delete selected files"; + } + { + on = "a"; + run = "create"; + desc = "Create a file (ends with / for directories)"; + } + { + on = "r"; + run = "rename --cursor=before_ext"; + desc = "Rename selected file(s)"; + } + { + on = ";"; + run = "shell --interactive"; + desc = "Run a shell command"; + } + { + on = ":"; + run = "shell --block --interactive"; + desc = "Run a shell command (block until finishes)"; + } + { + on = "."; + run = "hidden toggle"; + desc = "Toggle the visibility of hidden files"; + } + { + on = "s"; + run = "search --via=fd"; + desc = "Search files by name via fd"; + } + { + on = "S"; + run = "search --via=rg"; + desc = "Search files by content via ripgrep"; + } + { + on = ""; + run = "escape --search"; + desc = "Cancel the ongoing search"; + } + { + on = "z"; + run = "plugin zoxide"; + desc = "Jump to a directory via zoxide"; + } + { + on = "Z"; + run = "plugin fzf"; + desc = "Jump to a file/directory via fzf"; + } + { + on = ["m" "s"]; + run = "linemode size"; + desc = "Linemode: size"; + } + { + on = ["m" "p"]; + run = "linemode permissions"; + desc = "Linemode: permissions"; + } + { + on = ["m" "b"]; + run = "linemode btime"; + desc = "Linemode: btime"; + } + { + on = ["m" "m"]; + run = "linemode mtime"; + desc = "Linemode: mtime"; + } + { + on = ["m" "o"]; + run = "linemode owner"; + desc = "Linemode: owner"; + } + { + on = ["m" "n"]; + run = "linemode none"; + desc = "Linemode: none"; + } + { + on = ["c" "c"]; + run = "copy path"; + desc = "Copy the file path"; + } + { + on = ["c" "d"]; + run = "copy dirname"; + desc = "Copy the directory path"; + } + { + on = ["c" "f"]; + run = "copy filename"; + desc = "Copy the filename"; + } + { + on = ["c" "n"]; + run = "copy name_without_ext"; + desc = "Copy the filename without extension"; + } + { + on = "f"; + run = "filter --smart"; + desc = "Filter files"; + } + { + on = "/"; + run = "find --smart"; + desc = "Find next file"; + } + { + on = "?"; + run = "find --previous --smart"; + desc = "Find previous file"; + } + { + on = "n"; + run = "find_arrow"; + desc = "Goto the next found"; + } + { + on = "N"; + run = "find_arrow --previous"; + desc = "Goto the previous found"; + } + { + on = ["," "m"]; + run = ["sort mtime --reverse=no" "linemode mtime"]; + desc = "Sort by modified time"; + } + { + on = ["," "M"]; + run = ["sort mtime --reverse" "linemode mtime"]; + desc = "Sort by modified time (reverse)"; + } + { + on = ["," "b"]; + run = ["sort btime --reverse=no" "linemode btime"]; + desc = "Sort by birth time"; + } + { + on = ["," "B"]; + run = ["sort btime --reverse" "linemode btime"]; + desc = "Sort by birth time (reverse)"; + } + { + on = ["," "e"]; + run = "sort extension --reverse=no"; + desc = "Sort by extension"; + } + { + on = ["," "E"]; + run = "sort extension --reverse"; + desc = "Sort by extension (reverse)"; + } + { + on = ["," "a"]; + run = "sort alphabetical --reverse=no"; + desc = "Sort alphabetically"; + } + { + on = ["," "A"]; + run = "sort alphabetical --reverse"; + desc = "Sort alphabetically (reverse)"; + } + { + on = ["," "n"]; + run = "sort natural --reverse=no"; + desc = "Sort naturally"; + } + { + on = ["," "N"]; + run = "sort natural --reverse"; + desc = "Sort naturally (reverse)"; + } + { + on = ["," "s"]; + run = ["sort size --reverse=no" "linemode size"]; + desc = "Sort by size"; + } + { + on = ["," "S"]; + run = ["sort size --reverse" "linemode size"]; + desc = "Sort by size (reverse)"; + } + { + on = ["," "r"]; + run = "sort random --reverse=no"; + desc = "Sort randomly"; + } + { + on = ["g" "h"]; + run = "cd ~"; + desc = "Go home"; + } + { + on = ["g" "c"]; + run = "cd ~/.config"; + desc = "Goto ~/.config"; + } + { + on = ["g" "d"]; + run = "cd ~/Downloads"; + desc = "Goto ~/Downloads"; + } + { + on = ["g" ""]; + run = "cd --interactive"; + desc = "Jump interactively"; + } + { + on = "t"; + run = "tab_create --current"; + desc = "Create a new tab with CWD"; + } + { + on = "1"; + run = "tab_switch 0"; + desc = "Switch to the first tab"; + } + { + on = "2"; + run = "tab_switch 1"; + desc = "Switch to the second tab"; + } + { + on = "3"; + run = "tab_switch 2"; + desc = "Switch to the third tab"; + } + { + on = "4"; + run = "tab_switch 3"; + desc = "Switch to the fourth tab"; + } + { + on = "5"; + run = "tab_switch 4"; + desc = "Switch to the fifth tab"; + } + { + on = "6"; + run = "tab_switch 5"; + desc = "Switch to the sixth tab"; + } + { + on = "7"; + run = "tab_switch 6"; + desc = "Switch to the seventh tab"; + } + { + on = "8"; + run = "tab_switch 7"; + desc = "Switch to the eighth tab"; + } + { + on = "9"; + run = "tab_switch 8"; + desc = "Switch to the ninth tab"; + } + { + on = "["; + run = "tab_switch -1 --relative"; + desc = "Switch to the previous tab"; + } + { + on = "]"; + run = "tab_switch 1 --relative"; + desc = "Switch to the next tab"; + } + { + on = "{"; + run = "tab_swap -1"; + desc = "Swap current tab with previous tab"; + } + { + on = "}"; + run = "tab_swap 1"; + desc = "Swap current tab with next tab"; + } + { + on = "w"; + run = "tasks_show"; + desc = "Show task manager"; + } + { + on = "~"; + run = "help"; + desc = "Open help"; + } + { + on = ""; + run = "help"; + desc = "Open help"; + } + ]; + prepend_keymap = [ + { + on = ["g" "i"]; + run = "plugin lazygit"; + desc = "run lazygit"; + } + { + on = "l"; + run = "plugin smart-enter"; + desc = "Enter the child directory, or open the file"; + } + ]; + }; + tasks = { + keymap = [ + { + on = ""; + run = "close"; + desc = "Close task manager"; + } + { + on = ""; + run = "close"; + desc = "Close task manager"; + } + { + on = ""; + run = "close"; + desc = "Close task manager"; + } + { + on = "w"; + run = "close"; + desc = "Close task manager"; + } + { + on = "k"; + run = "arrow -1"; + desc = "Move cursor up"; + } + { + on = "j"; + run = "arrow 1"; + desc = "Move cursor down"; + } + { + on = ""; + run = "arrow -1"; + desc = "Move cursor up"; + } + { + on = ""; + run = "arrow 1"; + desc = "Move cursor down"; + } + { + on = ""; + run = "inspect"; + desc = "Inspect the task"; + } + { + on = "x"; + run = "cancel"; + desc = "Cancel the task"; + } + { + on = "~"; + run = "help"; + desc = "Open help"; + } + { + on = ""; + run = "help"; + desc = "Open help"; + } + ]; + }; + spot = { + keymap = [ + { + on = ""; + run = "close"; + desc = "Close the spot"; + } + { + on = ""; + run = "close"; + desc = "Close the spot"; + } + { + on = ""; + run = "close"; + desc = "Close the spot"; + } + { + on = ""; + run = "close"; + desc = "Close the spot"; + } + { + on = "k"; + run = "arrow -1"; + desc = "Move cursor up"; + } + { + on = "j"; + run = "arrow 1"; + desc = "Move cursor down"; + } + { + on = "h"; + run = "swipe -1"; + desc = "Swipe to the previous file"; + } + { + on = "l"; + run = "swipe 1"; + desc = "Swipe to the next file"; + } + { + on = ""; + run = "arrow -1"; + desc = "Move cursor up"; + } + { + on = ""; + run = "arrow 1"; + desc = "Move cursor down"; + } + { + on = ""; + run = "swipe -1"; + desc = "Swipe to the next file"; + } + { + on = ""; + run = "swipe 1"; + desc = "Swipe to the previous file"; + } + { + on = ["c" "c"]; + run = "copy cell"; + desc = "Copy selected cell"; + } + { + on = "~"; + run = "help"; + desc = "Open help"; + } + { + on = ""; + run = "help"; + desc = "Open help"; + } + ]; + }; + pick = { + keymap = [ + { + on = ""; + run = "close"; + desc = "Cancel pick"; + } + { + on = ""; + run = "close"; + desc = "Cancel pick"; + } + { + on = ""; + run = "close"; + desc = "Cancel pick"; + } + { + on = ""; + run = "close --submit"; + desc = "Submit the pick"; + } + { + on = "k"; + run = "arrow -1"; + desc = "Move cursor up"; + } + { + on = "j"; + run = "arrow 1"; + desc = "Move cursor down"; + } + { + on = ""; + run = "arrow -1"; + desc = "Move cursor up"; + } + { + on = ""; + run = "arrow 1"; + desc = "Move cursor down"; + } + { + on = "~"; + run = "help"; + desc = "Open help"; + } + { + on = ""; + run = "help"; + desc = "Open help"; + } + ]; + }; + input = { + keymap = [ + { + on = ""; + run = "close"; + desc = "Cancel input"; + } + { + on = ""; + run = "close --submit"; + desc = "Submit input"; + } + { + on = ""; + run = "escape"; + desc = "Go back the normal mode, or cancel input"; + } + { + on = ""; + run = "escape"; + desc = "Go back the normal mode, or cancel input"; + } + { + on = "i"; + run = "insert"; + desc = "Enter insert mode"; + } + { + on = "I"; + run = ["move first-char" "insert"]; + desc = "Move to the BOL, and enter insert mode"; + } + { + on = "a"; + run = "insert --append"; + desc = "Enter append mode"; + } + { + on = "A"; + run = ["move eol" "insert --append"]; + desc = "Move to the EOL, and enter append mode"; + } + { + on = "v"; + run = "visual"; + desc = "Enter visual mode"; + } + { + on = "r"; + run = "replace"; + desc = "Replace a single character"; + } + { + on = "V"; + run = ["move bol" "visual" "move eol"]; + desc = "Select from BOL to EOL"; + } + { + on = ""; + run = ["move eol" "visual" "move bol"]; + desc = "Select from EOL to BOL"; + } + { + on = ""; + run = ["move bol" "visual" "move eol"]; + desc = "Select from BOL to EOL"; + } + { + on = "h"; + run = "move -1"; + desc = "Move back a character"; + } + { + on = "l"; + run = "move 1"; + desc = "Move forward a character"; + } + { + on = ""; + run = "move -1"; + desc = "Move back a character"; + } + { + on = ""; + run = "move 1"; + desc = "Move forward a character"; + } + { + on = ""; + run = "move -1"; + desc = "Move back a character"; + } + { + on = ""; + run = "move 1"; + desc = "Move forward a character"; + } + { + on = "b"; + run = "backward"; + desc = "Move back to the start of the current or previous word"; + } + { + on = "B"; + run = "backward --far"; + desc = "Move back to the start of the current or previous WORD"; + } + { + on = "w"; + run = "forward"; + desc = "Move forward to the start of the next word"; + } + { + on = "W"; + run = "forward --far"; + desc = "Move forward to the start of the next WORD"; + } + { + on = "e"; + run = "forward --end-of-word"; + desc = "Move forward to the end of the current or next word"; + } + { + on = "E"; + run = "forward --far --end-of-word"; + desc = "Move forward to the end of the current or next WORD"; + } + { + on = ""; + run = "backward"; + desc = "Move back to the start of the current or previous word"; + } + { + on = ""; + run = "forward --end-of-word"; + desc = "Move forward to the end of the current or next word"; + } + { + on = "0"; + run = "move bol"; + desc = "Move to the BOL"; + } + { + on = "$"; + run = "move eol"; + desc = "Move to the EOL"; + } + { + on = "_"; + run = "move first-char"; + desc = "Move to the first non-whitespace character"; + } + { + on = "^"; + run = "move first-char"; + desc = "Move to the first non-whitespace character"; + } + { + on = ""; + run = "move bol"; + desc = "Move to the BOL"; + } + { + on = ""; + run = "move eol"; + desc = "Move to the EOL"; + } + { + on = ""; + run = "move bol"; + desc = "Move to the BOL"; + } + { + on = ""; + run = "move eol"; + desc = "Move to the EOL"; + } + { + on = ""; + run = "backspace"; + desc = "Delete the character before the cursor"; + } + { + on = ""; + run = "backspace --under"; + desc = "Delete the character under the cursor"; + } + { + on = ""; + run = "backspace"; + desc = "Delete the character before the cursor"; + } + { + on = ""; + run = "backspace --under"; + desc = "Delete the character under the cursor"; + } + { + on = ""; + run = "kill bol"; + desc = "Kill backwards to the BOL"; + } + { + on = ""; + run = "kill eol"; + desc = "Kill forwards to the EOL"; + } + { + on = ""; + run = "kill backward"; + desc = "Kill backwards to the start of the current word"; + } + { + on = ""; + run = "kill forward"; + desc = "Kill forwards to the end of the current word"; + } + { + on = "d"; + run = "delete --cut"; + desc = "Cut the selected characters"; + } + { + on = "D"; + run = ["delete --cut" "move eol"]; + desc = "Cut until the EOL"; + } + { + on = "c"; + run = "delete --cut --insert"; + desc = "Cut the selected characters, and enter insert mode"; + } + { + on = "C"; + run = ["delete --cut --insert" "move eol"]; + desc = "Cut until the EOL, and enter insert mode"; + } + { + on = "x"; + run = ["delete --cut" "move 1 --in-operating"]; + desc = "Cut the current character"; + } + { + on = "y"; + run = "yank"; + desc = "Copy the selected characters"; + } + { + on = "p"; + run = "paste"; + desc = "Paste the copied characters after the cursor"; + } + { + on = "P"; + run = "paste --before"; + desc = "Paste the copied characters before the cursor"; + } + { + on = "u"; + run = "undo"; + desc = "Undo the last operation"; + } + { + on = ""; + run = "redo"; + desc = "Redo the last operation"; + } + { + on = "~"; + run = "help"; + desc = "Open help"; + } + { + on = ""; + run = "help"; + desc = "Open help"; + } + ]; + }; + confirm = { + keymap = [ + { + on = ""; + run = "close"; + desc = "Cancel the confirm"; + } + { + on = ""; + run = "close"; + desc = "Cancel the confirm"; + } + { + on = ""; + run = "close"; + desc = "Cancel the confirm"; + } + { + on = ""; + run = "close --submit"; + desc = "Submit the confirm"; + } + { + on = "n"; + run = "close"; + desc = "Cancel the confirm"; + } + { + on = "y"; + run = "close --submit"; + desc = "Submit the confirm"; + } + { + on = "k"; + run = "arrow -1"; + desc = "Move cursor up"; + } + { + on = "j"; + run = "arrow 1"; + desc = "Move cursor down"; + } + { + on = ""; + run = "arrow -1"; + desc = "Move cursor up"; + } + { + on = ""; + run = "arrow 1"; + desc = "Move cursor down"; + } + { + on = "~"; + run = "help"; + desc = "Open help"; + } + { + on = ""; + run = "help"; + desc = "Open help"; + } + ]; + }; + cmp = { + keymap = [ + { + on = ""; + run = "close"; + desc = "Cancel completion"; + } + { + on = ""; + run = "close --submit"; + desc = "Submit the completion"; + } + { + on = ""; + run = ["close --submit" "close_input --submit"]; + desc = "Submit the completion and input"; + } + { + on = ""; + run = "arrow -1"; + desc = "Move cursor up"; + } + { + on = ""; + run = "arrow 1"; + desc = "Move cursor down"; + } + { + on = ""; + run = "arrow -1"; + desc = "Move cursor up"; + } + { + on = ""; + run = "arrow 1"; + desc = "Move cursor down"; + } + { + on = ""; + run = "arrow -1"; + desc = "Move cursor up"; + } + { + on = ""; + run = "arrow 1"; + desc = "Move cursor down"; + } + { + on = "~"; + run = "help"; + desc = "Open help"; + } + { + on = ""; + run = "help"; + desc = "Open help"; + } + ]; + }; + help = { + keymap = [ + { + on = ""; + run = "escape"; + desc = "Clear the filter, or hide the help"; + } + { + on = ""; + run = "escape"; + desc = "Clear the filter, or hide the help"; + } + { + on = ""; + run = "close"; + desc = "Hide the help"; + } + { + on = "k"; + run = "arrow -1"; + desc = "Move cursor up"; + } + { + on = "j"; + run = "arrow 1"; + desc = "Move cursor down"; + } + { + on = ""; + run = "arrow -1"; + desc = "Move cursor up"; + } + { + on = ""; + run = "arrow 1"; + desc = "Move cursor down"; + } + { + on = "f"; + run = "filter"; + desc = "Apply a filter for the help items"; + } + ]; + }; +} diff --git a/modules/yazi/theme.nix b/modules/yazi/theme.nix new file mode 100644 index 0000000..392eb24 --- /dev/null +++ b/modules/yazi/theme.nix @@ -0,0 +1,3404 @@ +{ + flavor = { + dark = ""; + light = ""; + }; + mgr = { + marker_marked = { + fg = "lightcyan"; + bg = "lightcyan"; + }; + tab_width = 1; + border_symbol = "│"; + }; + mode = {}; + status = { + overall = {bold = true;}; + sep_left = ["░▒▓" "▓▒░"]; + sep_right = ["░▒▓" "▓▒░"]; + }; + which = { + cols = 3; + separator = "  "; + }; + confirm = { + border = {fg = "gray";}; + title = { + fg = "blue"; + bold = true; + }; + content = {}; + list = {}; + btn_yes = { + bg = "green"; + fg = "black"; + bold = true; + }; + btn_no = { + bg = "red"; + fg = "black"; + bold = true; + }; + btn_labels = [" [Y]es " " (N)o "]; + }; + spot = { + border = {fg = "blue";}; + title = {fg = "blue";}; + tbl_col = {fg = "blue";}; + tbl_cell = { + fg = "yellow"; + reversed = true; + }; + }; + notify = { + title_info = {fg = "green";}; + title_warn = {fg = "yellow";}; + title_error = {fg = "red";}; + icon_info = ""; + icon_warn = ""; + icon_error = ""; + }; + pick = {}; + input = {}; + cmp = { + active = {reversed = true;}; + inactive = {}; + icon_file = ""; + icon_folder = ""; + icon_command = ""; + }; + tasks = {}; + help = {}; + filetype = {}; + icon = { + globs = []; + dirs = [ + { + name = ".config"; + text = ""; + } + { + name = ".git"; + text = ""; + } + { + name = ".github"; + text = ""; + } + { + name = ".npm"; + text = ""; + } + { + name = "Desktop"; + text = ""; + } + { + name = "Development"; + text = ""; + } + { + name = "Documents"; + text = ""; + } + { + name = "Downloads"; + text = ""; + } + { + name = "Library"; + text = ""; + } + { + name = "Movies"; + text = ""; + } + { + name = "Music"; + text = ""; + } + { + name = "Pictures"; + text = ""; + } + { + name = "Public"; + text = ""; + } + { + name = "Videos"; + text = ""; + } + ]; + files = [ + { + name = ".babelrc"; + text = ""; + fg = "#cbcb41"; + } + { + name = ".bash_profile"; + text = ""; + fg = "#89e051"; + } + { + name = ".bashrc"; + text = ""; + fg = "#89e051"; + } + { + name = ".clang-format"; + text = ""; + fg = "#6d8086"; + } + { + name = ".clang-tidy"; + text = ""; + fg = "#6d8086"; + } + { + name = ".codespellrc"; + text = "󰓆"; + fg = "#35da60"; + } + { + name = ".condarc"; + text = ""; + fg = "#43b02a"; + } + { + name = ".dockerignore"; + text = "󰡨"; + fg = "#458ee6"; + } + { + name = ".ds_store"; + text = ""; + fg = "#41535b"; + } + { + name = ".editorconfig"; + text = ""; + fg = "#fff2f2"; + } + { + name = ".env"; + text = ""; + fg = "#faf743"; + } + { + name = ".eslintignore"; + text = ""; + fg = "#4b32c3"; + } + { + name = ".eslintrc"; + text = ""; + fg = "#4b32c3"; + } + { + name = ".git-blame-ignore-revs"; + text = ""; + fg = "#f54d27"; + } + { + name = ".gitattributes"; + text = ""; + fg = "#f54d27"; + } + { + name = ".gitconfig"; + text = ""; + fg = "#f54d27"; + } + { + name = ".gitignore"; + text = ""; + fg = "#f54d27"; + } + { + name = ".gitlab-ci.yml"; + text = ""; + fg = "#e24329"; + } + { + name = ".gitmodules"; + text = ""; + fg = "#f54d27"; + } + { + name = ".gtkrc-2.0"; + text = ""; + fg = "#ffffff"; + } + { + name = ".gvimrc"; + text = ""; + fg = "#019833"; + } + { + name = ".justfile"; + text = ""; + fg = "#6d8086"; + } + { + name = ".luacheckrc"; + text = ""; + fg = "#00a2ff"; + } + { + name = ".luaurc"; + text = ""; + fg = "#00a2ff"; + } + { + name = ".mailmap"; + text = "󰊢"; + fg = "#f54d27"; + } + { + name = ".nanorc"; + text = ""; + fg = "#440077"; + } + { + name = ".npmignore"; + text = ""; + fg = "#e8274b"; + } + { + name = ".npmrc"; + text = ""; + fg = "#e8274b"; + } + { + name = ".nuxtrc"; + text = "󱄆"; + fg = "#00c58e"; + } + { + name = ".nvmrc"; + text = ""; + fg = "#5fa04e"; + } + { + name = ".pre-commit-config.yaml"; + text = "󰛢"; + fg = "#f8b424"; + } + { + name = ".prettierignore"; + text = ""; + fg = "#4285f4"; + } + { + name = ".prettierrc"; + text = ""; + fg = "#4285f4"; + } + { + name = ".prettierrc.cjs"; + text = ""; + fg = "#4285f4"; + } + { + name = ".prettierrc.js"; + text = ""; + fg = "#4285f4"; + } + { + name = ".prettierrc.json"; + text = ""; + fg = "#4285f4"; + } + { + name = ".prettierrc.json5"; + text = ""; + fg = "#4285f4"; + } + { + name = ".prettierrc.mjs"; + text = ""; + fg = "#4285f4"; + } + { + name = ".prettierrc.toml"; + text = ""; + fg = "#4285f4"; + } + { + name = ".prettierrc.yaml"; + text = ""; + fg = "#4285f4"; + } + { + name = ".prettierrc.yml"; + text = ""; + fg = "#4285f4"; + } + { + name = ".pylintrc"; + text = ""; + fg = "#6d8086"; + } + { + name = ".settings.json"; + text = ""; + fg = "#854cc7"; + } + { + name = ".SRCINFO"; + text = "󰣇"; + fg = "#0f94d2"; + } + { + name = ".vimrc"; + text = ""; + fg = "#019833"; + } + { + name = ".Xauthority"; + text = ""; + fg = "#e54d18"; + } + { + name = ".xinitrc"; + text = ""; + fg = "#e54d18"; + } + { + name = ".Xresources"; + text = ""; + fg = "#e54d18"; + } + { + name = ".xsession"; + text = ""; + fg = "#e54d18"; + } + { + name = ".zprofile"; + text = ""; + fg = "#89e051"; + } + { + name = ".zshenv"; + text = ""; + fg = "#89e051"; + } + { + name = ".zshrc"; + text = ""; + fg = "#89e051"; + } + { + name = "_gvimrc"; + text = ""; + fg = "#019833"; + } + { + name = "_vimrc"; + text = ""; + fg = "#019833"; + } + { + name = "AUTHORS"; + text = ""; + fg = "#a172ff"; + } + { + name = "AUTHORS.txt"; + text = ""; + fg = "#a172ff"; + } + { + name = "brewfile"; + text = ""; + fg = "#701516"; + } + { + name = "bspwmrc"; + text = ""; + fg = "#2f2f2f"; + } + { + name = "build"; + text = ""; + fg = "#89e051"; + } + { + name = "build.gradle"; + text = ""; + fg = "#005f87"; + } + { + name = "build.zig.zon"; + text = ""; + fg = "#f69a1b"; + } + { + name = "bun.lockb"; + text = ""; + fg = "#eadcd1"; + } + { + name = "cantorrc"; + text = ""; + fg = "#1c99f3"; + } + { + name = "checkhealth"; + text = "󰓙"; + fg = "#75b4fb"; + } + { + name = "cmakelists.txt"; + text = ""; + fg = "#dce3eb"; + } + { + name = "code_of_conduct"; + text = ""; + fg = "#e41662"; + } + { + name = "code_of_conduct.md"; + text = ""; + fg = "#e41662"; + } + { + name = "commit_editmsg"; + text = ""; + fg = "#f54d27"; + } + { + name = "commitlint.config.js"; + text = "󰜘"; + fg = "#2b9689"; + } + { + name = "commitlint.config.ts"; + text = "󰜘"; + fg = "#2b9689"; + } + { + name = "compose.yaml"; + text = "󰡨"; + fg = "#458ee6"; + } + { + name = "compose.yml"; + text = "󰡨"; + fg = "#458ee6"; + } + { + name = "config"; + text = ""; + fg = "#6d8086"; + } + { + name = "containerfile"; + text = "󰡨"; + fg = "#458ee6"; + } + { + name = "copying"; + text = ""; + fg = "#cbcb41"; + } + { + name = "copying.lesser"; + text = ""; + fg = "#cbcb41"; + } + { + name = "Directory.Build.props"; + text = ""; + fg = "#00a2ff"; + } + { + name = "Directory.Build.targets"; + text = ""; + fg = "#00a2ff"; + } + { + name = "Directory.Packages.props"; + text = ""; + fg = "#00a2ff"; + } + { + name = "docker-compose.yaml"; + text = "󰡨"; + fg = "#458ee6"; + } + { + name = "docker-compose.yml"; + text = "󰡨"; + fg = "#458ee6"; + } + { + name = "dockerfile"; + text = "󰡨"; + fg = "#458ee6"; + } + { + name = "eslint.config.cjs"; + text = ""; + fg = "#4b32c3"; + } + { + name = "eslint.config.js"; + text = ""; + fg = "#4b32c3"; + } + { + name = "eslint.config.mjs"; + text = ""; + fg = "#4b32c3"; + } + { + name = "eslint.config.ts"; + text = ""; + fg = "#4b32c3"; + } + { + name = "ext_typoscript_setup.txt"; + text = ""; + fg = "#ff8700"; + } + { + name = "favicon.ico"; + text = ""; + fg = "#cbcb41"; + } + { + name = "fp-info-cache"; + text = ""; + fg = "#ffffff"; + } + { + name = "fp-lib-table"; + text = ""; + fg = "#ffffff"; + } + { + name = "FreeCAD.conf"; + text = ""; + fg = "#cb333b"; + } + { + name = "Gemfile"; + text = ""; + fg = "#701516"; + } + { + name = "gnumakefile"; + text = ""; + fg = "#6d8086"; + } + { + name = "go.mod"; + text = ""; + fg = "#519aba"; + } + { + name = "go.sum"; + text = ""; + fg = "#519aba"; + } + { + name = "go.work"; + text = ""; + fg = "#519aba"; + } + { + name = "gradle-wrapper.properties"; + text = ""; + fg = "#005f87"; + } + { + name = "gradle.properties"; + text = ""; + fg = "#005f87"; + } + { + name = "gradlew"; + text = ""; + fg = "#005f87"; + } + { + name = "groovy"; + text = ""; + fg = "#4a687c"; + } + { + name = "gruntfile.babel.js"; + text = ""; + fg = "#e37933"; + } + { + name = "gruntfile.coffee"; + text = ""; + fg = "#e37933"; + } + { + name = "gruntfile.js"; + text = ""; + fg = "#e37933"; + } + { + name = "gruntfile.ts"; + text = ""; + fg = "#e37933"; + } + { + name = "gtkrc"; + text = ""; + fg = "#ffffff"; + } + { + name = "gulpfile.babel.js"; + text = ""; + fg = "#cc3e44"; + } + { + name = "gulpfile.coffee"; + text = ""; + fg = "#cc3e44"; + } + { + name = "gulpfile.js"; + text = ""; + fg = "#cc3e44"; + } + { + name = "gulpfile.ts"; + text = ""; + fg = "#cc3e44"; + } + { + name = "hypridle.conf"; + text = ""; + fg = "#00aaae"; + } + { + name = "hyprland.conf"; + text = ""; + fg = "#00aaae"; + } + { + name = "hyprlock.conf"; + text = ""; + fg = "#00aaae"; + } + { + name = "hyprpaper.conf"; + text = ""; + fg = "#00aaae"; + } + { + name = "i18n.config.js"; + text = "󰗊"; + fg = "#7986cb"; + } + { + name = "i18n.config.ts"; + text = "󰗊"; + fg = "#7986cb"; + } + { + name = "i3blocks.conf"; + text = ""; + fg = "#e8ebee"; + } + { + name = "i3status.conf"; + text = ""; + fg = "#e8ebee"; + } + { + name = "index.theme"; + text = ""; + fg = "#2db96f"; + } + { + name = "ionic.config.json"; + text = ""; + fg = "#4f8ff7"; + } + { + name = "justfile"; + text = ""; + fg = "#6d8086"; + } + { + name = "kalgebrarc"; + text = ""; + fg = "#1c99f3"; + } + { + name = "kdeglobals"; + text = ""; + fg = "#1c99f3"; + } + { + name = "kdenlive-layoutsrc"; + text = ""; + fg = "#83b8f2"; + } + { + name = "kdenliverc"; + text = ""; + fg = "#83b8f2"; + } + { + name = "kritadisplayrc"; + text = ""; + fg = "#f245fb"; + } + { + name = "kritarc"; + text = ""; + fg = "#f245fb"; + } + { + name = "license"; + text = ""; + fg = "#d0bf41"; + } + { + name = "license.md"; + text = ""; + fg = "#d0bf41"; + } + { + name = "lxde-rc.xml"; + text = ""; + fg = "#909090"; + } + { + name = "lxqt.conf"; + text = ""; + fg = "#0192d3"; + } + { + name = "makefile"; + text = ""; + fg = "#6d8086"; + } + { + name = "mix.lock"; + text = ""; + fg = "#a074c4"; + } + { + name = "mpv.conf"; + text = ""; + fg = "#3b1342"; + } + { + name = "node_modules"; + text = ""; + fg = "#e8274b"; + } + { + name = "nuxt.config.cjs"; + text = "󱄆"; + fg = "#00c58e"; + } + { + name = "nuxt.config.js"; + text = "󱄆"; + fg = "#00c58e"; + } + { + name = "nuxt.config.mjs"; + text = "󱄆"; + fg = "#00c58e"; + } + { + name = "nuxt.config.ts"; + text = "󱄆"; + fg = "#00c58e"; + } + { + name = "package-lock.json"; + text = ""; + fg = "#7a0d21"; + } + { + name = "package.json"; + text = ""; + fg = "#e8274b"; + } + { + name = "PKGBUILD"; + text = ""; + fg = "#0f94d2"; + } + { + name = "platformio.ini"; + text = ""; + fg = "#f6822b"; + } + { + name = "pom.xml"; + text = ""; + fg = "#7a0d21"; + } + { + name = "prettier.config.cjs"; + text = ""; + fg = "#4285f4"; + } + { + name = "prettier.config.js"; + text = ""; + fg = "#4285f4"; + } + { + name = "prettier.config.mjs"; + text = ""; + fg = "#4285f4"; + } + { + name = "prettier.config.ts"; + text = ""; + fg = "#4285f4"; + } + { + name = "procfile"; + text = ""; + fg = "#a074c4"; + } + { + name = "PrusaSlicer.ini"; + text = ""; + fg = "#ec6b23"; + } + { + name = "PrusaSlicerGcodeViewer.ini"; + text = ""; + fg = "#ec6b23"; + } + { + name = "py.typed"; + text = ""; + fg = "#ffbc03"; + } + { + name = "QtProject.conf"; + text = ""; + fg = "#40cd52"; + } + { + name = "rakefile"; + text = ""; + fg = "#701516"; + } + { + name = "readme"; + text = "󰂺"; + fg = "#ededed"; + } + { + name = "readme.md"; + text = "󰂺"; + fg = "#ededed"; + } + { + name = "rmd"; + text = ""; + fg = "#519aba"; + } + { + name = "robots.txt"; + text = "󰚩"; + fg = "#5d7096"; + } + { + name = "security"; + text = "󰒃"; + fg = "#bec4c9"; + } + { + name = "security.md"; + text = "󰒃"; + fg = "#bec4c9"; + } + { + name = "settings.gradle"; + text = ""; + fg = "#005f87"; + } + { + name = "svelte.config.js"; + text = ""; + fg = "#ff3e00"; + } + { + name = "sxhkdrc"; + text = ""; + fg = "#2f2f2f"; + } + { + name = "sym-lib-table"; + text = ""; + fg = "#ffffff"; + } + { + name = "tailwind.config.js"; + text = "󱏿"; + fg = "#20c2e3"; + } + { + name = "tailwind.config.mjs"; + text = "󱏿"; + fg = "#20c2e3"; + } + { + name = "tailwind.config.ts"; + text = "󱏿"; + fg = "#20c2e3"; + } + { + name = "tmux.conf"; + text = ""; + fg = "#14ba19"; + } + { + name = "tmux.conf.local"; + text = ""; + fg = "#14ba19"; + } + { + name = "tsconfig.json"; + text = ""; + fg = "#519aba"; + } + { + name = "unlicense"; + text = ""; + fg = "#d0bf41"; + } + { + name = "vagrantfile"; + text = ""; + fg = "#1563ff"; + } + { + name = "vercel.json"; + text = ""; + fg = "#ffffff"; + } + { + name = "vlcrc"; + text = "󰕼"; + fg = "#ee7a00"; + } + { + name = "webpack"; + text = "󰜫"; + fg = "#519aba"; + } + { + name = "weston.ini"; + text = ""; + fg = "#ffbb01"; + } + { + name = "workspace"; + text = ""; + fg = "#89e051"; + } + { + name = "xmobarrc"; + text = ""; + fg = "#fd4d5d"; + } + { + name = "xmobarrc.hs"; + text = ""; + fg = "#fd4d5d"; + } + { + name = "xmonad.hs"; + text = ""; + fg = "#fd4d5d"; + } + { + name = "xorg.conf"; + text = ""; + fg = "#e54d18"; + } + { + name = "xsettingsd.conf"; + text = ""; + fg = "#e54d18"; + } + ]; + exts = [ + { + name = "3gp"; + text = ""; + fg = "#fd971f"; + } + { + name = "3mf"; + text = "󰆧"; + fg = "#888888"; + } + { + name = "7z"; + text = ""; + fg = "#eca517"; + } + { + name = "a"; + text = ""; + fg = "#dcddd6"; + } + { + name = "aac"; + text = ""; + fg = "#00afff"; + } + { + name = "adb"; + text = ""; + fg = "#22ffff"; + } + { + name = "ads"; + text = ""; + fg = "#ffffff"; + } + { + name = "ai"; + text = ""; + fg = "#cbcb41"; + } + { + name = "aif"; + text = ""; + fg = "#00afff"; + } + { + name = "aiff"; + text = ""; + fg = "#00afff"; + } + { + name = "android"; + text = ""; + fg = "#34a853"; + } + { + name = "ape"; + text = ""; + fg = "#00afff"; + } + { + name = "apk"; + text = ""; + fg = "#34a853"; + } + { + name = "apl"; + text = ""; + fg = "#24a148"; + } + { + name = "app"; + text = ""; + fg = "#9f0500"; + } + { + name = "applescript"; + text = ""; + fg = "#6d8085"; + } + { + name = "asc"; + text = "󰦝"; + fg = "#576d7f"; + } + { + name = "asm"; + text = ""; + fg = "#0091bd"; + } + { + name = "ass"; + text = "󰨖"; + fg = "#ffb713"; + } + { + name = "astro"; + text = ""; + fg = "#e23f67"; + } + { + name = "avif"; + text = ""; + fg = "#a074c4"; + } + { + name = "awk"; + text = ""; + fg = "#4d5a5e"; + } + { + name = "azcli"; + text = ""; + fg = "#0078d4"; + } + { + name = "bak"; + text = "󰁯"; + fg = "#6d8086"; + } + { + name = "bash"; + text = ""; + fg = "#89e051"; + } + { + name = "bat"; + text = ""; + fg = "#c1f12e"; + } + { + name = "bazel"; + text = ""; + fg = "#89e051"; + } + { + name = "bib"; + text = "󱉟"; + fg = "#cbcb41"; + } + { + name = "bicep"; + text = ""; + fg = "#519aba"; + } + { + name = "bicepparam"; + text = ""; + fg = "#9f74b3"; + } + { + name = "bin"; + text = ""; + fg = "#9f0500"; + } + { + name = "blade.php"; + text = ""; + fg = "#f05340"; + } + { + name = "blend"; + text = "󰂫"; + fg = "#ea7600"; + } + { + name = "blp"; + text = "󰺾"; + fg = "#5796e2"; + } + { + name = "bmp"; + text = ""; + fg = "#a074c4"; + } + { + name = "bqn"; + text = ""; + fg = "#24a148"; + } + { + name = "brep"; + text = "󰻫"; + fg = "#839463"; + } + { + name = "bz"; + text = ""; + fg = "#eca517"; + } + { + name = "bz2"; + text = ""; + fg = "#eca517"; + } + { + name = "bz3"; + text = ""; + fg = "#eca517"; + } + { + name = "bzl"; + text = ""; + fg = "#89e051"; + } + { + name = "c"; + text = ""; + fg = "#599eff"; + } + { + name = "c++"; + text = ""; + fg = "#f34b7d"; + } + { + name = "cache"; + text = ""; + fg = "#ffffff"; + } + { + name = "cast"; + text = ""; + fg = "#fd971f"; + } + { + name = "cbl"; + text = ""; + fg = "#005ca5"; + } + { + name = "cc"; + text = ""; + fg = "#f34b7d"; + } + { + name = "ccm"; + text = ""; + fg = "#f34b7d"; + } + { + name = "cfg"; + text = ""; + fg = "#6d8086"; + } + { + name = "cjs"; + text = ""; + fg = "#cbcb41"; + } + { + name = "clj"; + text = ""; + fg = "#8dc149"; + } + { + name = "cljc"; + text = ""; + fg = "#8dc149"; + } + { + name = "cljd"; + text = ""; + fg = "#519aba"; + } + { + name = "cljs"; + text = ""; + fg = "#519aba"; + } + { + name = "cmake"; + text = ""; + fg = "#dce3eb"; + } + { + name = "cob"; + text = ""; + fg = "#005ca5"; + } + { + name = "cobol"; + text = ""; + fg = "#005ca5"; + } + { + name = "coffee"; + text = ""; + fg = "#cbcb41"; + } + { + name = "conda"; + text = ""; + fg = "#43b02a"; + } + { + name = "conf"; + text = ""; + fg = "#6d8086"; + } + { + name = "config.ru"; + text = ""; + fg = "#701516"; + } + { + name = "cow"; + text = "󰆚"; + fg = "#965824"; + } + { + name = "cp"; + text = ""; + fg = "#519aba"; + } + { + name = "cpp"; + text = ""; + fg = "#519aba"; + } + { + name = "cppm"; + text = ""; + fg = "#519aba"; + } + { + name = "cpy"; + text = ""; + fg = "#005ca5"; + } + { + name = "cr"; + text = ""; + fg = "#c8c8c8"; + } + { + name = "crdownload"; + text = ""; + fg = "#44cda8"; + } + { + name = "cs"; + text = "󰌛"; + fg = "#596706"; + } + { + name = "csh"; + text = ""; + fg = "#4d5a5e"; + } + { + name = "cshtml"; + text = "󱦗"; + fg = "#512bd4"; + } + { + name = "cson"; + text = ""; + fg = "#cbcb41"; + } + { + name = "csproj"; + text = "󰪮"; + fg = "#512bd4"; + } + { + name = "css"; + text = ""; + fg = "#42a5f5"; + } + { + name = "csv"; + text = ""; + fg = "#89e051"; + } + { + name = "cts"; + text = ""; + fg = "#519aba"; + } + { + name = "cu"; + text = ""; + fg = "#89e051"; + } + { + name = "cue"; + text = "󰲹"; + fg = "#ed95ae"; + } + { + name = "cuh"; + text = ""; + fg = "#a074c4"; + } + { + name = "cxx"; + text = ""; + fg = "#519aba"; + } + { + name = "cxxm"; + text = ""; + fg = "#519aba"; + } + { + name = "d"; + text = ""; + fg = "#b03931"; + } + { + name = "d.ts"; + text = ""; + fg = "#d59855"; + } + { + name = "dart"; + text = ""; + fg = "#03589c"; + } + { + name = "db"; + text = ""; + fg = "#dad8d8"; + } + { + name = "dconf"; + text = ""; + fg = "#ffffff"; + } + { + name = "desktop"; + text = ""; + fg = "#563d7c"; + } + { + name = "diff"; + text = ""; + fg = "#41535b"; + } + { + name = "dll"; + text = ""; + fg = "#4d2c0b"; + } + { + name = "doc"; + text = "󰈬"; + fg = "#185abd"; + } + { + name = "Dockerfile"; + text = "󰡨"; + fg = "#458ee6"; + } + { + name = "docx"; + text = "󰈬"; + fg = "#185abd"; + } + { + name = "dot"; + text = "󱁉"; + fg = "#30638e"; + } + { + name = "download"; + text = ""; + fg = "#44cda8"; + } + { + name = "drl"; + text = ""; + fg = "#ffafaf"; + } + { + name = "dropbox"; + text = ""; + fg = "#0061fe"; + } + { + name = "dump"; + text = ""; + fg = "#dad8d8"; + } + { + name = "dwg"; + text = "󰻫"; + fg = "#839463"; + } + { + name = "dxf"; + text = "󰻫"; + fg = "#839463"; + } + { + name = "ebook"; + text = ""; + fg = "#eab16d"; + } + { + name = "ebuild"; + text = ""; + fg = "#4c416e"; + } + { + name = "edn"; + text = ""; + fg = "#519aba"; + } + { + name = "eex"; + text = ""; + fg = "#a074c4"; + } + { + name = "ejs"; + text = ""; + fg = "#cbcb41"; + } + { + name = "el"; + text = ""; + fg = "#8172be"; + } + { + name = "elc"; + text = ""; + fg = "#8172be"; + } + { + name = "elf"; + text = ""; + fg = "#9f0500"; + } + { + name = "elm"; + text = ""; + fg = "#519aba"; + } + { + name = "eln"; + text = ""; + fg = "#8172be"; + } + { + name = "env"; + text = ""; + fg = "#faf743"; + } + { + name = "eot"; + text = ""; + fg = "#ececec"; + } + { + name = "epp"; + text = ""; + fg = "#ffa61a"; + } + { + name = "epub"; + text = ""; + fg = "#eab16d"; + } + { + name = "erb"; + text = ""; + fg = "#701516"; + } + { + name = "erl"; + text = ""; + fg = "#b83998"; + } + { + name = "ex"; + text = ""; + fg = "#a074c4"; + } + { + name = "exe"; + text = ""; + fg = "#9f0500"; + } + { + name = "exs"; + text = ""; + fg = "#a074c4"; + } + { + name = "f#"; + text = ""; + fg = "#519aba"; + } + { + name = "f3d"; + text = "󰻫"; + fg = "#839463"; + } + { + name = "f90"; + text = "󱈚"; + fg = "#734f96"; + } + { + name = "fbx"; + text = "󰆧"; + fg = "#888888"; + } + { + name = "fcbak"; + text = ""; + fg = "#cb333b"; + } + { + name = "fcmacro"; + text = ""; + fg = "#cb333b"; + } + { + name = "fcmat"; + text = ""; + fg = "#cb333b"; + } + { + name = "fcparam"; + text = ""; + fg = "#cb333b"; + } + { + name = "fcscript"; + text = ""; + fg = "#cb333b"; + } + { + name = "fcstd"; + text = ""; + fg = "#cb333b"; + } + { + name = "fcstd1"; + text = ""; + fg = "#cb333b"; + } + { + name = "fctb"; + text = ""; + fg = "#cb333b"; + } + { + name = "fctl"; + text = ""; + fg = "#cb333b"; + } + { + name = "fdmdownload"; + text = ""; + fg = "#44cda8"; + } + { + name = "fish"; + text = ""; + fg = "#4d5a5e"; + } + { + name = "flac"; + text = ""; + fg = "#0075aa"; + } + { + name = "flc"; + text = ""; + fg = "#ececec"; + } + { + name = "flf"; + text = ""; + fg = "#ececec"; + } + { + name = "fnl"; + text = ""; + fg = "#fff3d7"; + } + { + name = "fodg"; + text = ""; + fg = "#fffb57"; + } + { + name = "fodp"; + text = ""; + fg = "#fe9c45"; + } + { + name = "fods"; + text = ""; + fg = "#78fc4e"; + } + { + name = "fodt"; + text = ""; + fg = "#2dcbfd"; + } + { + name = "fs"; + text = ""; + fg = "#519aba"; + } + { + name = "fsi"; + text = ""; + fg = "#519aba"; + } + { + name = "fsscript"; + text = ""; + fg = "#519aba"; + } + { + name = "fsx"; + text = ""; + fg = "#519aba"; + } + { + name = "gcode"; + text = "󰐫"; + fg = "#1471ad"; + } + { + name = "gd"; + text = ""; + fg = "#6d8086"; + } + { + name = "gemspec"; + text = ""; + fg = "#701516"; + } + { + name = "gif"; + text = ""; + fg = "#a074c4"; + } + { + name = "git"; + text = ""; + fg = "#f14c28"; + } + { + name = "glb"; + text = ""; + fg = "#ffb13b"; + } + { + name = "gleam"; + text = ""; + fg = "#ffaff3"; + } + { + name = "gnumakefile"; + text = ""; + fg = "#6d8086"; + } + { + name = "go"; + text = ""; + fg = "#519aba"; + } + { + name = "godot"; + text = ""; + fg = "#6d8086"; + } + { + name = "gpr"; + text = ""; + fg = "#ff33ff"; + } + { + name = "gql"; + text = ""; + fg = "#e535ab"; + } + { + name = "gradle"; + text = ""; + fg = "#005f87"; + } + { + name = "graphql"; + text = ""; + fg = "#e535ab"; + } + { + name = "gresource"; + text = ""; + fg = "#ffffff"; + } + { + name = "gv"; + text = "󱁉"; + fg = "#30638e"; + } + { + name = "gz"; + text = ""; + fg = "#eca517"; + } + { + name = "h"; + text = ""; + fg = "#a074c4"; + } + { + name = "haml"; + text = ""; + fg = "#eaeae1"; + } + { + name = "hbs"; + text = ""; + fg = "#f0772b"; + } + { + name = "heex"; + text = ""; + fg = "#a074c4"; + } + { + name = "hex"; + text = ""; + fg = "#2e63ff"; + } + { + name = "hh"; + text = ""; + fg = "#a074c4"; + } + { + name = "hpp"; + text = ""; + fg = "#a074c4"; + } + { + name = "hrl"; + text = ""; + fg = "#b83998"; + } + { + name = "hs"; + text = ""; + fg = "#a074c4"; + } + { + name = "htm"; + text = ""; + fg = "#e34c26"; + } + { + name = "html"; + text = ""; + fg = "#e44d26"; + } + { + name = "http"; + text = ""; + fg = "#008ec7"; + } + { + name = "huff"; + text = "󰡘"; + fg = "#4242c7"; + } + { + name = "hurl"; + text = ""; + fg = "#ff0288"; + } + { + name = "hx"; + text = ""; + fg = "#ea8220"; + } + { + name = "hxx"; + text = ""; + fg = "#a074c4"; + } + { + name = "ical"; + text = ""; + fg = "#2b2e83"; + } + { + name = "icalendar"; + text = ""; + fg = "#2b2e83"; + } + { + name = "ico"; + text = ""; + fg = "#cbcb41"; + } + { + name = "ics"; + text = ""; + fg = "#2b2e83"; + } + { + name = "ifb"; + text = ""; + fg = "#2b2e83"; + } + { + name = "ifc"; + text = "󰻫"; + fg = "#839463"; + } + { + name = "ige"; + text = "󰻫"; + fg = "#839463"; + } + { + name = "iges"; + text = "󰻫"; + fg = "#839463"; + } + { + name = "igs"; + text = "󰻫"; + fg = "#839463"; + } + { + name = "image"; + text = ""; + fg = "#d0bec8"; + } + { + name = "img"; + text = ""; + fg = "#d0bec8"; + } + { + name = "import"; + text = ""; + fg = "#ececec"; + } + { + name = "info"; + text = ""; + fg = "#ffffcd"; + } + { + name = "ini"; + text = ""; + fg = "#6d8086"; + } + { + name = "ino"; + text = ""; + fg = "#56b6c2"; + } + { + name = "ipynb"; + text = ""; + fg = "#f57d01"; + } + { + name = "iso"; + text = ""; + fg = "#d0bec8"; + } + { + name = "ixx"; + text = ""; + fg = "#519aba"; + } + { + name = "java"; + text = ""; + fg = "#cc3e44"; + } + { + name = "jl"; + text = ""; + fg = "#a270ba"; + } + { + name = "jpeg"; + text = ""; + fg = "#a074c4"; + } + { + name = "jpg"; + text = ""; + fg = "#a074c4"; + } + { + name = "js"; + text = ""; + fg = "#cbcb41"; + } + { + name = "json"; + text = ""; + fg = "#cbcb41"; + } + { + name = "json5"; + text = ""; + fg = "#cbcb41"; + } + { + name = "jsonc"; + text = ""; + fg = "#cbcb41"; + } + { + name = "jsx"; + text = ""; + fg = "#20c2e3"; + } + { + name = "jwmrc"; + text = ""; + fg = "#0078cd"; + } + { + name = "jxl"; + text = ""; + fg = "#a074c4"; + } + { + name = "kbx"; + text = "󰯄"; + fg = "#737672"; + } + { + name = "kdb"; + text = ""; + fg = "#529b34"; + } + { + name = "kdbx"; + text = ""; + fg = "#529b34"; + } + { + name = "kdenlive"; + text = ""; + fg = "#83b8f2"; + } + { + name = "kdenlivetitle"; + text = ""; + fg = "#83b8f2"; + } + { + name = "kicad_dru"; + text = ""; + fg = "#ffffff"; + } + { + name = "kicad_mod"; + text = ""; + fg = "#ffffff"; + } + { + name = "kicad_pcb"; + text = ""; + fg = "#ffffff"; + } + { + name = "kicad_prl"; + text = ""; + fg = "#ffffff"; + } + { + name = "kicad_pro"; + text = ""; + fg = "#ffffff"; + } + { + name = "kicad_sch"; + text = ""; + fg = "#ffffff"; + } + { + name = "kicad_sym"; + text = ""; + fg = "#ffffff"; + } + { + name = "kicad_wks"; + text = ""; + fg = "#ffffff"; + } + { + name = "ko"; + text = ""; + fg = "#dcddd6"; + } + { + name = "kpp"; + text = ""; + fg = "#f245fb"; + } + { + name = "kra"; + text = ""; + fg = "#f245fb"; + } + { + name = "krz"; + text = ""; + fg = "#f245fb"; + } + { + name = "ksh"; + text = ""; + fg = "#4d5a5e"; + } + { + name = "kt"; + text = ""; + fg = "#7f52ff"; + } + { + name = "kts"; + text = ""; + fg = "#7f52ff"; + } + { + name = "lck"; + text = ""; + fg = "#bbbbbb"; + } + { + name = "leex"; + text = ""; + fg = "#a074c4"; + } + { + name = "less"; + text = ""; + fg = "#563d7c"; + } + { + name = "lff"; + text = ""; + fg = "#ececec"; + } + { + name = "lhs"; + text = ""; + fg = "#a074c4"; + } + { + name = "lib"; + text = ""; + fg = "#4d2c0b"; + } + { + name = "license"; + text = ""; + fg = "#cbcb41"; + } + { + name = "liquid"; + text = ""; + fg = "#95bf47"; + } + { + name = "lock"; + text = ""; + fg = "#bbbbbb"; + } + { + name = "log"; + text = "󰌱"; + fg = "#dddddd"; + } + { + name = "lrc"; + text = "󰨖"; + fg = "#ffb713"; + } + { + name = "lua"; + text = ""; + fg = "#51a0cf"; + } + { + name = "luac"; + text = ""; + fg = "#51a0cf"; + } + { + name = "luau"; + text = ""; + fg = "#00a2ff"; + } + { + name = "m"; + text = ""; + fg = "#599eff"; + } + { + name = "m3u"; + text = "󰲹"; + fg = "#ed95ae"; + } + { + name = "m3u8"; + text = "󰲹"; + fg = "#ed95ae"; + } + { + name = "m4a"; + text = ""; + fg = "#00afff"; + } + { + name = "m4v"; + text = ""; + fg = "#fd971f"; + } + { + name = "magnet"; + text = ""; + fg = "#a51b16"; + } + { + name = "makefile"; + text = ""; + fg = "#6d8086"; + } + { + name = "markdown"; + text = ""; + fg = "#dddddd"; + } + { + name = "material"; + text = ""; + fg = "#b83998"; + } + { + name = "md"; + text = ""; + fg = "#dddddd"; + } + { + name = "md5"; + text = "󰕥"; + fg = "#8c86af"; + } + { + name = "mdx"; + text = ""; + fg = "#519aba"; + } + { + name = "mint"; + text = "󰌪"; + fg = "#87c095"; + } + { + name = "mjs"; + text = ""; + fg = "#f1e05a"; + } + { + name = "mk"; + text = ""; + fg = "#6d8086"; + } + { + name = "mkv"; + text = ""; + fg = "#fd971f"; + } + { + name = "ml"; + text = ""; + fg = "#e37933"; + } + { + name = "mli"; + text = ""; + fg = "#e37933"; + } + { + name = "mm"; + text = ""; + fg = "#519aba"; + } + { + name = "mo"; + text = ""; + fg = "#9772fb"; + } + { + name = "mobi"; + text = ""; + fg = "#eab16d"; + } + { + name = "mojo"; + text = ""; + fg = "#ff4c1f"; + } + { + name = "mov"; + text = ""; + fg = "#fd971f"; + } + { + name = "mp3"; + text = ""; + fg = "#00afff"; + } + { + name = "mp4"; + text = ""; + fg = "#fd971f"; + } + { + name = "mpp"; + text = ""; + fg = "#519aba"; + } + { + name = "msf"; + text = ""; + fg = "#137be1"; + } + { + name = "mts"; + text = ""; + fg = "#519aba"; + } + { + name = "mustache"; + text = ""; + fg = "#e37933"; + } + { + name = "nfo"; + text = ""; + fg = "#ffffcd"; + } + { + name = "nim"; + text = ""; + fg = "#f3d400"; + } + { + name = "nix"; + text = ""; + fg = "#7ebae4"; + } + { + name = "norg"; + text = ""; + fg = "#4878be"; + } + { + name = "nswag"; + text = ""; + fg = "#85ea2d"; + } + { + name = "nu"; + text = ""; + fg = "#3aa675"; + } + { + name = "o"; + text = ""; + fg = "#9f0500"; + } + { + name = "obj"; + text = "󰆧"; + fg = "#888888"; + } + { + name = "odf"; + text = ""; + fg = "#ff5a96"; + } + { + name = "odg"; + text = ""; + fg = "#fffb57"; + } + { + name = "odin"; + text = "󰟢"; + fg = "#3882d2"; + } + { + name = "odp"; + text = ""; + fg = "#fe9c45"; + } + { + name = "ods"; + text = ""; + fg = "#78fc4e"; + } + { + name = "odt"; + text = ""; + fg = "#2dcbfd"; + } + { + name = "oga"; + text = ""; + fg = "#0075aa"; + } + { + name = "ogg"; + text = ""; + fg = "#0075aa"; + } + { + name = "ogv"; + text = ""; + fg = "#fd971f"; + } + { + name = "ogx"; + text = ""; + fg = "#fd971f"; + } + { + name = "opus"; + text = ""; + fg = "#0075aa"; + } + { + name = "org"; + text = ""; + fg = "#77aa99"; + } + { + name = "otf"; + text = ""; + fg = "#ececec"; + } + { + name = "out"; + text = ""; + fg = "#9f0500"; + } + { + name = "part"; + text = ""; + fg = "#44cda8"; + } + { + name = "patch"; + text = ""; + fg = "#41535b"; + } + { + name = "pck"; + text = ""; + fg = "#6d8086"; + } + { + name = "pcm"; + text = ""; + fg = "#0075aa"; + } + { + name = "pdf"; + text = ""; + fg = "#b30b00"; + } + { + name = "php"; + text = ""; + fg = "#a074c4"; + } + { + name = "pl"; + text = ""; + fg = "#519aba"; + } + { + name = "pls"; + text = "󰲹"; + fg = "#ed95ae"; + } + { + name = "ply"; + text = "󰆧"; + fg = "#888888"; + } + { + name = "pm"; + text = ""; + fg = "#519aba"; + } + { + name = "png"; + text = ""; + fg = "#a074c4"; + } + { + name = "po"; + text = ""; + fg = "#2596be"; + } + { + name = "pot"; + text = ""; + fg = "#2596be"; + } + { + name = "pp"; + text = ""; + fg = "#ffa61a"; + } + { + name = "ppt"; + text = "󰈧"; + fg = "#cb4a32"; + } + { + name = "pptx"; + text = "󰈧"; + fg = "#cb4a32"; + } + { + name = "prisma"; + text = ""; + fg = "#5a67d8"; + } + { + name = "pro"; + text = ""; + fg = "#e4b854"; + } + { + name = "ps1"; + text = "󰨊"; + fg = "#4273ca"; + } + { + name = "psb"; + text = ""; + fg = "#519aba"; + } + { + name = "psd"; + text = ""; + fg = "#519aba"; + } + { + name = "psd1"; + text = "󰨊"; + fg = "#6975c4"; + } + { + name = "psm1"; + text = "󰨊"; + fg = "#6975c4"; + } + { + name = "pub"; + text = "󰷖"; + fg = "#e3c58e"; + } + { + name = "pxd"; + text = ""; + fg = "#5aa7e4"; + } + { + name = "pxi"; + text = ""; + fg = "#5aa7e4"; + } + { + name = "py"; + text = ""; + fg = "#ffbc03"; + } + { + name = "pyc"; + text = ""; + fg = "#ffe291"; + } + { + name = "pyd"; + text = ""; + fg = "#ffe291"; + } + { + name = "pyi"; + text = ""; + fg = "#ffbc03"; + } + { + name = "pyo"; + text = ""; + fg = "#ffe291"; + } + { + name = "pyw"; + text = ""; + fg = "#5aa7e4"; + } + { + name = "pyx"; + text = ""; + fg = "#5aa7e4"; + } + { + name = "qm"; + text = ""; + fg = "#2596be"; + } + { + name = "qml"; + text = ""; + fg = "#40cd52"; + } + { + name = "qrc"; + text = ""; + fg = "#40cd52"; + } + { + name = "qss"; + text = ""; + fg = "#40cd52"; + } + { + name = "query"; + text = ""; + fg = "#90a850"; + } + { + name = "r"; + text = "󰟔"; + fg = "#2266ba"; + } + { + name = "R"; + text = "󰟔"; + fg = "#2266ba"; + } + { + name = "rake"; + text = ""; + fg = "#701516"; + } + { + name = "rar"; + text = ""; + fg = "#eca517"; + } + { + name = "razor"; + text = "󱦘"; + fg = "#512bd4"; + } + { + name = "rb"; + text = ""; + fg = "#701516"; + } + { + name = "res"; + text = ""; + fg = "#cc3e44"; + } + { + name = "resi"; + text = ""; + fg = "#f55385"; + } + { + name = "rlib"; + text = ""; + fg = "#dea584"; + } + { + name = "rmd"; + text = ""; + fg = "#519aba"; + } + { + name = "rproj"; + text = "󰗆"; + fg = "#358a5b"; + } + { + name = "rs"; + text = ""; + fg = "#dea584"; + } + { + name = "rss"; + text = ""; + fg = "#fb9d3b"; + } + { + name = "s"; + text = ""; + fg = "#0071c5"; + } + { + name = "sass"; + text = ""; + fg = "#f55385"; + } + { + name = "sbt"; + text = ""; + fg = "#cc3e44"; + } + { + name = "sc"; + text = ""; + fg = "#cc3e44"; + } + { + name = "scad"; + text = ""; + fg = "#f9d72c"; + } + { + name = "scala"; + text = ""; + fg = "#cc3e44"; + } + { + name = "scm"; + text = "󰘧"; + fg = "#eeeeee"; + } + { + name = "scss"; + text = ""; + fg = "#f55385"; + } + { + name = "sh"; + text = ""; + fg = "#4d5a5e"; + } + { + name = "sha1"; + text = "󰕥"; + fg = "#8c86af"; + } + { + name = "sha224"; + text = "󰕥"; + fg = "#8c86af"; + } + { + name = "sha256"; + text = "󰕥"; + fg = "#8c86af"; + } + { + name = "sha384"; + text = "󰕥"; + fg = "#8c86af"; + } + { + name = "sha512"; + text = "󰕥"; + fg = "#8c86af"; + } + { + name = "sig"; + text = "󰘧"; + fg = "#e37933"; + } + { + name = "signature"; + text = "󰘧"; + fg = "#e37933"; + } + { + name = "skp"; + text = "󰻫"; + fg = "#839463"; + } + { + name = "sldasm"; + text = "󰻫"; + fg = "#839463"; + } + { + name = "sldprt"; + text = "󰻫"; + fg = "#839463"; + } + { + name = "slim"; + text = ""; + fg = "#e34c26"; + } + { + name = "sln"; + text = ""; + fg = "#854cc7"; + } + { + name = "slnx"; + text = ""; + fg = "#854cc7"; + } + { + name = "slvs"; + text = "󰻫"; + fg = "#839463"; + } + { + name = "sml"; + text = "󰘧"; + fg = "#e37933"; + } + { + name = "so"; + text = ""; + fg = "#dcddd6"; + } + { + name = "sol"; + text = ""; + fg = "#519aba"; + } + { + name = "spec.js"; + text = ""; + fg = "#cbcb41"; + } + { + name = "spec.jsx"; + text = ""; + fg = "#20c2e3"; + } + { + name = "spec.ts"; + text = ""; + fg = "#519aba"; + } + { + name = "spec.tsx"; + text = ""; + fg = "#1354bf"; + } + { + name = "spx"; + text = ""; + fg = "#0075aa"; + } + { + name = "sql"; + text = ""; + fg = "#dad8d8"; + } + { + name = "sqlite"; + text = ""; + fg = "#dad8d8"; + } + { + name = "sqlite3"; + text = ""; + fg = "#dad8d8"; + } + { + name = "srt"; + text = "󰨖"; + fg = "#ffb713"; + } + { + name = "ssa"; + text = "󰨖"; + fg = "#ffb713"; + } + { + name = "ste"; + text = "󰻫"; + fg = "#839463"; + } + { + name = "step"; + text = "󰻫"; + fg = "#839463"; + } + { + name = "stl"; + text = "󰆧"; + fg = "#888888"; + } + { + name = "stp"; + text = "󰻫"; + fg = "#839463"; + } + { + name = "strings"; + text = ""; + fg = "#2596be"; + } + { + name = "styl"; + text = ""; + fg = "#8dc149"; + } + { + name = "sub"; + text = "󰨖"; + fg = "#ffb713"; + } + { + name = "sublime"; + text = ""; + fg = "#e37933"; + } + { + name = "suo"; + text = ""; + fg = "#854cc7"; + } + { + name = "sv"; + text = "󰍛"; + fg = "#019833"; + } + { + name = "svelte"; + text = ""; + fg = "#ff3e00"; + } + { + name = "svg"; + text = "󰜡"; + fg = "#ffb13b"; + } + { + name = "svh"; + text = "󰍛"; + fg = "#019833"; + } + { + name = "swift"; + text = ""; + fg = "#e37933"; + } + { + name = "t"; + text = ""; + fg = "#519aba"; + } + { + name = "tbc"; + text = "󰛓"; + fg = "#1e5cb3"; + } + { + name = "tcl"; + text = "󰛓"; + fg = "#1e5cb3"; + } + { + name = "templ"; + text = ""; + fg = "#dbbd30"; + } + { + name = "terminal"; + text = ""; + fg = "#31b53e"; + } + { + name = "test.js"; + text = ""; + fg = "#cbcb41"; + } + { + name = "test.jsx"; + text = ""; + fg = "#20c2e3"; + } + { + name = "test.ts"; + text = ""; + fg = "#519aba"; + } + { + name = "test.tsx"; + text = ""; + fg = "#1354bf"; + } + { + name = "tex"; + text = ""; + fg = "#3d6117"; + } + { + name = "tf"; + text = ""; + fg = "#5f43e9"; + } + { + name = "tfvars"; + text = ""; + fg = "#5f43e9"; + } + { + name = "tgz"; + text = ""; + fg = "#eca517"; + } + { + name = "tmux"; + text = ""; + fg = "#14ba19"; + } + { + name = "toml"; + text = ""; + fg = "#9c4221"; + } + { + name = "torrent"; + text = ""; + fg = "#44cda8"; + } + { + name = "tres"; + text = ""; + fg = "#6d8086"; + } + { + name = "ts"; + text = ""; + fg = "#519aba"; + } + { + name = "tscn"; + text = ""; + fg = "#6d8086"; + } + { + name = "tsconfig"; + text = ""; + fg = "#ff8700"; + } + { + name = "tsx"; + text = ""; + fg = "#1354bf"; + } + { + name = "ttf"; + text = ""; + fg = "#ececec"; + } + { + name = "twig"; + text = ""; + fg = "#8dc149"; + } + { + name = "txt"; + text = "󰈙"; + fg = "#89e051"; + } + { + name = "txz"; + text = ""; + fg = "#eca517"; + } + { + name = "typ"; + text = ""; + fg = "#0dbcc0"; + } + { + name = "typoscript"; + text = ""; + fg = "#ff8700"; + } + { + name = "ui"; + text = ""; + fg = "#015bf0"; + } + { + name = "v"; + text = "󰍛"; + fg = "#019833"; + } + { + name = "vala"; + text = ""; + fg = "#7b3db9"; + } + { + name = "vh"; + text = "󰍛"; + fg = "#019833"; + } + { + name = "vhd"; + text = "󰍛"; + fg = "#019833"; + } + { + name = "vhdl"; + text = "󰍛"; + fg = "#019833"; + } + { + name = "vi"; + text = ""; + fg = "#fec60a"; + } + { + name = "vim"; + text = ""; + fg = "#019833"; + } + { + name = "vsh"; + text = ""; + fg = "#5d87bf"; + } + { + name = "vsix"; + text = ""; + fg = "#854cc7"; + } + { + name = "vue"; + text = ""; + fg = "#8dc149"; + } + { + name = "wasm"; + text = ""; + fg = "#5c4cdb"; + } + { + name = "wav"; + text = ""; + fg = "#00afff"; + } + { + name = "webm"; + text = ""; + fg = "#fd971f"; + } + { + name = "webmanifest"; + text = ""; + fg = "#f1e05a"; + } + { + name = "webp"; + text = ""; + fg = "#a074c4"; + } + { + name = "webpack"; + text = "󰜫"; + fg = "#519aba"; + } + { + name = "wma"; + text = ""; + fg = "#00afff"; + } + { + name = "woff"; + text = ""; + fg = "#ececec"; + } + { + name = "woff2"; + text = ""; + fg = "#ececec"; + } + { + name = "wrl"; + text = "󰆧"; + fg = "#888888"; + } + { + name = "wrz"; + text = "󰆧"; + fg = "#888888"; + } + { + name = "wv"; + text = ""; + fg = "#00afff"; + } + { + name = "wvc"; + text = ""; + fg = "#00afff"; + } + { + name = "x"; + text = ""; + fg = "#599eff"; + } + { + name = "xaml"; + text = "󰙳"; + fg = "#512bd4"; + } + { + name = "xcf"; + text = ""; + fg = "#635b46"; + } + { + name = "xcplayground"; + text = ""; + fg = "#e37933"; + } + { + name = "xcstrings"; + text = ""; + fg = "#2596be"; + } + { + name = "xls"; + text = "󰈛"; + fg = "#207245"; + } + { + name = "xlsx"; + text = "󰈛"; + fg = "#207245"; + } + { + name = "xm"; + text = ""; + fg = "#519aba"; + } + { + name = "xml"; + text = "󰗀"; + fg = "#e37933"; + } + { + name = "xpi"; + text = ""; + fg = "#ff1b01"; + } + { + name = "xul"; + text = ""; + fg = "#e37933"; + } + { + name = "xz"; + text = ""; + fg = "#eca517"; + } + { + name = "yaml"; + text = ""; + fg = "#6d8086"; + } + { + name = "yml"; + text = ""; + fg = "#6d8086"; + } + { + name = "zig"; + text = ""; + fg = "#f69a1b"; + } + { + name = "zip"; + text = ""; + fg = "#eca517"; + } + { + name = "zsh"; + text = ""; + fg = "#89e051"; + } + { + name = "zst"; + text = ""; + fg = "#eca517"; + } + { + name = "🔥"; + text = ""; + fg = "#ff4c1f"; + } + ]; + conds = [ + { + "if" = "orphan"; + text = ""; + } + { + "if" = "link"; + text = ""; + } + { + "if" = "block"; + text = ""; + } + { + "if" = "char"; + text = ""; + } + { + "if" = "fifo"; + text = ""; + } + { + "if" = "sock"; + text = ""; + } + { + "if" = "sticky"; + text = ""; + } + { + "if" = "dummy"; + text = ""; + } + { + "if" = "dir"; + text = ""; + } + { + "if" = "exec"; + text = ""; + } + { + "if" = "!dir"; + text = ""; + } + ]; + }; +} diff --git a/modules/yazi/yazi.nix b/modules/yazi/yazi.nix new file mode 100644 index 0000000..cfb42e0 --- /dev/null +++ b/modules/yazi/yazi.nix @@ -0,0 +1,387 @@ +{ + settings = { + manager = { + ratio = [1 4 3]; + sort_by = "alphabetical"; + sort_sensitive = false; + sort_reverse = false; + sort_dir_first = true; + sort_translit = false; + linemode = "none"; + show_hidden = false; + show_symlink = true; + scrolloff = 5; + mouse_events = ["click" "scroll"]; + title_format = "Yazi: {cwd}"; + }; + preview = { + wrap = "no"; + tab_size = 2; + max_width = 600; + max_height = 900; + cache_dir = ""; + image_delay = 30; + image_filter = "triangle"; + image_quality = 75; + sixel_fraction = 15; + ueberzug_scale = 1; + ueberzug_offset = [0 0 0 0]; + }; + opener = { + edit = [ + { + run = ''nvim "$@"''; + desc = "nvim"; + block = true; + for = "unix"; + } + { + run = "code %*"; + orphan = true; + desc = "code"; + for = "windows"; + } + { + run = "code -w %*"; + block = true; + desc = "code (block)"; + for = "windows"; + } + ]; + open = [ + { + run = ''xdg-open "$1"''; + desc = "Open"; + for = "linux"; + } + { + run = ''open "$@"''; + desc = "Open"; + for = "macos"; + } + { + run = ''start "" "%1"''; + orphan = true; + desc = "Open"; + for = "windows"; + } + { + run = ''termux-open "$1"''; + desc = "Open"; + for = "android"; + } + ]; + reveal = [ + { + run = ''xdg-open "$(dirname "$1")"''; + desc = "Reveal"; + for = "linux"; + } + { + run = ''open -R "$1"''; + desc = "Reveal"; + for = "macos"; + } + { + run = ''explorer /select,"%1"''; + orphan = true; + desc = "Reveal"; + for = "windows"; + } + { + run = ''termux-open "$(dirname "$1")"''; + desc = "Reveal"; + for = "android"; + } + { + run = ''exiftool "$1"; echo "Press enter to exit"; read _''; + block = true; + desc = "Show EXIF"; + for = "unix"; + } + ]; + extract = [ + { + run = ''ya pub extract --list "$@"''; + desc = "Extract here"; + for = "unix"; + } + { + run = "ya pub extract --list %*"; + desc = "Extract here"; + for = "windows"; + } + ]; + play = [ + { + run = ''mpv --force-window "$@"''; + orphan = true; + for = "unix"; + } + { + run = "mpv --force-window %*"; + orphan = true; + for = "windows"; + } + { + run = ''mediainfo "$1"; echo "Press enter to exit"; read _''; + block = true; + desc = "Show media info"; + for = "unix"; + } + ]; + }; + open = { + rules = [ + { + name = "*/"; + use = ["edit" "open" "reveal"]; + } + { + mime = "text/*"; + use = ["edit" "reveal"]; + } + { + mime = "image/*"; + use = ["open" "reveal"]; + } + { + mime = "{audio,video}/*"; + use = ["play" "reveal"]; + } + { + mime = "application/{zip,rar,7z*,tar,gzip,xz,zstd,bzip*,lzma,compress,archive,cpio,arj,xar,ms-cab*}"; + use = ["extract" "reveal"]; + } + { + mime = "application/{json,ndjson}"; + use = ["edit" "reveal"]; + } + { + mime = "*/javascript"; + use = ["edit" "reveal"]; + } + { + mime = "inode/empty"; + use = ["edit" "reveal"]; + } + { + name = "*"; + use = ["open" "reveal"]; + } + ]; + }; + tasks = { + micro_workers = 10; + macro_workers = 10; + bizarre_retry = 3; + image_alloc = 536870912; + image_bound = [0 0]; + suppress_preload = false; + }; + plugin = { + fetchers = [ + { + id = "mime"; + name = "*"; + run = "mime"; + prio = "high"; + } + ]; + spotters = [ + { + name = "*/"; + run = "folder"; + } + { + mime = "text/*"; + run = "code"; + } + { + mime = "application/{mbox,javascript,wine-extension-ini}"; + run = "code"; + } + { + mime = "image/{avif,hei?,jxl,svg+xml}"; + run = "magick"; + } + { + mime = "image/*"; + run = "image"; + } + { + mime = "video/*"; + run = "video"; + } + { + name = "*"; + run = "file"; + } + ]; + preloaders = [ + { + mime = "image/{avif,hei?,jxl,svg+xml}"; + run = "magick"; + } + { + mime = "image/*"; + run = "image"; + } + { + mime = "video/*"; + run = "video"; + } + { + mime = "application/pdf"; + run = "pdf"; + } + { + mime = "font/*"; + run = "font"; + } + { + mime = "application/ms-opentype"; + run = "font"; + } + ]; + previewers = [ + { + name = "*/"; + run = "folder"; + sync = true; + } + { + mime = "text/*"; + run = "code"; + } + { + mime = "application/{mbox,javascript,wine-extension-ini}"; + run = "code"; + } + { + mime = "application/{json,ndjson}"; + run = "json"; + } + { + mime = "image/{avif,hei?,jxl,svg+xml}"; + run = "magick"; + } + { + mime = "image/*"; + run = "image"; + } + { + mime = "video/*"; + run = "video"; + } + { + mime = "application/pdf"; + run = "pdf"; + } + { + mime = "application/{zip,rar,7z*,tar,gzip,xz,zstd,bzip*,lzma,compress,archive,cpio,arj,xar,ms-cab*}"; + run = "archive"; + } + { + mime = "application/{debian*-package,redhat-package-manager,rpm,android.package-archive}"; + run = "archive"; + } + { + name = "*.{AppImage,appimage}"; + run = "archive"; + } + { + mime = "application/{iso9660-image,qemu-disk,ms-wim,apple-diskimage}"; + run = "archive"; + } + { + mime = "application/virtualbox-{vhd,vhdx}"; + run = "archive"; + } + { + name = "*.{img,fat,ext,ext2,ext3,ext4,squashfs,ntfs,hfs,hfsx}"; + run = "archive"; + } + { + mime = "font/*"; + run = "font"; + } + { + mime = "application/ms-opentype"; + run = "font"; + } + { + mime = "inode/empty"; + run = "empty"; + } + { + name = "*"; + run = "file"; + } + ]; + prepend_fetchers = [ + { + id = "git"; + name = "*"; + run = "git"; + } + { + id = "git"; + name = "*/"; + run = "git"; + } + ]; + }; + input = { + cursor_blink = false; + cd_title = "Change directory:"; + cd_origin = "top-center"; + cd_offset = [0 2 50 3]; + create_title = ["Create:" "Create (dir):"]; + create_origin = "top-center"; + create_offset = [0 2 50 3]; + rename_title = "Rename:"; + rename_origin = "hovered"; + rename_offset = [0 1 50 3]; + filter_title = "Filter:"; + filter_origin = "top-center"; + filter_offset = [0 2 50 3]; + find_title = ["Find next:" "Find previous:"]; + find_origin = "top-center"; + find_offset = [0 2 50 3]; + search_title = "Search via {n}:"; + search_origin = "top-center"; + search_offset = [0 2 50 3]; + shell_title = ["Shell:" "Shell (block):"]; + shell_origin = "top-center"; + shell_offset = [0 2 50 3]; + }; + confirm = { + trash_title = "Trash {n} selected file{s}?"; + trash_origin = "center"; + trash_offset = [0 0 70 20]; + delete_title = "Permanently delete {n} selected file{s}?"; + delete_origin = "center"; + delete_offset = [0 0 70 20]; + overwrite_title = "Overwrite file?"; + overwrite_content = "Will overwrite the following file:"; + overwrite_origin = "center"; + overwrite_offset = [0 0 50 15]; + quit_title = "Quit?"; + quit_content = "The following tasks are still running, are you sure you want to quit?"; + quit_origin = "center"; + quit_offset = [0 0 50 15]; + }; + pick = { + open_title = "Open with:"; + open_origin = "hovered"; + open_offset = [0 1 50 7]; + }; + which = { + sort_by = "none"; + sort_sensitive = false; + sort_reverse = false; + sort_translit = false; + }; + }; +} diff --git a/overlays/default.nix b/overlays/default.nix new file mode 100644 index 0000000..1bbd5fb --- /dev/null +++ b/overlays/default.nix @@ -0,0 +1,8 @@ +{ + # Overlay custom derivations into nixpkgs so you can use pkgs. + # These packages are automatically available in all modules and configurations + customPackages = final: _prev: + import ../pkgs { + pkgs = final; + }; +} diff --git a/pkgs/default.nix b/pkgs/default.nix new file mode 100644 index 0000000..9004e37 --- /dev/null +++ b/pkgs/default.nix @@ -0,0 +1,7 @@ +{ pkgs, ... }: +{ + # SDDM theme packages + # These will be overlayed into nixpkgs automatically + # Usage: pkgs.sddm-sugar-dark-theme + sddm-sugar-dark-theme = pkgs.callPackage ./sddm-themes/sugar-dark.nix { }; +} diff --git a/pkgs/sddm-themes/sugar-dark.nix b/pkgs/sddm-themes/sugar-dark.nix new file mode 100644 index 0000000..2d0e2e5 --- /dev/null +++ b/pkgs/sddm-themes/sugar-dark.nix @@ -0,0 +1,27 @@ +{ + stdenv, + fetchFromGitHub, +}: +stdenv.mkDerivation rec { + pname = "sddm-sugar-dark-theme"; + version = "ceb2c45"; + dontBuild = true; + + installPhase = '' + mkdir -p $out/share/sddm/themes + cp -aR $src $out/share/sddm/themes/sugar-dark + ''; + + src = fetchFromGitHub { + owner = "MarianArlt"; + repo = "sddm-sugar-dark"; + rev = "ceb2c455663429be03ba62d9f898c571650ef7fe"; + sha256 = "0153z1kylbhc9d12nxy9vpn0spxgrhgy36wy37pk6ysq7akaqlvy"; + }; + + meta = { + description = "Sugar Dark Theme for SDDM"; + homepage = "https://github.com/MarianArlt/sddm-sugar-dark"; + license = "GPL-3.0-or-later"; + }; +} diff --git a/scripts/amdgpu.py b/scripts/amdgpu.py new file mode 100755 index 0000000..c273375 --- /dev/null +++ b/scripts/amdgpu.py @@ -0,0 +1,83 @@ +import pyamdgpuinfo +import json + +def format_frequency(frequency_hz: int) -> str: + """ + Takes a frequency (in Hz) and normalizes it: `Hz`, `MHz`, or `GHz` + + Returns: + str: frequency string with the appropriate suffix applied + """ + return ( + format_size(frequency_hz, binary=False) + .replace("B", "Hz") + .replace("bytes", "Hz") + ) + +def format_size(size: int, binary=True) -> str: + """ + Format size in bytes to a human-readable format. + + Args: + size (int): Size in bytes. + binary (bool): If True, use binary (base 1024) units. + + Returns: + str: Formatted size string. + """ + suffixes = ["B", "KiB", "MiB", "GiB", "TiB"] if binary else ["B", "KB", "MB", "GB", "TB"] + base = 1024 if binary else 1000 + index = 0 + + while size >= base and index < len(suffixes) - 1: + size /= base + index += 1 + + return f"{size:.0f} {suffixes[index]}" + +def main(): + # Detect the number of GPUs available + n_devices = pyamdgpuinfo.detect_gpus() + + if n_devices == 0: + print("No AMD GPUs detected.") + return + + # Get GPU information for the first GPU (index 0) + first_gpu = pyamdgpuinfo.get_gpu(0) + + try: + # Query GPU temperature + temperature = first_gpu.query_temperature() + temperature = f"{temperature:.0f}°C" # Format temperature to 2 digits with "°C" + + # Query GPU core clock + core_clock_hz = first_gpu.query_sclk() # In Hz + formatted_core_clock = format_frequency(core_clock_hz) + + # Query GPU power consumption + power_usage = first_gpu.query_power() + + # Query GPU load + gpu_load = first_gpu.query_load() + formatted_gpu_load = f"{gpu_load:.1f}%" # Format GPU load to 1 decimal place + + # Create a dictionary with the GPU information + gpu_info = { + "GPU Temperature": temperature, + "GPU Load": formatted_gpu_load, + "GPU Core Clock": formatted_core_clock, + "GPU Power Usage": f"{power_usage} Watts" + } + + # Convert the dictionary to a JSON string, ensure_ascii=False to prevent escaping + json_output = json.dumps(gpu_info, ensure_ascii=False) + + # Print the JSON string + print(json_output) + + except Exception as e: + print(f"Error: {str(e)}") + +if __name__ == "__main__": + main() diff --git a/scripts/animations.sh b/scripts/animations.sh new file mode 100755 index 0000000..a145d5f --- /dev/null +++ b/scripts/animations.sh @@ -0,0 +1,84 @@ +#!/usr/bin/env bash + +# Define paths +scrDir=$(dirname "$(realpath "$0")") +source "$scrDir/globalcontrol.sh" +config_dir="$HOME/.config" +animations_dir="$config_dir/hypr/animations" +animations_conf="$config_dir/hypr/animations.conf" +rofi_theme="$config_dir/rofi/clipboard.rasi" + +# Set rofi scaling +[[ "${rofiScale}" =~ ^[0-9]+$ ]] || rofiScale=10 +r_scale="configuration {font: \"JetBrainsMono Nerd Font ${rofiScale}\";}" +wind_border=$((hypr_border * 3 / 2)) +elem_border=$([ $hypr_border -eq 0 ] && echo "5" || echo $hypr_border) + +# Evaluate spawn position +readarray -t curPos < <(hyprctl cursorpos -j | jq -r '.x,.y') +readarray -t monRes < <(hyprctl -j monitors | jq '.[] | select(.focused==true) | .width,.height,.scale,.x,.y') +readarray -t offRes < <(hyprctl -j monitors | jq -r '.[] | select(.focused==true).reserved | map(tostring) | join("\n")') +monRes[2]="$(echo "${monRes[2]}" | sed "s/\.//")" +monRes[0]="$(( ${monRes[0]} * 100 / ${monRes[2]} ))" +monRes[1]="$(( ${monRes[1]} * 100 / ${monRes[2]} ))" +curPos[0]="$(( ${curPos[0]} - ${monRes[3]} ))" +curPos[1]="$(( ${curPos[1]} - ${monRes[4]} ))" + +if [ "${curPos[0]}" -ge "$((${monRes[0]} / 2))" ] ; then + x_pos="east" + x_off="-$(( ${monRes[0]} - ${curPos[0]} - ${offRes[2]} ))" +else + x_pos="west" + x_off="$(( ${curPos[0]} - ${offRes[0]} ))" +fi + +if [ "${curPos[1]}" -ge "$((${monRes[1]} / 2))" ] ; then + y_pos="south" + y_off="-$(( ${monRes[1]} - ${curPos[1]} - ${offRes[3]} ))" +else + y_pos="north" + y_off="$(( ${curPos[1]} - ${offRes[1]} ))" +fi + +r_override="window{location:${x_pos} ${y_pos};anchor:${x_pos} ${y_pos};x-offset:${x_off}px;y-offset:${y_off}px;border:${hypr_width}px;border-radius:${wind_border}px;} wallbox{border-radius:${elem_border}px;} element{border-radius:${elem_border}px;}" + +# Ensure the animations directory exists +if [ ! -d "$animations_dir" ]; then + notify-send "Error" "Animations directory does not exist at $animations_dir" + exit 1 +fi + +# List available .conf files in animations directory +animation_files=$(ls "$animations_dir"/*.conf 2>/dev/null) +if [ -z "$animation_files" ]; then + notify-send "Error" "No .conf files found in $animations_dir" + exit 1 +fi + +# Display options using Rofi with custom scaling, positioning, and placeholder +selected_animation=$(echo "$animation_files" | awk -F/ '{print $NF}' | \ + rofi -dmenu \ + -p "Select animation" \ + -theme-str "entry { placeholder: \"Select animation...\"; }" \ + -theme-str "${r_scale}" \ + -theme-str "${r_override}" \ + -theme "$rofi_theme") + +# Exit if no selection was made +if [ -z "$selected_animation" ]; then + exit 0 +fi + +# Generate the new source line +selected_path="$animations_dir/$selected_animation" +new_source_line="source = $selected_path" + +# Update the animations.conf file +if grep -q "^source = " "$animations_conf"; then + sed -i "s|^source = .*|$new_source_line|" "$animations_conf" +else + echo "$new_source_line" >> "$animations_conf" +fi + +# Notify the user +notify-send "Animation Updated" "Sourced $selected_animation" diff --git a/scripts/batterynotify.sh b/scripts/batterynotify.sh new file mode 100755 index 0000000..0cb5b46 --- /dev/null +++ b/scripts/batterynotify.sh @@ -0,0 +1,228 @@ +#!/usr/bin/env bash + +undock=false +scrDir=$(dirname "$(realpath "$0")") +source $scrDir/globalcontrol.sh +batterynotify_conf="${hydeConfDir}/hyde.conf" # Shared with hyde configuration +config_info() { +cat << EOF + +Modify $batterynotify_conf to set options. + + STATUS THRESHOLD INTERVAL + Full $battery_full_threshold $notify Minutes + Critical $battery_critical_threshold $timer Seconds then '$execute_critical' + Low $battery_low_threshold $interval Percent then '$execute_low' + Unplug $unplug_charger_threshold $interval Percent then '$execute_unplug' + + Charging: $execute_charging + Discharging: $execute_discharging +EOF +} + +is_laptop() { # Check if the system is a laptop + if grep -q "Battery" /sys/class/power_supply/BAT*/type; then + return 0 # It's a laptop + else + echo "No battery detected. If you think this is an error please post a report to the repo" + exit 0 # It's not a laptop + fi +} +is_laptop +fn_verbose () { +if $verbose; then +cat << VERBOSE +============================================= + Battery Status: $battery_status + Battery Percentage: $battery_percentage +============================================= +VERBOSE +fi +} +fn_notify () { # Send notification + + notify-send -a "Power" $1 -u $2 "$3" "$4" -p # Call the notify-send command with the provided arguments \$1 is the flags \$2 is the urgency \$3 is the title \$4 is the message +} +fn_percentage () { + if [[ "$battery_percentage" -ge "$unplug_charger_threshold" ]] && [[ "$battery_status" != "Discharging" ]] && [[ "$battery_status" != "Full" ]] && (( (battery_percentage - last_notified_percentage) >= $interval )); then if $verbose; then echo "Prompt:UNPLUG: $battery_unplug_threshold $battery_status $battery_percentage" ; fi + fn_notify "-t 5000 " "CRITICAL" "Battery Charged" "Battery is at $battery_percentage%. You can unplug the charger!" + last_notified_percentage=$battery_percentage + elif [[ "$battery_percentage" -le "$battery_critical_threshold" ]]; then + count=$(( timer > $mnt ? timer : $mnt )) # reset count + while [ $count -gt 0 ] && [[ $battery_status == "Discharging"* ]]; do + for battery in /sys/class/power_supply/BAT*; do battery_status=$(< "$battery/status") ; done + if [[ $battery_status != "Discharging" ]] ; then break ; fi + fn_notify "-t 5000 -r 69 " "CRITICAL" "Battery Critically Low" "$battery_percentage% is critically low. Device will execute $execute_critical in $((count/60)):$((count%60)) ." + count=$((count-1)) + sleep 1 + done + [ $count -eq 0 ] && fn_action + elif [[ "$battery_percentage" -le "$battery_low_threshold" ]] && [[ "$battery_status" == "Discharging" ]] && (( (last_notified_percentage - battery_percentage) >= $interval )); then if $verbose; then echo "Prompt:LOW: $battery_low_threshold $battery_status $battery_percentage" ; fi + fn_notify "-t 5000 " "CRITICAL" "Battery Low" "Battery is at $battery_percentage%. Connect the charger." + last_notified_percentage=$battery_percentage + fi +} +fn_action () { #handles the $execute_critical command #? This is special as it will try to execute always + count=$(( timer > $mnt ? timer : $mnt )) # reset count + nohup $execute_critical +} + +fn_status () { +if [[ $battery_percentage -ge $battery_full_threshold ]] && [[ "$battery_status" != *"Discharging"* ]]; then echo "Full and $battery_status" + battery_status="Full" ;fi +case "$battery_status" in # Handle the power supply status + "Discharging") if $verbose; then echo "Case:$battery_status Level: $battery_percentage" ;fi + if [[ "$prev_status" != "Discharging" ]] || [[ "$prev_status" == "Full" ]] ; then + prev_status=$battery_status + urgency=$([[ $battery_percentage -le "$battery_low_threshold" ]] && echo "CRITICAL" || echo "NORMAL") + fn_notify "-t 5000 -r 54321 " "$urgency" "Charger Plug OUT" "Battery is at $battery_percentage%." + $execute_discharging + fi + fn_percentage + ;; + "Not"*|"Charging") if $verbose; then echo "Case:$battery_status Level: $battery_percentage" ;fi + if [[ "$prev_status" == "Discharging" ]] || [[ "$prev_status" == "Not"* ]] ; then + prev_status=$battery_status + count=$(( timer > $mnt ? timer : $mnt )) # reset count + urgency=$([[ "$battery_percentage" -ge $unplug_charger_threshold ]] && echo "CRITICAL" || echo "NORMAL") + fn_notify "-t 5000 -r 54321 " "$urgency" "Charger Plug In" "Battery is at $battery_percentage%." + $execute_charging + fi + fn_percentage + ;; + "Full") if $verbose; then echo "Case:$battery_status Level: $battery_percentage" ;fi + if [[ $battery_status != "Discharging" ]]; then + now=$(date +%s) + if [[ "$prev_status" == *"harging"* ]] || ((now - lt >= $((notify*60)) )); then + fn_notify "-t 5000 -r 54321" "CRITICAL" "Battery Full" "Please unplug your Charger" + prev_status=$battery_status lt=$now + $execute_charging + fi + fi + ;; + *) + if [[ ! -f "/tmp/hyprdots.batterynotify.status.fallback.$battery_status-$$" ]]; then + echo "Status: '==>> "$battery_status" <<==' Script on Fallback mode,Unknown power supply status.Please copy this line and raise an issue to the Github Repo.Also run 'ls /tmp/hyprdots.batterynotify' to see the list of lock files.*" + touch "/tmp/hyprdots.batterynotify.status.fallback.$battery_status-$$" + fi + fn_percentage + ;; + esac +} + +get_battery_info() { #TODO Might change this if we can get an effective way to parse dbus. I will do it some time... + total_percentage=0 battery_count=0 + for battery in /sys/class/power_supply/BAT*; do + battery_status=$(<"$battery/status") battery_percentage=$(<"$battery/capacity") + total_percentage=$((total_percentage + battery_percentage)) + battery_count=$((battery_count + 1)) + done + battery_percentage=$((total_percentage / battery_count)) #? For Multiple Battery +} + +fn_status_change () { # Handle when status changes +get_battery_info + # Add these two lines at the beginning of the function + local executed_low=false + local executed_unplug=false + + if [ "$battery_status" != "$last_battery_status" ] || [ "$battery_percentage" != "$last_battery_percentage" ]; then + last_battery_status=$battery_status + last_battery_percentage=$battery_percentage # Check if battery status or percentage has changed + fn_verbose + fn_percentage + + if [[ "$battery_percentage" -le "$battery_low_threshold" ]] && ! $executed_low; then $execute_low + executed_low=true executed_unplug=false + fi + if [[ "$battery_percentage" -ge "$unplug_charger_threshold" ]] && ! $executed_unplug; then $execute_unplug + executed_unplug=true executed_low=false + fi + + if $undock; then fn_status; fi + fi +} + +# resume_processes() { for pid in $pids ; do if [ "$pid" -ne "$current_pid" ] ; then kill -CONT $pid ; notify-send -a "Battery Notify" -t 2000 -r 9889 -u "CRITICAL" "Debugging ENDED, Resuming Regular Process" ; fi ; done } + +main() { # Main function +rm -fr /tmp/hyprdots.batterynotify* # Cleaning the lock file +battery_full_threshold=${battery_full_threshold:-100} +battery_critical_threshold=${battery_critical_threshold:-5} +unplug_charger_threshold=${unplug_charger_threshold:-80} +battery_low_threshold=${battery_low_threshold:-20} +timer=${timer:-120} +notify=${notify:-1140} +interval=${interval:-5} +execute_critical=${execute_critical:-"systemctl suspend"} +execute_low=${execute_low:-} +execute_unplug=${execute_unplug:-} + +config_info +if $verbose; then for line in "Verbose Mode is ON..." "" "" "" "" ; do echo $line ; done; +#TODO Might still need this in the future but for now we don't have any battery notify issues +# current_pid=$$ +# pids=$(pgrep -f "/usr/bin/env bash ${scrDir}/batterynotify.sh" ) +# for pid in $pids ; do if [ "$pid" -ne $current_pid ] ;then kill -STOP "$pid" ;notify-send -a "Battery Notify" -t 2000 -r 9889 -u "CRITICAL" "Debugging STARTED, Pausing Regular Process" ;fi ; done ; trap resume_processes SIGINT ; +fi + get_battery_info # initiate the function + last_notified_percentage=$battery_percentage + prev_status=$battery_status +dbus-monitor --system "type='signal',interface='org.freedesktop.DBus.Properties',path='$(upower -e | grep battery)'" 2> /dev/null | while read -r battery_status_change; do fn_status_change ; done +} + +verbose=false + case "$1" in + -m|--modify) + EDITOR="${EDITOR:-code}" #* Use VS Code as the default editor + echo -e "[Editor]: $EDITOR \n To change editor, run 'export EDITOR=preferred-editor' \n[Modifying]: $batterynotify_conf \nPress Any Key if done editing" + #kitty -o allow_remote_control=yes -o listen_on=unix:/tmp/mykitty $(which $EDITOR) "$batterynotify_conf" > /dev/null 2>&1 & + kitty "$(which $EDITOR)" "$batterynotify_conf" > /dev/null 2>&1 & + LAST_MD5SUM=$(md5sum "$batterynotify_conf") + while true; do CURRENT_MD5SUM=$(md5sum "$batterynotify_conf") + if [ "$CURRENT_MD5SUM" != "$LAST_MD5SUM" ]; then + notify-send "Config Changed: Needs reboot or restart $0" + LAST_MD5SUM="$CURRENT_MD5SUM" + fi ; read -t 2 -n 1 > /dev/null && break #? loop every 2 seconds + done + exit 0 + ;; + -i|--info) + config_info + exit 0 + ;; + -v|--verbose) + verbose=true + ;; + -*) + cat << HELP +Usage: $0 [options] + +[-m|--modify] Modify configuration file +[-i|--info] Display configuration information +[-v|--verbose] Debugging mode +[-h|--help] This Message +HELP + exit 0 + ;; + esac + +mnc=2 mxc=50 mnl=10 mxl=80 mnu=50 mxu=100 mnt=60 mxt=1000 mnf=80 mxf=100 mnn=1 mxn=1140 mni=1 mxi=10 #Defaults Ranges +check_range() { + local var=$1 min=$2 max=$3 error_message=$4 + if [[ $var =~ ^[0-9]+$ ]] && (( var >= min && var <= max )); then + var=$var ; shift 2 + else + echo -e "$1 WARNING: $error_message must be $min - $max." >&2 + fi +} + + check_range "$battery_full_threshold" $mnf $mxf "Full Threshold" + check_range "$battery_critical_threshold" $mnc $mxc "Critical Threshold" + check_range "$battery_low_threshold" $mnl $mxl "Low Threshold" + check_range "$unplug_charger_threshold" $mnu $mxu "Unplug Threshold" + check_range "$timer" $mnt $mxt "Timer" + check_range "$notify" $mnn $mxn "Notify" + check_range "$interval" $mni $mxi "Interval" + +main diff --git a/scripts/brightnesscontrol.sh b/scripts/brightnesscontrol.sh new file mode 100755 index 0000000..d3c0bd9 --- /dev/null +++ b/scripts/brightnesscontrol.sh @@ -0,0 +1,111 @@ +#!/usr/bin/env bash + +# Check if the script is already running +pgrep -cf "${0##*/}" | grep -qv 1 && echo "An instance of the script is already running..." && exit 1 + +scrDir=`dirname "$(realpath "$0")"` +source $scrDir/globalcontrol.sh + +# Check if SwayOSD is installed +use_swayosd=false +if command -v swayosd-client >/dev/null 2>&1 && pgrep -x swayosd-server >/dev/null; then + use_swayosd=true +fi + +print_error() +{ +cat << EOF + $(basename ${0}) [step] [mode] + ...valid actions are... + i -- ncrease brightness [+5%] + d -- ecrease brightness [-5%] + + Example: + $(basename ${0}) i 10 # Increase brightness by 10% + $(basename ${0}) d # Decrease brightness by default step (5%) + $(basename ${0}) i 5 -q # Increase brightness by 5% quietly +EOF +} +notify="${waybar_brightness_notification:-true}" # Default: notifications are enabled +action="" # Will store 'increase' or 'decrease' +step=5 # Default step value + +# Parse all arguments +for arg in "$@"; do + case $arg in + i|-i) + [ -n "$action" ] && + { + echo -e "\033[38;2;255;0;0mOne or more actions are provided\033[0m"; + print_error; + exit 1; + } # Prevent multiple actions + action="increase" ;; # Increase brightness + d|-d) + [ -n "$action" ] && + { + echo -e "\033[38;2;255;0;0mOne or more actions are provided\033[0m"; + print_error; + exit 1; + } # Prevent multiple actions + action="decrease" ;; # Decrease brightness + q|-q) + notify=false ;; # Disabling notification + [0-9]*) + if ! echo "$arg" | grep -Eq '^[0-9]+$'; then + print_error + exit 1 + fi + step=$arg ;; # Step value + *) + print_error && exit 1 ;; # Invalid input + esac +done + +if [ -z "$action" ]; then # If actions are missing with mode/value + echo -e "\033[38;2;255;0;0mActions are not provided\033[0m" + print_error + exit 1 +fi + +send_notification() { + brightness=`brightnessctl info | grep -oP "(?<=\()\d+(?=%)" | cat` + brightinfo=$(brightnessctl info | awk -F "'" '/Device/ {print $2}') + angle="$(((($brightness + 2) / 5) * 5))" + ico="$HOME/.config/dunst/icons/vol/vol-${angle}.svg" + bar=$(seq -s "." $(($brightness / 15)) | sed 's/[0-9]//g') + notify-send -a "t2" -r 91190 -t 800 -i "${ico}" "${brightness}${bar}" "${brightinfo}" +} + +get_brightness() { + brightnessctl -m | grep -o '[0-9]\+%' | head -c-2 +} + + +case $action in +increase) # increase the backlight + if [[ $(get_brightness) -lt 10 ]] ; then + # increase the backlight by 1% if less than 10% + step=1 + fi + + $use_swayosd && swayosd-client --brightness raise "$step" && exit 0 + brightnessctl set +${step}% + [ "$notify" = true ] && send_notification ;; +decrease) # decrease the backlight + + if [[ $(get_brightness) -le 10 ]] ; then + # decrease the backlight by 1% if less than 10% + step=1 + fi + + if [[ $(get_brightness) -le 1 ]]; then + brightnessctl set ${step}% + $use_swayosd && exit 0 + else + $use_swayosd && swayosd-client --brightness lower "$step" && exit 0 + brightnessctl set ${step}%- + fi + + [ "$notify" = true ] && send_notification ;; +esac diff --git a/scripts/center-window.sh b/scripts/center-window.sh new file mode 100755 index 0000000..ad57a01 --- /dev/null +++ b/scripts/center-window.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env bash + +# Toggle single_window_aspect_ratio in dwindle layout +# This script toggles between enforcing a 1:1 aspect ratio and allowing full width + +# Get current dwindle settings +CURRENT_RATIO=$(hyprctl getoption dwindle:single_window_aspect_ratio | grep -oP 'vec2: \K.*') + +if [ "$CURRENT_RATIO" = "[1, 1]" ]; then + # Disable aspect ratio (set to 0 0 to disable) + hyprctl keyword dwindle:single_window_aspect_ratio "0 0" +else + # Enable aspect ratio (1 1 for square) + hyprctl keyword dwindle:single_window_aspect_ratio "1 1" +fi + diff --git a/scripts/cliphist-paste.sh b/scripts/cliphist-paste.sh new file mode 100755 index 0000000..f11928b --- /dev/null +++ b/scripts/cliphist-paste.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env sh + +selected_item="$(/run/current-system/sw/bin/cliphist list | rofi -dmenu -i -p 'Clipboard')" + +[ -z "$selected_item" ] && exit 0 + +printf '%s' "$selected_item" | /run/current-system/sw/bin/cliphist decode | /run/current-system/sw/bin/wl-copy +sleep 0.05 +/run/current-system/sw/bin/wtype -M ctrl -k v -m ctrl diff --git a/scripts/cliphist.sh b/scripts/cliphist.sh new file mode 100755 index 0000000..9943398 --- /dev/null +++ b/scripts/cliphist.sh @@ -0,0 +1,182 @@ +#!/usr/bin/env sh + +# Set variables +scrDir=$(dirname "$(realpath "$0")") +source "$scrDir/globalcontrol.sh" +roconf="${confDir}/rofi/clipboard.rasi" +favoritesFile="${HOME}/.cliphist_favorites" + +# Set rofi scaling +[[ "${rofiScale}" =~ ^[0-9]+$ ]] || rofiScale=10 +r_scale="configuration {font: \"JetBrainsMono Nerd Font ${rofiScale}\";}" +wind_border=$((hypr_border * 3 / 2)) +elem_border=$([ $hypr_border -eq 0 ] && echo "5" || echo $hypr_border) + +# Evaluate spawn position +readarray -t curPos < <(hyprctl cursorpos -j | jq -r '.x,.y') +readarray -t monRes < <(hyprctl -j monitors | jq '.[] | select(.focused==true) | .width,.height,.scale,.x,.y') +readarray -t offRes < <(hyprctl -j monitors | jq -r '.[] | select(.focused==true).reserved | map(tostring) | join("\n")') +monRes[2]="$(echo "${monRes[2]}" | sed "s/\.//")" +monRes[0]="$(( ${monRes[0]} * 100 / ${monRes[2]} ))" +monRes[1]="$(( ${monRes[1]} * 100 / ${monRes[2]} ))" +curPos[0]="$(( ${curPos[0]} - ${monRes[3]} ))" +curPos[1]="$(( ${curPos[1]} - ${monRes[4]} ))" + +if [ "${curPos[0]}" -ge "$((${monRes[0]} / 2))" ] ; then + x_pos="east" + x_off="-$(( ${monRes[0]} - ${curPos[0]} - ${offRes[2]} ))" +else + x_pos="west" + x_off="$(( ${curPos[0]} - ${offRes[0]} ))" +fi + +if [ "${curPos[1]}" -ge "$((${monRes[1]} / 2))" ] ; then + y_pos="south" + y_off="-$(( ${monRes[1]} - ${curPos[1]} - ${offRes[3]} ))" +else + y_pos="north" + y_off="$(( ${curPos[1]} - ${offRes[1]} ))" +fi + +r_override="window{location:${x_pos} ${y_pos};anchor:${x_pos} ${y_pos};x-offset:${x_off}px;y-offset:${y_off}px;border:${hypr_width}px;border-radius:${wind_border}px;} wallbox{border-radius:${elem_border}px;} element{border-radius:${elem_border}px;}" + +# Show main menu if no arguments are passed +if [ $# -eq 0 ]; then + main_action=$(echo -e "History\nDelete\nView Favorites\nManage Favorites\nClear History" | rofi -dmenu -theme-str "entry { placeholder: \"Choose action\";}" -theme-str "${r_scale}" -theme-str "${r_override}" -config "${roconf}") +else + main_action="History" +fi + +case "${main_action}" in +"History") + selected_item=$(stash list | rofi -dmenu -theme-str "entry { placeholder: \"History...\";}" -theme-str "${r_scale}" -theme-str "${r_override}" -config "${roconf}") + if [ -n "$selected_item" ]; then + echo "$selected_item" | stash decode | wl-copy + notify-send "Copied to clipboard." + fi + ;; +"Delete") + selected_item=$(stash list | rofi -dmenu -theme-str "entry { placeholder: \"Delete...\";}" -theme-str "${r_scale}" -theme-str "${r_override}" -config "${roconf}") + if [ -n "$selected_item" ]; then + echo "$selected_item" | stash delete + notify-send "Deleted." + fi + ;; +"View Favorites") + if [ -f "$favoritesFile" ] && [ -s "$favoritesFile" ]; then + # Read each Base64 encoded favorite as a separate line + mapfile -t favorites < "$favoritesFile" + + # Prepare a list of decoded single-line representations for rofi + decoded_lines=() + for favorite in "${favorites[@]}"; do + decoded_favorite=$(echo "$favorite" | base64 --decode) + # Replace newlines with spaces for rofi display + single_line_favorite=$(echo "$decoded_favorite" | tr '\n' ' ') + decoded_lines+=("$single_line_favorite") + done + + selected_favorite=$(printf "%s\n" "${decoded_lines[@]}" | rofi -dmenu -theme-str "entry { placeholder: \"View Favorites\";}" -theme-str "${r_scale}" -theme-str "${r_override}" -config "${roconf}") + if [ -n "$selected_favorite" ]; then + # Find the index of the selected favorite + index=$(printf "%s\n" "${decoded_lines[@]}" | grep -nxF "$selected_favorite" | cut -d: -f1) + # Use the index to get the Base64 encoded favorite + if [ -n "$index" ]; then + selected_encoded_favorite="${favorites[$((index - 1))]}" + # Decode and copy the full multi-line content to clipboard + echo "$selected_encoded_favorite" | base64 --decode | wl-copy + notify-send "Copied to clipboard." + else + notify-send "Error: Selected favorite not found." + fi + fi + else + notify-send "No favorites." + fi + ;; +"Manage Favorites") + manage_action=$(echo -e "Add to Favorites\nDelete from Favorites\nClear All Favorites" | rofi -dmenu -theme-str "entry { placeholder: \"Manage Favorites\";}" -theme-str "${r_scale}" -theme-str "${r_override}" -config "${roconf}") + + case "${manage_action}" in + "Add to Favorites") + # Show clipboard history to add to favorites + item=$(stash list | rofi -dmenu -theme-str "entry { placeholder: \"Add to Favorites...\";}" -theme-str "${r_scale}" -theme-str "${r_override}" -config "${roconf}") + if [ -n "$item" ]; then + full_item=$(echo "$item" | stash decode) + encoded_item=$(echo "$full_item" | base64 -w 0) + + # Check if the item is already in the favorites file + if grep -Fxq "$encoded_item" "$favoritesFile"; then + notify-send "Item is already in favorites." + else + # Add the encoded item to the favorites file + echo "$encoded_item" >> "$favoritesFile" + notify-send "Added in favorites." + fi + fi + ;; + "Delete from Favorites") + if [ -f "$favoritesFile" ] && [ -s "$favoritesFile" ]; then + # Read each Base64 encoded favorite as a separate line + mapfile -t favorites < "$favoritesFile" + + # Prepare a list of decoded single-line representations for rofi + decoded_lines=() + for favorite in "${favorites[@]}"; do + decoded_favorite=$(echo "$favorite" | base64 --decode) + # Replace newlines with spaces for rofi display + single_line_favorite=$(echo "$decoded_favorite" | tr '\n' ' ') + decoded_lines+=("$single_line_favorite") + done + + selected_favorite=$(printf "%s\n" "${decoded_lines[@]}" | rofi -dmenu -theme-str "entry { placeholder: \"Remove from Favorites...\";}" -theme-str "${r_scale}" -theme-str "${r_override}" -config "${roconf}") + if [ -n "$selected_favorite" ]; then + index=$(printf "%s\n" "${decoded_lines[@]}" | grep -nxF "$selected_favorite" | cut -d: -f1) + if [ -n "$index" ]; then + selected_encoded_favorite="${favorites[$((index - 1))]}" + + # Handle case where only one item is present + if [ "$(wc -l < "$favoritesFile")" -eq 1 ]; then + # Remove the single encoded item from the file + > "$favoritesFile" + else + # Remove the selected encoded item from the favorites file + grep -vF -x "$selected_encoded_favorite" "$favoritesFile" > "${favoritesFile}.tmp" && mv "${favoritesFile}.tmp" "$favoritesFile" + fi + notify-send "Item removed from favorites." + else + notify-send "Error: Selected favorite not found." + fi + fi + else + notify-send "No favorites to remove." + fi + ;; + "Clear All Favorites") + if [ -f "$favoritesFile" ] && [ -s "$favoritesFile" ]; then + confirm=$(echo -e "Yes\nNo" | rofi -dmenu -theme-str "entry { placeholder: \"Clear All Favorites?\";}" -theme-str "${r_scale}" -theme-str "${r_override}" -config "${roconf}") + if [ "$confirm" = "Yes" ]; then + > "$favoritesFile" + notify-send "All favorites have been deleted." + fi + else + notify-send "No favorites to delete." + fi + ;; + *) + echo "Invalid action" + exit 1 + ;; + esac + ;; +"Clear History") + if [ "$(echo -e "Yes\nNo" | rofi -dmenu -theme-str "entry { placeholder: \"Clear Clipboard History?\";}" -theme-str "${r_scale}" -theme-str "${r_override}" -config "${roconf}")" == "Yes" ] ; then + stash db wipe --expired + notify-send "Clipboard history cleared." + fi + ;; +*) + echo "Invalid action" + exit 1 + ;; +esac \ No newline at end of file diff --git a/scripts/cpuinfo.sh b/scripts/cpuinfo.sh new file mode 100755 index 0000000..79a2d48 --- /dev/null +++ b/scripts/cpuinfo.sh @@ -0,0 +1,64 @@ +#!/usr/bin/env sh + +map_floor() { + + IFS=', ' read -r -a pairs <<< "$1" + + if [[ ${pairs[-1]} != *":"* ]]; then + def_val="${pairs[-1]}" + unset 'pairs[${#pairs[@]}-1]' + fi + for pair in "${pairs[@]}"; do + IFS=':' read -r key value <<< "$pair" + if [ ${2%%.*} -gt $key ]; then + echo "$value" + return + fi + done + [ -n "$def_val" ] && echo $def_val || echo " " +} + +# Define glyphs +if [[ $NO_EMOJI -eq 1 ]]; then + temp_lv="85:, 65:, 45:☁, ❄" +else + temp_lv="85:🌋, 65:🔥, 45:☁️, ❄️" +fi +util_lv="90:, 60:󰓅, 30:󰾅, 󰾆" + +# Get static CPU information +model=$(lscpu | awk -F': ' '/Model name/ {gsub(/^ *| *$| CPU.*/,"",$2); print $2}') +maxfreq=$(lscpu | awk '/CPU max MHz/ { sub(/\..*/,"",$4); print $4}') + +# Get CPU stat +statFile=$(cat /proc/stat | head -1) +prevStat=$(awk '{print $2+$3+$4+$6+$7+$8 }' <<< $statFile) +prevIdle=$(awk '{print $5 }' <<< $statFile) + +while true; do + # Get CPU stat + statFile=$(cat /proc/stat | head -1) + currStat=$(awk '{print $2+$3+$4+$6+$7+$8 }' <<< $statFile) + currIdle=$(awk '{print $5 }' <<< $statFile) + diffStat=$((currStat-prevStat)) + diffIdle=$((currIdle-prevIdle)) + + # Get dynamic CPU information + utilization=$(awk -v stat="$diffStat" -v idle="$diffIdle" 'BEGIN {printf "%.1f", (stat/(stat+idle))*100}') + temperature=$(sensors | awk -F': ' '/Package id 0|Tctl/ { gsub(/^ *\+?|\..*/,"",$2); print $2; f=1; exit} END { if (!f) print "N/A"; }') + frequency=$(cat /proc/cpuinfo | awk '/cpu MHz/{ sum+=$4; c+=1 } END { printf "%.0f", sum/c }') + + # Generate glyphs + icons=$(echo "$(map_floor "$util_lv" $utilization)$(map_floor "$temp_lv" $temperature)") + speedo=$(echo ${icons:0:1}) + thermo=$(echo ${icons:1:1}) + emoji=$(echo ${icons:2}) + + # Print the output + echo "{\"text\":\"$thermo $temperature°C\", \"tooltip\":\"$model\n$thermo Temperature: $temperature°C $emoji\n$speedo Utilization: $utilization%\n Clock Speed: $frequency/$maxfreq MHz\"}" + + # Store state and sleep + prevStat=$currStat + prevIdle=$currIdle + sleep 5 +done diff --git a/scripts/dontkillsteam.sh b/scripts/dontkillsteam.sh new file mode 100755 index 0000000..d162ddc --- /dev/null +++ b/scripts/dontkillsteam.sh @@ -0,0 +1,5 @@ +if [[ $(hyprctl activewindow -j | jq -r ".class") == "Steam" ]]; then + xdotool windowunmap $(xdotool getactivewindow) +else + hyprctl dispatch killactive "" +fi diff --git a/scripts/gamelauncher.sh b/scripts/gamelauncher.sh new file mode 100755 index 0000000..d08f413 --- /dev/null +++ b/scripts/gamelauncher.sh @@ -0,0 +1,96 @@ +#!/usr/bin/env sh + +# set variables +MODE=${1:-5} +scrDir=`dirname "$(realpath "$0")"` +source $scrDir/globalcontrol.sh +ThemeSet="${confDir}/hypr/themes/theme.conf" +RofiConf="${confDir}/rofi/steam/gamelauncher_${MODE}.rasi" + +# set rofi override +elem_border=$(( hypr_border * 2 )) +icon_border=$(( elem_border - 3 )) +r_override="element{border-radius:${elem_border}px;} element-icon{border-radius:${icon_border}px;}" + +fn_steam() { +# check steam mount paths +SteamPaths=`grep '"path"' $SteamLib | awk -F '"' '{print $4}'` +ManifestList=`find $SteamPaths/steamapps/ -type f -name "appmanifest_*.acf" 2>/dev/null` + +# read installed games +GameList=$(echo "$ManifestList" | while read acf +do + appid=`grep '"appid"' $acf | cut -d '"' -f 4` + if [ -f ${SteamThumb}/${appid}_library_600x900.jpg ] ; then + game=`grep '"name"' $acf | cut -d '"' -f 4` + echo "$game|$appid" + else + continue + fi +done | sort) + +# launch rofi menu +RofiSel=$( echo "$GameList" | while read acf +do + appid=`echo $acf | cut -d '|' -f 2` + game=`echo $acf | cut -d '|' -f 1` + echo -en "$game\x00icon\x1f${SteamThumb}/${appid}_library_600x900.jpg\n" +done | rofi -dmenu -theme-str "${r_override}" -config $RofiConf) + +# launch game +if [ ! -z "$RofiSel" ] ; then + launchid=`echo "$GameList" | grep "$RofiSel" | cut -d '|' -f 2` + ${steamlaunch} -applaunch "${launchid} [gamemoderun %command%]" & + # dunstify "t1" -a "Launching ${RofiSel}..." -i ${SteamThumb}/${launchid}_header.jpg -r 91190 -t 2200 + notify-send -a "t1" -i "${SteamThumb}/${launchid}_header.jpg" "Launching ${RofiSel}..." + +fi +} + +fn_lutris() { +[ ! -e "${icon_path}" ] && icon_path="${HOME}/.local/share/lutris/coverart" +[ ! -e "${icon_path}" ] && icon_path="${HOME}/.cache/lutris/coverart" +meta_data="/tmp/hyprdots-$(id -u)-lutrisgames.json" + +# Retrieve the list of games from Lutris in JSON format +#TODO Only call this if new apps are installed... + # [ ! -s "${meta_data}" ] && +notify-send -a "t1" "Please wait... " -t 4000 + +eval "${run_lutris}" -j -l 2> /dev/null| jq --arg icons "$icon_path/" --arg prefix ".jpg" '.[] |= . + {"select": (.name + "\u0000icon\u001f" + $icons + .slug + $prefix)}' > "${meta_data}" + +[ ! -s "${meta_data}" ] && notify-send -a "t1" "Cannot Fetch Lutris Games!" && exit 1 + + +CHOICE=$(jq -r '.[].select' "${meta_data}" | rofi -dmenu -p Lutris -theme-str "${r_override}" -config "${RofiConf}" ) +[ -z "$CHOICE" ] && exit 0 + SLUG=$(jq -r --arg choice "$CHOICE" '.[] | select(.name == $choice).slug' "${meta_data}" ) + notify-send -a "t1" -i "${icon_path}/${SLUG}.jpg" "Launching ${CHOICE}..." + exec xdg-open "lutris:rungame/${SLUG}" +} + +# Handle if flatpak or pkgmgr +run_lutris="" +( flatpak list --columns=application | grep -q "net.lutris.Lutris" ) && run_lutris="flatpak run net.lutris.Lutris" ; icon_path="${HOME}/.var/app/net.lutris.Lutris/data/lutris/coverart/" +[ -z "${run_lutris}" ] && ( pkg_installed 'lutris' ) && run_lutris="lutris" + +if [ -z "${run_lutris}" ] || echo "$*" | grep -q "steam" ; then + # set steam library + if pkg_installed steam ; then + SteamLib="${XDG_DATA_HOME:-$HOME/.local/share}/Steam/config/libraryfolders.vdf" + SteamThumb="${XDG_DATA_HOME:-$HOME/.local/share}/Steam/appcache/librarycache" + steamlaunch="steam" + else + SteamLib="$HOME/.var/app/com.valvesoftware.Steam/.local/share/Steam/config/libraryfolders.vdf" + SteamThumb="$HOME/.var/app/com.valvesoftware.Steam/.local/share/Steam/appcache/librarycache" + steamlaunch="flatpak run com.valvesoftware.Steam" + fi + + if [ ! -f $SteamLib ] || [ ! -d $SteamThumb ] ; then + notify-send -a "t1" "Steam library not found!" + exit 1 + fi + fn_steam +else + fn_lutris +fi diff --git a/scripts/gamemode.nix b/scripts/gamemode.nix new file mode 100644 index 0000000..3bf77e6 --- /dev/null +++ b/scripts/gamemode.nix @@ -0,0 +1,16 @@ +{ pkgs }: + +pkgs.writeShellScriptBin "gamemode" '' + # Toggle animations on/off for gaming mode + status=$(${pkgs.hyprland}/bin/hyprctl getoption animations:enabled | grep -oP 'int: \K[0-9]+') + + if [ "$status" = "1" ]; then + # Disable animations + ${pkgs.hyprland}/bin/hyprctl keyword animations:enabled 0 + ${pkgs.libnotify}/bin/notify-send "Gamemode: ON" "Animations disabled" + else + # Enable animations + ${pkgs.hyprland}/bin/hyprctl keyword animations:enabled 1 + ${pkgs.libnotify}/bin/notify-send "Gamemode: OFF" "Animations enabled" + fi +'' diff --git a/scripts/gamemode.sh b/scripts/gamemode.sh new file mode 100755 index 0000000..eb15b4c --- /dev/null +++ b/scripts/gamemode.sh @@ -0,0 +1,29 @@ +#!/usr/bin/env sh +HYPRGAMEMODE=$(hyprctl getoption animations:enabled | sed -n '1p' | awk '{print $2}') + +# Waybar performance +FILE="$HOME/.config/waybar/style.css" + +sed -i 's/\/\* \(.*animation:.*\) \*\//\1/g' $FILE +sed -i 's/\/\* \(.*transition:.*\) \*\//\1/g' $FILE +if [ $HYPRGAMEMODE = 1 ]; then + sed -i 's/^\(.*animation:.*\)$/\/\* \1 \*\//g' $FILE + sed -i 's/^\(.*transition:.*\)$/\/\* \1 \*\//g' $FILE +fi +killall waybar +waybar >/dev/null 2>&1 & + +# Hyprland performance +if [ $HYPRGAMEMODE = 1 ]; then + hyprctl --batch "\ + keyword animations:enabled 0;\ + keyword decoration:drop_shadow 0;\ + keyword decoration:blur:enabled 0;\ + keyword general:gaps_in 0;\ + keyword general:gaps_out 0;\ + keyword general:border_size 1;\ + keyword decoration:rounding 0" + exit +else + hyprctl reload +fi diff --git a/scripts/globalcontrol.sh b/scripts/globalcontrol.sh new file mode 100755 index 0000000..73c6244 --- /dev/null +++ b/scripts/globalcontrol.sh @@ -0,0 +1,159 @@ +#!/usr/bin/env bash + + +#// hyde envs + +export confDir="${XDG_CONFIG_HOME:-$HOME/.config}" +export hydeConfDir="${confDir}/hyde" +export cacheDir="$HOME/.cache/hyde" +export thmbDir="${cacheDir}/thumbs" +export dcolDir="${cacheDir}/dcols" +export hashMech="sha1sum" + +get_hashmap() +{ + unset wallHash + unset wallList + unset skipStrays + unset verboseMap + + for wallSource in "$@"; do + [ -z "${wallSource}" ] && continue + [ "${wallSource}" == "--skipstrays" ] && skipStrays=1 && continue + [ "${wallSource}" == "--verbose" ] && verboseMap=1 && continue + + hashMap=$(find "${wallSource}" -type f \( -iname "*.gif" -o -iname "*.jpg" -o -iname "*.jpeg" -o -iname "*.png" \) -exec "${hashMech}" {} + | sort -k2) + if [ -z "${hashMap}" ] ; then + echo "WARNING: No image found in \"${wallSource}\"" + continue + fi + + while read -r hash image ; do + wallHash+=("${hash}") + wallList+=("${image}") + done <<< "${hashMap}" + done + + if [ -z "${#wallList[@]}" ] || [[ "${#wallList[@]}" -eq 0 ]] ; then + if [[ "${skipStrays}" -eq 1 ]] ; then + return 1 + else + echo "ERROR: No image found in any source" + exit 1 + fi + fi + + if [[ "${verboseMap}" -eq 1 ]] ; then + echo "// Hash Map //" + for indx in "${!wallHash[@]}" ; do + echo ":: \${wallHash[${indx}]}=\"${wallHash[indx]}\" :: \${wallList[${indx}]}=\"${wallList[indx]}\"" + done + fi +} + +get_themes() +{ + unset thmSortS + unset thmListS + unset thmWallS + unset thmSort + unset thmList + unset thmWall + + while read thmDir ; do + if [ ! -e "$(readlink "${thmDir}/wall.set")" ] ; then + get_hashmap "${thmDir}" --skipstrays || continue + echo "fixig link :: ${thmDir}/wall.set" + ln -fs "${wallList[0]}" "${thmDir}/wall.set" + fi + [ -f "${thmDir}/.sort" ] && thmSortS+=("$(head -1 "${thmDir}/.sort")") || thmSortS+=("0") + thmListS+=("$(basename "${thmDir}")") + thmWallS+=("$(readlink "${thmDir}/wall.set")") + done < <(find "${hydeConfDir}/themes" -mindepth 1 -maxdepth 1 -type d) + + while IFS='|' read -r sort theme wall ; do + thmSort+=("${sort}") + thmList+=("${theme}") + thmWall+=("${wall}") + done < <(parallel --link echo "{1}\|{2}\|{3}" ::: "${thmSortS[@]}" ::: "${thmListS[@]}" ::: "${thmWallS[@]}" | sort -n -k 1 -k 2) + + if [ "${1}" == "--verbose" ] ; then + echo "// Theme Control //" + for indx in "${!thmList[@]}" ; do + echo -e ":: \${thmSort[${indx}]}=\"${thmSort[indx]}\" :: \${thmList[${indx}]}=\"${thmList[indx]}\" :: \${thmWall[${indx}]}=\"${thmWall[indx]}\"" + done + fi +} + +[ -f "${hydeConfDir}/hyde.conf" ] && source "${hydeConfDir}/hyde.conf" + +case "${enableWallDcol}" in + 0|1|2|3) ;; + *) enableWallDcol=0 ;; +esac + +if [ -z "${hydeTheme}" ] || [ ! -d "${hydeConfDir}/themes/${hydeTheme}" ] ; then + get_themes + hydeTheme="${thmList[0]}" +fi + +export hydeTheme +export hydeThemeDir="${hydeConfDir}/themes/${hydeTheme}" +export wallbashDir="${hydeConfDir}/wallbash" +export enableWallDcol + + +#// hypr vars + +if printenv HYPRLAND_INSTANCE_SIGNATURE &> /dev/null; then + export hypr_border="$(hyprctl -j getoption decoration:rounding | jq '.int')" + export hypr_width="$(hyprctl -j getoption general:border_size | jq '.int')" +fi + + +#// extra fns + +pkg_installed() +{ + local pkgIn=$1 + if pacman -Qi "${pkgIn}" &> /dev/null ; then + return 0 + elif pacman -Qi "flatpak" &> /dev/null && flatpak info "${pkgIn}" &> /dev/null ; then + return 0 + elif command -v "${pkgIn}" &> /dev/null ; then + return 0 + else + return 1 + fi +} + +get_aurhlpr() +{ + if pkg_installed yay + then + aurhlpr="yay" + elif pkg_installed paru + then + aurhlpr="paru" + fi +} + +set_conf() +{ + local varName="${1}" + local varData="${2}" + touch "${hydeConfDir}/hyde.conf" + + if [ $(grep -c "^${varName}=" "${hydeConfDir}/hyde.conf") -eq 1 ] ; then + sed -i "/^${varName}=/c${varName}=\"${varData}\"" "${hydeConfDir}/hyde.conf" + else + echo "${varName}=\"${varData}\"" >> "${hydeConfDir}/hyde.conf" + fi +} + +set_hash() +{ + local hashImage="${1}" + "${hashMech}" "${hashImage}" | awk '{print $1}' +} + diff --git a/scripts/gpuinfo.sh b/scripts/gpuinfo.sh new file mode 100755 index 0000000..d4da0e1 --- /dev/null +++ b/scripts/gpuinfo.sh @@ -0,0 +1,292 @@ +#!/usr/bin/env bash +# shellcheck disable=SC2312 +# shellcheck disable=SC1090 +scrDir=`dirname "$(realpath "$0")"` +gpuQ="/tmp/hyprdots-${UID}-gpuinfo-query" +tired=false +[[ " $* " =~ " tired " ]] && ! grep -q "tired" "${gpuQ}" && echo "tired=true" >>"${gpuQ}" +[[ " $* " =~ " no_emoji " ]] && ! grep -q "NO_EMOJI" "${gpuQ}" && echo "NO_EMOJI=1" >>"${gpuQ}" + +if [[ ! " $* " =~ " startup " ]]; then + gpuQ="${gpuQ}$2" +fi +detect() { # Auto detect Gpu used by Hyprland(declared using env = WLR_DRM_DEVICES) Sophisticated? +card=$(echo "${WLR_DRM_DEVICES}" | cut -d':' -f1 | cut -d'/' -f4) +# shellcheck disable=SC2010 +slot_number=$(ls -l /dev/dri/by-path/ | grep "${card}" | awk -F'pci-0000:|-card' '{print $2}') +vendor_id=$(lspci -nn -s "${slot_number}" ) +declare -A vendors=(["10de"]="nvidia" ["8086"]="intel" ["1002"]="amd") +for vendor in "${!vendors[@]}"; do + if [[ ${vendor_id} == *"${vendor}"* ]]; then + initGPU="${vendors[${vendor}]}" + break + fi +done +if [[ -n ${initGPU} ]]; then + $0 --use "${initGPU}" startup +fi +} + +query() { + nvidia_flag=0 amd_flag=0 intel_flag=0 +touch "${gpuQ}" + +if lsmod | grep -q 'nouveau'; then + echo "nvidia_gpu=\"Linux\"" >>"${gpuQ}" #? Incase If nouveau is installed + echo "nvidia_flag=1 # Using nouveau an open-source nvidia driver" >>"${gpuQ}" +elif command -v nvidia-smi &> /dev/null; then +nvidia_gpu=$(nvidia-smi --query-gpu=gpu_name --format=csv,noheader,nounits | head -n 1) + if [[ -n "${nvidia_gpu}" ]] ; then # Check for NVIDIA GPU + if [[ "${nvidia_gpu}" == *"NVIDIA-SMI has failed"* ]]; then #? Second Layer for dGPU + echo "nvidia_flag=0 # NVIDIA-SMI has failed" >> "${gpuQ}" + else + nvidia_address=$(lspci | grep -Ei "VGA|3D" | grep -i "${nvidia_gpu/NVIDIA /}" | cut -d' ' -f1) + { echo "nvidia_address=\"${nvidia_address}\"" + echo "nvidia_gpu=\"${nvidia_gpu/NVIDIA /}\"" + echo "nvidia_flag=1" + } >> "${gpuQ}" + fi + fi +fi + +if lspci -nn | grep -E "(VGA|3D)" | grep -iq "1002"; then +amd_gpu="$(lspci -nn | grep -Ei "VGA|3D" | grep -m 1 "1002" | awk -F'Advanced Micro Devices, Inc. ' '{gsub(/ *\[[^\]]*\]/,""); gsub(/ *\([^)]*\)/,""); print $2}')" +amd_address=$(lspci | grep -Ei "VGA|3D" | grep -i "${amd_gpu}" | cut -d' ' -f1) +{ echo "amd_address=\"${amd_address}\"" + echo "amd_flag=1" # Check for Amd GPU + echo "amd_gpu=\"${amd_gpu}\"" +} >> "${gpuQ}";fi + +if lspci -nn | grep -E "(VGA|3D)" | grep -iq "8086"; then +intel_gpu="$(lspci -nn | grep -Ei "VGA|3D" | grep -m 1 "8086" | awk -F'Intel Corporation ' '{gsub(/ *\[[^\]]*\]/,""); gsub(/ *\([^)]*\)/,""); print $2}')" +intel_address=$(lspci | grep -Ei "VGA|3D" | grep -i "${intel_gpu}" | cut -d' ' -f1) +{ echo "intel_address=\"${intel_address}\"" + echo "intel_flag=1" # Check for Intel GPU + echo "intel_gpu=\"${intel_gpu}\"" +} >>"${gpuQ}"; fi + +if ! grep -q "prioGPU=" "${gpuQ}" && [[ -n "${WLR_DRM_DEVICES}" ]]; then + trap detect EXIT +fi + +} + +toggle() { + if [[ -n "$1" ]]; then + next_prioGPU="$1_flag" + else + # Initialize gpu_flags and prioGPU if they don't exist + if ! grep -q "gpu_flags=" "${gpuQ}"; then + gpu_flags=$(grep "flag=1" "${gpuQ}" | cut -d '=' -f 1 | tr '\n' ' ' | tr -d '#') + echo "" >> "${gpuQ}" + echo "gpu_flags=\"${gpu_flags[*]}\"" >> "${gpuQ}" + fi + + if ! grep -q "prioGPU=" "${gpuQ}"; then + gpu_flags=$(grep "gpu_flags=" "${gpuQ}" | cut -d'=' -f 2) + initGPU=$(echo "${gpu_flags}" | cut -d ' ' -f 1) + echo "prioGPU=${initGPU}" >> "${gpuQ}" + fi + mapfile -t anchor < <(grep "flag=1" "${gpuQ}" | cut -d '=' -f 1) + prioGPU=$(grep "prioGPU=" "${gpuQ}" | cut -d'=' -f 2) # Get the current prioGPU from the file + # Find the index of the current prioGPU in the anchor array + for index in "${!anchor[@]}"; do + if [[ "${anchor[${index}]}" = "${prioGPU}" ]]; then + current_index=${index} + fi + done + next_index=$(( (current_index + 1) % ${#anchor[@]} )) + next_prioGPU=${anchor[${next_index}]#\#} +fi + +# Set the next prioGPU and remove the '#' character +sed -i 's/^\(nvidia_flag=1\|amd_flag=1\|intel_flag=1\)/#\1/' "${gpuQ}" # Comment out all the gpu flags in the file +sed -i "s/^#${next_prioGPU}/${next_prioGPU}/" "${gpuQ}" # Uncomment the next prioGPU in the file +sed -i "s/prioGPU=${prioGPU}/prioGPU=${next_prioGPU}/" "${gpuQ}" # Update the prioGPU in the file +} + +# Thee shalt find the greatest one, +# He who not more than the chosen one +map_floor() { + + # From the depths of the string, words arise, + # Keys in pairs, a treasure in disguise. + IFS=', ' read -r -a pairs <<< "$1" + + # If the final token stands alone and bold, + # Declare it the default, its worth untold. + if [[ ${pairs[-1]} != *":"* ]]; then + def_val="${pairs[-1]}" + unset 'pairs[${#pairs[@]}-1]' + fi + + # Scans the map, a peak it seeks, + # The highest passed, the value speaks. + for pair in "${pairs[@]}"; do + IFS=':' read -r key value <<< "$pair" + + # Behold! Thou holds the secrets they seek, + # Declare it and silence the whispers unique. + if [ ${2%%.*} -gt $key ]; then + echo "$value" + return + fi + done + + # On this lonely shore, where silence dwells + # Even the waves, echoes words unheard + [ -n "$def_val" ] && echo $def_val || echo " " +} + +generate_json() { +# Generate glyphs + icons=$(echo "$(map_floor "$util_lv" $utilization)$(map_floor "$temp_lv" $temperature)") + speedo=$(echo ${icons:0:1}) + thermo=$(echo ${icons:1:1}) + emoji=$(echo ${icons:2}) + + local json="{\"text\":\"${thermo} ${temperature}°C\", \"tooltip\":\"${primary_gpu}\n${thermo} Temperature: ${temperature}°C ${emoji}" +#? Soon Add Something incase needed. + declare -A tooltip_parts + if [[ -n "${utilization}" ]]; then tooltip_parts["\n$speedo Utilization: "]="${utilization}%" ; fi + if [[ -n "${current_clock_speed}" ]] && [[ -n "${max_clock_speed}" ]]; then tooltip_parts["\n Clock Speed: "]="${current_clock_speed}/${max_clock_speed} MHz" ; fi + if [[ -n "${gpu_load}" ]]; then tooltip_parts["\n$speedo Utilization: "]="${gpu_load}%" ; fi + if [[ -n "${core_clock}" ]]; then tooltip_parts["\n Clock Speed: "]="${core_clock} MHz" ;fi + if [[ -n "${power_usage}" ]]; then if [[ -n "${power_limit}" ]]; then + tooltip_parts["\n󱪉 Power Usage: "]="${power_usage}/${power_limit} W" + else + tooltip_parts["\n󱪉 Power Usage: "]="${power_usage} W" + fi + fi + if [[ -n "${power_discharge}" ]] && [[ "${power_discharge}" != "0" ]]; then tooltip_parts["\n Power Discharge: "]="${power_discharge} W" ;fi + + for key in "${!tooltip_parts[@]}"; do + local value="${tooltip_parts[${key}]}" + if [[ -n "${value}" && "${value}" =~ [a-zA-Z0-9] ]]; then + json+="${key}${value}" + fi + done + json="${json}\"}" + echo "${json}" +} + +general_query() { # Function to get temperature from 'sensors' + filter='' +temperature=$(sensors | ${filter} grep -m 1 -E "(edge|Package id.*|another keyword)" | awk -F ':' '{print int($2)}') #! We can get json data from sensors too + # gpu_load=$() + # core_clock=$() +for file in /sys/class/power_supply/BAT*/power_now; do + [[ -f "${file}" ]] && power_discharge=$(awk '{print $1*10^-6 ""}' "${file}") && break +done +[[ -z "${power_discharge}" ]] && for file in /sys/class/power_supply/BAT*/current_now; do + [[ -e "${file}" ]] && power_discharge=$(awk -v current="$(cat "${file}")" -v voltage="$(cat "${file/current_now/voltage_now}")" 'BEGIN {print (current * voltage) / 10^12 ""}') && break +done +# power_limit=$() +utilization=$(top -bn1 | grep "Cpu(s)" | sed "s/.*, *\([0-9.]*\)%* id.*/\1/" | awk '{print 100 - $1" "}') +current_clock_speed=$(awk '{sum += $1; n++} END {if (n > 0) print sum / n / 1000 ""}' /sys/devices/system/cpu/cpufreq/policy*/scaling_cur_freq) +max_clock_speed=$(awk '{print $1/1000}' /sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq) +} + +intel_GPU() { #? Function to query basic intel GPU + primary_gpu="Intel ${intel_gpu}" + general_query +} + +nvidia_GPU() { #? Function to query Nvidia GPU + primary_gpu="NVIDIA ${nvidia_gpu}" + if [[ "${nvidia_gpu}" == "Linux" ]]; then general_query ; return ; fi #? Open source driver +#? Tired Flag for not using nvidia-smi if GPU is in suspend mode. +if ${tired}; then is_suspend="$(cat /sys/bus/pci/devices/0000:"${nvidia_address}"/power/runtime_status)" + if [[ ${is_suspend} == *"suspend"* ]]; then + printf '{"text":"󰤂", "tooltip":"%s ⏾ Suspended mode"}' "${primary_gpu}"; exit ;fi +fi + gpu_info=$(nvidia-smi --query-gpu=temperature.gpu,utilization.gpu,clocks.current.graphics,clocks.max.graphics,power.draw,power.limit --format=csv,noheader,nounits) + # Split the comma-separated values into an array + IFS=',' read -ra gpu_data <<< "${gpu_info}" + # Extract individual values + temperature="${gpu_data[0]// /}" + utilization="${gpu_data[1]// /}" + current_clock_speed="${gpu_data[2]// /}" + max_clock_speed="${gpu_data[3]// /}" + power_usage="${gpu_data[4]// /}" + power_limit="${gpu_data[5]// /}" +} + +amd_GPU() { #? Function to query amd GPU + primary_gpu="AMD ${amd_gpu}" + # Execute the AMD GPU Python script and use its output + amd_output=$(python3 ${scrDir}/amdgpu.py) +if [[ ! ${amd_output} == *"No AMD GPUs detected."* ]] && [[ ! ${amd_output} == *"Unknown query failure"* ]]; then + # Extract GPU Temperature, GPU Load, GPU Core Clock, and GPU Power Usage from amd_output + temperature=$(echo "${amd_output}" | jq -r '.["GPU Temperature"]' | sed 's/°C//') + gpu_load=$(echo "${amd_output}" | jq -r '.["GPU Load"]' | sed 's/%//') + core_clock=$(echo "${amd_output}" | jq -r '.["GPU Core Clock"]' | sed 's/ GHz//;s/ MHz//') + power_usage=$(echo "${amd_output}" | jq -r '.["GPU Power Usage"]' | sed 's/ Watts//') + + +else +general_query +fi +} + +if [[ ! -f "${gpuQ}" ]]; then +query ; echo -e "Initialized Variable:\n$(cat "${gpuQ}")\n\nReboot or '$0 --reset' to RESET Variables" +fi +source "${gpuQ}" +case "$1" in + "--toggle"|"-t") + toggle +echo -e "Sensor: ${next_prioGPU} GPU" | sed 's/_flag//g' + exit + ;; + "--use"|"-u") + toggle "$2" + ;; + "--reset"|"-rf") + rm -fr "${gpuQ}"* + query + echo -e "Initialized Variable:\n$(cat "${gpuQ}" || true)\n\nReboot or '$0 --reset' to RESET Variables" + exit + ;; + *"-"*) +gpu_flags=$(grep "flag=1" "${gpuQ}" | cut -d '=' -f 1 | tr '\n' ' ' | tr -d '#') +cat << EOF + +Available GPU: ${gpu_flags//_flag/} +[options] +--toggle * Toggle available GPU +--use [GPU] * Only call the specified GPU (Useful for adding specific GPU on waybar) +--reset * Remove & restart all query + +[flags] +tired * Adding this option will not query nvidia-smi if gpu is in suspend mode +startup * Useful if you want a certain GPU to be set at startup +no_emoji * Use glyphs instead of emoji + +* If ${USER} declared env = WLR_DRM_DEVICES on hyprland then use this as the primary GPU +EOF +exit + ;; +esac + +# Define glyphs +if [[ $NO_EMOJI -eq 1 ]]; then + temp_lv="85:, 65:, 45:☁, ❄" +else + temp_lv="85:🌋, 65:🔥, 45:☁️, ❄️" +fi +util_lv="90:, 60:󰓅, 30:󰾅, 󰾆" + +nvidia_flag=${nvidia_flag:-0} intel_flag=${intel_flag:-0} amd_flag=${amd_flag:-0} +#? Based on the flags, call the corresponding function multi flags means multi GPU. +if [[ "${nvidia_flag}" -eq 1 ]]; then + nvidia_GPU +elif [[ "${amd_flag}" -eq 1 ]]; then + amd_GPU +elif [[ "${intel_flag}" -eq 1 ]]; then + intel_GPU +else primary_gpu="Not found" + general_query +fi + +generate_json #? AutoGen the Json txt for Waybar diff --git a/scripts/install.sh b/scripts/install.sh new file mode 100644 index 0000000..2d0c690 --- /dev/null +++ b/scripts/install.sh @@ -0,0 +1,96 @@ +# #!/usr/bin/env bash +# # install.sh - Setup Cody's Dotfiles Environment (Nix + Home Manager) +# +# set -e +# # Always cd to the parent (repo root) so all operations work from repo base directory +# cd "$(dirname "$0")/.." +# +# # Colors for prettiness +# green='\033[0;32m' +# red='\033[0;31m' +# yellow='\033[1;33m' +# normal='\033[0m' +# +# info() { echo -e "${green}[INFO]${normal} $*"; } +# warn() { echo -e "${yellow}[WARN]${normal} $*"; } +# err() { echo -e "${red}[ERROR]${normal} $*"; } +# +# ## Step 1: Check for Nix +# if ! command -v nix &> /dev/null; then +# err "Nix is not installed! Please install Nix first: https://nixos.org/download.html" +# exit 1 +# else +# info "Nix is installed." +# fi +# +# ## Step 2: Enable flakes (if needed) +# if ! nix --experimental-features 'nix-command flakes' flake show &> /dev/null; then +# warn "Nix flakes may not be enabled. Ensure your Nix version supports flakes!" +# info "Try adding experimental-features in /etc/nix/nix.conf or your user config." +# exit 1 +# else +# info "Nix flakes are working." +# fi +# +# ## Step 3: Home Manager presence (not mandatory but recommended) +# if ! nix flake show | grep -q 'homeConfigurations'; then +# warn "Home Manager config not detected in flake output. Ensure it's declared if you want full integration." +# fi +# +# ## Step 4: Detect host +# HOST="$(hostname)" +# +# # Step 4a: Ensure hosts/ exists +# if [[ ! -d hosts ]]; then +# warn "No hosts/ directory detected. Creating one." +# mkdir hosts +# info "Created hosts/ directory." +# fi +# +# # Step 4b: Prompt for host if needed; create scaffold if host missing +# if [[ ! -d "hosts/$HOST" ]]; then +# warn "No host config found for '$HOST' in hosts/." +# ls -1 hosts/ || info "No hosts configured yet." +# read -rp "Enter the host name you want to use (type exactly): " HOST +# if [[ ! -d "hosts/$HOST" ]]; then +# info "Scaffolding minimal host config in hosts/$HOST ..." +# mkdir -p "hosts/$HOST" +# # Make home.nix +# cat > "hosts/$HOST/home.nix" << EOF +# { config, pkgs, ... }: +# { +# home.username = "$USER"; +# home.homeDirectory = "/home/$USER"; +# programs.zsh.enable = true; +# home.stateVersion = "24.05"; +# } +# EOF +# # Make configuration.nix +# cat > "hosts/$HOST/configuration.nix" << EOF +# { config, pkgs, ... }: +# { +# imports = [ ]; +# networking.hostName = "$HOST"; +# system.stateVersion = "24.05"; +# } +# EOF +# info "Scaffolded hosts/$HOST/home.nix and configuration.nix." +# warn "You MUST now add this new host to your flake.nix under nixosConfigurations and/or homeConfigurations." +# info "See hosts/$HOST/home.nix and configuration.nix for templates." +# fi +# fi +# info "Using host: $HOST" +# +# ## Step 5: Run Home Manager activation +# info "Applying Nix Flake config using Home Manager..." +# nix run .#homeConfigurations."$HOST".activationPackage +# +# ## Step 6: Symlink basic shell dotfiles (optional) +# info "Symlinking .p10k.zsh (Powerlevel10k config)..." +# ln -sf "$PWD/.p10k.zsh" "$HOME/.p10k.zsh" +# +# info "Install complete!" +# echo -e "${green}Dotfiles and system config applied for $HOST. You may wish to relogin, or reload your shell, or review configs now.${normal}" +# +# exit 0 + diff --git a/scripts/keybinds_hint.sh b/scripts/keybinds_hint.sh new file mode 100755 index 0000000..b211008 --- /dev/null +++ b/scripts/keybinds_hint.sh @@ -0,0 +1,418 @@ +#!/usr/bin/env sh + +#* jq to parse and create a metadata. +#* Users are advised to use bindd to explicitly add the description +#* Please inform us if there are new Categories upstream will try to add comments to this script +#* Khing 🦆 + +pkill -x rofi && exit +scrDir=$(dirname "$(realpath "$0")") +source "$scrDir/globalcontrol.sh" + +confDir="${XDG_CONFIG_HOME:-$HOME/.config}" +keyconfDir="$confDir/hypr" +kb_hint_conf=("$keyconfDir/hyprland.conf" "$keyconfDir/keybindings.conf" "$keyconfDir/userprefs.conf" ) +tmpMapDir="/tmp" +tmpMap="$tmpMapDir/hyde-keybinds.jq" +keycodeFile="${hydeConfDir}/keycode.kb" +modmaskFile="${hydeConfDir}/modmask.kb" +keyFile="${hydeConfDir}/key.kb" +categoryFile="${hydeConfDir}/category.kb" +dispatcherFile="${hydeConfDir}/dispatcher.kb" + +roDir="$confDir/rofi" +roconf="$HOME/.config/rofi/user.rasi" + +HELP() { + cat <') + -f Add custom file + -w Custom width + -h Custom height + --help Display this help message +Example: + $(basename "$0") -j -p -d '>' -f custom_file.txt -w 80 -h 90" +Users can also add a global overrides inside ${hydeConfDir}/hyde.conf + Available overrides: + + kb_hint_delim=">" ﯦ add a custom custom delimiter + kb_hint_conf=("file1.conf" "file2.conf") ﯦ add a custom keybinds.conf path (add it like an array) + kb_hint_width="30em" ﯦ custom width supports [ 'em' '%' 'px' ] + kb_hint_height="35em" ﯦ custom height supports [ 'em' '%' 'px' ] + kb_hint_line=13 ﯦ adjust how many lines are listed + +Users can also add a key overrides inside ${hydeConfDir} +List of file override: +${keycodeFile} => keycode +${modmaskFile} => modmask +${keyFile} => keys +${categoryFile} => category +${dispatcherFile} => dispatcher + +Example for keycode override +create a file named $keycodeFile and use the following format: + + "number": "display name/symbol", + "61": "/", + +HELP +} + +while [ "$#" -gt 0 ]; do + case "$1" in + -j) # show the json format + kb_hint_json=true + ;; + -p) # show the pretty format + kb_hint_pretty=true + ;; + -d) # Add custom delimiter symbol default '>' + shift + kb_hint_delim="$1" + ;; + -f) # Add custom file + shift + kb_hint_conf+=("${@}") + ;; + -w) # Custom kb_hint_width + shift + kb_hint_width="$1" + ;; + -h) # Custom height + shift + kb_hint_height="$1" + ;; + -l) # Custom number of line + shift + kb_hint_line="$1" + ;; + -*) # Add Help message + HELP + exit + ;; + esac + shift +done + +#? Read all the variables in the configuration file +#! Intentional globbing on the $keyconf variable +# shellcheck disable=SC2086 +keyVars="$(awk -F '=' '/^ *\$/ && !/^ *#[^#]/ || /^ *##/ {gsub(/^ *\$| *$/, "", $1); gsub(/#.*/, "", $2); gsub(/^ *| *$/, "", $2); print $1 "='\''"$2"'\''"}' ${kb_hint_conf[@]})" +keyVars+=" +" +keyVars+="HOME=$HOME" +# echo "$keyVars" + +#? This part substitutes the variables into the actual value. +#TODO It will be easier if hyprland will expose the variables. +substitute_vars() { + local s="$1" + local IFS=$'\n' + for var in $keyVars; do + varName="${var%%=*}" + varValue="${var#*=}" + varValue="${varValue#\'}" + varValue="${varValue%\'}" + s="${s//\$$varName/$varValue}" + done + IFS=$' \t\n' + echo "$s" +} +#? Other accurate but risky option +# eval "$keyVars" +# substitute_vars() { +# local s="$1" +# local IFS=$'\n' +# for var in $keyVars; do +# varName="${var%%=*}" +# s="${s//\$$varName/${!varName}}" +# done +# IFS=$' \t\n' +# echo "$s" +# } + +initialized_comments=$(awk -F ',' '!/^#/ && /bind*/ && $3 ~ /exec/ && NF && $4 !~ /^ *$/ { print $4}' ${kb_hint_conf[@]} | sed "s#\"#'#g") +comments=$(substitute_vars "$initialized_comments" | awk -F'#' \ + '{gsub(/^ */, "", $1);\ + gsub(/ *$/, "", $1);\ + split($2, a, " ");\ + a[1] = toupper(substr(a[1], 1, 1)) substr(a[1], 2);\ + $2 = a[1]; for(i=2;\ + i<=length(a); i++) $2 = $2" "a[i];\ + gsub(/^ */, "", $2);\ + gsub(/ *$/, "", $2);\ + if (length($1) > 0) print "\""$1"\" : \""(length($2) > 0 ? $2 : $1)"\","}' | + awk '!seen[$0]++') +# echo "$comments" + +cat <$tmpMap +# hyde-keybinds.jq +#! This is Our Translator for some binds #🦆 +def executables_mapping: { #? Derived from .args to parse scripts to be Readable +#? Auto Generated Comment Conversion +$comments +#? Defaults +" empty " : "Empty", +"r+1" : "Relative Right", +"r-1" : "Relative Left", +"e+1" : "Next", +"e-1" : "Previous", +"movewindow" : "Move window", +"resizewindow" : "Resize window", +"d" : "Down", +"l" : "Left", +"r" : "Right", +"u" : "Up", +"f" : "Forward", +"b" : "Backward", + +}; + +def keycode_mapping: { #? Fetches keycode from a file + "0": "", + $([ -f "${keycodeFile}" ] && cat "${keycodeFile}") +}; + + def modmask_mapping: { #? Define mapping for modmask numbers represents bitmask + "64": " ", #? SUPER  󰻀 Also added 2 En space ' ' <<< + "8": "ALT", + "4": "CTRL", + "1": "SHIFT", + "0": " ", + $([ -f "${modmaskFile}" ] && cat "${modmaskFile}") + }; + + def key_mapping: { #?Define mappings for .keys to be readable symbols + "mouse_up" : "󱕑", + "mouse_down" : "󱕐", + "mouse:272" : "󰍽", + "mouse:273" : "󰍽", + "UP" : "", + "DOWN" : "", + "LEFT" : "", + "RIGHT" : "", + "XF86AudioLowerVolume" : "󰝞", + "XF86AudioMicMute" : "󰍭", + "XF86AudioMute" : "󰓄", + "XF86AudioNext" : "󰒭", + "XF86AudioPause" : "󰏤", + "XF86AudioPlay" : "󰐊", + "XF86AudioPrev" : "󰒮", + "XF86AudioRaiseVolume" : "󰝝", + "XF86MonBrightnessDown" : "󰃜", + "XF86MonBrightnessUp" : "󰃠", + "switch:on:Lid Switch" : "󰛧", + "backspace" : "󰁮 ", + $([ -f "${keyFile}" ] && cat "${keyFile}") + }; + def category_mapping: { #? Define Category Names, derive from Dispatcher #? This will serve as the Group header + "exec" : "Execute a Command:", + "global": "Global:", + "exit" : "Exit Hyprland Session", + "fullscreen" : "Toggle Functions", + "fakefullscreen" : "Toggle Functions", + "mouse" : "Mouse functions", + "movefocus" : "Window functions", + "movewindow" : "Window functions", + "resizeactive" : "Window functions", + "togglefloating" : "Toggle Functions", + "togglegroup" : "Toggle Functions", + "togglespecialworkspace" : "Toggle Functions", + "togglesplit" : "Toggle Functions", + "workspace" : "Navigate Workspace", + "movetoworkspace" : "Navigate Workspace", + "movetoworkspacesilent" : "Navigate Workspace", + "changegroupactive" : "Change Active Group", + $([ -f "${categoryFile}" ] && cat "${categoryFile}") + }; +def arg_mapping: { #! Do not Change this used for Demo only... As this will change .args! will be fatal + "arg2": "mapped_arg2", + }; + + def description_mapping: { #? Derived from dispatcher and Gives Description for Dispatchers; Basically translates dispatcher. + "movefocus": "Move Focus", + "resizeactive": "Resize Active Floating Window", + "exit" : "End Hyprland Session", + "movetoworkspacesilent" : "Silently Move to Workspace", + "movewindow" : "Move Window", + "exec" : "" , #? Remove exec as executable will give the Description from separate function + "movetoworkspace" : "Move To Workspace:", + "workspace" : "Navigate to Workspace:", + "togglefloating" : "Toggle Floating", + "fullscreen" : "Toggle Fullscreen", + "togglegroup" : "Toggle Group", + "togglesplit" : "Toggle Split", + "togglespecialworkspace" : "Toggle Special Workspace", + "mouse" : "Use Mouse", + "changegroupactive" : "Switch Active group", + $([ -f "${dispatcherFile}" ] && cat "${dispatcherFile}") + }; + +OVERRIDES + +#? Script to re Modify hyprctl json output +#? Basically we are using jq to handle json data and outputs a pretty and friendly output +jsonData="$( + hyprctl binds -j | jq -L "$tmpMapDir" -c ' +include "hyde-keybinds"; + + #? Functions to Convert modmask into Keys, There should be a better math for this but Im lazy + #? Also we can just map it manually too + def get_keys: + if . == 0 then + "" + elif . >= 64 then + . -= 64 | modmask_mapping["64"] + " " + get_keys + elif . >= 32 then + . -= 32 | modmask_mapping["32"] + " " + get_keys + elif . >= 16 then + . -= 16 | modmask_mapping["16"] + " " + get_keys + elif . >= 8 then + . -= 8 | modmask_mapping["8"] + " " + get_keys + elif . >= 4 then + . -= 4 | modmask_mapping["4"] + " " + get_keys + elif . >= 2 then + . -= 2 | modmask_mapping["2"] + " " + get_keys + elif . >= 1 then + . -= 1 | modmask_mapping["1"] + " " + get_keys + else + . + end; +def get_keycode: + (keycode_mapping[(. | tostring)] // .); #? use the keycode conversion... and turn to string + +.[] | #? Filter 1 +.dispatcher as $dispatcher | .desc_dispatcher = $dispatcher | #? Value conversions for the description +.dispatcher as $dispatcher | .category = $dispatcher | #? Value conversions for the category +.arg as $arg | .desc_executable = $arg | #? creates new key .desc_executable to be use later +.modmask |= (get_keys | ltrimstr(" ")) | #? Execute Momask conversions, b +.keycode |= (get_keycode // .) | #? Apply the get_keycode transformation +.key |= (key_mapping[.] // .) | #? Apply the get_key +# .keybind = (.modmask | tostring // "") + (.key // "") | #! Same as below but without the keycode +.keybind = (.modmask | tostring // "") + (.key // "") + ((.keycode // 0) | tostring) | #? Show the keybindings +.flags = " locked=" + (.locked | tostring) + " mouse=" + (.mouse | tostring) + " release=" + (.release | tostring) + " repeat=" + (.repeat | tostring) + " non_consuming=" + (.non_consuming | tostring) | #? This are the flags repeat,lock etc +.category |= (category_mapping[.] // .) | #? Group by Categories will be use for headers +#!if .modmask and .modmask != " " and .modmask != "" then .modmask |= (split(" ") | map(select(length > 0)) | if length > 1 then join(" + ") else .[0] end) else .modmask = "" end | +if .keybind and .keybind != " " and .keybind != "" then .keybind |= (split(" ") | map(select(length > 0)) | if length > 1 then join(" + ") else .[0] end) else .keybind = "" end | #? Clean up + .arg |= (arg_mapping[.] // .) | #? See above for how arg is converted + #! .desc_executable |= gsub(".sh"; "") | #? Maybe Useful soon removes ".sh" to file + #? Creates a key desc... for fallback if "has description" is false + .desc_executable |= (executables_mapping[.] // .) | #? exclusive for "exec" dispatchers + .desc_dispatcher |= (description_mapping[.] // .) | #? for all other dispatchers + .description = if .has_description == false then "\(.desc_dispatcher) \(.desc_executable)" else.description end +' #* <---- There is a ' do not delete this' +)" + +#? Now we have the metadata we can Group it accordingly +GROUP() { +awk -v cols="$cols" -F '!=!' ' +{ + category = $1 + binds[category] = binds[category]? binds[category] "\n" $0 : $0 +} + +END { + n = asorti(binds, b) + for (i = 1; i <= n; i++) { + print b[i] # Print the header name + gsub(/\[.*\] =/, "", b[i]) + split(binds[b[i]], lines, "\n") + for (j in lines) { + line = substr(lines[j], index(lines[j], "=") + 2) + print line + } + for (j = 1; j <= cols; j++) printf "━" + printf "\n" + } +}' +} + +#? Display the JSON format +[ "$kb_hint_json" = true ] && jq <<< "$jsonData" && exit 0 + +#? Format this is how the keybinds are displayed. +DISPLAY() { awk -v kb_hint_delim="${kb_hint_delim:->}" -F '!=!' '{if ($0 ~ /=/ && $6 != "") printf "%-25s %-2s %-30s\n", $5, kb_hint_delim, $6; else if ($0 ~ /=/) printf "%-25s\n", $5; else print $0}'; } + +#? Extra design use for distinction +header="$(printf "%-35s %-1s %-20s\n" "󰌌 Keybinds" "󱧣" "Description")" +cols=$(tput cols) +cols=${cols:-999} +linebreak="$(printf '%.0s━' $(seq 1 "${cols}") "")" + +#! this Part Gives extra loading time as I don't have efforts to make single space for each class +metaData="$(jq -r '"\(.category) !=! \(.modmask) !=! \(.key) !=! \(.dispatcher) !=! \(.arg) !=! \(.keybind) !=! \(.description) !=! \(.flags)"' <<< "${jsonData}" | tr -s ' ' | sort -k 1)" + +#? This formats the pretty output +display="$(GROUP <<< "$metaData" | DISPLAY)" + +# output=$(echo -e "${header}\n${linebreak}\n${primMenu}\n${linebreak}\n${display}") +output=$(echo -e "${header}\n${linebreak}\n${display}") + +[ "$kb_hint_pretty" = true ] && echo -e "$output" && exit 0 + +#? will display on the terminal if rofi is not found or have -j flag +if ! command -v rofi &>/dev/null; then + echo "$output" + echo "rofi not detected. Displaying on terminal instead" + exit 0 +fi + +#? Put rofi configuration here +# Read hypr theme border +wind_border=$((hypr_border * 3 / 2)) +elem_border=$([ "$hypr_border" -eq 0 ] && echo "5" || echo "$hypr_border") + +# TODO Dynamic scaling for text and the window >>> I do not know if rofi is capable of this +r_width="width: ${kb_hint_width:-35em};" +r_height="height: ${kb_hint_height:-35em};" +r_listview="listview { lines: ${kb_hint_line:-13}; }" +r_override="window {$r_height $r_width border: ${hypr_width}px; border-radius: ${wind_border}px;} entry {border-radius: ${elem_border}px;} element {border-radius: ${elem_border}px;} ${r_listview} " + +# Read hypr font size +fnt_override=$(gsettings get org.gnome.desktop.interface font-name | awk '{gsub(/'\''/,""); print $NF}') +fnt_override="configuration {font: \"JetBrainsMono Nerd Font ${fnt_override}\";}" + +# Read hypr theme icon +icon_override=$(gsettings get org.gnome.desktop.interface icon-theme | sed "s/'//g") +icon_override="configuration {icon-theme: \"${icon_override}\";}" + +#? Actions to do when selected +selected=$(echo "$output" | rofi -dmenu -p -i -theme-str "${fnt_override}" -theme-str "${r_override}" -theme-str "${icon_override}" -config "${roconf}" | sed 's/.*\s*//') +if [ -z "$selected" ]; then exit 0; fi + +sel_1=$(awk -F "${kb_hint_delim:->}" '{print $1}' <<< "$selected" | awk '{$1=$1};1') +sel_2=$(awk -F "${kb_hint_delim:->}" '{print $2}' <<< "$selected" | awk '{$1=$1};1') +run="$(grep "$sel_1" <<< "$metaData" | grep "$sel_2")" + +run_flg="$(echo "$run" | awk -F '!=!' '{print $8}')" +run_sel="$(echo "$run" | awk -F '!=!' '{gsub(/^ *| *$/, "", $5); if ($5 ~ /[[:space:]]/ && $5 !~ /^[0-9]+$/ && substr($5, 1, 1) != "-") print $4, "\""$5"\""; else print $4, $5}')" +# echo "$run_sel" ; echo "$run_flg" + +#? +RUN() { case "$(eval "hyprctl dispatch $run_sel")" in *"Not enough arguments"*) exec $0 ;; esac } + +#? If flag is repeat then repeat rofi if not then just execute once +if [ -n "$run_sel" ] && [ "$(echo "$run_sel" | wc -l)" -eq 1 ]; then + eval "$run_flg" + if [ "$repeat" = true ]; then + + while true; do + repeat_command=$(echo -e "Repeat" | rofi -dmenu -no-custom -p "[Enter] repeat; [ESC] exit") #? Needed a separate Rasi ? Dunno how to make; Maybe Something like confirmation rasi for buttons Yes and No then the -p will be the Question like Proceed? Repeat? + + if [ "$repeat_command" = "Repeat" ]; then + # Repeat the command here + RUN + else + exit 0 + fi + done + else + RUN + fi +else + exec $0 +fi diff --git a/scripts/keyboardswitch.sh b/scripts/keyboardswitch.sh new file mode 100755 index 0000000..9a4fcdd --- /dev/null +++ b/scripts/keyboardswitch.sh @@ -0,0 +1,10 @@ +#!/usr/bin/env sh + +scrDir=`dirname "$(realpath "$0")"` +source $scrDir/globalcontrol.sh + +hyprctl switchxkblayout all next + +layMain=$(hyprctl -j devices | jq '.keyboards' | jq '.[] | select (.main == true)' | awk -F '"' '{if ($2=="active_keymap") print $4}') +notify-send -a "t1" -r 91190 -t 800 -i "~/.config/dunst/icons/keyboard.svg" "${layMain}" + diff --git a/scripts/launch-vm.sh b/scripts/launch-vm.sh new file mode 100644 index 0000000..fb0694c --- /dev/null +++ b/scripts/launch-vm.sh @@ -0,0 +1,35 @@ +#!/usr/bin/env bash + +ISO_URL="https://blackarch.org/blackarch-linux-live-2023.12.01-x86_64.iso" +ISO_PATH="$HOME/blackarch.iso" +VM_DISK="$HOME/blackarch.qcow2" + +# Ensure required binaries are available +nix shell nixpkgs#qemu nixpkgs#wget -c bash < /dev/null +then + pkill -x "wlogout" + exit 0 +fi + + +#// set file variables + +scrDir=`dirname "$(realpath "$0")"` +source $scrDir/globalcontrol.sh +[ -z "${1}" ] || wlogoutStyle="${1}" +wLayout="${confDir}/wlogout/layout_${wlogoutStyle}" +wlTmplt="${confDir}/wlogout/style_${wlogoutStyle}.css" + +if [ ! -f "${wLayout}" ] || [ ! -f "${wlTmplt}" ] ; then + echo "ERROR: Config ${wlogoutStyle} not found..." + wlogoutStyle=1 + wLayout="${confDir}/wlogout/layout_${wlogoutStyle}" + wlTmplt="${confDir}/wlogout/style_${wlogoutStyle}.css" +fi + + +#// detect monitor res + +x_mon=$(hyprctl -j monitors | jq '.[] | select(.focused==true) | .width') +y_mon=$(hyprctl -j monitors | jq '.[] | select(.focused==true) | .height') +hypr_scale=$(hyprctl -j monitors | jq '.[] | select (.focused == true) | .scale' | sed 's/\.//') + + +#// scale config layout and style + +case "${wlogoutStyle}" in + 1) wlColms=6 + export mgn=$(( y_mon * 28 / hypr_scale )) + export hvr=$(( y_mon * 23 / hypr_scale )) ;; + 2) wlColms=2 + export x_mgn=$(( x_mon * 35 / hypr_scale )) + export y_mgn=$(( y_mon * 25 / hypr_scale )) + export x_hvr=$(( x_mon * 32 / hypr_scale )) + export y_hvr=$(( y_mon * 20 / hypr_scale )) ;; +esac + + +#// scale font size + +export fntSize=$(( y_mon * 2 / 100 )) + + +#// detect wallpaper brightness + +[ -f "${cacheDir}/wall.dcol" ] && source "${cacheDir}/wall.dcol" +# Theme mode: detects the color-scheme set in hypr.theme and falls back if nothing is parsed. +if [ "${enableWallDcol}" -eq 0 ]; then + colorScheme="$({ grep -q "^[[:space:]]*\$COLOR[-_]SCHEME\s*=" "${hydeThemeDir}/hypr.theme" && grep "^[[:space:]]*\$COLOR[-_]SCHEME\s*=" "${hydeThemeDir}/hypr.theme" | cut -d '=' -f2 | sed 's/^[[:space:]]*//;s/[[:space:]]*$//' ;} || + grep 'gsettings set org.gnome.desktop.interface color-scheme' "${hydeThemeDir}/hypr.theme" | awk -F "'" '{print $((NF - 1))}')" + colorScheme=${colorScheme:-$(gsettings get org.gnome.desktop.interface color-scheme)} + # should be declared explicitly so we can easily debug + grep -q "dark" <<< "${colorScheme}" && dcol_mode="dark" + grep -q "light" <<< "${colorScheme}" && dcol_mode="light" +[ -f "${hydeThemeDir}/theme.dcol" ] && source "${hydeThemeDir}/theme.dcol" +fi +[ "${dcol_mode}" == "dark" ] && export BtnCol="white" || export BtnCol="black" + + +#// eval hypr border radius + +export active_rad=$(( hypr_border * 5 )) +export button_rad=$(( hypr_border * 8 )) + + +#// eval config files + +wlStyle="$(envsubst < $wlTmplt)" + + +#// launch wlogout + +wlogout -b "${wlColms}" -c 0 -r 0 -m 0 --layout "${wLayout}" --css <(echo "${wlStyle}") --protocol layer-shell + diff --git a/scripts/mediaplayer.py b/scripts/mediaplayer.py new file mode 100755 index 0000000..eee55b6 --- /dev/null +++ b/scripts/mediaplayer.py @@ -0,0 +1,183 @@ +#!/usr/bin/env python3 +import gi +gi.require_version("Playerctl", "2.0") +from gi.repository import Playerctl, GLib +from gi.repository.Playerctl import Player +import argparse +import logging +import sys +import signal +import gi +import json +import os +from typing import List + +logger = logging.getLogger(__name__) + +def signal_handler(sig, frame): + logger.info("Received signal to stop, exiting") + sys.stdout.write("\n") + sys.stdout.flush() + # loop.quit() + sys.exit(0) + + +class PlayerManager: + def __init__(self, selected_player=None): + self.manager = Playerctl.PlayerManager() + self.loop = GLib.MainLoop() + self.manager.connect( + "name-appeared", lambda *args: self.on_player_appeared(*args)) + self.manager.connect( + "player-vanished", lambda *args: self.on_player_vanished(*args)) + + signal.signal(signal.SIGINT, signal_handler) + signal.signal(signal.SIGTERM, signal_handler) + signal.signal(signal.SIGPIPE, signal.SIG_DFL) + self.selected_player = selected_player + + self.init_players() + + def init_players(self): + for player in self.manager.props.player_names: + if self.selected_player is not None and self.selected_player != player.name: + logger.debug(f"{player.name} is not the filtered player, skipping it") + continue + self.init_player(player) + + def run(self): + logger.info("Starting main loop") + self.loop.run() + + def init_player(self, player): + logger.info(f"Initialize new player: {player.name}") + player = Playerctl.Player.new_from_name(player) + player.connect("playback-status", + self.on_playback_status_changed, None) + player.connect("metadata", self.on_metadata_changed, None) + self.manager.manage_player(player) + self.on_metadata_changed(player, player.props.metadata) + + def get_players(self) -> List[Player]: + return self.manager.props.players + + def write_output(self, text, player, tooltip): + logger.debug(f"Writing output: {text}") + + output = {"text": text, + "class": "custom-" + player.props.player_name, + "alt": player.props.player_name, + "tooltip": tooltip} + + sys.stdout.write(json.dumps(output) + "\n") + sys.stdout.flush() + + def clear_output(self): + sys.stdout.write("\n") + sys.stdout.flush() + + def on_playback_status_changed(self, player, status, _=None): + logger.debug(f"Playback status changed for player {player.props.player_name}: {status}") + self.on_metadata_changed(player, player.props.metadata) + + def get_first_playing_player(self): + players = self.get_players() + logger.debug(f"Getting first playing player from {len(players)} players") + if len(players) > 0: + # if any are playing, show the first one that is playing + # reverse order, so that the most recently added ones are preferred + for player in players[::-1]: + if player.props.status == "Playing": + return player + # if none are playing, show the first one + return players[0] + else: + logger.debug("No players found") + return None + + def show_most_important_player(self): + logger.debug("Showing most important player") + # show the currently playing player + # or else show the first paused player + # or else show nothing + current_player = self.get_first_playing_player() + if current_player is not None: + self.on_metadata_changed(current_player, current_player.props.metadata) + else: + self.clear_output() + + def on_metadata_changed(self, player, metadata, _=None): + logger.debug(f"Metadata changed for player {player.props.player_name}") + player_name = player.props.player_name + artist = player.get_artist() + title = player.get_title() + + track_info = "" + if player_name == "spotify" and "mpris:trackid" in metadata.keys() and ":ad:" in player.props.metadata["mpris:trackid"]: + track_info = "Advertisement" + elif artist is not None and title is not None: + track_info = f"{artist} - {title}" + else: + track_info = title + tooltip = track_info + if track_info: + if player.props.status == "Playing": + track_info = " " + track_info + else: + track_info = " " + track_info + # only print output if no other player is playing + current_playing = self.get_first_playing_player() + if current_playing is None or current_playing.props.player_name == player.props.player_name: + self.write_output(track_info, player, tooltip) + else: + logger.debug(f"Other player {current_playing.props.player_name} is playing, skipping") + + def on_player_appeared(self, _, player): + logger.info(f"Player has appeared: {player.name}") + if player is not None and (self.selected_player is None or player.name == self.selected_player): + self.init_player(player) + else: + logger.debug( + "New player appeared, but it's not the selected player, skipping") + + def on_player_vanished(self, _, player): + logger.info(f"Player {player.props.player_name} has vanished") + self.show_most_important_player() + +def parse_arguments(): + parser = argparse.ArgumentParser() + + # Increase verbosity with every occurrence of -v + parser.add_argument("-v", "--verbose", action="count", default=0) + + # Define for which player we"re listening + parser.add_argument("--player") + + parser.add_argument("--enable-logging", action="store_true") + + return parser.parse_args() + + +def main(): + arguments = parse_arguments() + + # Initialize logging + if arguments.enable_logging: + logfile = os.path.join(os.path.dirname( + os.path.realpath(__file__)), "media-player.log") + logging.basicConfig(filename=logfile, level=logging.DEBUG, + format="%(asctime)s %(name)s %(levelname)s:%(lineno)d %(message)s") + + # Logging is set by default to WARN and higher. + # With every occurrence of -v it's lowered by one + logger.setLevel(max((3 - arguments.verbose) * 10, 0)) + + logger.info("Creating player manager") + if arguments.player: + logger.info(f"Filtering for player: {arguments.player}") + player = PlayerManager(arguments.player) + player.run() + + +if __name__ == "__main__": + main() diff --git a/scripts/move-floating.sh b/scripts/move-floating.sh new file mode 100644 index 0000000..794ec7e --- /dev/null +++ b/scripts/move-floating.sh @@ -0,0 +1,57 @@ +# #!/usr/bin/env bash +# +# # Move floating window or fallback to tiling move +# direction=$1 +# amount=${2:-10} +# +# # normalize direction to the single-letter hyprctl form +# case "${direction,,}" in +# left|l) dir=l ;; +# right|r) dir=r ;; +# up|u|top|t) dir=u ;; +# down|d|bottom|b) dir=d ;; +# *) +# echo "Usage: move-floating.sh [amount]" +# exit 1 +# ;; +# esac +# +# # ensure dependencies +# if ! command -v hyprctl >/dev/null 2>&1; then +# echo "hyprctl not found in PATH" >&2 +# exit 1 +# fi +# if ! command -v jq >/dev/null 2>&1; then +# echo "jq not found in PATH" >&2 +# exit 1 +# fi +# +# if hyprctl activewindow -j | jq -r .floating | grep -q true; then +# hyprctl dispatch moveactive "$dir" "$amount" +# else +# hyprctl dispatch movewindow "$dir" +# fi +# +#!/usr/bin/env sh +# move_floating.sh + +STEP=50 +case "$1" in + l) + hyprctl dispatch moveactive -50 0 + ;; + r) + hyprctl dispatch moveactive 50 0 + ;; + u) + hyprctl dispatch moveactive 0 -50 + ;; + d) + hyprctl dispatch moveactive 0 50 + ;; + *) + echo "Usage: $0 {left|right|up|down}" + exit 1 + ;; +esac + diff --git a/scripts/notifications.py b/scripts/notifications.py new file mode 100755 index 0000000..99719f0 --- /dev/null +++ b/scripts/notifications.py @@ -0,0 +1,55 @@ +#!/usr/bin/python3 + +import subprocess +import json +import sys + +def get_dunst_history(): + result = subprocess.run(['dunstctl', 'history'], stdout=subprocess.PIPE) + history = json.loads(result.stdout.decode('utf-8')) + return history + +def format_history(history): + count = len(history['data'][0]) + alt = 'none' + tooltip_click = [] + tooltip_click.append("󰎟 Notifications") + tooltip_click.append("󰳽 scroll-down:  history pop") + tooltip_click.append("󰳽 click-left:  Enable & Disable DND") + tooltip_click.append("󰳽 click-middle: 󰛌 clear history") + tooltip_click.append("󰳽 click-right: 󱄊 close all") + + tooltip = [] + + if count > 0: + notifications = history['data'][0][:10] # Get the first 10 notifications + for notification in notifications: + body = notification.get('body', {}).get('data', '') + category = notification.get('category', {}).get('data', '') + if category: + alt = category + '-notification' + tooltip.append(f" {body} ({category})\n") + else: + alt = 'notification' + tooltip.append(f" {body}\n") + + isDND = subprocess.run(['dunstctl', 'get-pause-level'], stdout=subprocess.PIPE) + isDND = isDND.stdout.decode('utf-8').strip() + if isDND != '0': + alt = "dnd" + formatted_history = { + "text": str(count), + "alt": alt, + "tooltip": '\n '.join(tooltip_click) + '\n\n ' + '\n '.join(tooltip), + "class": alt + } + return formatted_history + +def main(): + history = get_dunst_history() + formatted_history = format_history(history) + sys.stdout.write(json.dumps(formatted_history) + '\n') + sys.stdout.flush() + +if __name__ == "__main__": + main() diff --git a/scripts/open-calendar-floating.sh b/scripts/open-calendar-floating.sh new file mode 100755 index 0000000..ace446b --- /dev/null +++ b/scripts/open-calendar-floating.sh @@ -0,0 +1,85 @@ +#!/usr/bin/env bash + +# Open Google Calendar as a floating web app window using Firefox + +# Check if Firefox is already running with the calendar +EXISTING=$(pgrep -f "firefox.*calendar.google.com" | head -1) +if [ ! -z "$EXISTING" ]; then + # Focus the existing window instead + WINDOW_ADDRESS=$(hyprctl clients -j | jq -r ".[] | select(.pid == $EXISTING) | .address" | head -1) + if [ ! -z "$WINDOW_ADDRESS" ]; then + hyprctl dispatch focuswindow "address:$WINDOW_ADDRESS" + fi + exit 0 +fi + +# Create a dedicated Firefox profile for calendar app +PROFILE_DIR="$HOME/.mozilla/firefox/calendar-app" +if [ ! -d "$PROFILE_DIR" ]; then + mkdir -p "$PROFILE_DIR/chrome" + # Create user.js to customize Firefox UI + cat > "$PROFILE_DIR/user.js" << 'EOF' +// Hide Firefox UI elements +user_pref("browser.chrome.toolbar_tips", false); +user_pref("browser.tabs.drawInTitlebar", true); +user_pref("browser.tabs.tabmanager.enabled", false); +user_pref("browser.uidensity", 2); + +// Disable notifications and other UI clutter +user_pref("extensions.activeThemeID", "firefox-compact-dark@mozilla.org"); +user_pref("browser.startup.homepage_override.mstone", "ignore"); + +// Hide various UI elements +user_pref("toolkit.legacyUserProfileCustomizations.stylesheets", true); +EOF + + # Create userChrome.css to hide the toolbar and tabs + cat > "$PROFILE_DIR/chrome/userChrome.css" << 'EOF' +/* Hide the entire toolbar area */ +#navigator-toolbox { + display: none !important; +} + +/* Hide tabs bar */ +#TabsToolbar { + display: none !important; +} + +/* Hide sidebar button */ +#sidebar-button { + display: none !important; +} + +/* Make content fill the window */ +#content { + margin: 0 !important; +} +EOF +fi + +# Open Firefox with the dedicated profile in a new window +firefox --new-instance --profile "$PROFILE_DIR" "https://calendar.google.com" & +FIREFOX_PID=$! + +# Wait for window to open +sleep 1.5 + +# Get the window address +WINDOW_ADDRESS=$(hyprctl clients -j | jq -r ".[] | select(.pid == $FIREFOX_PID) | .address" | head -1) + +if [ ! -z "$WINDOW_ADDRESS" ]; then + # Make it floating + hyprctl dispatch togglefloating "address:$WINDOW_ADDRESS" + + # Resize to a smaller window size (900x700) + hyprctl dispatch resizewindowpixel "exact 900 700" "address:$WINDOW_ADDRESS" + + # Center it on screen + hyprctl dispatch centerwindow "address:$WINDOW_ADDRESS" + + # Collapse sidebar - press 'm' to toggle sidebar in Google Calendar + ( + sleep 2 + xdotool search --name "calendar" key "m" 2>/dev/null || true + ) & +fi diff --git a/scripts/polkitkdeauth.sh b/scripts/polkitkdeauth.sh new file mode 100755 index 0000000..7e6e10c --- /dev/null +++ b/scripts/polkitkdeauth.sh @@ -0,0 +1,10 @@ +#!/usr/bin/env sh + +# Use different directory on NixOS +if [ -d /run/current-system/sw/libexec ]; then + libDir=/run/current-system/sw/libexec +else + libDir=/usr/lib +fi + +${libDir}/polkit-gnome/polkit-gnome-authentication-agent-1 & diff --git a/scripts/quickapps.sh b/scripts/quickapps.sh new file mode 100755 index 0000000..7de3c23 --- /dev/null +++ b/scripts/quickapps.sh @@ -0,0 +1,77 @@ +#!/usr/bin/env bash + +# set variables + +scrDir=`dirname "$(realpath "$0")"` +source $scrDir/globalcontrol.sh +roconf="~/.config/rofi/quickapps.rasi" + +if [ $# -eq 0 ] ; then + echo "usage: ./quickapps.sh ... " + exit 1 +else + appCount="$#" +fi + + +# set position + +x_mon=$( cat /sys/class/drm/*/modes | head -1 ) +y_mon=$( echo $x_mon | cut -d 'x' -f 2 ) +x_mon=$( echo $x_mon | cut -d 'x' -f 1 ) + +x_cur=$(hyprctl cursorpos | sed 's/ //g') +y_cur=$( echo $x_cur | cut -d ',' -f 2 ) +x_cur=$( echo $x_cur | cut -d ',' -f 1 ) + +if [ ${x_cur} -le $(( x_mon/3 )) ] ; then + x_rofi="west" + x_offset="x-offset: 20px;" +elif [ ${x_cur} -ge $(( x_mon/3*2 )) ] ; then + x_rofi="east" + x_offset="x-offset: -20px;" +else + unset x_rofi +fi + +if [ ${y_cur} -le $(( y_mon/3 )) ] ; then + y_rofi="north" + y_offset="y-offset: 20px;" +elif [ ${y_cur} -ge $(( y_mon/3*2 )) ] ; then + y_rofi="south" + y_offset="y-offset: -20px;" +else + unset y_rofi +fi + +if [ ! -z $x_rofi ] || [ ! -z $y_rofi ] ; then + pos="window {location: $y_rofi $x_rofi; $x_offset $y_offset}" +fi + + +# override rofi + +dockHeight=$(( x_mon * 3 / 100)) +dockWidth=$(( dockHeight * appCount )) +iconSize=$(( dockHeight - 4 )) +wind_border=$(( hypr_border * 3/2 )) +r_override="window{height:${dockHeight};width:${dockWidth};border-radius:${wind_border}px;} listview{columns:${appCount};} element{border-radius:${wind_border}px;} element-icon{size:${iconSize}px;}" + + +# launch rofi menu + +if [ -d /run/current-system/sw/share/applications ]; then + appDir=/run/current-system/sw/share/applications +else + appDir=/usr/share/applications +fi + +RofiSel=$( for qapp in "$@" +do + Lkp=`grep "$qapp" $appDir/* | grep 'Exec=' | awk -F ':' '{print $1}' | head -1` + Ico=`grep 'Icon=' $Lkp | awk -F '=' '{print $2}' | head -1` + echo -en "${qapp}\x00icon\x1f${Ico}\n" +done | rofi -no-fixed-num-lines -dmenu -theme-str "${r_override}" -theme-str "${pos}" -config $roconf) + +$RofiSel & + diff --git a/scripts/resetxdgportal.sh b/scripts/resetxdgportal.sh new file mode 100755 index 0000000..c1c26a0 --- /dev/null +++ b/scripts/resetxdgportal.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env bash +sleep 1 +killall xdg-desktop-portal-hyprland +killall xdg-desktop-portal-gnome +killall xdg-desktop-portal-kde +killall xdg-desktop-portal-lxqt +killall xdg-desktop-portal-wlr +killall xdg-desktop-portal +sleep 1 + +# Use different directory on NixOS +if [ -d /run/current-system/sw/libexec ]; then + libDir=/run/current-system/sw/libexec +else + libDir=/usr/lib +fi + +$libDir/xdg-desktop-portal-hyprland & +sleep 2 +$libDir/xdg-desktop-portal & diff --git a/scripts/rofi-network.sh b/scripts/rofi-network.sh new file mode 100755 index 0000000..9bb1df3 --- /dev/null +++ b/scripts/rofi-network.sh @@ -0,0 +1,84 @@ +#!/usr/bin/env bash + +# Simple rofi-based WiFi network manager with pywal color support + +# Function to get WiFi networks +get_networks() { + nmcli --fields SSID,SIGNAL device wifi list 2>/dev/null | tail -n +2 | awk ' +{ + ssid = $1 + signal = $2 + if (ssid == "") next + + # Skip duplicates + if (seen[ssid]) next + seen[ssid] = 1 + + # Signal strength icons + if (signal >= 75) icon = "󰤾" + else if (signal >= 50) icon = "󰤿" + else if (signal >= 25) icon = "󰤽" + else icon = "󰤼" + + printf "%s %s (%d%%)\n", icon, ssid, signal +}' | sort -u +} + +# Start background scan immediately +nmcli device wifi rescan >/dev/null 2>&1 & +SCAN_PID=$! + +# Get initial networks (cached from previous scan) +networks=$(get_networks) + +# Add action options at the top +menu="📶 Refresh Networks +🔆 Enable WiFi +🔅 Disable WiFi +--- +$networks" + +# Show rofi menu with network theme +selected=$(echo "$menu" | rofi -dmenu -theme network -p "WiFi" 2>/dev/null) + +[[ -z "$selected" ]] && exit 0 + +case "$selected" in + "📶 Refresh Networks") + # Trigger a scan and call self again after short delay + nmcli device wifi rescan >/dev/null 2>&1 + sleep 1 + bash "$0" + ;; + "🔆 Enable WiFi") + nmcli radio wifi on + notify-send "WiFi" "WiFi enabled" 2>/dev/null + ;; + "🔅 Disable WiFi") + nmcli radio wifi off + notify-send "WiFi" "WiFi disabled" 2>/dev/null + ;; + "---") + ;; + *) + # Extract SSID from selection (remove icon and signal strength) + ssid=$(echo "$selected" | sed 's/^[^ ]* \(.*\) ([0-9]*%)$/\1/') + + # Try to connect + if nmcli connection show | grep -q "^$ssid"; then + # Already saved connection + nmcli connection up "$ssid" 2>/dev/null && \ + notify-send "WiFi" "Connected to $ssid" 2>/dev/null || \ + notify-send "WiFi" "Failed to connect to $ssid" 2>/dev/null + else + # Need password + password=$(rofi -dmenu -password -theme network \ + -p "Password for $ssid" 2>/dev/null) + if [[ -n "$password" ]]; then + nmcli device wifi connect "$ssid" password "$password" 2>/dev/null && \ + notify-send "WiFi" "Connected to $ssid" 2>/dev/null || \ + notify-send "WiFi" "Failed to connect to $ssid" 2>/dev/null + fi + fi + ;; +esac diff --git a/scripts/rofi-wallpaper-preview.sh b/scripts/rofi-wallpaper-preview.sh new file mode 100644 index 0000000..29996af --- /dev/null +++ b/scripts/rofi-wallpaper-preview.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash + +# Rofi preview using chafa +# $1 is the file path of the wallpaper +if [[ -f "$1" ]]; then + chafa "$1" --fill=block --symbols=block --size=30x15 +fi + diff --git a/scripts/rofilaunch.sh b/scripts/rofilaunch.sh new file mode 100755 index 0000000..8ae9187 --- /dev/null +++ b/scripts/rofilaunch.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +rofi -show drun -theme ~/.config/rofi/config.rasi diff --git a/scripts/rofiselect.sh b/scripts/rofiselect.sh new file mode 100755 index 0000000..56db821 --- /dev/null +++ b/scripts/rofiselect.sh @@ -0,0 +1,51 @@ +#!/usr/bin/env sh + + +#// set variables + +scrDir="$(dirname "$(realpath "$0")")" +source "${scrDir}/globalcontrol.sh" +rofiConf="${confDir}/rofi/selector.rasi" +rofiStyleDir="${confDir}/rofi/styles" +rofiAssetDir="${confDir}/rofi/assets" + + +#// set rofi scaling + +[[ "${rofiScale}" =~ ^[0-9]+$ ]] || rofiScale=10 +r_scale="configuration {font: \"JetBrainsMono Nerd Font ${rofiScale}\";}" +elem_border=$(( hypr_border * 5 )) +icon_border=$(( elem_border - 5 )) + + +#// scale for monitor + +mon_x_res=$(hyprctl -j monitors | jq '.[] | select(.focused==true) | .width') +mon_scale=$(hyprctl -j monitors | jq '.[] | select(.focused==true) | .scale' | sed "s/\.//") +mon_x_res=$(( mon_x_res * 100 / mon_scale )) + + +#// generate config + +elm_width=$(( (20 + 12 + 16 ) * rofiScale )) +max_avail=$(( mon_x_res - (4 * rofiScale) )) +col_count=$(( max_avail / elm_width )) +[[ "${col_count}" -gt 5 ]] && col_count=5 +r_override="window{width:100%;} listview{columns:${col_count};} element{orientation:vertical;border-radius:${elem_border}px;} element-icon{border-radius:${icon_border}px;size:20em;} element-text{enabled:false;}" + + +#// launch rofi menu + +RofiSel=$(ls ${rofiStyleDir}/style_*.rasi | awk -F '[_.]' '{print $((NF - 1))}' | while read styleNum +do + echo -en "${styleNum}\x00icon\x1f${rofiAssetDir}/style_${styleNum}.png\n" +done | sort -n | rofi -dmenu -theme-str "${r_override}" -config "${rofiConf}" -select "${rofiStyle}") + + +#// apply rofi style + +if [ ! -z "${RofiSel}" ] ; then + set_conf "rofiStyle" "${RofiSel}" + notify-send -a "t1" -r 91190 -t 2200 -i "${rofiAssetDir}/style_${RofiSel}.png" " style ${RofiSel} applied..." +fi + diff --git a/scripts/screenshot.sh b/scripts/screenshot.sh new file mode 100755 index 0000000..4559b5b --- /dev/null +++ b/scripts/screenshot.sh @@ -0,0 +1,63 @@ +#!/usr/bin/env bash + +# Restores the shader after screenshot has been taken +restore_shader() { + if [ -n "$shader" ]; then + hyprshade on "$shader" + fi +} + +# Saves the current shader and turns it off +save_shader() { + shader=$(hyprshade current) + hyprshade off + trap restore_shader EXIT +} + +save_shader # Saving the current shader + +if [ -z "$XDG_PICTURES_DIR" ]; then + XDG_PICTURES_DIR="$HOME/Pictures" +fi + +scrDir=$(dirname "$(realpath "$0")") +source $scrDir/globalcontrol.sh +swpy_dir="${confDir}/swappy" +save_dir="${2:-$XDG_PICTURES_DIR/Screenshots}" +save_file=$(date +'%y%m%d_%Hh%Mm%Ss_screenshot.png') +temp_screenshot="/tmp/screenshot.png" + +mkdir -p $save_dir +mkdir -p $swpy_dir +echo -e "[Default]\nsave_dir=$save_dir\nsave_filename_format=$save_file" >$swpy_dir/config + +function print_error +{ + cat <<"EOF" + ./screenshot.sh + ...valid actions are... + p : print all screens + s : snip current screen + sf : snip current screen (frozen) + m : print focused monitor +EOF +} + +case $1 in +p) # print all outputs + grimblast copysave screen $temp_screenshot && restore_shader && swappy -f $temp_screenshot ;; +s) # drag to manually snip an area / click on a window to print it + grimblast copysave area $temp_screenshot && restore_shader && swappy -f $temp_screenshot ;; +sf) # frozen screen, drag to manually snip an area / click on a window to print it + grimblast --freeze copysave area $temp_screenshot && restore_shader && swappy -f $temp_screenshot ;; +m) # print focused monitor + grimblast copysave output $temp_screenshot && restore_shader && swappy -f $temp_screenshot ;; +*) # invalid option + print_error ;; +esac + +rm "$temp_screenshot" + +if [ -f "${save_dir}/${save_file}" ]; then + notify-send -a "t1" -i "${save_dir}/${save_file}" "saved in ${save_dir}" +fi diff --git a/scripts/set-wallpaper.sh b/scripts/set-wallpaper.sh new file mode 100755 index 0000000..5ac3825 --- /dev/null +++ b/scripts/set-wallpaper.sh @@ -0,0 +1,239 @@ +#!/usr/bin/env bash + +# ----------------------------- +# CONFIGURATION +# ----------------------------- +WALLPAPER_DIR="$HOME/Pictures/wallpapers" +WAYBAR_CONFIG_DIR="$HOME/.config/waybar" +ROFI_CONFIG_DIR="$HOME/.config/rofi" +INDEX_FILE="/tmp/current_wallpaper_index" + +# Collect wallpapers +WALLPAPERS=("${WALLPAPER_DIR}"/*) +TOTAL_WALLPAPERS=${#WALLPAPERS[@]} + +# Load current index +if [[ -f "$INDEX_FILE" ]]; then + CURRENT_INDEX=$(<"$INDEX_FILE") +else + CURRENT_INDEX=0 +fi + +# ----------------------------- +# HELPER FUNCTIONS +# ----------------------------- + +extract_rofi_colors() { + if [[ -f "$HOME/.cache/wal/colors-rofi-dark.rasi" ]]; then + awk '/^\* {/,/^}/' "$HOME/.cache/wal/colors-rofi-dark.rasi" > "$ROFI_CONFIG_DIR/colors.rasi" 2>/dev/null || true + fi +} + +update_hyprlock_colors() { + # Extract colors from pywal JSON and update hyprlock config + local colors_json="$HOME/.cache/wal/colors.json" + + if [[ -f "$colors_json" ]]; then + # This function is called after set_wallpaper, which updates the symlink + # Hyprlock will read the new wallpaper on next lock + # Note: Colors in hyprlock.nix are set statically at build time + # so they won't update dynamically - only the wallpaper updates + : + fi +} + +copy_current_wallpaper() { + local wallpaper="$1" + local wallpaper_filename=$(basename "$wallpaper") + local output_file="$ROFI_CONFIG_DIR/current_wallpaper.$(echo "$wallpaper_filename" | awk -F. '{print $NF}')" + + # Remove existing file if it's read-only + if [[ -f "$output_file" ]]; then + chmod u+w "$output_file" 2>/dev/null || true + fi + + cp "$wallpaper" "$output_file" 2>/dev/null || true +} + +generate_posting_theme() { + # Generate posting theme from pywal colors + local WAL_COLORS="${XDG_CACHE_HOME:-$HOME/.cache}/wal/colors" + + if [ ! -f "$WAL_COLORS" ]; then + return + fi + + # Read colors from wal + mapfile -t COLORS < "$WAL_COLORS" + + # Extract colors (wal provides 16 colors) + BG="${COLORS[0]}" # background + COLOR1="${COLORS[1]}" # red + COLOR2="${COLORS[2]}" # green + COLOR3="${COLORS[3]}" # yellow + COLOR4="${COLORS[4]}" # blue + COLOR5="${COLORS[5]}" # magenta + COLOR6="${COLORS[6]}" # cyan + + POSTING_THEME_DIR="${XDG_DATA_HOME:-$HOME/.local/share}/posting/themes" + mkdir -p "$POSTING_THEME_DIR" + + # Generate theme from pywal colors with proper variable substitution + cat > "$POSTING_THEME_DIR/pywal.yaml" < /dev/null; then + pywalfox update + fi + + # Reload Hyprland to apply new colors from generated config + hyprctl reload + + # Copy Waybar color scheme + cp "$HOME/.cache/wal/colors-waybar.css" "$WAYBAR_CONFIG_DIR/colors-waybar.css" + cp "$HOME/.cache/wal/colors-waybar.css" "$HOME/.config/wlogout/colors-waybar.css" + cp "$HOME/.cache/wal/colors-wal.vim" "$HOME/.config/nvim/colors-wal.vim" + cp "$HOME/.cache/wal/colors.css" "$HOME/.config/wlogout/colors.css" + + # Extract Rofi colors + extract_rofi_colors + + # Copy current wallpaper for Rofi preview + copy_current_wallpaper "$wallpaper" + + # Symlink wallpaper for hyprlock + ln -sf "$wallpaper" "$HOME/.cache/hyprlock_wallpaper" + + # Update hyprlock colors dynamically using hyprctl + update_hyprlock_colors + + + # Reload swaync to apply new colors (CSS is cached until service restarts) + systemctl --user restart swaync.service 2>/dev/null || true + + # Reload waybar to apply new colors + pkill -SIGUSR2 waybar 2>/dev/null || true + + # Reload nvim colors if running + if pgrep nvim > /dev/null; then + nvim --server /tmp/nvim.pipe --remote-send ':source $HOME/.cache/wal/colors-wal.vim' + fi +} + +next_wallpaper() { + CURRENT_INDEX=$(( (CURRENT_INDEX + 1) % TOTAL_WALLPAPERS )) + echo "$CURRENT_INDEX" > "$INDEX_FILE" + set_wallpaper +} + +prev_wallpaper() { + CURRENT_INDEX=$(( (CURRENT_INDEX - 1 + TOTAL_WALLPAPERS) % TOTAL_WALLPAPERS )) + echo "$CURRENT_INDEX" > "$INDEX_FILE" + set_wallpaper +} +select_wallpaper_rofi() { + local THUMB_DIR="$HOME/.cache/wallpaper-thumbs" + + local selected=$( + for wp in "${WALLPAPERS[@]}"; do + filename="$(basename "$wp")" + name_no_ext="${filename%.*}" + + thumb=$(find "$THUMB_DIR" -maxdepth 1 -type f -name "${name_no_ext}_*.png" | head -n1) + + [[ -z "$thumb" ]] && thumb="$wp" + + # IMPORTANT: real null byte + icon metadata + printf "%s\0icon\x1f%s\n" "$filename" "$thumb" + done | rofi -dmenu -i -show-icons \ + -theme "$HOME/.config/rofi/wallpaper.rasi" + ) + + if [[ -n "$selected" ]]; then + for i in "${!WALLPAPERS[@]}"; do + if [[ "$(basename "${WALLPAPERS[$i]}")" == "$selected" ]]; then + CURRENT_INDEX=$i + echo "$CURRENT_INDEX" > "$INDEX_FILE" + set_wallpaper + break + fi + done + fi +} + +case "$1" in + next) + next_wallpaper + ;; + prev) + prev_wallpaper + ;; + rofi) + select_wallpaper_rofi + ;; + *) + echo "Usage: $0 {next|prev|rofi}" + ;; +esac + diff --git a/scripts/setup-firefox-calendar-profile.sh b/scripts/setup-firefox-calendar-profile.sh new file mode 100755 index 0000000..cc87f9b --- /dev/null +++ b/scripts/setup-firefox-calendar-profile.sh @@ -0,0 +1,50 @@ +#!/usr/bin/env bash + +# Setup Firefox calendar app profile with custom UI customizations +# Dark Reader should be installed manually via about:addons + +PROFILE_DIR="$HOME/.mozilla/firefox/calendar-app" + +# Create profile directory if it doesn't exist +mkdir -p "$PROFILE_DIR/chrome" + +# Create user.js with preferences +cat > "$PROFILE_DIR/user.js" << 'EOF' +// Hide Firefox UI elements +user_pref("browser.chrome.toolbar_tips", false); +user_pref("browser.tabs.drawInTitlebar", true); +user_pref("browser.tabs.tabmanager.enabled", false); +user_pref("browser.uidensity", 2); + +// Disable notifications and other UI clutter +user_pref("extensions.activeThemeID", "firefox-compact-dark@mozilla.org"); +user_pref("browser.startup.homepage_override.mstone", "ignore"); + +// Hide various UI elements +user_pref("toolkit.legacyUserProfileCustomizations.stylesheets", true); +EOF + +# Create userChrome.css to hide the toolbar and tabs +cat > "$PROFILE_DIR/chrome/userChrome.css" << 'EOF' +/* Hide the entire toolbar area */ +#navigator-toolbox { + display: none !important; +} + +/* Hide tabs bar */ +#TabsToolbar { + display: none !important; +} + +/* Hide sidebar button */ +#sidebar-button { + display: none !important; +} + +/* Make content fill the window */ +#content { + margin: 0 !important; +} +EOF + +echo "Firefox calendar app profile configured successfully" diff --git a/scripts/switch-workspace.sh b/scripts/switch-workspace.sh new file mode 100644 index 0000000..16b50d2 --- /dev/null +++ b/scripts/switch-workspace.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env bash + +current_workspace=$(hyprctl monitors | grep "active workspace" | awk '{print $NF}') +if [ "$1" == "up" ]; then + new_workspace=$((current_workspace + 1)) +elif [ "$1" == "down" ]; then + new_workspace=$((current_workspace - 1)) +fi +hyprctl dispatch workspace "$new_workspace" \ No newline at end of file diff --git a/scripts/swwwallbash.sh b/scripts/swwwallbash.sh new file mode 100755 index 0000000..47a89e7 --- /dev/null +++ b/scripts/swwwallbash.sh @@ -0,0 +1,265 @@ +#!/usr/bin/env bash + +#// set variables + +export scrDir="$(dirname "$(realpath "$0")")" +source "${scrDir}/globalcontrol.sh" +wallbashImg="${1}" + + +#// validate input + +if [ -z "${wallbashImg}" ] || [ ! -f "${wallbashImg}" ] ; then + echo "Error: Input wallpaper not found!" + exit 1 +fi +wallbashOut="${dcolDir}/$(set_hash "${wallbashImg}").dcol" + +if [ ! -f "${wallbashOut}" ] ; then + "${scrDir}/swwwallcache.sh" -w "${wallbashImg}" &> /dev/null +fi + +set -a +source "${wallbashOut}" +if [ -f "${hydeThemeDir}/theme.dcol" ] && [ "${enableWallDcol}" -eq 0 ] ; then + source "${hydeThemeDir}/theme.dcol" + echo "[theme] Overriding dominant colors from \"${hydeTheme}\"" + echo "[note] Remove \"${hydeThemeDir}/theme.dcol\" to use wallpaper dominant colors" +fi +[ "${dcol_mode}" == "dark" ] && dcol_invt="light" || dcol_invt="dark" +set +a + + +#// deploy wallbash colors + +fn_wallbash () { + local tplt="${1}" + [ -f "${hydeConfDir}/hyde.conf" ] && source "${hydeConfDir}/hyde.conf" + # Skips the the template declared in ./hyde.conf + [[ " ${skip_wallbash[@]} " =~ " ${tplt} " ]] && echo "[skip: template] ${tplt}" && return 0 + eval target="$(head -1 "${tplt}" | awk -F '|' '{print $1}')" + [ ! -d "$(dirname "${target}")" ] && echo "[skip: no dir] \"${target}\"" && return 0 + appexe="$(head -1 "${tplt}" | awk -F '|' '{print $2}')" + sed '1d' "${tplt}" > "${target}" + + if [[ "${enableWallDcol}" -eq 2 && "${dcol_mode}" == "light" ]] || [[ "${enableWallDcol}" -eq 3 && "${dcol_mode}" == "dark" ]] ; then + sed -i 's//'"${dcol_invt}"'/g + s//'"${dcol_pry4}"'/g + s//'"${dcol_txt4}"'/g + s//'"${dcol_4xa9}"'/g + s//'"${dcol_4xa8}"'/g + s//'"${dcol_4xa7}"'/g + s//'"${dcol_4xa6}"'/g + s//'"${dcol_4xa5}"'/g + s//'"${dcol_4xa4}"'/g + s//'"${dcol_4xa3}"'/g + s//'"${dcol_4xa2}"'/g + s//'"${dcol_4xa1}"'/g + s//'"${dcol_pry3}"'/g + s//'"${dcol_txt3}"'/g + s//'"${dcol_3xa9}"'/g + s//'"${dcol_3xa8}"'/g + s//'"${dcol_3xa7}"'/g + s//'"${dcol_3xa6}"'/g + s//'"${dcol_3xa5}"'/g + s//'"${dcol_3xa4}"'/g + s//'"${dcol_3xa3}"'/g + s//'"${dcol_3xa2}"'/g + s//'"${dcol_3xa1}"'/g + s//'"${dcol_pry2}"'/g + s//'"${dcol_txt2}"'/g + s//'"${dcol_2xa9}"'/g + s//'"${dcol_2xa8}"'/g + s//'"${dcol_2xa7}"'/g + s//'"${dcol_2xa6}"'/g + s//'"${dcol_2xa5}"'/g + s//'"${dcol_2xa4}"'/g + s//'"${dcol_2xa3}"'/g + s//'"${dcol_2xa2}"'/g + s//'"${dcol_2xa1}"'/g + s//'"${dcol_pry1}"'/g + s//'"${dcol_txt1}"'/g + s//'"${dcol_1xa9}"'/g + s//'"${dcol_1xa8}"'/g + s//'"${dcol_1xa7}"'/g + s//'"${dcol_1xa6}"'/g + s//'"${dcol_1xa5}"'/g + s//'"${dcol_1xa4}"'/g + s//'"${dcol_1xa3}"'/g + s//'"${dcol_1xa2}"'/g + s//'"${dcol_1xa1}"'/g + s//'"${dcol_pry4_rgba}"'/g + s//'"${dcol_txt4_rgba}"'/g + s//'"${dcol_4xa9_rgba}"'/g + s//'"${dcol_4xa8_rgba}"'/g + s//'"${dcol_4xa7_rgba}"'/g + s//'"${dcol_4xa6_rgba}"'/g + s//'"${dcol_4xa5_rgba}"'/g + s//'"${dcol_4xa4_rgba}"'/g + s//'"${dcol_4xa3_rgba}"'/g + s//'"${dcol_4xa2_rgba}"'/g + s//'"${dcol_4xa1_rgba}"'/g + s//'"${dcol_pry3_rgba}"'/g + s//'"${dcol_txt3_rgba}"'/g + s//'"${dcol_3xa9_rgba}"'/g + s//'"${dcol_3xa8_rgba}"'/g + s//'"${dcol_3xa7_rgba}"'/g + s//'"${dcol_3xa6_rgba}"'/g + s//'"${dcol_3xa5_rgba}"'/g + s//'"${dcol_3xa4_rgba}"'/g + s//'"${dcol_3xa3_rgba}"'/g + s//'"${dcol_3xa2_rgba}"'/g + s//'"${dcol_3xa1_rgba}"'/g + s//'"${dcol_pry2_rgba}"'/g + s//'"${dcol_txt2_rgba}"'/g + s//'"${dcol_2xa9_rgba}"'/g + s//'"${dcol_2xa8_rgba}"'/g + s//'"${dcol_2xa7_rgba}"'/g + s//'"${dcol_2xa6_rgba}"'/g + s//'"${dcol_2xa5_rgba}"'/g + s//'"${dcol_2xa4_rgba}"'/g + s//'"${dcol_2xa3_rgba}"'/g + s//'"${dcol_2xa2_rgba}"'/g + s//'"${dcol_2xa1_rgba}"'/g + s//'"${dcol_pry1_rgba}"'/g + s//'"${dcol_txt1_rgba}"'/g + s//'"${dcol_1xa9_rgba}"'/g + s//'"${dcol_1xa8_rgba}"'/g + s//'"${dcol_1xa7_rgba}"'/g + s//'"${dcol_1xa6_rgba}"'/g + s//'"${dcol_1xa5_rgba}"'/g + s//'"${dcol_1xa4_rgba}"'/g + s//'"${dcol_1xa3_rgba}"'/g + s//'"${dcol_1xa2_rgba}"'/g + s//'"${dcol_1xa1_rgba}"'/g' "${target}" + else + sed -i 's//'"${dcol_mode}"'/g + s//'"${dcol_pry1}"'/g + s//'"${dcol_txt1}"'/g + s//'"${dcol_1xa1}"'/g + s//'"${dcol_1xa2}"'/g + s//'"${dcol_1xa3}"'/g + s//'"${dcol_1xa4}"'/g + s//'"${dcol_1xa5}"'/g + s//'"${dcol_1xa6}"'/g + s//'"${dcol_1xa7}"'/g + s//'"${dcol_1xa8}"'/g + s//'"${dcol_1xa9}"'/g + s//'"${dcol_pry2}"'/g + s//'"${dcol_txt2}"'/g + s//'"${dcol_2xa1}"'/g + s//'"${dcol_2xa2}"'/g + s//'"${dcol_2xa3}"'/g + s//'"${dcol_2xa4}"'/g + s//'"${dcol_2xa5}"'/g + s//'"${dcol_2xa6}"'/g + s//'"${dcol_2xa7}"'/g + s//'"${dcol_2xa8}"'/g + s//'"${dcol_2xa9}"'/g + s//'"${dcol_pry3}"'/g + s//'"${dcol_txt3}"'/g + s//'"${dcol_3xa1}"'/g + s//'"${dcol_3xa2}"'/g + s//'"${dcol_3xa3}"'/g + s//'"${dcol_3xa4}"'/g + s//'"${dcol_3xa5}"'/g + s//'"${dcol_3xa6}"'/g + s//'"${dcol_3xa7}"'/g + s//'"${dcol_3xa8}"'/g + s//'"${dcol_3xa9}"'/g + s//'"${dcol_pry4}"'/g + s//'"${dcol_txt4}"'/g + s//'"${dcol_4xa1}"'/g + s//'"${dcol_4xa2}"'/g + s//'"${dcol_4xa3}"'/g + s//'"${dcol_4xa4}"'/g + s//'"${dcol_4xa5}"'/g + s//'"${dcol_4xa6}"'/g + s//'"${dcol_4xa7}"'/g + s//'"${dcol_4xa8}"'/g + s//'"${dcol_4xa9}"'/g + s//'"${dcol_pry1_rgba}"'/g + s//'"${dcol_txt1_rgba}"'/g + s//'"${dcol_1xa1_rgba}"'/g + s//'"${dcol_1xa2_rgba}"'/g + s//'"${dcol_1xa3_rgba}"'/g + s//'"${dcol_1xa4_rgba}"'/g + s//'"${dcol_1xa5_rgba}"'/g + s//'"${dcol_1xa6_rgba}"'/g + s//'"${dcol_1xa7_rgba}"'/g + s//'"${dcol_1xa8_rgba}"'/g + s//'"${dcol_1xa9_rgba}"'/g + s//'"${dcol_pry2_rgba}"'/g + s//'"${dcol_txt2_rgba}"'/g + s//'"${dcol_2xa1_rgba}"'/g + s//'"${dcol_2xa2_rgba}"'/g + s//'"${dcol_2xa3_rgba}"'/g + s//'"${dcol_2xa4_rgba}"'/g + s//'"${dcol_2xa5_rgba}"'/g + s//'"${dcol_2xa6_rgba}"'/g + s//'"${dcol_2xa7_rgba}"'/g + s//'"${dcol_2xa8_rgba}"'/g + s//'"${dcol_2xa9_rgba}"'/g + s//'"${dcol_pry3_rgba}"'/g + s//'"${dcol_txt3_rgba}"'/g + s//'"${dcol_3xa1_rgba}"'/g + s//'"${dcol_3xa2_rgba}"'/g + s//'"${dcol_3xa3_rgba}"'/g + s//'"${dcol_3xa4_rgba}"'/g + s//'"${dcol_3xa5_rgba}"'/g + s//'"${dcol_3xa6_rgba}"'/g + s//'"${dcol_3xa7_rgba}"'/g + s//'"${dcol_3xa8_rgba}"'/g + s//'"${dcol_3xa9_rgba}"'/g + s//'"${dcol_pry4_rgba}"'/g + s//'"${dcol_txt4_rgba}"'/g + s//'"${dcol_4xa1_rgba}"'/g + s//'"${dcol_4xa2_rgba}"'/g + s//'"${dcol_4xa3_rgba}"'/g + s//'"${dcol_4xa4_rgba}"'/g + s//'"${dcol_4xa5_rgba}"'/g + s//'"${dcol_4xa6_rgba}"'/g + s//'"${dcol_4xa7_rgba}"'/g + s//'"${dcol_4xa8_rgba}"'/g + s//'"${dcol_4xa9_rgba}"'/g' "${target}" + fi + + [ -z "${appexe}" ] || bash -c "${appexe}" +} + +export -f fn_wallbash + +[ -n "$HYPRLAND_INSTANCE_SIGNATURE" ] && hyprctl keyword misc:disable_autoreload 1 -q && trap 'hyprctl reload -q && echo "[swwwallbash] reload :: Hyprland"' EXIT + +#// switch theme wall based colors + +if [ "${enableWallDcol}" -eq 0 ] && [[ "${reload_flag}" -eq 1 ]] ; then + + echo ":: deploying ${hydeTheme} colors :: ${dcol_mode} wallpaper detected" + mapfile -d '' -t deployList < <(find "${hydeThemeDir}" -type f -name "*.theme" -print0) + + while read -r pKey ; do + fKey="$(find "${hydeThemeDir}" -type f -name "$(basename "${pKey%.dcol}.theme")")" + [ -z "${fKey}" ] && deployList+=("${pKey}") + done < <(find "${wallbashDir}/Wall-Dcol" -type f -name "*.dcol") + + parallel fn_wallbash ::: "${deployList[@]}" + +elif [ "${enableWallDcol}" -gt 0 ] ; then + + echo ":: deploying wallbash colors :: ${dcol_mode} wallpaper detected" + find "${wallbashDir}/Wall-Dcol" -type f -name "*.dcol" | parallel fn_wallbash {} + +fi + +# Theme mode: detects the color-scheme set in hypr.theme and falls back if nothing is parsed. +if [ "${enableWallDcol}" -eq 0 ]; then + colorScheme="$({ grep -q "^[[:space:]]*\$COLOR-SCHEME\s*=" "${hydeThemeDir}/hypr.theme" && grep "^[[:space:]]*\$COLOR-SCHEME\s*=" "${hydeThemeDir}/hypr.theme" | cut -d '=' -f2 | sed 's/^[[:space:]]*//;s/[[:space:]]*$//' ;} || + grep 'gsettings set org.gnome.desktop.interface color-scheme' "${hydeThemeDir}/hypr.theme" | awk -F "'" '{print $((NF - 1))}')" + colorScheme=${colorScheme:-$(gsettings get org.gnome.desktop.interface color-scheme)} + # should be declared explicitly so we can easily debug + grep -q "dark" <<< "${colorScheme}" && enableWallDcol=2 + grep -q "light" <<< "${colorScheme}" && enableWallDcol=3 +fi + +find "${wallbashDir}/Wall-Ways" -type f -name "*.dcol" | parallel fn_wallbash {} diff --git a/scripts/swwwallcache.sh b/scripts/swwwallcache.sh new file mode 100755 index 0000000..78d910c --- /dev/null +++ b/scripts/swwwallcache.sh @@ -0,0 +1,91 @@ +#!/usr/bin/env bash + + +#// set variables + +export scrDir="$(dirname "$(realpath "$0")")" +source "${scrDir}/globalcontrol.sh" +export thmbDir +export dcolDir + +[ -d "${hydeThemeDir}" ] && cacheIn="${hydeThemeDir}" || exit 1 +[ -d "${thmbDir}" ] || mkdir -p "${thmbDir}" +[ -d "${dcolDir}" ] || mkdir -p "${dcolDir}" +[ -d "${cacheDir}/landing" ] || mkdir -p "${cacheDir}/landing" + +if [ ! -z "${wallbashCustomCurve}" ] && [[ "${wallbashCustomCurve}" =~ ^([0-9]+[[:space:]][0-9]+\\n){8}[0-9]+[[:space:]][0-9]+$ ]] ; then + export wallbashCustomCurve + echo ":: wallbash --custom \"${wallbashCustomCurve}\"" +else + export wallbashCustomCurve="32 50\n42 46\n49 40\n56 39\n64 38\n76 37\n90 33\n94 29\n100 20" +fi + + +#// define functions + +fn_wallcache() +{ + local x_hash="${1}" + local x_wall="${2}" + [ ! -e "${thmbDir}/${x_hash}.thmb" ] && magick "${x_wall}"[0] -strip -resize 1000 -gravity center -extent 1000 -quality 90 "${thmbDir}/${x_hash}.thmb" + [ ! -e "${thmbDir}/${x_hash}.sqre" ] && magick "${x_wall}"[0] -strip -thumbnail 500x500^ -gravity center -extent 500x500 "${thmbDir}/${x_hash}.sqre" + [ ! -e "${thmbDir}/${x_hash}.blur" ] && magick "${x_wall}"[0] -strip -scale 10% -blur 0x3 -resize 100% "${thmbDir}/${x_hash}.blur" + [ ! -e "${thmbDir}/${x_hash}.quad" ] && magick "${thmbDir}/${x_hash}.sqre" \( -size 500x500 xc:white -fill "rgba(0,0,0,0.7)" -draw "polygon 400,500 500,500 500,0 450,0" -fill black -draw "polygon 500,500 500,0 450,500" \) -alpha Off -compose CopyOpacity -composite "${thmbDir}/${x_hash}.png" && mv "${thmbDir}/${x_hash}.png" "${thmbDir}/${x_hash}.quad" + { [ ! -e "${dcolDir}/${x_hash}.dcol" ] || [ "$(wc -l < "${dcolDir}/${x_hash}.dcol")" -ne 89 ] ;} && "${scrDir}/wallbash.sh" --custom "${wallbashCustomCurve}" "${thmbDir}/${x_hash}.thmb" "${dcolDir}/${x_hash}" &> /dev/null +} + +fn_wallcache_force() +{ + local x_hash="${1}" + local x_wall="${2}" + magick "${x_wall}"[0] -strip -resize 1000 -gravity center -extent 1000 -quality 90 "${thmbDir}/${x_hash}.thmb" + magick "${x_wall}"[0] -strip -thumbnail 500x500^ -gravity center -extent 500x500 "${thmbDir}/${x_hash}.sqre" + magick "${x_wall}"[0] -strip -scale 10% -blur 0x3 -resize 100% "${thmbDir}/${x_hash}.blur" + magick "${thmbDir}/${x_hash}.sqre" \( -size 500x500 xc:white -fill "rgba(0,0,0,0.7)" -draw "polygon 400,500 500,500 500,0 450,0" -fill black -draw "polygon 500,500 500,0 450,500" \) -alpha Off -compose CopyOpacity -composite "${thmbDir}/${x_hash}.png" && mv "${thmbDir}/${x_hash}.png" "${thmbDir}/${x_hash}.quad" + "${scrDir}/wallbash.sh" --custom "${wallbashCustomCurve}" "${thmbDir}/${x_hash}.thmb" "${dcolDir}/${x_hash}" &> /dev/null +} + +export -f fn_wallcache +export -f fn_wallcache_force + + +#// evaluate options + +while getopts "w:t:f" option ; do + case $option in + w ) # generate cache for input wallpaper + if [ -z "${OPTARG}" ] || [ ! -f "${OPTARG}" ] ; then + echo "Error: Input wallpaper \"${OPTARG}\" not found!" + exit 1 + fi + cacheIn="${OPTARG}" + ;; + t ) # generate cache for input theme + cacheIn="$(dirname "${hydeThemeDir}")/${OPTARG}" + if [ ! -d "${cacheIn}" ] ; then + echo "Error: Input theme \"${OPTARG}\" not found!" + exit 1 + fi + ;; + f ) # full cache rebuild + cacheIn="$(dirname "${hydeThemeDir}")" + mode="_force" + ;; + * ) # invalid option + echo "... invalid option ..." + echo "$(basename "${0}") -[option]" + echo "w : generate cache for input wallpaper" + echo "t : generate cache for input theme" + echo "f : full cache rebuild" + exit 1 ;; + esac +done + + +#// generate cache + +wallPathArray=("${cacheIn}") +wallPathArray+=("${wallAddCustomPath[@]}") +get_hashmap "${wallPathArray[@]}" +parallel --bar --link "fn_wallcache${mode}" ::: "${wallHash[@]}" ::: "${wallList[@]}" +exit 0 diff --git a/scripts/swwwallkon.sh b/scripts/swwwallkon.sh new file mode 100755 index 0000000..20e8b36 --- /dev/null +++ b/scripts/swwwallkon.sh @@ -0,0 +1,73 @@ +#!/usr/bin/env bash + + +#// Set variables + +scrDir=$(dirname "$(realpath "$0")") +source "${scrDir}/globalcontrol.sh" +scrName="$(basename "$0")" +kmenuPath="$HOME/.local/share/kio/servicemenus" +kmenuDesk="${kmenuPath}/hydewallpaper.desktop" +tgtPath="$(dirname "${hydeThemeDir}")" +get_themes + + +#// Evaluate options + +while getopts "t:w:" option ; do + case $option in + + t ) # Set theme + for x in "${!thmList[@]}" ; do + if [ "${thmList[x]}" == "$OPTARG" ] ; then + setTheme="${thmList[x]}" + break + fi + done + [ -z "${setTheme}" ] && echo "Error: '$OPTARG' theme not available..." && exit 1 + ;; + + w ) # Set wallpaper + if [ -f "$OPTARG" ] && file --mime-type "$OPTARG" | grep -q 'image/' ; then + setWall="$OPTARG" + else + echo "Error: '$OPTARG' is not an image file..." + exit 1 + fi + ;; + + * ) # Refresh menu + unset setTheme + unset setWall + ;; + + esac +done + + +#// Regenerate desktop + +if [ ! -z "${setTheme}" ] && [ ! -z "${setWall}" ] ; then + + inwallHash="$(set_hash "${setWall}")" + get_hashmap "${tgtPath}/${setTheme}" + if [[ "${wallHash[@]}" == *"${inwallHash}"* ]] ; then + notify-send -a "t2" -i "${thmbDir}/${inwallHash}.sqre" "Error" "Hash matched in ${setTheme}" + exit 0 + fi + + cp "${setWall}" "${tgtPath}/${setTheme}/wallpapers" + ln -fs "${tgtPath}/${setTheme}/wallpapers/$(basename "${setWall}")" "${tgtPath}/${setTheme}/wall.set" + + "${scrDir}/themeswitch.sh" -s "${setTheme}" + notify-send -a "t1" -i "${thmbDir}/${inwallHash}.sqre" "Wallpaper set in ${setTheme}" + +else + + echo -e "[Desktop Entry]\nType=Service\nMimeType=image/png;image/jpeg;image/jpg;image/gif\nActions=Menu-Refresh$(printf ";%s" "${thmList[@]}")\nX-KDE-Submenu=Set As Wallpaper...\n\n[Desktop Action Menu-Refresh]\nName=.: Refresh List :.\nExec=${scrName}" > "${kmenuDesk}" + for i in "${!thmList[@]}" ; do + echo -e "\n[Desktop Action ${thmList[i]}]\nName=${thmList[i]}\nExec=${scrName} -t \"${thmList[i]}\" -w %u" >> "${kmenuDesk}" + done + +fi + diff --git a/scripts/swwwallpaper.sh b/scripts/swwwallpaper.sh new file mode 100755 index 0000000..e69de29 diff --git a/scripts/swwwallselect.sh b/scripts/swwwallselect.sh new file mode 100755 index 0000000..999ea48 --- /dev/null +++ b/scripts/swwwallselect.sh @@ -0,0 +1,52 @@ +#!/usr/bin/env bash + + +#// set variables + +scrDir="$(dirname "$(realpath "$0")")" +source "${scrDir}/globalcontrol.sh" +rofiConf="${confDir}/rofi/selector.rasi" + + +#// set rofi scaling + +[[ "${rofiScale}" =~ ^[0-9]+$ ]] || rofiScale=10 +r_scale="configuration {font: \"JetBrainsMono Nerd Font ${rofiScale}\";}" +elem_border=$(( hypr_border * 3 )) + + +#// scale for monitor + +mon_x_res=$(hyprctl -j monitors | jq '.[] | select(.focused==true) | .width') +mon_scale=$(hyprctl -j monitors | jq '.[] | select(.focused==true) | .scale' | sed "s/\.//") +mon_x_res=$(( mon_x_res * 100 / mon_scale )) + + +#// generate config + +elm_width=$(( (28 + 8 + 5) * rofiScale )) +max_avail=$(( mon_x_res - (4 * rofiScale) )) +col_count=$(( max_avail / elm_width )) +r_override="window{width:100%;} listview{columns:${col_count};spacing:5em;} element{border-radius:${elem_border}px;orientation:vertical;} element-icon{size:28em;border-radius:0em;} element-text{padding:1em;}" + + +#// launch rofi menu + +currentWall="$(basename "$(readlink "${hydeThemeDir}/wall.set")")" +wallPathArray=("${hydeThemeDir}") +wallPathArray+=("${wallAddCustomPath[@]}") +get_hashmap "${wallPathArray[@]}" +rofiSel=$(parallel --link echo -en "\$(basename "{1}")"'\\x00icon\\x1f'"${thmbDir}"'/'"{2}"'.sqre\\n' ::: "${wallList[@]}" ::: "${wallHash[@]}" | rofi -dmenu -theme-str "${r_scale}" -theme-str "${r_override}" -config "${rofiConf}" -select "${currentWall}") + + +#// apply wallpaper + +if [ ! -z "${rofiSel}" ] ; then + for i in "${!wallPathArray[@]}" ; do + setWall="$(find "${wallPathArray[i]}" -type f -name "${rofiSel}")" + [ -z "${setWall}" ] || break + done + "${scrDir}/swwwallpaper.sh" -s "${setWall}" + notify-send -a "t1" -i "${thmbDir}/$(set_hash "${setWall}").sqre" " ${rofiSel}" +fi + diff --git a/scripts/sysmonlaunch.sh b/scripts/sysmonlaunch.sh new file mode 100755 index 0000000..82e105b --- /dev/null +++ b/scripts/sysmonlaunch.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env bash + +scrDir="$(dirname "$(realpath "$0")")" +source "${scrDir}/globalcontrol.sh" +pkgChk=("io.missioncenter.MissionCenter" "htop" "btop" "top") + +for sysMon in "${!pkgChk[@]}"; do + [ "${sysMon}" -gt 0 ] && term=$(cat $HOME/.config/hypr/keybindings.conf | grep ^'$term' | cut -d '=' -f2) + if pkg_installed "${pkgChk[sysMon]}" ; then + pkill -x "${pkgChk[sysMon]}" || ${term} "${pkgChk[sysMon]}" & + break + fi +done + diff --git a/scripts/systemupdate.sh b/scripts/systemupdate.sh new file mode 100755 index 0000000..ae72bd7 --- /dev/null +++ b/scripts/systemupdate.sh @@ -0,0 +1,53 @@ +#!/usr/bin/env bash + +# Check release +if [ ! -f /etc/arch-release ] ; then + exit 0 +fi + +# source variables +scrDir=$(dirname "$(realpath "$0")") +source "$scrDir/globalcontrol.sh" +get_aurhlpr +export -f pkg_installed +fpk_exup="pkg_installed flatpak && flatpak update" + +# Trigger upgrade +if [ "$1" == "up" ] ; then + trap 'pkill -RTMIN+20 waybar' EXIT + command=" + fastfetch + $0 upgrade + ${aurhlpr} -Syu + $fpk_exup + read -n 1 -p 'Press any key to continue...' + " + kitty --title systemupdate sh -c "${command}" +fi + +# Check for AUR updates +aur=$(${aurhlpr} -Qua | wc -l) +ofc=$( (while pgrep -x checkupdates > /dev/null ; do sleep 1; done) ; checkupdates | wc -l) + +# Check for flatpak updates +if pkg_installed flatpak ; then + fpk=$(flatpak remote-ls --updates | wc -l) + fpk_disp="\n󰏓 Flatpak $fpk" +else + fpk=0 + fpk_disp="" +fi + +# Calculate total available updates +upd=$(( ofc + aur + fpk )) + +[ "${1}" == upgrade ] && printf "[Official] %-10s\n[AUR] %-10s\n[Flatpak] %-10s\n" "$ofc" "$aur" "$fpk" && exit + +# Show tooltip +if [ $upd -eq 0 ] ; then + upd="" #Remove Icon completely + # upd="󰮯" #If zero Display Icon only + echo "{\"text\":\"$upd\", \"tooltip\":\" Packages are up to date\"}" +else + echo "{\"text\":\"󰮯 $upd\", \"tooltip\":\"󱓽 Official $ofc\n󱓾 AUR $aur$fpk_disp\"}" +fi diff --git a/scripts/testrunner.sh b/scripts/testrunner.sh new file mode 100755 index 0000000..91ac66d --- /dev/null +++ b/scripts/testrunner.sh @@ -0,0 +1,27 @@ +#!/usr/bin/env bash + +scrDir=`dirname "$(realpath "$0")"` +source $scrDir/globalcontrol.sh +rofDir="${confDir}/rofi" + +if [ "${1}" == "--verbose" ] || [ "${1}" == "-v" ] ; then + + case ${enableWallDcol} in + 0) wallbashStatus="disabled";; + 1) wallbashStatus="enabled // auto change based on wallpaper brightness";; + 2) wallbashStatus="enabled // dark mode --forced";; + 3) wallbashStatus="enabled // light mode --forced";; + esac + + echo -e "\n\ncurrent theme :: \"${hydeTheme}\" :: \"$(readlink "${hydeThemeDir}/wall.set")\"" + echo -e "wallbash status :: ${enableWallDcol} :: ${wallbashStatus}\n" + get_themes + + for x in "${!thmList[@]}" ; do + echo -e "\nTheme $((x + 1)) :: \${thmList[${x}]}=\"${thmList[x]}\" :: \${thmWall[${x}]}=\"${thmWall[x]}\"\n" + get_hashmap "$(dirname "${hydeThemeDir}")/${thmList[x]}" --verbose + echo -e "\n" + done + + exit 0 +fi diff --git a/scripts/themeselect.sh b/scripts/themeselect.sh new file mode 100755 index 0000000..c774224 --- /dev/null +++ b/scripts/themeselect.sh @@ -0,0 +1,59 @@ +#!/usr/bin/env bash + + +#// set variables + +scrDir="$(dirname "$(realpath "$0")")" +source "${scrDir}/globalcontrol.sh" +rofiConf="${confDir}/rofi/selector.rasi" + + +#// set rofi scaling + +[[ "${rofiScale}" =~ ^[0-9]+$ ]] || rofiScale=10 +r_scale="configuration {font: \"JetBrainsMono Nerd Font ${rofiScale}\";}" +elem_border=$(( hypr_border * 5 )) +icon_border=$(( elem_border - 5 )) + + +#// scale for monitor + +mon_x_res=$(hyprctl -j monitors | jq '.[] | select(.focused==true) | .width') +mon_scale=$(hyprctl -j monitors | jq '.[] | select(.focused==true) | .scale' | sed "s/\.//") +mon_x_res=$(( mon_x_res * 100 / mon_scale )) + + +#// generate config + +case "${themeSelect}" in +2) # adapt to style 2 + elm_width=$(( (20 + 12) * rofiScale * 2 )) + max_avail=$(( mon_x_res - (4 * rofiScale) )) + col_count=$(( max_avail / elm_width )) + r_override="window{width:100%;background-color:#00000003;} listview{columns:${col_count};} element{border-radius:${elem_border}px;background-color:@main-bg;} element-icon{size:20em;border-radius:${icon_border}px 0px 0px ${icon_border}px;}" + thmbExtn="quad" ;; +*) # default to style 1 + elm_width=$(( (23 + 12 + 1) * rofiScale * 2 )) + max_avail=$(( mon_x_res - (4 * rofiScale) )) + col_count=$(( max_avail / elm_width )) + r_override="window{width:100%;} listview{columns:${col_count};} element{border-radius:${elem_border}px;padding:0.5em;} element-icon{size:23em;border-radius:${icon_border}px;}" + thmbExtn="sqre" ;; +esac + + +#// launch rofi menu + +get_themes + +rofiSel=$(for i in ${!thmList[@]} ; do + echo -en "${thmList[i]}\x00icon\x1f${thmbDir}/$(set_hash "${thmWall[i]}").${thmbExtn}\n" +done | rofi -dmenu -theme-str "${r_scale}" -theme-str "${r_override}" -config "${rofiConf}" -select "${hydeTheme}") + + +#// apply theme + +if [ ! -z "${rofiSel}" ] ; then + "${scrDir}/themeswitch.sh" -s "${rofiSel}" + notify-send -a "t1" -i "$HOME/.config/dunst/icons/hyprdots.png" " ${rofiSel}" +fi + diff --git a/scripts/themestyle.sh b/scripts/themestyle.sh new file mode 100755 index 0000000..55f7214 --- /dev/null +++ b/scripts/themestyle.sh @@ -0,0 +1,42 @@ +#!/usr/bin/env bash + +#// set variables +scrDir="$(dirname "$(realpath "$0")")" +source "${scrDir}/globalcontrol.sh" +rofiConf="${confDir}/rofi/selector.rasi" +rofiAssetDir="${confDir}/rofi/assets" + +#// set rofi scaling +[[ "${rofiScale}" =~ ^[0-9]+$ ]] || rofiScale=15 +r_scale="configuration {font: \"JetBrainsMono Nerd Font ${rofiScale}\";}" +elem_border=$(( hypr_border * 5 )) +icon_border=$(( elem_border - 5 )) + +#// defining 2 png files to select from +options="Style 1\x00icon\x1f${rofiAssetDir}/theme_style_1.png\nStyle 2\x00icon\x1f${rofiAssetDir}/theme_style_2.png" + +#// generate config +mon_x_res=$(hyprctl -j monitors | jq '.[] | select(.focused==true) | .width') +mon_scale=$(hyprctl -j monitors | jq '.[] | select(.focused==true) | .scale' | sed "s/\.//") +mon_x_res=$(( mon_x_res * 100 / mon_scale )) + +elm_width=$(( (20 + 12 + 16 ) * rofiScale )) +max_avail=$(( mon_x_res - (4 * rofiScale) )) +col_count=$(( max_avail / elm_width )) +[[ "${col_count}" -gt 5 ]] && col_count=5 +r_override="window{width:100%;} listview{columns:${col_count};} element{orientation:vertical;border-radius:${elem_border}px;} element-icon{border-radius:${icon_border}px;size:20em;} element-text{enabled:false;}" + +#// launch rofi menu +RofiSel=$(echo -e "$options" | rofi -dmenu -theme-str "${r_override}" -config "${rofiConf}") + +#// apply selected theme +if [ ! -z "${RofiSel}" ]; then + #// extract selected style number ('Style 1' -> '1') + selectedStyle=$(echo "${RofiSel}" | awk -F '\x00' '{print $1}' | sed 's/Style //') + + #// notify the user + notify-send -a "t1" -r 91190 -t 2200 -i "${rofiAssetDir}/theme_style_${selectedStyle}.png" "Style ${selectedStyle} applied..." + + #// save selection in config file + set_conf "themeSelect" "${selectedStyle}" +fi diff --git a/scripts/themeswitch.sh b/scripts/themeswitch.sh new file mode 100755 index 0000000..510f349 --- /dev/null +++ b/scripts/themeswitch.sh @@ -0,0 +1,121 @@ +#!/usr/bin/env bash + + +#// set variables + +scrDir="$(dirname "$(realpath "$0")")" +source "${scrDir}/globalcontrol.sh" +[ -z "${hydeTheme}" ] && echo "ERROR: unable to detect theme" && exit 1 +get_themes + + +#// define functions + +Theme_Change() +{ + local x_switch=$1 + for i in ${!thmList[@]} ; do + if [ "${thmList[i]}" == "${hydeTheme}" ] ; then + if [ "${x_switch}" == 'n' ] ; then + setIndex=$(( (i + 1) % ${#thmList[@]} )) + elif [ "${x_switch}" == 'p' ] ; then + setIndex=$(( i - 1 )) + fi + themeSet="${thmList[setIndex]}" + break + fi + done +} + + +#// evaluate options + +while getopts "nps:" option ; do + case $option in + + n ) # set next theme + Theme_Change n + export xtrans="grow" ;; + + p ) # set previous theme + Theme_Change p + export xtrans="outer" ;; + + s ) # set selected theme + themeSet="$OPTARG" ;; + + * ) # invalid option + echo "... invalid option ..." + echo "$(basename "${0}") -[option]" + echo "n : set next theme" + echo "p : set previous theme" + echo "s : set input theme" + exit 1 ;; + esac +done + + +#// update control file + +if ! $(echo "${thmList[@]}" | grep -wq "${themeSet}") ; then + themeSet="${hydeTheme}" +fi + +set_conf "hydeTheme" "${themeSet}" +echo ":: applying theme :: \"${themeSet}\"" +export reload_flag=1 +source "${scrDir}/globalcontrol.sh" + + +#// hypr +[ -n "$HYPRLAND_INSTANCE_SIGNATURE" ] && hyprctl keyword misc:disable_autoreload 1 -q +sed '1d' "${hydeThemeDir}/hypr.theme" > "${confDir}/hypr/themes/theme.conf" # Useless and already handled by swwwallbash.sh but kept for robustness +gtkTheme="$( +{ grep -q "^[[:space:]]*\$GTK[-_]THEME\s*=" "${hydeThemeDir}/hypr.theme" && grep "^[[:space:]]*\$GTK[-_]THEME\s*=" "${hydeThemeDir}/hypr.theme" | cut -d '=' -f2 | sed 's/^[[:space:]]*//;s/[[:space:]]*$//' ;} || +grep 'gsettings set org.gnome.desktop.interface gtk-theme' "${hydeThemeDir}/hypr.theme" | awk -F "'" '{print $((NF - 1))}' +)" + +gtkIcon="$( +{ grep -q "^[[:space:]]*\$ICON[-_]THEME\s*=" "${hydeThemeDir}/hypr.theme" && grep "^[[:space:]]*\$ICON[-_]THEME\s*=" "${hydeThemeDir}/hypr.theme" | cut -d '=' -f2 | sed 's/^[[:space:]]*//;s/[[:space:]]*$//' ;} || +grep 'gsettings set org.gnome.desktop.interface icon-theme' "${hydeThemeDir}/hypr.theme" | awk -F "'" '{print $(NF - 1)}' +)" + +#// qtct + +sed -i "/^icon_theme=/c\icon_theme=${gtkIcon}" "${confDir}/qt5ct/qt5ct.conf" +sed -i "/^icon_theme=/c\icon_theme=${gtkIcon}" "${confDir}/qt6ct/qt6ct.conf" +sed -i "/^Theme=/c\Theme=${gtkIcon}" "${confDir}/kdeglobals" + +#// gtk3 + +sed -i "/^gtk-theme-name=/c\gtk-theme-name=${gtkTheme}" $confDir/gtk-3.0/settings.ini +sed -i "/^gtk-icon-theme-name=/c\gtk-icon-theme-name=${gtkIcon}" $confDir/gtk-3.0/settings.ini + + +#// gtk4 + +if [ -d /run/current-system/sw/share/themes ] ; then + themeDir=/run/current-system/sw/share/themes +else + themeDir=~/.themes +fi +rm -rf "${confDir}/gtk-4.0" +ln -s "${themeDir}/${gtkTheme}/gtk-4.0" "${confDir}/gtk-4.0" + + +#// flatpak GTK + +if pkg_installed flatpak ; then + if [ "${enableWallDcol}" -eq 0 ] ; then + flatpak --user override --env=GTK_THEME="${gtkTheme}" + flatpak --user override --env=ICON_THEME="${gtkIcon}" + else + flatpak --user override --env=GTK_THEME="Wallbash-Gtk" + flatpak --user override --env=ICON_THEME="${gtkIcon}" + fi +fi + +#// wallpaper + +"${scrDir}/swwwallpaper.sh" -s "$(readlink "${hydeThemeDir}/wall.set")" + diff --git a/scripts/tmux-session-manager b/scripts/tmux-session-manager new file mode 100755 index 0000000..67891b2 --- /dev/null +++ b/scripts/tmux-session-manager @@ -0,0 +1,4 @@ +#!/usr/bin/env bash + +SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)" +exec "$SCRIPT_DIR/tmux-session-manager.sh" "$@" diff --git a/scripts/tmux-session-manager.sh b/scripts/tmux-session-manager.sh new file mode 100755 index 0000000..f1dd008 --- /dev/null +++ b/scripts/tmux-session-manager.sh @@ -0,0 +1,409 @@ +#!/usr/bin/env bash +# Tmux Session Manager - Manage multiple named tmux sessions with persistence +# Usage: tmux-session-manager.sh [session-name] [action] +# Actions: save, restore, list, delete + +set -euo pipefail + +SESSION_DIR="${XDG_DATA_HOME:-$HOME/.local/share}/tmux/sessions" +RESURRECT_DIR="${XDG_DATA_HOME:-$HOME/.local/share}/tmux/resurrect" + +# Create directories if they don't exist +mkdir -p "$SESSION_DIR" "$RESURRECT_DIR" + +show_usage() { + cat < Create or switch to a named session + save Manually save current session state + restore Restore a specific named session + delete Delete a named session configuration + restore-all Restore all sessions at once + auto-save Automatically save all active sessions (for cron/timer) + +Examples: + tmux-session-manager create main # Create/switch to 'main' session + tmux-session-manager save work # Save current session as 'work' + tmux-session-manager restore dev # Restore 'dev' session + tmux-session-manager list # List all sessions +EOF +} + +last_snapshot_sessions() { + local last_file="$RESURRECT_DIR/last" + + if [ ! -f "$last_file" ]; then + return 0 + fi + + awk -F '\t' '$1 == "pane" { print $2 }' "$last_file" | sort -u +} + +session_path_matches_name() { + local session="$1" + local desired_name="$2" + local desired_basename="$desired_name" + local path="" + + if [[ "$desired_name" == _* ]]; then + desired_basename=".${desired_name#_}" + fi + + while IFS= read -r path; do + [ -n "$path" ] || continue + if [ "$(basename "$path")" = "$desired_basename" ]; then + return 0 + fi + done < <(tmux list-panes -t "=${session}" -F "#{pane_current_path}" 2>/dev/null) + + if [ "$desired_name" = "main" ]; then + while IFS= read -r path; do + [ -n "$path" ] || continue + if [ "$path" = "$HOME" ]; then + return 0 + fi + done < <(tmux list-panes -t "=${session}" -F "#{pane_current_path}" 2>/dev/null) + fi + + return 1 +} + +run_resurrect_restore() { + local restore_script + restore_script="$(tmux show-options -gv @resurrect-restore-script-path 2>/dev/null || true)" + + if [ -z "$restore_script" ]; then + echo "Error: Could not determine resurrect restore script path" + return 1 + fi + + tmux run-shell "$restore_script" +} + +run_resurrect_save() { + local save_script + save_script="$(tmux show-options -gv @resurrect-save-script-path 2>/dev/null || true)" + + if [ -z "$save_script" ]; then + echo "Error: Could not determine resurrect save script path" + return 1 + fi + + tmux run-shell "$save_script quiet" +} + +save_session() { + local session_name="$1" + + # Get the current session if not specified + if [ -z "$session_name" ]; then + session_name=$(tmux display-message -p '#{session_name}' 2>/dev/null || echo "") + if [ -z "$session_name" ]; then + echo "Error: No active tmux session found" + return 1 + fi + fi + + # Check if session exists + if ! tmux has-session -t "$session_name" 2>/dev/null; then + echo "Error: Session '$session_name' does not exist" + return 1 + fi + + # Save session using resurrect script + run_resurrect_save + + echo "Saving session '$session_name'..." + sleep 1 + + # Also create a backup of the session state + local backup_file="$SESSION_DIR/${session_name}.state" + tmux capture-pane -t "$session_name" -p > "$backup_file" || true + + echo "Session '$session_name' saved" +} + +restore_session() { + local session_name="$1" + local bootstrap_session="__tsm_restore_bootstrap" + local trigger_session="" + local restored=0 + local renamed=0 + local candidate_session="" + local -a before_sessions=() + local -a after_sessions=() + local -a new_sessions=() + + if [ -z "$session_name" ]; then + echo "Error: Session name required" + show_usage + return 1 + fi + + # Use resurrect to restore the most recent snapshot. + # A target session might not currently exist, so trigger restore from any live session. + echo "Restoring session '$session_name' from latest resurrect save..." + + while IFS= read -r session; do + [ -n "$session" ] && before_sessions+=("$session") + done < <(tmux list-sessions -F "#{session_name}" 2>/dev/null || true) + + if ! tmux list-sessions >/dev/null 2>&1; then + tmux new-session -d -s "$bootstrap_session" + trigger_session="$bootstrap_session" + else + while IFS= read -r session; do + if [ -n "$session" ]; then + trigger_session="$session" + break + fi + done < <(tmux list-sessions -F "#{session_name}" 2>/dev/null) + fi + + if [ -z "$trigger_session" ]; then + echo "Error: Could not find a tmux session to trigger restore" + return 1 + fi + + run_resurrect_restore + + for _ in $(seq 1 20); do + if tmux has-session -t "$session_name" 2>/dev/null; then + restored=1 + break + fi + sleep 0.25 + done + + while IFS= read -r session; do + [ -n "$session" ] && after_sessions+=("$session") + done < <(tmux list-sessions -F "#{session_name}" 2>/dev/null || true) + + if [ "$restored" -eq 0 ]; then + for session in "${after_sessions[@]}"; do + local existed=0 + for before in "${before_sessions[@]}"; do + if [ "$session" = "$before" ]; then + existed=1 + break + fi + done + if [ "$existed" -eq 0 ]; then + new_sessions+=("$session") + fi + done + + # Give resurrect a moment to fully materialize pane paths before matching. + for _ in $(seq 1 20); do + candidate_session="" + + for session in "${new_sessions[@]}"; do + if session_path_matches_name "$session" "$session_name"; then + candidate_session="$session" + break + fi + done + + # If no brand-new session matched, fall back to any current session. + # This handles cases where restore reused existing numeric sessions. + if [ -z "$candidate_session" ]; then + for session in "${after_sessions[@]}"; do + if [ "$session" = "$session_name" ]; then + continue + fi + if session_path_matches_name "$session" "$session_name"; then + candidate_session="$session" + break + fi + done + fi + + if [ -n "$candidate_session" ]; then + break + fi + + sleep 0.25 + done + + if [ -z "$candidate_session" ] && [ "${#new_sessions[@]}" -eq 1 ]; then + candidate_session="${new_sessions[0]}" + fi + + if [ -n "$candidate_session" ] && ! tmux has-session -t "$session_name" 2>/dev/null; then + tmux rename-session -t "=${candidate_session}" "$session_name" + restored=1 + renamed=1 + fi + fi + + if [ "$trigger_session" = "$bootstrap_session" ] && tmux has-session -t "$bootstrap_session" 2>/dev/null; then + tmux kill-session -t "$bootstrap_session" 2>/dev/null || true + fi + + if [ "$restored" -eq 1 ]; then + if [ "$renamed" -eq 1 ]; then + echo "Session '$session_name' restored by renaming '$candidate_session'" + else + echo "Session '$session_name' restored and available" + fi + else + local snapshot_sessions + snapshot_sessions="$(last_snapshot_sessions | tr '\n' ' ' | sed 's/[[:space:]]*$//')" + if [ -n "$snapshot_sessions" ]; then + echo "Restore was triggered, but '$session_name' was not found in the latest snapshot (contains: $snapshot_sessions)" + else + echo "Restore was triggered, but '$session_name' was not found and no snapshot sessions were detected" + fi + return 1 + fi +} + +create_session() { + local session_name="$1" + + if [ -z "$session_name" ]; then + echo "Error: Session name required" + show_usage + return 1 + fi + + # Check if session already exists + if tmux has-session -t "$session_name" 2>/dev/null; then + echo "Session '$session_name' already exists, attaching..." + tmux attach-session -t "=${session_name}" + else + echo "Creating new session '$session_name'..." + tmux new-session -d -s "$session_name" + tmux send-keys -t "$session_name" "# Session: $session_name" Enter + echo "Session '$session_name' created" + tmux attach-session -t "=${session_name}" + fi +} + +list_sessions() { + echo "Available tmux sessions:" + tmux list-sessions -F "#{session_name}: #{session_windows} windows" 2>/dev/null || echo "No tmux sessions found" + + echo "" + echo "Session names in latest resurrect snapshot:" + local snapshot_sessions + snapshot_sessions="$(last_snapshot_sessions)" + if [ -n "$snapshot_sessions" ]; then + echo "$snapshot_sessions" + else + echo "No resurrect snapshot found" + fi + + echo "" + echo "Saved session labels (local backups):" + if [ -d "$SESSION_DIR" ]; then + ls -1 "$SESSION_DIR" 2>/dev/null | sed 's/.state$//' | sort | uniq || echo "No saved sessions" + else + echo "No saved sessions" + fi +} + +delete_session() { + local session_name="$1" + + if [ -z "$session_name" ]; then + echo "Error: Session name required" + return 1 + fi + + # Kill the tmux session if it exists + if tmux has-session -t "$session_name" 2>/dev/null; then + tmux kill-session -t "=${session_name}" + echo "Killed tmux session '$session_name'" + fi + + # Remove saved state files + rm -f "$SESSION_DIR/${session_name}.state" + echo "Deleted session configuration '$session_name'" +} + +restore_all_sessions() { + local bootstrap_session="__tsm_restore_bootstrap" + local trigger_session="" + + echo "Restoring all sessions from latest resurrect save..." + + if ! tmux list-sessions >/dev/null 2>&1; then + tmux new-session -d -s "$bootstrap_session" + trigger_session="$bootstrap_session" + else + while IFS= read -r session; do + if [ -n "$session" ]; then + trigger_session="$session" + break + fi + done < <(tmux list-sessions -F "#{session_name}" 2>/dev/null) + fi + + if [ -z "$trigger_session" ]; then + echo "Error: Could not find a tmux session to trigger restore" + return 1 + fi + + run_resurrect_restore + sleep 1 + + if [ "$trigger_session" = "$bootstrap_session" ] && tmux has-session -t "$bootstrap_session" 2>/dev/null; then + tmux kill-session -t "=${bootstrap_session}" 2>/dev/null || true + fi + + echo "Restore triggered for all sessions" +} + +auto_save() { + echo "Auto-saving all active tmux sessions..." + while IFS= read -r session; do + save_session "$session" || true + done < <(tmux list-sessions -F "#{session_name}" 2>/dev/null) + echo "All sessions auto-saved" +} + +# Main command dispatcher +main() { + local command="${1:-list}" + local arg="${2:-}" + + case "$command" in + list) + list_sessions + ;; + create) + create_session "$arg" + ;; + save) + save_session "$arg" + ;; + restore) + restore_session "$arg" + ;; + delete) + delete_session "$arg" + ;; + restore-all) + restore_all_sessions + ;; + auto-save) + auto_save + ;; + --help|-h|help) + show_usage + ;; + *) + echo "Unknown command: $command" + show_usage + return 1 + ;; + esac +} + +main "$@" diff --git a/scripts/togglepowermode.nix b/scripts/togglepowermode.nix new file mode 100644 index 0000000..3f77424 --- /dev/null +++ b/scripts/togglepowermode.nix @@ -0,0 +1,22 @@ +{ pkgs }: + +pkgs.writeShellScriptBin "togglepowermode" '' + # Toggle between performance and power saving mode + config_dir="$HOME/.config/hypr" + power_mode_file="$config_dir/power_mode" + + mkdir -p "$config_dir" + + # Read current mode or default to balanced + current_mode=$(cat "$power_mode_file" 2>/dev/null || echo "balanced") + + if [ "$current_mode" = "powersave" ]; then + # Switch to performance mode + echo "performance" > "$power_mode_file" + echo "Performance Mode" + else + # Switch to powersave mode + echo "powersave" > "$power_mode_file" + echo "Power Saving Mode" + fi +'' diff --git a/scripts/update-hyprland-colors.sh b/scripts/update-hyprland-colors.sh new file mode 100755 index 0000000..6f64bae --- /dev/null +++ b/scripts/update-hyprland-colors.sh @@ -0,0 +1,22 @@ +#!/usr/bin/env bash + +# Update Hyprland border colors based on pywal colors +# This script reads the pywal colors.json and applies them to Hyprland + +COLORS_JSON="$HOME/.cache/wal/colors.json" + +if [[ ! -f "$COLORS_JSON" ]]; then + exit 1 +fi + +# Extract colors from pywal (remove the # prefix) +ACTIVE_COLOR=$(jq -r '.colors.color7' "$COLORS_JSON" | sed 's/#//') +INACTIVE_COLOR=$(jq -r '.colors.color8' "$COLORS_JSON" | sed 's/#//') + +# Add alpha channel (ff for fully opaque) +ACTIVE_COLOR="0xff${ACTIVE_COLOR}" +INACTIVE_COLOR="0xff${INACTIVE_COLOR}" + +# Apply colors to Hyprland +hyprctl keyword "general:col.active_border" "$ACTIVE_COLOR" +hyprctl keyword "general:col.inactive_border" "$INACTIVE_COLOR" diff --git a/scripts/volumecontrol.sh b/scripts/volumecontrol.sh new file mode 100755 index 0000000..f53810e --- /dev/null +++ b/scripts/volumecontrol.sh @@ -0,0 +1,163 @@ +#!/usr/bin/env bash + +# Source global control script +scrDir=$(dirname "$(realpath "$0")") +source "$scrDir/globalcontrol.sh" + +# Check if SwayOSD is installed +use_swayosd=false +if command -v swayosd-client >/dev/null 2>&1 && pgrep -x swayosd-server >/dev/null; then + use_swayosd=true +fi + +# Define functions + +print_usage() { + cat < [step] + +Devices/Actions: + -i Input device + -o Output device + -p Player application + -s Select output device + -t Toggle to next output device + +Actions: + i Increase volume + d Decrease volume + m Toggle mute + +Optional: + step Volume change step (default: 5) + +Examples: + $(basename "$0") -o i 5 # Increase output volume by 5 + $(basename "$0") -i m # Toggle input mute + $(basename "$0") -p spotify d 10 # Decrease Spotify volume by 10 + $(basename "$0") -p '' d 10 # Decrease volume by 10 for all players + +EOF + exit 1 +} + +notify_vol() { + angle=$(( (($vol + 2) / 5) * 5 )) + ico="${icodir}/vol-${angle}.svg" + bar=$(seq -s "." $(($vol / 15)) | sed 's/[0-9]//g') + notify-send -a "t2" -r 91190 -t 800 -i "${ico}" "${vol}${bar}" "${nsink}" +} + +notify_mute() { + mute=$(pamixer "${srce}" --get-mute | cat) + [ "${srce}" == "--default-source" ] && dvce="mic" || dvce="speaker" + if [ "${mute}" == "true" ]; then + notify-send -a "t2" -r 91190 -t 800 -i "${icodir}/muted-${dvce}.svg" "muted" "${nsink}" + else + notify-send -a "t2" -r 91190 -t 800 -i "${icodir}/unmuted-${dvce}.svg" "unmuted" "${nsink}" + fi +} + +change_volume() { + local action=$1 + local step=$2 + local device=$3 + local delta="-" + local mode="--output-volume" + + [ "${action}" = "i" ] && delta="+" + [ "${srce}" = "--default-source" ] && mode="--input-volume" + case $device in + "pamixer") + $use_swayosd && swayosd-client ${mode} "${delta}${step}" && exit 0 + pamixer $srce -"$action" "$step" + vol=$(pamixer $srce --get-volume) + ;; + "playerctl") + playerctl --player="$srce" volume "$(awk -v step="$step" 'BEGIN {print step/100}')${delta}" + vol=$(playerctl --player="$srce" volume | awk '{ printf "%.0f\n", $0 * 100 }') + ;; + esac + + notify_vol +} + +toggle_mute() { + local device=$1 + local mode="--output-volume" + [ "${srce}" = "--default-source" ] && mode="--input-volume" + case $device in + "pamixer") + $use_swayosd && swayosd-client "${mode}" mute-toggle && exit 0 + pamixer $srce -t + notify_mute + ;; + "playerctl") + local volume_file="/tmp/$(basename "$0")_last_volume_${srce:-all}" + if [ "$(playerctl --player="$srce" volume | awk '{ printf "%.2f", $0 }')" != "0.00" ]; then + playerctl --player="$srce" volume | awk '{ printf "%.2f", $0 }' > "$volume_file" + playerctl --player="$srce" volume 0 + else + if [ -f "$volume_file" ]; then + last_volume=$(cat "$volume_file") + playerctl --player="$srce" volume "$last_volume" + else + playerctl --player="$srce" volume 0.5 # Default to 50% if no saved volume + fi + fi + notify_mute + ;; + esac +} + +select_output() { + local selection=$1 + if [ -n "$selection" ]; then + device=$(pactl list sinks | grep -C2 -F "Description: $selection" | grep Name | cut -d: -f2 | xargs) + if pactl set-default-sink "$device"; then + notify-send -t 2000 -r 2 -u low "Activated: $selection" + else + notify-send -t 2000 -r 2 -u critical "Error activating $selection" + fi + else + pactl list sinks | grep -ie "Description:" | awk -F ': ' '{print $2}' | sort + fi +} + +toggle_output() { + local default_sink=$(pamixer --get-default-sink | awk -F '"' 'END{print $(NF - 1)}') + mapfile -t sink_array < <(select_output) + local current_index=$(printf '%s\n' "${sink_array[@]}" | grep -n "$default_sink" | cut -d: -f1) + local next_index=$(( (current_index % ${#sink_array[@]}) + 1 )) + local next_sink="${sink_array[next_index-1]}" + select_output "$next_sink" +} + +# Main script logic + +# Set default variables +icodir="${confDir}/dunst/icons/vol" +step=5 +# Parse options +while getopts "iop:st" opt; do + case $opt in + i) device="pamixer"; srce="--default-source"; nsink=$(pamixer --list-sources | awk -F '"' 'END {print $(NF - 1)}') ;; + o) device="pamixer"; srce=""; nsink=$(pamixer --get-default-sink | awk -F '"' 'END{print $(NF - 1)}') ;; + p) device="playerctl"; srce="${OPTARG}"; nsink=$(playerctl --list-all | grep -w "$srce") ;; + s) select_output "$(select_output | rofi -dmenu -config "${confDir}/rofi/notification.rasi")"; exit ;; + t) toggle_output; exit ;; + *) print_usage ;; + esac +done + +shift $((OPTIND-1)) + +# Check if device is set +[ -z "$device" ] && print_usage + +# Execute action +case $1 in + i|d) change_volume "$1" "${2:-$step}" "$device" ;; + m) toggle_mute "$device" ;; + *) print_usage ;; +esac diff --git a/scripts/wallbash.sh b/scripts/wallbash.sh new file mode 100755 index 0000000..787d318 --- /dev/null +++ b/scripts/wallbash.sh @@ -0,0 +1,220 @@ +#!/usr/bin/env bash +#|---/ /+---------------------------------------------+---/ /|# +#|--/ /-| Script to generate color palette from image |--/ /-|# +#|-/ /--| Prasanth Rangan |-/ /--|# +#|/ /---+---------------------------------------------+/ /---|# + + +#// accent color profile + +colorProfile="default" +wallbashCurve="32 50\n42 46\n49 40\n56 39\n64 38\n76 37\n90 33\n94 29\n100 20" +sortMode="auto" + +while [ $# -gt 0 ] ; do + case "$1" in + -v|--vibrant) colorProfile="vibrant" + wallbashCurve="18 99\n32 97\n48 95\n55 90\n70 80\n80 70\n88 60\n94 40\n99 24" + ;; + -p|--pastel) colorProfile="pastel" + wallbashCurve="10 99\n17 66\n24 49\n39 41\n51 37\n58 34\n72 30\n84 26\n99 22" + ;; + -m|--mono) colorProfile="mono" + wallbashCurve="10 0\n17 0\n24 0\n39 0\n51 0\n58 0\n72 0\n84 0\n99 0" + ;; + -c|--custom) + shift + if [ -n "${1}" ] && [[ "${1}" =~ ^([0-9]+[[:space:]][0-9]+\\n){8}[0-9]+[[:space:]][0-9]+$ ]] ; then + colorProfile="custom" + wallbashCurve="${1}" + else + echo "Error: Custom color curve format is incorrect ${1}" + exit 1 + fi + ;; + -d|--dark) sortMode="dark" + colSort="" + ;; + -l|--light) sortMode="light" + colSort="-r" + ;; + *) break + ;; + esac + shift +done + + +#// set variables + +wallbashImg="${1}" +wallbashColors=4 +wallbashFuzz=70 +wallbashRaw="${2:-"${wallbashImg}"}.mpc" +wallbashOut="${2:-"${wallbashImg}"}.dcol" +wallbashCache="${2:-"${wallbashImg}"}.cache" + + +#// color modulations + +pryDarkBri=116 +pryDarkSat=110 +pryDarkHue=88 +pryLightBri=100 +pryLightSat=100 +pryLightHue=114 +txtDarkBri=188 +txtLightBri=16 + + +#// input image validation + +if [ -z "${wallbashImg}" ] || [ ! -f "${wallbashImg}" ] ; then + echo "Error: Input file not found!" + exit 1 +fi + +magick -ping "${wallbashImg}" -format "%t" info: &> /dev/null +if [ $? -ne 0 ] ; then + echo "Error: Unsuppoted image format ${wallbashImg}" + exit 1 +fi + +echo -e "wallbash ${colorProfile} profile :: ${sortMode} :: Colors ${wallbashColors} :: Fuzzy ${wallbashFuzz} :: \"${wallbashOut}\"" +mkdir -p "${cacheDir}/${cacheThm}" +> "${wallbashOut}" + + +#// define functions + +rgb_negative() { + local inCol=$1 + local r=${inCol:0:2} + local g=${inCol:2:2} + local b=${inCol:4:2} + local r16=$((16#$r)) + local g16=$((16#$g)) + local b16=$((16#$b)) + r=$(printf "%02X" $((255 - $r16))) + g=$(printf "%02X" $((255 - $g16))) + b=$(printf "%02X" $((255 - $b16))) + echo "${r}${g}${b}" +} + +rgba_convert() { + local inCol=$1 + local r=${inCol:0:2} + local g=${inCol:2:2} + local b=${inCol:4:2} + local r16=$((16#$r)) + local g16=$((16#$g)) + local b16=$((16#$b)) + printf "rgba(%d,%d,%d,\1341)\n" "$r16" "$g16" "$b16" +} + +fx_brightness() { + local inCol="${1}" + local fxb=$(magick "${inCol}" -colorspace gray -format "%[fx:mean]" info:) + if awk -v fxb="${fxb}" 'BEGIN {exit !(fxb < 0.5)}' ; then + return 0 #// echo ":: ${fxb} :: dark :: ${inCol}" + else + return 1 #// echo ":: ${fxb} :: light :: ${inCol}" + fi +} + + +#// quantize raw primary colors + +magick -quiet -regard-warnings "${wallbashImg}"[0] -alpha off +repage "${wallbashRaw}" +readarray -t dcolRaw <<< $(magick "${wallbashRaw}" -depth 8 -fuzz ${wallbashFuzz}% +dither -kmeans ${wallbashColors} -depth 8 -format "%c" histogram:info: | sed -n 's/^[ ]*\(.*\):.*[#]\([0-9a-fA-F]*\) .*$/\1,\2/p' | sort -r -n -k 1 -t ",") + +if [ ${#dcolRaw[*]} -lt ${wallbashColors} ] ; then + echo -e "RETRYING :: distinct colors ${#dcolRaw[*]} is less than ${wallbashColors} palette color..." + readarray -t dcolRaw <<< $(magick "${wallbashRaw}" -depth 8 -fuzz ${wallbashFuzz}% +dither -kmeans $((wallbashColors + 2)) -depth 8 -format "%c" histogram:info: | sed -n 's/^[ ]*\(.*\):.*[#]\([0-9a-fA-F]*\) .*$/\1,\2/p' | sort -r -n -k 1 -t ",") +fi + + +#// sort colors based on image brightness + +if [ "${sortMode}" == "auto" ] ; then + if fx_brightness "${wallbashRaw}" ; then + sortMode="dark" + colSort="" + else + sortMode="light" + colSort="-r" + fi +fi + +echo "dcol_mode=\"${sortMode}\"" >> "${wallbashOut}" +dcolHex=($(echo -e "${dcolRaw[@]:0:$wallbashColors}" | tr ' ' '\n' | awk -F ',' '{print $2}' | sort ${colSort})) +greyCheck=$(magick "${wallbashRaw}" -colorspace HSL -channel g -separate +channel -format "%[fx:mean]" info:) + +if (( $(awk 'BEGIN {print ('"$greyCheck"' < 0.12)}') )); then + wallbashCurve="10 0\n17 0\n24 0\n39 0\n51 0\n58 0\n72 0\n84 0\n99 0" +fi + + +#// loop for derived colors + +for (( i=0; i<${wallbashColors}; i++ )) ; do + + + #// generate missing primary colors + + if [ -z "${dcolHex[i]}" ] ; then + + if fx_brightness "xc:#${dcolHex[i - 1]}" ; then + modBri=$pryDarkBri + modSat=$pryDarkSat + modHue=$pryDarkHue + else + modBri=$pryLightBri + modSat=$pryLightSat + modHue=$pryLightHue + fi + + echo -e "dcol_pry$((i + 1)) :: regen missing color" + dcol[i]=$(magick xc:"#${dcolHex[i - 1]}" -depth 8 -normalize -modulate ${modBri},${modSat},${modHue} -depth 8 -format "%c" histogram:info: | sed -n 's/^[ ]*\(.*\):.*[#]\([0-9a-fA-F]*\) .*$/\2/p') + + fi + + echo "dcol_pry$((i + 1))=\"${dcolHex[i]}\"" >> "${wallbashOut}" + echo "dcol_pry$((i + 1))_rgba=\"$( rgba_convert "${dcolHex[i]}" )\"" >> "${wallbashOut}" + + + #// generate primary text colors + + nTxt=$(rgb_negative ${dcolHex[i]}) + + if fx_brightness "xc:#${dcolHex[i]}" ; then + modBri=$txtDarkBri + else + modBri=$txtLightBri + fi + + tcol=$(magick xc:"#${nTxt}" -depth 8 -normalize -modulate ${modBri},10,100 -depth 8 -format "%c" histogram:info: | sed -n 's/^[ ]*\(.*\):.*[#]\([0-9a-fA-F]*\) .*$/\2/p') + echo "dcol_txt$((i + 1))=\"${tcol}\"" >> "${wallbashOut}" + echo "dcol_txt$((i + 1))_rgba=\"$( rgba_convert "${tcol}" )\"" >> "${wallbashOut}" + + + #// generate accent colors + + xHue=$(magick xc:"#${dcolHex[i]}" -colorspace HSB -format "%c" histogram:info: | awk -F '[hsb(,]' '{print $2}') + acnt=1 + + echo -e "${wallbashCurve}" | sort -n ${colSort} | while read -r xBri xSat + do + acol=$(magick xc:"hsb(${xHue},${xSat}%,${xBri}%)" -depth 8 -format "%c" histogram:info: | sed -n 's/^[ ]*\(.*\):.*[#]\([0-9a-fA-F]*\) .*$/\2/p') + echo "dcol_$((i + 1))xa${acnt}=\"${acol}\"" >> "${wallbashOut}" + echo "dcol_$((i + 1))xa${acnt}_rgba=\"$( rgba_convert "${acol}" )\"" >> "${wallbashOut}" + ((acnt++)) + done + +done + + +#// cleanup temp cache + +rm -f "${wallbashRaw}" "${wallbashCache}" + diff --git a/scripts/wallbashcava.sh b/scripts/wallbashcava.sh new file mode 100755 index 0000000..68d83b7 --- /dev/null +++ b/scripts/wallbashcava.sh @@ -0,0 +1,22 @@ +#!/usr/bin/env sh + +scrDir=`dirname "$(realpath "$0")"` +source $scrDir/globalcontrol.sh +cvaDir="${confDir}/cava" +CAVA_CONF="${cvaDir}/config" +WALL_DCOL="${cvaDir}/Wall-Dcol" +KEY_LINE='### HYPRDOTS CAVA: Autogenerated line below for wallbash###' + +if pkg_installed cava ; then + + sed -i "/${KEY_LINE}/,\$d" "${CAVA_CONF}" + if grep -q "${KEY_LINE}" "${CAVA_CONF}"; then + sed -i "/${KEY_LINE}/r ${WALL_DCOL}" "${CAVA_CONF}" + else + echo "${KEY_LINE}" >> "${CAVA_CONF}" + sed -i "/${KEY_LINE}/r ${WALL_DCOL}" "${CAVA_CONF}" + fi + + pkill -USR2 cava + +fi diff --git a/scripts/wallbashcode.sh b/scripts/wallbashcode.sh new file mode 100755 index 0000000..b24954d --- /dev/null +++ b/scripts/wallbashcode.sh @@ -0,0 +1,41 @@ +#!/usr/bin/env bash + +#// set variables +scrDir="$(dirname "$(realpath "$0")")" +source "${scrDir}/globalcontrol.sh" +readarray -t codeConf < <(find "${confDir}" -mindepth 1 -maxdepth 1 -type d -name "Code*" -o -name "VSCodium*" -o -name "Cursor*" | sort) +readarray -t codeVsix < <(find "$HOME" -mindepth 1 -maxdepth 1 -type d -name ".vscode*" -o -name ".cursor" | sort) +tmpFile="/tmp/$(id -u)$(basename ${0}).tmp" +tgtFile="extensions/undefined_publisher.wallbash-0.0.1/themes/wallbash-color-theme.json" + +#// install ext + +for i in "${!codeVsix[@]}" ;do + if [ ! -f "${codeVsix[i]}/${tgtFile}" ] ; then + [ -f "${cacheDir}/landing/Code_Wallbash.vsix" ] || curl -L -o "${cacheDir}/landing/Code_Wallbash.vsix" https://github.com/prasanthrangan/hyprdots/raw/main/Source/arcs/Code_Wallbash.vsix + case ${codeVsix[i]} in + *".cursor"*) + echo "[wallbashcode] Cursor IDE: Manual intervention required for extension installation." + echo "[wallbashcode] Read the instructions here: https://www.cursor.com/how-to-install-extension " + ;; + *) + pkg_installed code-insiders && code-insiders --install-extension "${cacheDir}/landing/Code_Wallbash.vsix" + pkg_installed code && code --install-extension "${cacheDir}/landing/Code_Wallbash.vsix" + pkg_installed vscodium && vscodium --install-extension "${cacheDir}/landing/Code_Wallbash.vsix" + ;; + esac + fi + [ -d "$(dirname "${codeVsix[i]}/${tgtFile}")" ] && cp "${cacheDir}/landing/wallbashcode.json" "${codeVsix[i]}/${tgtFile}" +done + +#// apply theme + +for i in "${!codeConf[@]}" ; do + [ -d "${codeConf[i]}/User" ] || continue + [ -f "${codeConf[i]}/User/settings.json" ] || echo -e "{\n \"workbench.colorTheme\":\"wallbash\" \n}" > "${codeConf[i]}/User/settings.json" + extTheme="$(jq -r '.["workbench.colorTheme"]' "${codeConf[i]}/User/settings.json")" + + if [ "${extTheme}" != "wallbash" ] ; then + jq '.["workbench.colorTheme"] = "wallbash"' "${codeConf[i]}/User/settings.json" > "${tmpFile}" && mv "${tmpFile}" "${codeConf[i]}/User/settings.json" + fi +done diff --git a/scripts/wallbashdiscord.sh b/scripts/wallbashdiscord.sh new file mode 100755 index 0000000..7dac5bf --- /dev/null +++ b/scripts/wallbashdiscord.sh @@ -0,0 +1,30 @@ +#!/usr/bin/env bash + + +#// source variables + +scrDir="$(dirname "$(realpath "$0")")" +source "${scrDir}/globalcontrol.sh" +discord_col="${cacheDir}/landing/discord.css" +declare -a client_list=() + + +#// List more clients + +client_list+=("$HOME/.config/Vencord/settings/quickCss.css") +client_list+=("$HOME/.config/vesktop/settings/quickCss.css") +client_list+=("$HOME/.var/app/dev.vencord.Vesktop/config/vesktop/settings/quickCss.css") +client_list+=("$HOME/.config/WebCord/Themes/theme.css") +client_list+=("$HOME/.var/app/io.github.spacingbat3.webcord/config/WebCord/Themes/theme.css") +client_list+=("$HOME/.var/app/xyz.armcord.ArmCord/config/ArmCord/themes/theme.css") + + +#// main loop + +for client_css in "${client_list[@]}" ; do + eval client_css="${client_css}" + if [[ -d $(dirname "${client_css}") ]] ; then + cp "${discord_col}" "${client_css}" + fi +done + diff --git a/scripts/wallbashdunst.sh b/scripts/wallbashdunst.sh new file mode 100755 index 0000000..70951e1 --- /dev/null +++ b/scripts/wallbashdunst.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env bash + +# set variables + +scrDir=`dirname "$(realpath "$0")"` +source $scrDir/globalcontrol.sh +dstDir="${confDir}/dunst" + +# regen conf + +export hypr_border +envsubst < "${dstDir}/dunst.conf" > "${dstDir}/dunstrc" +envsubst < "${dstDir}/wallbash.conf" >> "${dstDir}/dunstrc" +killall dunst +dunst & + diff --git a/scripts/wallbashqt.sh b/scripts/wallbashqt.sh new file mode 100755 index 0000000..cb75a39 --- /dev/null +++ b/scripts/wallbashqt.sh @@ -0,0 +1,23 @@ +#!/usr/bin/env bash + + +# set variables + +scrDir=`dirname "$(realpath "$0")"` +source $scrDir/globalcontrol.sh + + +# sync qt5 and qt6 colors + +cp "${confDir}/qt5ct/colors.conf" "${confDir}/qt6ct/colors.conf" + + +# restart dolphin + +a_ws=$(hyprctl -j activeworkspace | jq '.id') +dpid=$(hyprctl -j clients | jq --arg wid "$a_ws" '.[] | select(.workspace.id == ($wid | tonumber)) | select(.class == "org.kde.dolphin") | .pid') +if [ ! -z ${dpid} ] ; then + hyprctl dispatch closewindow pid:${dpid} + hyprctl dispatch exec dolphin & +fi + diff --git a/scripts/wallbashspotify.sh b/scripts/wallbashspotify.sh new file mode 100755 index 0000000..c81fe6d --- /dev/null +++ b/scripts/wallbashspotify.sh @@ -0,0 +1,42 @@ +#!/usr/bin/env sh + + +# set variables + +scrDir="$(dirname "$(realpath "$0")")" +source "${scrDir}/globalcontrol.sh" + + +# regen conf + +if pkg_installed spotify && pkg_installed spicetify-cli ; then + + if [ ! -w /opt/spotify ] || [ ! -w /opt/spotify/Apps ]; then + notify-send -a "Hyprdots" "Permission needed for Wallbash Spotify theme" + pkexec chmod a+wr /opt/spotify + pkexec chmod a+wr /opt/spotify/Apps -R + fi + + if [ "$(spicetify config | awk '{if ($1=="color_scheme") print $2}')" != "Wallbash" ] || [[ "${*}" == *"--reset"* ]] ; then + spicetify &> /dev/null + mkdir -p ~/.config/spotify + touch ~/.config/spotify/prefs + sptfyConf=$(spicetify -c) + spotfy_flags='--ozone-platform=wayland' + sed -i -e "/^prefs_path/ s+=.*$+= $HOME/.config/spotify/prefs+g" \ + -e "/^spotify_launch_flags/ s+=.*$+= $spotfy_flags+g" "$sptfyConf" + curl -L -o ${cacheDir}/landing/Spotify_Sleek.tar.gz https://github.com/prasanthrangan/hyprdots/raw/main/Source/arcs/Spotify_Sleek.tar.gz + tar -xzf ${cacheDir}/landing/Spotify_Sleek.tar.gz -C ~/.config/spicetify/Themes/ + spicetify backup apply + spicetify config current_theme Sleek + spicetify config color_scheme Wallbash + spicetify apply + fi + + if pgrep -x spotify > /dev/null ; then + pkill -x spicetify + spicetify -q watch -s & + fi + +fi + diff --git a/scripts/wallbashtoggle.sh b/scripts/wallbashtoggle.sh new file mode 100755 index 0000000..9d8877c --- /dev/null +++ b/scripts/wallbashtoggle.sh @@ -0,0 +1,61 @@ +#!/usr/bin/env sh + + +#// set variables + +scrDir="$(dirname "$(realpath "$0")")" +source "${scrDir}/globalcontrol.sh" +TgtScr="$scrDir/globalcontrol.sh" +rofiConf="${confDir}/rofi/wallbash.rasi" +wallbashModes=("theme" "auto" "dark" "light") + + +#// rofi select mode + +rofi_wallbash() +{ + [[ "${rofiScale}" =~ ^[0-9]+$ ]] || rofiScale=10 + r_scale="configuration {font: \"JetBrainsMono Nerd Font ${rofiScale}\";}" + elem_border=$(( hypr_border * 4 )) + r_override="window{border-radius:${elem_border}px;} element{border-radius:${elem_border}px;}" + rofiSel=$(parallel echo {} ::: "${wallbashModes[@]}" | rofi -dmenu -theme-str "${r_scale}" -theme-str "${r_override}" -config "${rofiConf}" -select "${wallbashModes[${enableWallDcol}]}") + if [ ! -z "${rofiSel}" ] ; then + setMode="$(parallel --link echo {} ::: "${!wallbashModes[@]}" ::: "${wallbashModes[@]}" ::: "${rofiSel}" | awk '{if ($2 == $3) print $1}')" + else + exit 0 + fi +} + + +#// switch mode + +step_wallbash() +{ + for i in "${!wallbashModes[@]}" ; do + if [ "${enableWallDcol}" == "${i}" ] ; then + if [ "${1}" == "n" ] ; then + setMode=$(( (i + 1) % ${#wallbashModes[@]} )) + elif [ "${1}" == "p" ] ; then + setMode=$(( i - 1 )) + fi + break + fi + done +} + + +#// apply wallbash mode + +case "${1}" in + m|-m|--menu) rofi_wallbash ;; + n|-n|--next) step_wallbash n ;; + p|-p|--prev) step_wallbash p ;; + *) step_wallbash n ;; +esac + +export reload_flag=1 +[[ "${setMode}" -lt 0 ]] && setMode=$((${#wallbashModes[@]} - 1)) +set_conf "enableWallDcol" "${setMode}" +"${scrDir}/themeswitch.sh" +notify-send -a "t1" -i "$HOME/.config/dunst/icons/hyprdots.png" " ${wallbashModes[setMode]} mode" + diff --git a/scripts/waybar-cava.sh b/scripts/waybar-cava.sh new file mode 100644 index 0000000..7a5fe77 --- /dev/null +++ b/scripts/waybar-cava.sh @@ -0,0 +1,41 @@ +#!/usr/bin/env bash +set -euo pipefail + +bar="▁ ▂ ▃ ▄ ▅ ▆ ▇ █" +dict="s/;//g" +for ((i=0; i<${#bar}; i++)); do + dict+=";s/$i/${bar:$i:1}/g" +done + +RUNTIME_DIR="${XDG_RUNTIME_DIR:-/tmp}" +pidfile="$RUNTIME_DIR/waybar-cava.pid" +if [ -f "$pidfile" ]; then + oldpid=$(cat "$pidfile" || true) + if [ -n "$oldpid" ] && kill -0 "$oldpid" 2>/dev/null; then + kill "$oldpid" 2>/dev/null || true + sleep 0.1 + fi +fi +echo $$ > "$pidfile" + +config_file=$(mktemp "$RUNTIME_DIR/waybar-cava.XXXXXX.conf") +cleanup() { rm -f "$config_file" "$pidfile"; } +trap cleanup EXIT INT TERM + +cat >"$config_file" </dev/null; then + pkill -f waybar +else + waybar & +fi + diff --git a/scripts/waybar_cava.sh b/scripts/waybar_cava.sh new file mode 100755 index 0000000..e6e373f --- /dev/null +++ b/scripts/waybar_cava.sh @@ -0,0 +1,130 @@ +#!/usr/bin/env bash +#----- Optimized bars animation without much CPU usage increase -------- +#----- Optimized bars animation without much CPU usage increase pt2 -------- + +# Default values +scrDir="$(dirname "$(realpath "$0")")" +# shellcheck disable=SC1091 +source "${scrDir}/globalcontrol.sh" + +usage() { + cat < Specify the characters to use for the bar animation (default: ▁▂▃▄▅▆▇█). + --width Specify the width of the bar. + --range Specify the range of the bar. + --help Display this help message and exit. + --restart Restart the waybar_cava. + --stb Specify the standby mode for waybar cava (default: 0). + 0: clean - totally hides the module + 1: blank - makes module expand as spaces + 2: full - occupies the module with full bar + 3: low - makes the module display the lowest set bar + *: string - displays a string +HELP + exit 1 +} + +# Parse command line arguments using getopt +if ! ARGS=$(getopt -o "hr" -l "help,bar:,width:,range:,restart,stb:" -n "$0" -- "$@"); then + usage +fi + +eval set -- "$ARGS" +while true; do + case "$1" in + --help | -h) + usage + ;; + --bar) + waybar_cava_bar="$2" + shift 2 + ;; + --width) + waybar_cava_width="$2" + shift 2 + ;; + --range) + waybar_cava_range="$2" + shift 2 + ;; + --restart) # restart by killing all waybar_cava + pkill -f "cava -p /tmp/bar_cava_config" + exit 0 + ;; + --stb) + waybar_cava_stbmode="$2" + shift 2 + ;; + --) + shift + break + ;; + *) + usage + ;; + esac +done + +bar="${waybar_cava_bar:-▁▂▃▄▅▆▇█}" + +# // waybar_cava_stbmode - standby mode for waybar cava - default 0 +# 0: clean - totally hides the module +# 1: blank - makes module expand as spaces +# 2: full - occupies the module with full bar +# 3: low - makes the module display the lowest set bar +# : - displays a string +case ${waybar_cava_stbmode:-} in +0) + stbBar='' + ;; # Clean +1) + stbBar="‎ " + ;; # Invisible char +2) + stbBar="${bar: -1}" + ;; # Full bar +3) + stbBar="${bar:0:1}" + ;; # Lowest bar +*) + asciiBar="${waybar_cava_stbmode:-${bar}}" + ;; +esac + +# Calculate the length of the bar outside the loop +bar_length=${#bar} +bar_width=${waybar_cava_width:-${bar_length}} +bar_range=${waybar_cava_range:-$((bar_length - 1))} +# Create dictionary to replace char with bar +dict="s/;//g" +stbAscii=$(printf '0%.0s' $(seq 1 "${bar_width}")) # predicts the amount of ancii characters to be used +[ -n "${asciiBar}" ] || asciiBar="${stbAscii//0/${stbBar}}" + +dict="$dict;s/${stbAscii}/${asciiBar}/g" +i=0 +while [ $i -lt "${bar_length}" ] || [ $i -lt "${bar_width}" ]; do + if [ $i -lt "${bar_length}" ]; then + dict="$dict;s/$i/${bar:$i:1}/g" + fi + ((i++)) +done + +# Create cava config +config_file="/tmp/bar_cava_config" +cat >"$config_file" < $waybar_dir/tmp && mv $waybar_dir/tmp $conf_ctl +fi + + +# overwrite config from header module + +export set_sysname=`hostnamectl hostname` +export w_position=`grep '^1|' $conf_ctl | cut -d '|' -f 3` + +# setting explicit waybar output + +if [ ${#waybar_output[@]} -gt 0 ]; then +w_output=$(printf '"%s", ' "${waybar_output[@]}") +w_output=${w_output%, } # Remove the trailing comma and space +echo "[outputs] $w_output" +fi +export w_output="${w_output:-\"*\"}" + +# setting waybar position + +case ${w_position} in + left) export hv_pos="width" ; export r_deg=90 ;; + right) export hv_pos="width" ; export r_deg=270 ;; + *) export hv_pos="height" ; export r_deg=0 ;; +esac + +export w_height=`grep '^1|' $conf_ctl | cut -d '|' -f 2` +if [ -z $w_height ] ; then + y_monres=`cat /sys/class/drm/*/modes | head -1 | cut -d 'x' -f 2` + export w_height=$(( y_monres*2/100 )) +fi + +export i_size=$(( w_height*6/10 )) +if [ $i_size -lt 12 ] ; then + export i_size="12" +fi + +export i_theme="$( +{ grep -q "^[[:space:]]*\$ICON[-_]THEME\s*=" "${hydeThemeDir}/hypr.theme" && grep "^[[:space:]]*\$ICON[-_]THEME\s*=" "${hydeThemeDir}/hypr.theme" | cut -d '=' -f2 | sed 's/^[[:space:]]*//;s/[[:space:]]*$//' ;} || +grep 'gsettings set org.gnome.desktop.interface icon-theme' "${hydeThemeDir}/hypr.theme" | awk -F "'" '{print $((NF - 1))}' +)" +export i_task=$(( w_height*6/10 )) +if [ $i_task -lt 16 ] ; then + export i_task="16" +fi +export i_priv=$(( w_height*6/13 )) +if [ $i_priv -lt 12 ] ; then + export i_priv="12" +fi + +envsubst < $modules_dir/header.jsonc > $conf_file + + +# module generator function + +gen_mod() +{ + local pos=$1 + local col=$2 + local mod="" + + mod=`grep '^1|' $conf_ctl | cut -d '|' -f ${col}` + mod="${mod//(/"custom/l_end"}" + mod="${mod//)/"custom/r_end"}" + mod="${mod//[/"custom/sl_end"}" + mod="${mod//]/"custom/sr_end"}" + mod="${mod//\{/"custom/rl_end"}" + mod="${mod//\}/"custom/rr_end"}" + mod="${mod// /"\",\""}" + + echo -e "\t\"modules-${pos}\": [\"custom/padd\",\"${mod}\",\"custom/padd\"]," >> $conf_file + write_mod=`echo $write_mod $mod` +} + + +# write positions for modules + +echo -e "\n\n// positions generated based on config.ctl //\n" >> $conf_file +gen_mod left 4 +gen_mod center 5 +gen_mod right 6 + + +# copy modules/*.jsonc to the config + +echo -e "\n\n// sourced from modules based on config.ctl //\n" >> $conf_file +echo "$write_mod" | sed 's/","/\n/g ; s/ /\n/g' | awk -F '/' '{print $NF}' | awk -F '#' '{print}' | awk '!x[$0]++' | while read mod_cpy +do + if [ -f $modules_dir/$mod_cpy.jsonc ] ; then + envsubst < $modules_dir/$mod_cpy.jsonc >> $conf_file + fi +done + +cat $modules_dir/footer.jsonc >> $conf_file + + +# generate style + +$scrDir/wbarstylegen.sh + + +# restart waybar + +if [ "$reload_flag" == "1" ] ; then + killall waybar + waybar --config ${waybar_dir}/config.jsonc --style ${waybar_dir}/style.css > /dev/null 2>&1 & +fi diff --git a/scripts/wbarstylegen.sh b/scripts/wbarstylegen.sh new file mode 100755 index 0000000..84f84e3 --- /dev/null +++ b/scripts/wbarstylegen.sh @@ -0,0 +1,118 @@ +#!/usr/bin/env bash + + +# detect hypr theme and initialize variables + +scrDir=`dirname "$(realpath "$0")"` +source $scrDir/globalcontrol.sh +waybar_dir="${confDir}/waybar" +modules_dir="$waybar_dir/modules" +conf_ctl="$waybar_dir/config.ctl" +in_file="$waybar_dir/modules/style.css" +out_file="$waybar_dir/style.css" +src_file="${confDir}/hypr/themes/theme.conf" + + +# calculate height from control file or monitor res + +b_height=`grep '^1|' $conf_ctl | cut -d '|' -f 2` + +if [ -z $b_height ] || [ "$b_height" == "0" ]; then + y_monres=`cat /sys/class/drm/*/modes | head -1 | cut -d 'x' -f 2` + b_height=$(( y_monres*3/100 )) +fi + + +# calculate values based on height + +export b_radius=$(( b_height*70/100 )) # block rad 70% of height (type1) +export c_radius=$(( b_height*25/100 )) # block rad 25% of height {type2} +export t_radius=$(( b_height*25/100 )) # tooltip rad 25% of height +export e_margin=$(( b_height*30/100 )) # block margin 30% of height +export e_paddin=$(( b_height*10/100 )) # block padding 10% of height +export g_margin=$(( b_height*14/100 )) # module margin 14% of height +export g_paddin=$(( b_height*15/100 )) # module padding 15% of height +export w_radius=$(( b_height*30/100 )) # workspace rad 30% of height +export w_margin=$(( b_height*10/100 )) # workspace margin 10% of height +export w_paddin=$(( b_height*10/100 )) # workspace padding 10% of height +export w_padact=$(( b_height*40/100 )) # workspace active padding 40% of height +export s_fontpx=$(( b_height*34/100 )) # font size 34% of height + +if [ $b_height -lt 30 ] ; then + export e_paddin=0 +fi +if [ $s_fontpx -lt 10 ] ; then + export s_fontpx=10 +fi + + +# adjust values for vert/horz + +export w_position=`grep '^1|' $conf_ctl | cut -d '|' -f 3` +case ${w_position} in + top|bottom) + export x1g_margin=${g_margin} + export x2g_margin=0 + export x3g_margin=${g_margin} + export x4g_margin=0 + export x1rb_radius=0 + export x2rb_radius=${b_radius} + export x3rb_radius=${b_radius} + export x4rb_radius=0 + export x1lb_radius=${b_radius} + export x2lb_radius=0 + export x3lb_radius=0 + export x4lb_radius=${b_radius} + export x1rc_radius=0 + export x2rc_radius=${c_radius} + export x3rc_radius=${c_radius} + export x4rc_radius=0 + export x1lc_radius=${c_radius} + export x2lc_radius=0 + export x3lc_radius=0 + export x4lc_radius=${c_radius} + export x1="top" + export x2="bottom" + export x3="left" + export x4="right" ;; + left|right) + export x1g_margin=0 + export x2g_margin=${g_margin} + export x3g_margin=0 + export x4g_margin=${g_margin} + export x1rb_radius=0 + export x2rb_radius=0 + export x3rb_radius=${b_radius} + export x4rb_radius=${b_radius} + export x1lb_radius=${b_radius} + export x2lb_radius=${b_radius} + export x3lb_radius=0 + export x4lb_radius=0 + export x1rc_radius=0 + export x2rc_radius=${c_radius} + export x3rc_radius=${c_radius} + export x4rc_radius=0 + export x1lc_radius=${c_radius} + export x2lc_radius=0 + export x3lc_radius=0 + export x4lc_radius=${c_radius} + export x1="left" + export x2="right" + export x3="top" + export x4="bottom" ;; +esac + + +# list modules and generate theme style + +export modules_ls=$(grep -m 1 '".*.": {' --exclude="$modules_dir/footer.jsonc" $modules_dir/*.jsonc | cut -d '"' -f 2 | awk -F '/' '{ if($1=="custom") print "#custom-"$NF"," ; else print "#"$NF","}') +envsubst < $in_file > $out_file + + +# override rounded couners + +hypr_border=`awk -F '=' '{if($1~" rounding ") print $2}' $src_file | sed 's/ //g'` +if [ "$hypr_border" == "0" ] ; then + sed -i "/border-radius: /c\ border-radius: 0px;" $out_file +fi + diff --git a/scripts/windowpin.sh b/scripts/windowpin.sh new file mode 100755 index 0000000..fa4caed --- /dev/null +++ b/scripts/windowpin.sh @@ -0,0 +1,21 @@ +#!/usr/bin/env bash + +# enable float +WinFloat=$(hyprctl -j clients | jq '.[] | select(.focusHistoryID == 0) | .floating') +WinPinned=$(hyprctl -j clients | jq '.[] | select(.focusHistoryID == 0) | .pinned') + +if [ "${WinFloat}" == "false" ] && [ "${WinPinned}" == "false" ] ; then + hyprctl dispatch togglefloating active +fi + +# toggle pin +hyprctl dispatch pin active + +# disable float +WinFloat=$(hyprctl -j clients | jq '.[] | select(.focusHistoryID == 0) | .floating') +WinPinned=$(hyprctl -j clients | jq '.[] | select(.focusHistoryID == 0) | .pinned') + +if [ "${WinFloat}" == "true" ] && [ "${WinPinned}" == "false" ] ; then + hyprctl dispatch togglefloating active +fi + diff --git a/wallpapers/FB_IMG_1696458682639.jpg b/wallpapers/FB_IMG_1696458682639.jpg new file mode 100644 index 0000000..e9076c0 Binary files /dev/null and b/wallpapers/FB_IMG_1696458682639.jpg differ diff --git a/wallpapers/wallhaven-1p55dw_1920x1080.png b/wallpapers/wallhaven-1p55dw_1920x1080.png new file mode 100644 index 0000000..ddd8158 Binary files /dev/null and b/wallpapers/wallhaven-1p55dw_1920x1080.png differ diff --git a/wallpapers/wallhaven-43ypj3_1920x1080.png b/wallpapers/wallhaven-43ypj3_1920x1080.png new file mode 100644 index 0000000..dfec1e3 Binary files /dev/null and b/wallpapers/wallhaven-43ypj3_1920x1080.png differ diff --git a/wallpapers/wallhaven-4vygll_1920x1080.png b/wallpapers/wallhaven-4vygll_1920x1080.png new file mode 100644 index 0000000..7871efc Binary files /dev/null and b/wallpapers/wallhaven-4vygll_1920x1080.png differ diff --git a/wallpapers/wallhaven-k81776_1920x1080.png b/wallpapers/wallhaven-k81776_1920x1080.png new file mode 100644 index 0000000..71b9884 Binary files /dev/null and b/wallpapers/wallhaven-k81776_1920x1080.png differ diff --git a/wallpapers/wallhaven-kxmz11_1920x1080.png b/wallpapers/wallhaven-kxmz11_1920x1080.png new file mode 100644 index 0000000..13aa685 Binary files /dev/null and b/wallpapers/wallhaven-kxmz11_1920x1080.png differ diff --git a/wallpapers/wallhaven-nel618_2560x1440.png b/wallpapers/wallhaven-nel618_2560x1440.png new file mode 100644 index 0000000..6be7fcd Binary files /dev/null and b/wallpapers/wallhaven-nel618_2560x1440.png differ diff --git a/wallpapers/wallhaven-o5ky29_2560x1440.png b/wallpapers/wallhaven-o5ky29_2560x1440.png new file mode 100644 index 0000000..13193ca Binary files /dev/null and b/wallpapers/wallhaven-o5ky29_2560x1440.png differ diff --git a/wallpapers/wallhaven-p9pd23_1920x1080.png b/wallpapers/wallhaven-p9pd23_1920x1080.png new file mode 100644 index 0000000..d0145f8 Binary files /dev/null and b/wallpapers/wallhaven-p9pd23_1920x1080.png differ diff --git a/wallpapers/wallhaven-p9q6ym_1920x1080.png b/wallpapers/wallhaven-p9q6ym_1920x1080.png new file mode 100644 index 0000000..68182aa Binary files /dev/null and b/wallpapers/wallhaven-p9q6ym_1920x1080.png differ diff --git a/wallpapers/wallhaven-qzyyxd_1920x1080.png b/wallpapers/wallhaven-qzyyxd_1920x1080.png new file mode 100644 index 0000000..35e3b6a Binary files /dev/null and b/wallpapers/wallhaven-qzyyxd_1920x1080.png differ diff --git a/wallpapers/wallhaven-x6x3gz_1920x1080.png b/wallpapers/wallhaven-x6x3gz_1920x1080.png new file mode 100644 index 0000000..e7e2d0e Binary files /dev/null and b/wallpapers/wallhaven-x6x3gz_1920x1080.png differ diff --git a/wallpapers/wallhaven-ym2q9k_1920x1080.png b/wallpapers/wallhaven-ym2q9k_1920x1080.png new file mode 100644 index 0000000..3713e15 Binary files /dev/null and b/wallpapers/wallhaven-ym2q9k_1920x1080.png differ diff --git a/wallpapers/wallhaven-zpx3xw_1920x1080.png b/wallpapers/wallhaven-zpx3xw_1920x1080.png new file mode 100644 index 0000000..0680ff1 Binary files /dev/null and b/wallpapers/wallhaven-zpx3xw_1920x1080.png differ