From 0cd329e8b9bb1a5c48386f30c7a77405789b6d04 Mon Sep 17 00:00:00 2001 From: nnduc Date: Tue, 17 Feb 2026 01:50:51 +0700 Subject: [PATCH 01/23] lua nvim --- nvim/.vimrc | 143 -------------------------- nvim/coc-settings.json | 2 - nvim/init.lua | 214 ++++++++++++++++++++++++++++++++++++++ nvim/init.vim | 132 ------------------------ nvim/init.vim(server) | 127 ----------------------- nvim/latexmk.vim | 227 ----------------------------------------- nvim/site/vi.utf-8.spl | Bin 20334 -> 0 bytes 7 files changed, 214 insertions(+), 631 deletions(-) delete mode 100644 nvim/.vimrc delete mode 100644 nvim/coc-settings.json create mode 100644 nvim/init.lua delete mode 100644 nvim/init.vim delete mode 100644 nvim/init.vim(server) delete mode 100644 nvim/latexmk.vim delete mode 100644 nvim/site/vi.utf-8.spl diff --git a/nvim/.vimrc b/nvim/.vimrc deleted file mode 100644 index 62860f8..0000000 --- a/nvim/.vimrc +++ /dev/null @@ -1,143 +0,0 @@ -syntax on -set number -set cursorline -set expandtab tabstop=4 shiftwidth=4 softtabstop=4 -set autoindent -set spelllang=vi,en - - -" Fold -set foldmethod=syntax -set foldlevel=1 -set foldnestmax=1 -set encoding=utf8 - -" Search -set hlsearch -nnoremap i :nohlsi - -" Plugin -call plug#begin() -Plug 'neoclide/coc.nvim', {'branch': 'release'} -Plug 'dense-analysis/ale' -Plug 'preservim/nerdtree' -Plug 'preservim/nerdcommenter' -Plug 'lervag/vimtex' -Plug 'JuliaEditorSupport/julia-vim' -Plug 'junegunn/fzf', { 'do': { -> fzf#install() } } -Plug 'junegunn/fzf.vim' -Plug 'honza/vim-snippets' -Plug 'vim-airline/vim-airline' -Plug 'vim-airline/vim-airline-themes' -Plug 'kevinhwang91/nvim-bqf' -Plug 'morhetz/gruvbox' -Plug 'tpope/vim-fugitive' -Plug 'ynkdir/vim-diff' -Plug '4ree/vim-ime' -call plug#end() - -"Color scheme -"colorscheme iceberg -"set background=light -colorscheme gruvbox -let g:gruvbox_contrast_light = 'hard' -hi clear SpellBad -hi SpellBad cterm=underline ctermfg=red - - -"Open NERDTree -:nnoremap g:NERDTree.IsOpen() ? "\:NERDTreeClose" : bufexists(expand('%')) ? "\:NERDTreeFind" : "\:NERDTree" - -"Coc.nvim -inoremap - \ coc#pum#visible() ? coc#_select_confirm() : - \ coc#expandableOrJumpable() ? "\=coc#rpc#request('doKeymap', ['snippets-expand-jump',''])\" : - \ CheckBackSpace() ? "\" : - \ coc#refresh() -inoremap pumvisible() ? coc#_select_confirm() - \: "\u\\=coc#on_enter()\" - -function! CheckBackSpace() abort - let col = col('.') - 1 - return !col || getline('.')[col - 1] =~# '\s' -endfunction - -let g:coc_snippet_next = '' -inoremap coc#pum#visible() ? coc#pum#confirm() - \: "\u\\=coc#on_enter()\" - -" Comments -let mapleader = "," - -" remap save -nnoremap :w - -" moving between windows -nnoremap h -nnoremap j -nnoremap k -nnoremap l -nnoremap h -nnoremap j -nnoremap k -nnoremap l -nnoremap to :tabonly -nnoremap o :only -nnoremap :tabn -nnoremap :tabp - -"set clipboard+=unnamedplus -" " Copy to clipboard -vnoremap y "+y -nnoremap Y "+yg_ -nnoremap y "+y -nnoremap yy "+yy - -" " Paste from clipboard -nnoremap p "+p -nnoremap P "+P - - -" FZF key mapping -nnoremap b :Buffers -nnoremap r :Rg -nnoremap f :Files -nnoremap g :GFiles -nnoremap w :Rg - -filetype plugin on -set splitright -set splitbelow - -let g:vimtex_view_method= 'zathura' - -"Language tool -map :ALEToggle - - -"Use 24-bit (true-color) mode in Vim/Neovim when outside tmux. -"If you're using tmux version 2.2 or later, you can remove the outermost $TMUX check and use tmux's 24-bit color support -"(see < http://sunaku.github.io/tmux-24bit-color.html#usage > for more information.) -if (empty($TMUX)) - if (has("nvim")) - "For Neovim 0.1.3 and 0.1.4 < https://github.com/neovim/neovim/pull/2198 > - let $NVIM_TUI_ENABLE_TRUE_COLOR=1 - endif - "For Neovim > 0.1.5 and Vim > patch 7.4.1799 < https://github.com/vim/vim/commit/61be73bb0f965a895bfb064ea3e55476ac175162 > - "Based on Vim patch 7.4.1770 (`guicolors` option) < https://github.com/vim/vim/commit/8a633e3427b47286869aa4b96f2bfc1fe65b25cd > - " < https://github.com/neovim/neovim/wiki/Following-HEAD#20160511 > - if (has("termguicolors")) - set termguicolors - endif -endif - -if &term =~ 'xterm' || &term == 'win32' - " Use DECSCUSR escape sequences - let &t_SI = "\e[5 q" " blink bar - let &t_SR = "\e[3 q" " blink underline - let &t_EI = "\e[1 q" " blink block - let &t_ti ..= "\e[1 q" " blink block - let &t_te ..= "\e[0 q" " default (depends on terminal, normally blink - " block) -endif - diff --git a/nvim/coc-settings.json b/nvim/coc-settings.json deleted file mode 100644 index 3ba2825..0000000 --- a/nvim/coc-settings.json +++ /dev/null @@ -1,2 +0,0 @@ -{"coc.preferences.diagnostic.displayByAle":1 -} diff --git a/nvim/init.lua b/nvim/init.lua new file mode 100644 index 0000000..c1c3463 --- /dev/null +++ b/nvim/init.lua @@ -0,0 +1,214 @@ +-- Leader key (must be set before lazy.nvim loads) +vim.g.mapleader = "," + +-------------------- Options -------------------- +vim.opt.number = true +vim.opt.cursorline = true +vim.opt.expandtab = true +vim.opt.tabstop = 4 +vim.opt.shiftwidth = 4 +vim.opt.softtabstop = 4 +vim.opt.autoindent = true +vim.opt.spelllang = "vi,en" +vim.opt.foldmethod = "syntax" +vim.opt.foldlevel = 1 +vim.opt.foldnestmax = 1 +vim.opt.hlsearch = true +vim.opt.splitright = true +vim.opt.splitbelow = true +vim.opt.termguicolors = true + +-------------------- Keymaps -------------------- +-- Clear hlsearch then enter insert mode +vim.keymap.set("n", "i", ":nohlsi", { silent = true }) + +-- Save with space +vim.keymap.set("n", "", ":w", { silent = true }) + +-- Window navigation +vim.keymap.set("n", "", "h") +vim.keymap.set("n", "", "j") +vim.keymap.set("n", "", "k") +vim.keymap.set("n", "", "l") +vim.keymap.set("n", "", "h") +vim.keymap.set("n", "", "j") +vim.keymap.set("n", "", "k") +vim.keymap.set("n", "", "l") + +-- Tab management +vim.keymap.set("n", "to", ":tabonly", { silent = true }) +vim.keymap.set("n", "o", ":only", { silent = true }) +vim.keymap.set("n", "", ":tabn", { silent = true }) +vim.keymap.set("n", "", ":tabp", { silent = true }) + +-- Clipboard operations +vim.keymap.set("v", "y", '"+y') +vim.keymap.set("n", "Y", '"+yg_') +vim.keymap.set("n", "y", '"+y') +vim.keymap.set("n", "yy", '"+yy') +vim.keymap.set("n", "p", '"+p') +vim.keymap.set("n", "P", '"+P') + +-------------------- Bootstrap lazy.nvim -------------------- +local lazypath = vim.fn.stdpath("data") .. "/lazy/lazy.nvim" +if not vim.uv.fs_stat(lazypath) then + vim.fn.system({ + "git", "clone", "--filter=blob:none", + "https://github.com/folke/lazy.nvim.git", + "--branch=stable", + lazypath, + }) +end +vim.opt.rtp:prepend(lazypath) + +-------------------- Plugins -------------------- +require("lazy").setup({ + + -- Colorscheme + { + "ellisonleao/gruvbox.nvim", + priority = 1000, + config = function() + require("gruvbox").setup({ + contrast = "hard", + }) + vim.cmd.colorscheme("gruvbox") + end, + }, + + -- Icons (dependency for nvim-tree and lualine) + { "nvim-tree/nvim-web-devicons", lazy = true }, + + -- File tree + { + "nvim-tree/nvim-tree.lua", + dependencies = { "nvim-tree/nvim-web-devicons" }, + keys = { + { "", "NvimTreeToggle", desc = "Toggle file tree" }, + }, + config = function() + require("nvim-tree").setup() + end, + }, + + -- Comments + { + "numToStr/Comment.nvim", + event = "VeryLazy", + config = function() + require("Comment").setup() + end, + }, + + -- Fuzzy finder (telescope replaces fzf) + { + "nvim-telescope/telescope.nvim", + dependencies = { + "nvim-lua/plenary.nvim", + { "nvim-telescope/telescope-fzf-native.nvim", build = "make" }, + }, + keys = { + { "b", "Telescope buffers", desc = "Buffers" }, + { "r", "Telescope live_grep", desc = "Live grep" }, + { "f", "Telescope find_files", desc = "Find files" }, + { "g", "Telescope git_files", desc = "Git files" }, + { "w", "Telescope grep_string", desc = "Grep word under cursor" }, + }, + config = function() + require("telescope").setup() + require("telescope").load_extension("fzf") + end, + }, + + -- Statusline + { + "nvim-lualine/lualine.nvim", + dependencies = { "nvim-tree/nvim-web-devicons" }, + config = function() + require("lualine").setup({ + options = { theme = "gruvbox" }, + }) + end, + }, + + -- Autopairs + { + "windwp/nvim-autopairs", + event = "InsertEnter", + opts = {}, + }, + + -- Surround + { "4ree/viml-surround", event = "VeryLazy" }, + + -- LSP + { + "neovim/nvim-lspconfig", + config = function() + vim.lsp.config("clangd", {}) + vim.lsp.config("pyright", {}) + vim.lsp.config("rust_analyzer", {}) + vim.lsp.config("julials", {}) + vim.lsp.enable({ "clangd", "pyright", "rust_analyzer", "julials" }) + + vim.api.nvim_create_autocmd("LspAttach", { + callback = function(args) + local opts = { buffer = args.buf } + vim.keymap.set("n", "gd", vim.lsp.buf.definition, opts) + vim.keymap.set("n", "gr", vim.lsp.buf.references, opts) + vim.keymap.set("n", "K", vim.lsp.buf.hover, opts) + vim.keymap.set("n", "rn", vim.lsp.buf.rename, opts) + vim.keymap.set("n", "ca", vim.lsp.buf.code_action, opts) + end, + }) + end, + }, + + -- Completion (coq_nvim) + { + "ms-jpq/coq_nvim", + branch = "coq", + dependencies = { + { "ms-jpq/coq.artifacts", branch = "artifacts" }, + { "ms-jpq/coq.thirdparty", branch = "3p" }, + }, + init = function() + vim.g.coq_settings = { auto_start = "shut-up" } + end, + }, + + -- Quickfix enhancements + { "kevinhwang91/nvim-bqf", ft = "qf" }, + + -- Git + { "tpope/vim-fugitive" }, + + -- IME support + { + "4ree/vim-ime", + event = "VeryLazy", + opts = {}, + }, + + -- LaTeX + { + "lervag/vimtex", + config = function() + vim.g.vimtex_view_method = "zathura" + vim.g.vimtex_compiler_latexmk = { + options = { + "-verbose", + "-file-line-error", + "-synctex=1", + "-interaction=nonstopmode", + "-shell-escape", + "-output-directory=./output", + "-aux-directory=./", + }, + } + end, + }, + + -- Julia + { "JuliaEditorSupport/julia-vim" }, +}) diff --git a/nvim/init.vim b/nvim/init.vim deleted file mode 100644 index d0b0480..0000000 --- a/nvim/init.vim +++ /dev/null @@ -1,132 +0,0 @@ -syntax on -set number -set cursorline -set expandtab tabstop=4 shiftwidth=4 softtabstop=4 -set autoindent -set spelllang=vi,en - - -" Fold -set foldmethod=syntax -set foldlevel=1 -set foldnestmax=1 -set encoding=utf8 - -" Search -set hlsearch -nnoremap i :nohlsi - -" Plugin -call plug#begin() -Plug 'neoclide/coc.nvim', {'branch': 'release'} -Plug 'dense-analysis/ale' -Plug 'preservim/nerdtree' -Plug 'preservim/nerdcommenter' -Plug 'lervag/vimtex' -Plug 'JuliaEditorSupport/julia-vim' -Plug 'junegunn/fzf', { 'do': { -> fzf#install() } } -Plug 'junegunn/fzf.vim' -Plug 'honza/vim-snippets' -Plug 'vim-airline/vim-airline' -Plug 'vim-airline/vim-airline-themes' -Plug 'kevinhwang91/nvim-bqf' -Plug 'morhetz/gruvbox' -Plug 'tpope/vim-fugitive' -Plug 'ynkdir/vim-diff' -Plug '4ree/vim-ime' -call plug#end() - -"Color scheme -"colorscheme iceberg -"set background=light -colorscheme gruvbox -let g:gruvbox_contrast_light = 'hard' - - - -"Open NERDTree - map :NERDTreeToggle - - -"Coc.nvim -inoremap - \ coc#pum#visible() ? coc#_select_confirm() : - \ coc#expandableOrJumpable() ? "\=coc#rpc#request('doKeymap', ['snippets-expand-jump',''])\" : - \ CheckBackSpace() ? "\" : - \ coc#refresh() -inoremap pumvisible() ? coc#_select_confirm() - \: "\u\\=coc#on_enter()\" - -function! CheckBackSpace() abort - let col = col('.') - 1 - return !col || getline('.')[col - 1] =~# '\s' -endfunction - -let g:coc_snippet_next = '' -inoremap coc#pum#visible() ? coc#pum#confirm() - \: "\u\\=coc#on_enter()\" - -" Comments -let mapleader = "," - -" remap save -nnoremap :w - -" moving between windows -nnoremap h -nnoremap j -nnoremap k -nnoremap l -nnoremap h -nnoremap j -nnoremap k -nnoremap l -nnoremap to :tabonly -nnoremap o :only -nnoremap :tabn -nnoremap :tabp - -"set clipboard+=unnamedplus -" " Copy to clipboard -vnoremap y "+y -nnoremap Y "+yg_ -nnoremap y "+y -nnoremap yy "+yy - -" " Paste from clipboard -nnoremap p "+p -nnoremap P "+P - - -" FZF key mapping -nnoremap b :Buffers -nnoremap r :Rg -nnoremap f :Files -nnoremap g :GFiles -nnoremap w :Rg - -filetype plugin on -set splitright -set splitbelow - -let g:vimtex_view_method= 'zathura' - -"Language tool -map :ALEToggle - - -"Use 24-bit (true-color) mode in Vim/Neovim when outside tmux. -"If you're using tmux version 2.2 or later, you can remove the outermost $TMUX check and use tmux's 24-bit color support -"(see < http://sunaku.github.io/tmux-24bit-color.html#usage > for more information.) -if (empty($TMUX)) - if (has("nvim")) - "For Neovim 0.1.3 and 0.1.4 < https://github.com/neovim/neovim/pull/2198 > - let $NVIM_TUI_ENABLE_TRUE_COLOR=1 - endif - "For Neovim > 0.1.5 and Vim > patch 7.4.1799 < https://github.com/vim/vim/commit/61be73bb0f965a895bfb064ea3e55476ac175162 > - "Based on Vim patch 7.4.1770 (`guicolors` option) < https://github.com/vim/vim/commit/8a633e3427b47286869aa4b96f2bfc1fe65b25cd > - " < https://github.com/neovim/neovim/wiki/Following-HEAD#20160511 > - if (has("termguicolors")) - set termguicolors - endif -endif diff --git a/nvim/init.vim(server) b/nvim/init.vim(server) deleted file mode 100644 index 842dadb..0000000 --- a/nvim/init.vim(server) +++ /dev/null @@ -1,127 +0,0 @@ -syntax on -set number -set cursorline -set expandtab tabstop=4 shiftwidth=4 softtabstop=4 -set autoindent -set spelllang=vi,en - -" Fold -set foldmethod=syntax -set foldlevel=1 -set foldnestmax=1 -set encoding=utf8 - -" Search -set hlsearch -nnoremap i :nohlsi - -" Plugin -call plug#begin() -Plug 'neoclide/coc.nvim', {'branch': 'release'} -Plug 'preservim/nerdtree' -Plug 'preservim/nerdcommenter' -Plug 'junegunn/fzf', { 'do': { -> fzf#install() } } -Plug 'junegunn/fzf.vim' -Plug 'vim-airline/vim-airline' -Plug 'vim-airline/vim-airline-themes' -Plug 'kevinhwang91/nvim-bqf' -Plug 'morhetz/gruvbox' -Plug 'tpope/vim-fugitive' -Plug 'ynkdir/vim-diff' -call plug#end() - -"Color scheme - -colorscheme gruvbox -let g:gruvbox_contrast_light = 'hard' - -set background=dark - -" Comments -let mapleader = "," - -"Open NERDTree -:nnoremap g:NERDTree.IsOpen() ? "\:NERDTreeClose" : bufexists(expand('%')) ? "\:NERDTreeFind" : "\:NERDTree" - - -"Coc.nvim -inoremap - \ coc#pum#visible() ? coc#_select_confirm() : - \ coc#expandableOrJumpable() ? "\=coc#rpc#request('doKeymap', ['snippets-expand-jump',''])\" : - \ CheckBackSpace() ? "\" : - \ coc#refresh() - -inoremap coc#pum#visible() ? coc#_select_confirm() : coc#refresh() - -function! CheckBackSpace() abort - let col = col('.') - 1 - return !col || getline('.')[col - 1] =~# '\s' -endfunction - -let g:coc_snippet_next = '' -" remap save -nnoremap :w - -" moving between windows -nnoremap h -nnoremap j -nnoremap k -nnoremap l -nnoremap h -nnoremap j -nnoremap k -nnoremap l -nnoremap to :tabonly -nnoremap o :only -nnoremap :tabn -nnoremap :tabp - -"set clipboard+=unnamedplus -" " Copy to clipboard -vnoremap y "+y -nnoremap Y "+yg_ -nnoremap y "+y -nnoremap yy "+yy - -" " Paste from clipboard -nnoremap p "+p -nnoremap P "+P - - -" FZF key mapping -nnoremap b :Buffers -nnoremap r :Rg -nnoremap f :Files -nnoremap g :GFiles -nnoremap w :Rg - -filetype plugin on -set splitright -set splitbelow - -"Use 24-bit (true-color) mode in Vim/Neovim when outside tmux. -"If you're using tmux version 2.2 or later, you can remove the outermost $TMUX check and use tmux's 24-bit color support -"(see < http://sunaku.github.io/tmux-24bit-color.html#usage > for more information.) -if (empty($TMUX)) - if (has("nvim")) - "For Neovim 0.1.3 and 0.1.4 < https://github.com/neovim/neovim/pull/2198 > - let $NVIM_TUI_ENABLE_TRUE_COLOR=1 - endif - "For Neovim > 0.1.5 and Vim > patch 7.4.1799 < https://github.com/vim/vim/commit/61be73bb0f965a895bfb064ea3e55476ac175162 > - "Based on Vim patch 7.4.1770 (`guicolors` option) < https://github.com/vim/vim/commit/8a633e3427b47286869aa4b96f2bfc1fe65b25cd > - " < https://github.com/neovim/neovim/wiki/Following-HEAD#20160511 > - if (has("termguicolors")) - set termguicolors - endif -endif - -if &term =~ 'xterm' || &term == 'win32' - " Use DECSCUSR escape sequences - let &t_SI = "\e[5 q" " blink bar - let &t_SR = "\e[3 q" " blink underline - let &t_EI = "\e[1 q" " blink block - let &t_ti ..= "\e[1 q" " blink block - let &t_te ..= "\e[0 q" " default (depends on terminal, normally blink - " block) -endif - diff --git a/nvim/latexmk.vim b/nvim/latexmk.vim deleted file mode 100644 index d244df6..0000000 --- a/nvim/latexmk.vim +++ /dev/null @@ -1,227 +0,0 @@ -" VimTeX - LaTeX plugin for Vim -" -" Maintainer: Karl Yngve Lervåg -" Email: karl.yngve@gmail.com -" - -function! vimtex#compiler#latexmk#init(options) abort " {{{1 - return s:compiler.new(a:options) -endfunction - -" }}}1 - -function! vimtex#compiler#latexmk#get_rc_opt(root, opt, type, default) abort " {{{1 - " - " Parse option from .latexmkrc. - " - " Arguments: - " root Root of LaTeX project - " opt Name of options - " type 0 if string, 1 if integer, 2 if list - " default Value to return if option not found in latexmkrc file - " - " Output: - " [value, location] - " - " value Option value (integer or string) - " location An integer that indicates where option was found - " -1: not found (default value returned) - " 0: global latexmkrc file - " 1: local latexmkrc file - " - - if a:type == 0 - let l:pattern = '^\s*\$' . a:opt . '\s*=\s*[''"]\(.\+\)[''"]' - elseif a:type == 1 - let l:pattern = '^\s*\$' . a:opt . '\s*=\s*\(\d\+\)' - elseif a:type == 2 - let l:pattern = '^\s*@' . a:opt . '\s*=\s*(\(.*\))' - else - throw 'VimTeX: Argument error' - endif - - " Candidate files - " - each element is a pair [path_to_file, is_local_rc_file]. - let l:files = [ - \ [a:root . '/latexmkrc', 1], - \ [a:root . '/.latexmkrc', 1], - \ [fnamemodify('~/.latexmkrc', ':p'), 0], - \ [fnamemodify( - \ !empty($XDG_CONFIG_HOME) ? $XDG_CONFIG_HOME : '~/.config', ':p') - \ . '/latexmk/latexmkrc', 0] - \] - - let l:result = [a:default, -1] - - for [l:file, l:is_local] in l:files - if filereadable(l:file) - let l:match = matchlist(readfile(l:file), l:pattern) - if len(l:match) > 1 - let l:result = [l:match[1], l:is_local] - break - end - endif - endfor - - " Parse the list - if a:type == 2 && l:result[1] > -1 - let l:array = split(l:result[0], ',') - let l:result[0] = [] - for l:x in l:array - let l:x = substitute(l:x, "^'", '', '') - let l:x = substitute(l:x, "'$", '', '') - let l:result[0] += [l:x] - endfor - endif - - return l:result -endfunction - -" }}}1 - - -let s:compiler = vimtex#compiler#_template#new({ - \ 'name' : 'latexmk', - \ 'callback' : 1, - \ 'continuous': 1, - \ 'executable' : 'latexmk', - \ 'options' : [ - \ '-verbose', - \ '-file-line-error', - \ '-synctex=1', - \ '-interaction=nonstopmode', - \ '-shell-escape', - \ '-output-directory=./output', - \ '-aux-directory=./', - \ ], - \}) - -function! s:compiler.__check_requirements() abort dict " {{{1 - if !executable(self.executable) - call vimtex#log#warning(self.executable . ' is not executable') - throw 'VimTeX: Requirements not met' - endif -endfunction - -" }}}1 -function! s:compiler.__init() abort dict " {{{1 - " Check if .latexmkrc sets the build_dir - if so this should be respected - let l:out_dir = - \ vimtex#compiler#latexmk#get_rc_opt(self.state.root, 'out_dir', 0, '')[0] - if !empty(l:out_dir) - if !empty(self.build_dir) && (self.build_dir !=# l:out_dir) - call vimtex#log#warning( - \ 'Setting out_dir from latexmkrc overrides build_dir!', - \ 'Changed build_dir from: ' . self.build_dir, - \ 'Changed build_dir to: ' . l:out_dir) - endif - let self.build_dir = l:out_dir - endif -endfunction - -" }}}1 -function! s:compiler.__build_cmd() abort dict " {{{1 - let l:cmd = (has('win32') - \ ? 'set max_print_line=2000 & ' - \ : 'max_print_line=2000 ') . self.executable - - let l:cmd .= ' ' . join(self.options) - let l:cmd .= ' ' . self.get_engine() - - if !empty(self.build_dir) - let l:cmd .= ' -outdir=' . fnameescape(self.build_dir) - endif - - if self.continuous - let l:cmd .= ' -pvc -view=none' - - if self.callback - for [l:opt, l:val] in [ - \ ['compiling_cmd', 'vimtex_compiler_callback_compiling'], - \ ['success_cmd', 'vimtex_compiler_callback_success'], - \ ['failure_cmd', 'vimtex_compiler_callback_failure'], - \] - let l:cmd .= s:wrap_option_appendcmd(l:opt, 'echo ' . l:val) - endfor - endif - endif - - return l:cmd . ' ' . vimtex#util#shellescape(self.state.base) -endfunction - -" }}}1 -function! s:compiler.__pprint_append() abort dict " {{{1 - return [ - \ ['callback', self.callback], - \ ['continuous', self.continuous], - \ ['executable', self.executable], - \] -endfunction - -" }}}1 - -function! s:compiler.clean(full) abort dict " {{{1 - let l:cmd = self.executable . ' ' . (a:full ? '-C ' : '-c ') - if !empty(self.build_dir) - let l:cmd .= printf(' -outdir=%s ', fnameescape(self.build_dir)) - endif - let l:cmd .= vimtex#util#shellescape(self.state.base) - - call vimtex#jobs#run(l:cmd, {'cwd': self.state.root}) -endfunction - -" }}}1 -function! s:compiler.get_engine() abort dict " {{{1 - " Parse tex_program from TeX directive - let l:tex_program_directive = self.state.get_tex_program() - let l:tex_program = l:tex_program_directive - - - " Parse tex_program from from pdf_mode option in .latexmkrc - let [l:pdf_mode, l:is_local] = - \ vimtex#compiler#latexmk#get_rc_opt(self.state.root, 'pdf_mode', 1, -1) - - if l:pdf_mode >= 1 && l:pdf_mode <= 5 - let l:tex_program_pdfmode = [ - \ 'pdflatex', - \ 'pdfps', - \ 'pdfdvi', - \ 'lualatex', - \ 'xelatex', - \][l:pdf_mode-1] - - " Use pdf_mode if there is no TeX directive - if l:tex_program_directive ==# '_' - let l:tex_program = l:tex_program_pdfmode - elseif l:is_local && l:tex_program_directive !=# l:tex_program_pdfmode - " Give warning when there may be a confusing conflict - call vimtex#log#warning( - \ 'Value of pdf_mode from latexmkrc is inconsistent with ' . - \ 'TeX program directive!', - \ 'TeX program: ' . l:tex_program_directive, - \ 'pdf_mode: ' . l:tex_program_pdfmode, - \ 'The value of pdf_mode will be ignored.') - endif - endif - - return get(g:vimtex_compiler_latexmk_engines, - \ l:tex_program, - \ g:vimtex_compiler_latexmk_engines._) -endfunction - -" }}}1 - - -function! s:wrap_option_appendcmd(name, value) abort " {{{1 - " Note: On Linux, we use double quoted perl strings; these interpolate - " variables. One should therefore NOT pass values that contain `$`. - let l:win_cmd_sep = has('nvim') ? '^&' : '&' - let l:common = printf('$%s = ($%s ? $%s', a:name, a:name, a:name) - return has('win32') - \ ? printf(' -e "%s . '' %s '' : '''') . ''%s''"', - \ l:common, l:win_cmd_sep, a:value) - \ : printf(' -e ''%s . " ; " : "") . "%s"''', - \ l:common, a:value) -endfunction - -"}}}1 diff --git a/nvim/site/vi.utf-8.spl b/nvim/site/vi.utf-8.spl deleted file mode 100644 index 19d945336d15c3f3a32b583569a8df5a4fcf1417..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 20334 zcmbVUYiu0Xb)Gx3!?(DSV#hIy)`+|PlK?FkJE`LaC;|gDEWiO+0j*LsMrm5K9_GU~ z*PD%rGz_y{E3T|cqO8h}WUUxkrc6eZL`5PQhUlzpIIW}~6#~Ht0)-S(1nr-sXaE_8 zoPOUqcjsO%>7=QCjAm!<<2=6exaZ#CUp?~ZvxD27dg@cg1c4d-TJZn*hpx4M(c1q4 z``CQQzaV`cBwtHLlCLMD$v2Wx@()Qlc_G=Id^345`Nw2W@=~%l`KM%GvOhVHj3oz? zmy<)uKPQKiSCUtgZzV^PqseQ@v80k5PsWpPCnu8Elat9C$wYE0c{7(!IhH>wlWQ`I-C zlhvu}cdDnW)73N8v(RgRCpF>z{g z>g>6h^Rsh}Depq76#(1kc_}vWeYf;g@#3e~$Z~~;Ta*{+q!O3*16F!`uEJGmb42Yj zz*mF33`xIk9msKORhk!8w@de%LJ-AtQ(7w-I#o*MmVP&tNJHn-saCaBnmJ^--WD+4+UVI&G?`Jq4g;F2Bkg1#q&r%2;_ZR(Vp8_;`gp(>Gk zZFo2OygR~}flY_7D>a=$X55ESoI?)RXj zT{5R+b|q3~7gyZCTbb6q@k9=Pj0S}=nNS!h(RrDsBz#jY@VJ+j8jgXSYZd(L8fULJ zaLG;JQaUR_(1wPuM$KG?4NGh|c6v6#e?o?pttw{7Q$Z^IE&WA!cQC|pPLT=TEOLax z2rr|&l+BEcnRY8P^pK3g#3Fm#>;dcHzOu%ILx=GwcP=GEJ&fv(Lu~06v+ZFk%LeWw zTHw(S#=-c0L=D{kWO52WuAYTgF&k#^;P!dknb|q#Hfk}LgQ=x!@KtWpIaY-cX`i|e z8yw}Kj!g~PAi_IUqciQB{h~CnEy0Gu$-mT_=5=5{amV;hjaTiUBKw zlmB|<8{cV*&g*@)xD8RJ52*he$wt?@Az~9OBrg}^n zs=Hq-uiJV|YSLzA&iSfJg&fUDL_1sh9sO!C?5lE8Ywpt_1Q1?G@t%r&wTpu-a3dbR z&sm_?PTs*frHPQMsL}p>;JICEy8b)LBG=;-Z+XGf67owEM3>L$OBp)_^OpW44CKg0q0-&5R8#as1sys|Z zBPPg9mn7`V=()VJ?s^SUqLE7ltOZqyBzBB|?W-Az_X&g42nTE|G&!OSIi6K7c7CWVLjEb2Ph>AgOffrr# z)L~i;O2VItP1td)dPdF2XLA4tCAQQtG=)-VeG~*{MX{rtxrEDb`Nci>@Ah8M`U+Dq zT0NSzaS3q)%tq792#BB{N8Z9luob-nw#@Y@KBPOE_f{Cz%=s$s2%-|KmmtBa6wSx^ zs>T4Fu8ZAVH#klP!k}A=Be|#A&~Bz1m%_H~I|iP~S0U4gr4r0&mbdKy_+_ZRCE6G$ zyev6qVMN})0TzNBlEr9x(sMT|By?b-{Y+kRs-{InXb+Sw@{5Kkzp-*#(7g>eoxNy( zO_VjL1sjDY8C&5R_}kVSNPCVkOo%(&#;ONK=|IY!IRWy_b&!|Y$t*UyI5RsZBYG}I z9lGaBJvnh`bFc#BTT$Y$WIc$C;gU z2szqFp#p}3E}DK0=F#vV_zlL?GMstai9|C30u{ao!~Uv@7rjeoA$Zf#9R^GrKpUNL zxD~WSmx&n)_&BI*8po4KS@Nu1@NP(c_tYNdZ1U_LcortI5QDPi2-j+;9V5&LD_6F$UFWWWA%(7#b}75gJ}*lV z#@OHqEV9%5fKR<7D-YtLhejZ~>CrOoee~y>;U?(>`B*5^&Q%EhGndpa>QKd)2nq`0 zY{^=|m<@{Tb)SvLJ$$Lo!pt>Q#tCX$u>%d4FFVS4+-HJ9Y2fFWS7|8W_pk_{Kr_gmTJXTim`qD5oLCG) z-blqE$c^BZnN3gvP@-XY*l-^#CCFXKLPU>QtD;b@Fi=D#c;Yxq;|gxkxMZzhI?%=Z z4>%8(=9)?7hp!bRf~(GBG;~VwOwsqm18k&7vSud_+`2Z^sydStiEz8le)>hhgW zKwi-_Ei<#z<~75!bAsFLUWh}3B zKCI(4%$G(@(0CG1iL<+j5=oVg>;+2p(Z^h)kGXXaGQP;1$^5Jq57ftWiMTR5DX!qQ zCQPT#xQMHa40=l`(W~QRNO+cqLcJ9nsqf*X{*5r+U3+couvT0e%%xl2#u}L@uP?R_ zh1;Gn&nRxjwgERy-|9AlhIc{dlZ_mdBX35!g+gO9ZYBMKPh+L@?IrctIwVBZSu@v$ zU7oo@oI$C?q@}SJqh(HrkLtsK;52@pmKVPdM-=XwsFR9SCCMm)r05~mFF6eTk?Az2*T!75laub(ZRsNI+BD1VG#WVlg&8K1xiqY z7|jMyBW^vq4Cl6Dp^^?{ja7cvR1U?6bCZb(R|{{M7im@I#SxM?N@G%sdJ(gA?18Md z(xN^=&vg;TBukGV$GoBIHHg|=rvYiG&P@rKB6Vuc?#QV*cv}G$^mSoX^h{&|-Bro* z!~3MXUMfipv7V0OYW7GrY!N~p(gRCOfc`{xxrMq6Tw4#YwOXrcPH5$5H+8E+bgKbU zn;G_)fMx({^TO;rt}iVB-#=XxO8h;8AqG-+wFoyuf%d9nT-0KW# z;xgsU{&e9)OCHFx0}Z0NlZz)((fPEpl#*-*fu5{Udld_^q=v!FFf&d1=rmcn5HzrX z4+Q)~4Q1^Fg?$I$3xs10jf9lB1|y35DttZ8{^}q|E2f%@(-&hk3=0qfvhdKlTVKym@W_0t(#r8BsSk+^NaK^E#V3@>r8 z_(3C8reNsaPSf>EL zAPelY@`AJ}nidfRx9G8?MiRX<#kN><6;1oDfquYCWB54wVU+`6*PS_aUGUzb(}YK71c{9ssFp6MB`iZD@hgY3q?Bm{ zY;7FxHq%#Jr81brM&urn4e#Y9{Z@0pl}O_F1?bjsSkcVs%1TG!7G zA8vR)jNvUbf=^Fi(@q#yb>amxckyN-D<r9yQIkT(hlRg?_elZMqRJPKwH59l!hBpW}u z1c!1SW}|3Hr&Bu+DXFK6IWMZ05W)kOG^e)y0nBOU!U#oabF1BSl*&RH9f=PpjKl44 zTy3I>?z^UxU{w%P4fx>r{rLsF+b1ULB`;bilcoc3rAXdJIamo!vH1$rh55R@UCW#n z3sk=EQ{384`@L8!3>GO;;lMd(12>+zPRp_vV`M+T(;8@>qAaq>9&^je@eN z9$ms(dx&EHK^H=;|EdJR$nndx_@XkOjzs3UIc{xG$kk2FI)8@ zzOf4!(IZ(cM5XS0(#`&ju+!*(M8qSIPc(TDGhLSj@XIwD4RWBQ_2)ECUH@t@yo9-B z!=Uw+w+>dZSX1m_3x%l4#CzaYY!aO$^5h0RGaM5AbYln?sl0p$qHg`Y+QKxtlb8=T zjZiTDMjOt&V1)Ym8Ba8#y@FYF#KfcZd4;d$q(X{)Y3A6R8bLaWOJUx{X)Z#S%#!Z7 z6-oxvb<6;H>`{QT4hkYDO|)ThEsr43nGOYF7Viav8sp4Mm|GT=(J*41E-IsG=8`VP zO#+yx1g}-7^3yGcO6TEgsC5~nT6rJH@Ldjn+AId*v%!Fkta@uPjt7!}nv1el1;Rzk zlv%pb=I3K-v#6p@w zda(A`b-JuGBWXa+A0<)9)gQKcKV#62E`Taj{wD1hCrPF0-C_D8d8h|fUKcU0_R^*)r*y23+k!lGlURrosDWbI#sT7t1 zJ9QnxP@eMDiV9g@^~Nx2wah*VUewmM^dqA(%Om_f3fd=u(;z1}4S`d0131;PCAUV* zjf0?>TUjl?AXtAyo~M~iaw`k#7`$yG&tVK}Yxy<7YBMYh^B~HYcpyr!Sr&WRLlZsf zk;#6!pQ4arAMzTuA#^RTRgA<933^a?1?>f9;gLAH7d$l{aQgvdy)urMveuUXCN@9D z(4T__Y!y%_)42v)x}V_lZQH@uMNHrHI)*bH1AHj^#_ztJ37+CFnTBWTTkg7qEB19; zy3uq$_ifBoBy~`E=OtX2%2|(L`*17{QH*4#!5-$8goGt)0zbw^5IWjq1)?i2J zC~AxAD3*2Cj!PD|Ogrl2>Lt#>vzzyragsiR3x+q#vs{hEDEN?bo^RnczNQjDO@+*kqd=7N`*SOkfUQ8ltD7~Kipq%v%-&zO7@hT!5DFc~NU zAvlJB3-+$;3E9#yGsgim6F5z|%VriNb=zg~dT4gI+|1Fe=Gh4nw23?+5R3rEXd_gD?N>D0CBj&}rB} zt1msgmHFh2E(g8eB0)i)U5@DhtyZJJ24zGM(~gMbXkXq9WlhljY3kfADp(xM{tLc4*?G)-X|06LIuOs+IZIKAC*3MNd2a))Xv%I2L8dkNg65US zh0A(eI4pDdK|Qews2_b`v&)%lDjlo~(Ll|}!GY)A7**H*9pK&e$AF|gCIU#}tO%ch zZ8_*Dd0pHG)o1?`sBB)G=XgFUtqQH1}eRVhH?1e7l>?qrFH5+$Ii7%Sm ziy03w&1QHM$AR!@Kcv8`NrXkS45C|p0ir`5^~gN8!gH7pKy(E z(;<$QD;3#g!{K=H23VVy$iT9~8qdC<)o_K6=vhD_)~Z|x)$+#UikuVyZ%F`a@TSNe z#E}6K-rTg-xTx@!Lou11wVE1456YuUfVQ0U3wmLX&0n2D&ksPodC!JNfUQl z%*C9b09$}d1p4S}wR`}bVSkFx7s+If$3pBb)j`}94uR-L4)cxZ9Wl1HgNPYwITyaf z#H>7DribMjmo`ig&GWMRDRHUsZgiIFmlWaFe-dzR*tgPTf|PV5Z(wsn}Yv z-BW@Ch_esXkHQMX*9RGb$(FbB|E&~CNLoBcl2oaH|^!3)mWZE0XO&YKsL5=A#)rZ zCvTu0=NqXP=Ywm8LGA0-u2}}tT0ygiah1Uy_S*q)H#`P_;3UZo4ll6}E&%2))<(8% zw6ocE_%Ku;;i>iBvR%XBfqv7LMlWe2hwr%s9F$m`qh*Xi_(;MdK7*QqF|i>=FO=kv z(ceq<_<4y$Fg+`)E zCRzzGz$^Tr-PvRh?rO^M#NalZai-ta*m^h^4SdA`JU&p1AL1)-zfv{h-h0`G+KmjD zO2v)}otjnOP^|wlT`+(d9fH1^_akY-hlXy!;HL?&G_DQS?HEkTDm2H z96@d0M=xw%n#W~%fw-yPy(GV@3*1zKNJ8C>u2u!I%46;PpX5<-7Kn`7prhtfyG^ih z5~%#hulHa|?p4Zn*OF7o*`>xmgx>T}0Kc6u9k1boDR}o=0HT~=LMDY6Qd6qBGR<(- zlIaSg?`A(IZu^zBJQb}q{^D`r3&S;j^BLp}I{K44Ob`B0#1n=o&o(|IV(|+n-KeaN z71*SMTXzlA^1BpXM{(&THcLz#)ZZa^t~fT^hC$mu4NAED=(n4nx(e!l8omDXS(z~C zdHnJDZ!RTDD+W& z@!9ydn4x~}Puv8*MwM(nW)6d+2W*E#28ZTdVlQ50#mRY3e+zjjXZN04lh9h;tf| z_dah+ok@I&4jiD&;ea=uMSO9aHE!7+=c&6<>b?X9+t1V4@hc=ffOh$ekm!il zV&6@VW;H#15Cs|`9zF#`Wj`Xe(!75(OE*fm$Z2LV0V&cnAIEGP-vAc%gq17|-DlOP zRjzr6(HaX0^<=@H>cEsb!NibT`MD72XANKv77T#HF}Gj{|8RP3F+d+v+kTPIqbj3N ztm~$bcuq}L^-Z5E%d9R03Bf$b5+S}|F9fYi`iBzevEX`G=x_ThpZAWhMX^1;Xb;#b>Tm2wX+e=do&N-3!v>V@mAAFE---w|NHV(KSaCR$LfUeTi>X3k3N{UU@0j zwp3eYckwsXt7E87(RHE7hp%$nHf_E#0&?%5JhFNkE%@agkj+JT=1Wu(&wk3fL(YEU zFYJKb^z3K!kW^718S|rYT;73P;#_(LG~lWADC@7x2ZdhB83)2ih1`-Ts~ Date: Tue, 17 Feb 2026 21:43:19 +0700 Subject: [PATCH 02/23] lua nvim, change mod key --- i3/config | 2 +- nvim-server/init.lua | 83 ++++++++++++++++++++++++++++++++++++++++++++ sway/config | 2 +- 3 files changed, 85 insertions(+), 2 deletions(-) create mode 100644 nvim-server/init.lua diff --git a/i3/config b/i3/config index 26a17d2..5237f5e 100644 --- a/i3/config +++ b/i3/config @@ -9,7 +9,7 @@ # # Please see https://i3wm.org/docs/userguide.html for a complete reference! -set $mod Mod1 +set $mod Mod4 set $wallpaper '/data/sync/images/wallpapers/suse.png' # Font for window titles. Will also be used by the bar unless a different font # is used in the bar {} block below. diff --git a/nvim-server/init.lua b/nvim-server/init.lua new file mode 100644 index 0000000..486e7bd --- /dev/null +++ b/nvim-server/init.lua @@ -0,0 +1,83 @@ +-- Minimal server editor config +-- Launch with: NVIM_APPNAME=nvim-server nvim + +-------------------- Options -------------------- +vim.g.mapleader = "," +vim.opt.number = true +vim.opt.cursorline = true +vim.opt.expandtab = true +vim.opt.tabstop = 4 +vim.opt.shiftwidth = 4 +vim.opt.softtabstop = 4 +vim.opt.autoindent = true +vim.opt.smartindent = true +vim.opt.hlsearch = true +vim.opt.incsearch = true +vim.opt.ignorecase = true +vim.opt.smartcase = true +vim.opt.splitright = true +vim.opt.splitbelow = true +vim.opt.termguicolors = true +vim.opt.scrolloff = 8 +vim.opt.signcolumn = "no" +vim.opt.updatetime = 250 +vim.opt.undofile = true +vim.opt.clipboard = "unnamedplus" + +-------------------- Keymaps -------------------- +vim.keymap.set("n", "i", ":nohlsi", { silent = true }) +vim.keymap.set("n", "", ":w", { silent = true }) + +-- Window navigation +vim.keymap.set("n", "", "h") +vim.keymap.set("n", "", "j") +vim.keymap.set("n", "", "k") +vim.keymap.set("n", "", "l") + +-- Tab management +vim.keymap.set("n", "to", ":tabonly", { silent = true }) +vim.keymap.set("n", "o", ":only", { silent = true }) +vim.keymap.set("n", "", ":tabn", { silent = true }) +vim.keymap.set("n", "", ":tabp", { silent = true }) + + +-------------------- Netrw (built-in file browser) -------------------- +vim.g.netrw_banner = 0 +vim.g.netrw_liststyle = 3 +vim.keymap.set("n", "", ":Explore", { silent = true }) + +-------------------- Statusline (built-in) -------------------- +vim.opt.statusline = " %f %m%r%= %y %l:%c %p%% " + +-------------------- Bootstrap lazy.nvim -------------------- +local lazypath = vim.fn.stdpath("data") .. "/lazy/lazy.nvim" +if vim.fn.isdirectory(lazypath) == 0 then + vim.fn.system({ + "git", "clone", "--filter=blob:none", + "https://github.com/folke/lazy.nvim.git", + "--branch=stable", + lazypath, + }) +end +vim.opt.rtp:prepend(lazypath) + +require("lazy").setup({ + { "4ree/viml-surround", event = "VeryLazy" }, + { "numToStr/Comment.nvim", event = "VeryLazy", opts = {} }, + { + "junegunn/fzf.vim", + dependencies = { "junegunn/fzf" }, + keys = { + { "f", "Files", desc = "Find files" }, + { "b", "Buffers", desc = "Buffers" }, + { "r", "Rg", desc = "Ripgrep" }, + { "g", "GFiles", desc = "Git files" }, + }, + }, +}) + +-------------------- Grep (use ripgrep if available) -------------------- +if vim.fn.executable("rg") == 1 then + vim.opt.grepprg = "rg --vimgrep --smart-case" + vim.opt.grepformat = "%f:%l:%c:%m" +end diff --git a/sway/config b/sway/config index 8fd0694..6e28831 100644 --- a/sway/config +++ b/sway/config @@ -7,7 +7,7 @@ ### Variables # # Logo key. Use Mod1 for Alt. -set $mod Mod1 +set $mod Mod4 # Home row direction keys, like vim #set $left h #set $down j From 324a833c816e26db0642eab9b997f6a56307218f Mon Sep 17 00:00:00 2001 From: nnduc Date: Sat, 21 Feb 2026 02:30:10 +0700 Subject: [PATCH 03/23] zsh --- .zshrc | 32 +------------------------------- 1 file changed, 1 insertion(+), 31 deletions(-) diff --git a/.zshrc b/.zshrc index f247c1c..6c4d30a 100644 --- a/.zshrc +++ b/.zshrc @@ -1,15 +1,8 @@ -# Enable Powerlevel10k instant prompt. Should stay close to the top of ~/.zshrc. -# Initialization code that may require console input (password prompts, [y/n] -# confirmations, etc.) must go above this block; everything else may go below. -if [[ -r "${XDG_CACHE_HOME:-$HOME/.cache}/p10k-instant-prompt-${(%):-%n}.zsh" ]]; then - source "${XDG_CACHE_HOME:-$HOME/.cache}/p10k-instant-prompt-${(%):-%n}.zsh" -fi - -# Lines configured by zsh-newuser-install HISTFILE=~/.histfile HISTSIZE=2000 SAVEHIST=2000 bindkey -v + # End of lines configured by zsh-newuser-install # The following lines were added by compinstall bindkey "\e[3~" delete-char @@ -17,35 +10,12 @@ autoload -Uz compinit compinit # End of lines added by compinstall -# zsh extensionst -source /data/kits/zsh/zsh-autosuggestions/zsh-autosuggestions.zsh -source /data/kits/zsh/powerlevel10k/powerlevel10k.zsh-theme -source /data/kits/zsh/zsh-syntax-highlighting/zsh-syntax-highlighting.zsh -eval `dircolors /data/kits/zsh/dircolor/bliss.dircolors` - -# To customize prompt, run `p10k configure` or edit ~/.p10k.zsh. - -[[ ! -f ~/.p10k.zsh ]] || source ~/.p10k.zsh - -export PATH="$HOME/.local/bin:$PATH" -export PATH="/data/runtimes/julia/bin/:$PATH" -export PATH="/data/runtimes/gurobi/linux64/bin/:$PATH" -export PATH="/data/runtimes/conda/bin:$PATH" -export PATH="/data/runtimes/nodejs/bin:$PATH" export EDITOR=nvim export TERM='xterm-256color' alias ls='ls --color=auto' -# >>> juliaup initialize >>> - -# !! Contents within this block are managed by juliaup !! - -path=('/data/runtimes/julia/bin' $path) -export PATH - -# <<< juliaup initialize <<< zshaddhistory() { whence ${${(z)1}[1]} >/dev/null || return 2 } From d6a1559119a712794fec3fc2cee10eb095675ed0 Mon Sep 17 00:00:00 2001 From: nnduc Date: Sat, 21 Feb 2026 03:02:56 +0700 Subject: [PATCH 04/23] systemd --- i3/config | 4 ++-- sway/config | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/i3/config b/i3/config index 5237f5e..537b52c 100644 --- a/i3/config +++ b/i3/config @@ -27,11 +27,11 @@ exec --no-startup-id dex --autostart --environment i3 # they are included here as an example. Modify as you see fit. #exec --no-startup-id /usr/bin/gnome-keyring-daemon --start --components=gpg,pkcs11,secrets,ssh # xss-lock grabs a logind suspend inhibit lock and will use i3lock to lock the -# screen before suspend. Use loginctl lock-session to lock your screen. +# screen before suspend. Use systemctl lock-session to lock your screen. exec --no-startup-id xrand --output HDMI-0 --mode 1920x1080 --rate 120 bindsym $mod+l exec i3lock --ignore-empty-password -i $wallpaper -bindsym $mod+Shift+p exec loginctl poweroff +bindsym $mod+Shift+p exec systemctl poweroff bindsym Print exec flameshot gui -c # NetworkManager is the most popular way to manage wireless networks on Linux, # and nm-applet is a desktop environment-independent system tray GUI for it. diff --git a/sway/config b/sway/config index 6e28831..c921512 100644 --- a/sway/config +++ b/sway/config @@ -145,7 +145,7 @@ bindsym $mod+Shift+c reload # Exit sway (logs you out of your Wayland session) #bindsym $mod+Shift+e exec swaynag -t warning -m 'You pressed the exit shortcut. Do you really want to exit sway? This will end your Wayland session.' -B 'Yes, exit sway' 'swaymsg exit' -bindsym $mod+Shift+p exec loginctl poweroff +bindsym $mod+Shift+p exec systemctl poweroff bindsym $mod+Shift+l exec swaymsg exit # # Moving around: From e9c80f0ae91af9804ed16f54997ff05acac07949 Mon Sep 17 00:00:00 2001 From: nnduc Date: Mon, 23 Feb 2026 08:00:11 +0700 Subject: [PATCH 05/23] up term --- .zshrc | 25 ++++++++++++++++++++----- i3/config | 5 +++-- sway/config | 2 +- 3 files changed, 24 insertions(+), 8 deletions(-) diff --git a/.zshrc b/.zshrc index 6c4d30a..4ea8e93 100644 --- a/.zshrc +++ b/.zshrc @@ -1,3 +1,10 @@ +# Enable Powerlevel10k instant prompt. Should stay close to the top of ~/.zshrc. +# Initialization code that may require console input (password prompts, [y/n] +# confirmations, etc.) must go above this block; everything else may go below. +if [[ -r "${XDG_CACHE_HOME:-$HOME/.cache}/p10k-instant-prompt-${(%):-%n}.zsh" ]]; then + source "${XDG_CACHE_HOME:-$HOME/.cache}/p10k-instant-prompt-${(%):-%n}.zsh" +fi + HISTFILE=~/.histfile HISTSIZE=2000 SAVEHIST=2000 @@ -6,17 +13,25 @@ bindkey -v # End of lines configured by zsh-newuser-install # The following lines were added by compinstall bindkey "\e[3~" delete-char -autoload -Uz compinit -compinit +autoload -Uz compinit && compinit +zstyle ':completion:*' menu select # End of lines added by compinstall -export EDITOR=nvim -export TERM='xterm-256color' +source /home/nnduc/git/powerlevel10k/powerlevel10k.zsh-theme -alias ls='ls --color=auto' zshaddhistory() { whence ${${(z)1}[1]} >/dev/null || return 2 } +# To customize prompt, run `p10k configure` or edit ~/.p10k.zsh. +[[ ! -f ~/.p10k.zsh ]] || source ~/.p10k.zsh + +export EDITOR=nvim +export TERM='xterm-256color' +export PATH="$HOME/.local/bin:$PATH" + +alias ls='ls --color=auto' +alias doc='docker-compose' +source ~/git/zsh-autosuggestions/zsh-autosuggestions.zsh diff --git a/i3/config b/i3/config index 537b52c..8408e8c 100644 --- a/i3/config +++ b/i3/config @@ -11,6 +11,7 @@ set $mod Mod4 set $wallpaper '/data/sync/images/wallpapers/suse.png' +set $term 'xfce4-terminal' # Font for window titles. Will also be used by the bar unless a different font # is used in the bar {} block below. font pango:NotoSans 12 @@ -87,9 +88,9 @@ floating_modifier $mod #tiling_drag modifier titlebar #xrandr --output HDMI-2 --auto --right-of eDP1 -# start a 3terminal +# start a terminal #bindsym $mod+Return exec i3-sensible-terminal -bindsym $mod+Return exec alacritty +bindsym $mod+Return exec $term # kill focused window bindsym $mod+Shift+q kill diff --git a/sway/config b/sway/config index c921512..073cd05 100644 --- a/sway/config +++ b/sway/config @@ -14,7 +14,7 @@ set $mod Mod4 #set $up k #set $right l # Your preferred terminal emulator -set $term alacritty +set $term xfce4-terminal # Your preferred application launcher # Note: pass the final command to swaymsg so that the resulting window can be opened # on the original workspace that the command was run on. From 271be6d985848777455174c3f4b32b7b54625dfd Mon Sep 17 00:00:00 2001 From: nnduc Date: Mon, 23 Feb 2026 18:32:39 +0700 Subject: [PATCH 06/23] hidden files --- i3/config | 10 ++++------ nvim/init.lua | 13 ++++++++++++- nvim/lazy-lock.json | 22 ++++++++++++++++++++++ 3 files changed, 38 insertions(+), 7 deletions(-) create mode 100644 nvim/lazy-lock.json diff --git a/i3/config b/i3/config index 8408e8c..eb1d9d6 100644 --- a/i3/config +++ b/i3/config @@ -10,8 +10,8 @@ # Please see https://i3wm.org/docs/userguide.html for a complete reference! set $mod Mod4 -set $wallpaper '/data/sync/images/wallpapers/suse.png' -set $term 'xfce4-terminal' +set $wallpaper '/home/nnduc/sync/images/wallpapers/suse.png' +set $terminal 'xfce4-terminal' # Font for window titles. Will also be used by the bar unless a different font # is used in the bar {} block below. font pango:NotoSans 12 @@ -41,13 +41,11 @@ bindsym Print exec flameshot gui -c exec --no-startup-id fcitx5 -d exec --no-startup-id nm-applet exec --no-startup-id blueman-applet +exec --no-startup-id kwalletd6 exec --no-startup-id feh --bg-fill $wallpaper exec --no-startup-id owncloud exec --no-startup-id pasystray exec --no-startup-id polybar -exec --no-startup-id xset m 1/1 0 -exec xinput --set-prop "Razer Razer DeathAdder V2 X HyperSpeed Mouse" "Device Accel Constant Deceleration" 3 -exec --no-startup-id gentoo-pipewire-launcher restart & set $refresh_i3status killall -SIGUSR1 i3status @@ -90,7 +88,7 @@ floating_modifier $mod # start a terminal #bindsym $mod+Return exec i3-sensible-terminal -bindsym $mod+Return exec $term +bindsym $mod+Return exec $terminal # kill focused window bindsym $mod+Shift+q kill diff --git a/nvim/init.lua b/nvim/init.lua index c1c3463..8a21d81 100644 --- a/nvim/init.lua +++ b/nvim/init.lua @@ -115,7 +115,18 @@ require("lazy").setup({ { "w", "Telescope grep_string", desc = "Grep word under cursor" }, }, config = function() - require("telescope").setup() + require('telescope').setup({ + defaults = { + file_ignore_patterns = { "%.git/" }, -- Note the lua escape character '%' for the dot + }, + pickers = { + find_files = { + hidden = true, + -- Optional: exclude the .git directory + -- find_command = { "rg", "--files", "--hidden", "--glob", "!**/.git/*" }, + }, + }, + }) require("telescope").load_extension("fzf") end, }, diff --git a/nvim/lazy-lock.json b/nvim/lazy-lock.json new file mode 100644 index 0000000..396615f --- /dev/null +++ b/nvim/lazy-lock.json @@ -0,0 +1,22 @@ +{ + "Comment.nvim": { "branch": "master", "commit": "e30b7f2008e52442154b66f7c519bfd2f1e32acb" }, + "coq.artifacts": { "branch": "artifacts", "commit": "ef5f21d638ccc456cfa5b8d0ab37093cefe48c8b" }, + "coq.thirdparty": { "branch": "3p", "commit": "2bd969a2bcd2624f9c260b1000957c7e665e308e" }, + "coq_nvim": { "branch": "coq", "commit": "d939a34ceb2b57d2937890337a4aa75eb55e18a8" }, + "gruvbox.nvim": { "branch": "main", "commit": "561126520034a1dac2f78ab063db025d12555998" }, + "julia-vim": { "branch": "master", "commit": "edd3512748bd07252fa79f3c01b759921192a319" }, + "lazy.nvim": { "branch": "main", "commit": "85c7ff3711b730b4030d03144f6db6375044ae82" }, + "lualine.nvim": { "branch": "master", "commit": "47f91c416daef12db467145e16bed5bbfe00add8" }, + "nvim-autopairs": { "branch": "master", "commit": "59bce2eef357189c3305e25bc6dd2d138c1683f5" }, + "nvim-bqf": { "branch": "main", "commit": "f65fba733268ffcf9c5b8ac381287eca7c223422" }, + "nvim-lspconfig": { "branch": "master", "commit": "44acfe887d4056f704ccc4f17513ed41c9e2b2e6" }, + "nvim-tree.lua": { "branch": "master", "commit": "e11ce83ed9a00f065bf676ae4e6c261c766989ba" }, + "nvim-web-devicons": { "branch": "master", "commit": "746ffbb17975ebd6c40142362eee1b0249969c5c" }, + "plenary.nvim": { "branch": "master", "commit": "b9fd5226c2f76c951fc8ed5923d85e4de065e509" }, + "telescope-fzf-native.nvim": { "branch": "main", "commit": "6fea601bd2b694c6f2ae08a6c6fab14930c60e2c" }, + "telescope.nvim": { "branch": "master", "commit": "5255aa27c422de944791318024167ad5d40aad20" }, + "vim-fugitive": { "branch": "master", "commit": "61b51c09b7c9ce04e821f6cf76ea4f6f903e3cf4" }, + "vim-ime": { "branch": "master", "commit": "79e3b02eb50a57305113550be7ca163b267b5e30" }, + "viml-surround": { "branch": "master", "commit": "98358bad347aa2b8a180c2edde84c3bd8a51fdd1" }, + "vimtex": { "branch": "master", "commit": "95b93a24740f7b89dd8331326b41bdd1337d79f6" } +} From 8b54b4e9fe19b5dab591f48044313d15aa883690 Mon Sep 17 00:00:00 2001 From: nnduc Date: Tue, 24 Feb 2026 17:48:46 +0700 Subject: [PATCH 07/23] switch back since mapping alt is different with each wm --- i3/config | 2 +- sway/config | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/i3/config b/i3/config index eb1d9d6..fddeb65 100644 --- a/i3/config +++ b/i3/config @@ -9,7 +9,7 @@ # # Please see https://i3wm.org/docs/userguide.html for a complete reference! -set $mod Mod4 +set $mod Mod1 set $wallpaper '/home/nnduc/sync/images/wallpapers/suse.png' set $terminal 'xfce4-terminal' # Font for window titles. Will also be used by the bar unless a different font diff --git a/sway/config b/sway/config index 073cd05..b86642d 100644 --- a/sway/config +++ b/sway/config @@ -7,7 +7,7 @@ ### Variables # # Logo key. Use Mod1 for Alt. -set $mod Mod4 +set $mod Mod1 # Home row direction keys, like vim #set $left h #set $down j From 04af9e9c0fe91f26091ac3cc538c1aad22b8acba Mon Sep 17 00:00:00 2001 From: nnduc Date: Tue, 3 Mar 2026 00:09:17 +0700 Subject: [PATCH 08/23] up --- nvim/init.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/nvim/init.lua b/nvim/init.lua index 8a21d81..c6d9be4 100644 --- a/nvim/init.lua +++ b/nvim/init.lua @@ -17,6 +17,7 @@ vim.opt.hlsearch = true vim.opt.splitright = true vim.opt.splitbelow = true vim.opt.termguicolors = true +vim.opt.autoread = true -------------------- Keymaps -------------------- -- Clear hlsearch then enter insert mode From f387a9176596387443fc80be0141171c1b310ee0 Mon Sep 17 00:00:00 2001 From: nnduc Date: Tue, 3 Mar 2026 00:22:53 +0700 Subject: [PATCH 09/23] up --- zathura/zathurarc | 1 + 1 file changed, 1 insertion(+) create mode 100644 zathura/zathurarc diff --git a/zathura/zathurarc b/zathura/zathurarc new file mode 100644 index 0000000..253954a --- /dev/null +++ b/zathura/zathurarc @@ -0,0 +1 @@ +set selection-clipboard clipboard \ No newline at end of file From efe87c44b1a97552bcbf5edfd2726e0ddd9e0ed8 Mon Sep 17 00:00:00 2001 From: nnduc Date: Fri, 6 Mar 2026 12:55:19 +0700 Subject: [PATCH 10/23] moving in vim --- nvim-server/init.lua | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/nvim-server/init.lua b/nvim-server/init.lua index 486e7bd..e6bb61e 100644 --- a/nvim-server/init.lua +++ b/nvim-server/init.lua @@ -33,6 +33,10 @@ vim.keymap.set("n", "", "h") vim.keymap.set("n", "", "j") vim.keymap.set("n", "", "k") vim.keymap.set("n", "", "l") +vim.keymap.set("n", "", "h") +vim.keymap.set("n", "", "j") +vim.keymap.set("n", "", "k") +vim.keymap.set("n", "", "l") -- Tab management vim.keymap.set("n", "to", ":tabonly", { silent = true }) From 1e81b70717a95e50c3bfd615fe813309e901bde7 Mon Sep 17 00:00:00 2001 From: nnduc Date: Thu, 12 Mar 2026 00:37:50 +0700 Subject: [PATCH 11/23] replace telescope with ripgrep since it is too slow --- nvim/init.lua | 34 +++++++++++++--------------------- 1 file changed, 13 insertions(+), 21 deletions(-) diff --git a/nvim/init.lua b/nvim/init.lua index c6d9be4..0981570 100644 --- a/nvim/init.lua +++ b/nvim/init.lua @@ -101,34 +101,26 @@ require("lazy").setup({ end, }, - -- Fuzzy finder (telescope replaces fzf) + -- Fuzzy finder (fzf-lua with ripgrep) { - "nvim-telescope/telescope.nvim", - dependencies = { - "nvim-lua/plenary.nvim", - { "nvim-telescope/telescope-fzf-native.nvim", build = "make" }, - }, + "ibhagwan/fzf-lua", + dependencies = { "nvim-tree/nvim-web-devicons" }, keys = { - { "b", "Telescope buffers", desc = "Buffers" }, - { "r", "Telescope live_grep", desc = "Live grep" }, - { "f", "Telescope find_files", desc = "Find files" }, - { "g", "Telescope git_files", desc = "Git files" }, - { "w", "Telescope grep_string", desc = "Grep word under cursor" }, + { "b", "FzfLua buffers", desc = "Buffers" }, + { "r", "FzfLua live_grep", desc = "Live grep" }, + { "f", "FzfLua files", desc = "Find files" }, + { "g", "FzfLua git_files", desc = "Git files" }, + { "w", "FzfLua grep_cword", desc = "Grep word under cursor" }, }, config = function() - require('telescope').setup({ - defaults = { - file_ignore_patterns = { "%.git/" }, -- Note the lua escape character '%' for the dot + require("fzf-lua").setup({ + files = { + cmd = "rg --files --hidden --glob '!**/.git/*'", }, - pickers = { - find_files = { - hidden = true, - -- Optional: exclude the .git directory - -- find_command = { "rg", "--files", "--hidden", "--glob", "!**/.git/*" }, - }, + grep = { + rg_opts = "--hidden --glob '!**/.git/*' --column --line-number --no-heading --color=always --smart-case", }, }) - require("telescope").load_extension("fzf") end, }, From fadaabba4f96792b07a5cd4190fdb65f5b27ae5e Mon Sep 17 00:00:00 2001 From: nnduc Date: Wed, 20 May 2026 23:18:07 +0700 Subject: [PATCH 12/23] add a terminal that is really support ime --- nvim-server/init.lua | 22 +++++++++++++++++++++- nvim/init.lua | 16 +++++++++++++++- wezterm/wezterm.lua | 26 ++++++++++++++++++++++++++ 3 files changed, 62 insertions(+), 2 deletions(-) create mode 100644 wezterm/wezterm.lua diff --git a/nvim-server/init.lua b/nvim-server/init.lua index e6bb61e..33a56e5 100644 --- a/nvim-server/init.lua +++ b/nvim-server/init.lua @@ -22,7 +22,27 @@ vim.opt.scrolloff = 8 vim.opt.signcolumn = "no" vim.opt.updatetime = 250 vim.opt.undofile = true -vim.opt.clipboard = "unnamedplus" + +-------------------- Clipboard -------------------- +vim.opt.clipboard = 'unnamedplus' + +vim.g.clipboard = { + name = 'OSC 52', + copy = { + ['+'] = require('vim.ui.clipboard.osc52').copy('+'), + ['*'] = require('vim.ui.clipboard.osc52').copy('*'), + }, + paste = { + ['+'] = require('vim.ui.clipboard.osc52').paste('+'), + ['*'] = require('vim.ui.clipboard.osc52').paste('*'), + }, +} +vim.keymap.set("v", "y", '"+y') +vim.keymap.set("n", "Y", '"+yg_') +vim.keymap.set("n", "y", '"+y') +vim.keymap.set("n", "yy", '"+yy') +vim.keymap.set("n", "p", '"+p') +vim.keymap.set("n", "P", '"+P') -------------------- Keymaps -------------------- vim.keymap.set("n", "i", ":nohlsi", { silent = true }) diff --git a/nvim/init.lua b/nvim/init.lua index 0981570..7e1e2ae 100644 --- a/nvim/init.lua +++ b/nvim/init.lua @@ -42,7 +42,21 @@ vim.keymap.set("n", "o", ":only", { silent = true }) vim.keymap.set("n", "", ":tabn", { silent = true }) vim.keymap.set("n", "", ":tabp", { silent = true }) --- Clipboard operations + +-------------------- Clipboard -------------------- +vim.opt.clipboard = 'unnamedplus' + +vim.g.clipboard = { + name = 'OSC 52', + copy = { + ['+'] = require('vim.ui.clipboard.osc52').copy('+'), + ['*'] = require('vim.ui.clipboard.osc52').copy('*'), + }, + paste = { + ['+'] = require('vim.ui.clipboard.osc52').paste('+'), + ['*'] = require('vim.ui.clipboard.osc52').paste('*'), + }, +} vim.keymap.set("v", "y", '"+y') vim.keymap.set("n", "Y", '"+yg_') vim.keymap.set("n", "y", '"+y') diff --git a/wezterm/wezterm.lua b/wezterm/wezterm.lua new file mode 100644 index 0000000..1b43c4c --- /dev/null +++ b/wezterm/wezterm.lua @@ -0,0 +1,26 @@ +local wezterm = require 'wezterm' +local config = wezterm.config_builder() + +-- Font +config.font = wezterm.font '0xProto Nerd Font' +config.font_size = 13 + + +-- Appearance +config.color_scheme = 'Tokyo Night' +config.enable_tab_bar = false +config.window_padding = { + left = 4, right = 4, top = 4, bottom = 4, +} + +-- IME (set to whatever you use) +config.use_ime = true +-- config.xim_im_name = 'fcitx' -- uncomment and adjust if needed + +-- Scrollback +config.scrollback_lines = 10000 + +-- OSC 52 — on by default, but explicit is fine +config.enable_kitty_keyboard = false -- avoid surprising keybinds + +return config From 8af6952294dac9cf53ff6034bad19a13cc636b4d Mon Sep 17 00:00:00 2001 From: nnduc Date: Mon, 25 May 2026 23:25:52 +0700 Subject: [PATCH 13/23] up --- nvim/init.lua | 27 +++++++++++---------------- nvim/lazy-lock.json | 20 +++++++++----------- wezterm/wezterm.lua | 4 ++-- 3 files changed, 22 insertions(+), 29 deletions(-) diff --git a/nvim/init.lua b/nvim/init.lua index 7e1e2ae..3501ac3 100644 --- a/nvim/init.lua +++ b/nvim/init.lua @@ -42,21 +42,7 @@ vim.keymap.set("n", "o", ":only", { silent = true }) vim.keymap.set("n", "", ":tabn", { silent = true }) vim.keymap.set("n", "", ":tabp", { silent = true }) - --------------------- Clipboard -------------------- -vim.opt.clipboard = 'unnamedplus' - -vim.g.clipboard = { - name = 'OSC 52', - copy = { - ['+'] = require('vim.ui.clipboard.osc52').copy('+'), - ['*'] = require('vim.ui.clipboard.osc52').copy('*'), - }, - paste = { - ['+'] = require('vim.ui.clipboard.osc52').paste('+'), - ['*'] = require('vim.ui.clipboard.osc52').paste('*'), - }, -} +-- Clipboard operations vim.keymap.set("v", "y", '"+y') vim.keymap.set("n", "Y", '"+yg_') vim.keymap.set("n", "y", '"+y') @@ -64,6 +50,14 @@ vim.keymap.set("n", "yy", '"+yy') vim.keymap.set("n", "p", '"+p') vim.keymap.set("n", "P", '"+P') +-- Background toogling +vim.keymap.set("n", "bg", function() + vim.o.background = vim.o.background == "dark" and "light" or "dark" +end, { desc = "Toggle light/dark background" }) + +-- Join paragraph +vim.keymap.set("n", "j", "vipJ", { desc = "Join paragraph into one line" }) + -------------------- Bootstrap lazy.nvim -------------------- local lazypath = vim.fn.stdpath("data") .. "/lazy/lazy.nvim" if not vim.uv.fs_stat(lazypath) then @@ -85,9 +79,10 @@ require("lazy").setup({ priority = 1000, config = function() require("gruvbox").setup({ - contrast = "hard", + contrast = "soft", }) vim.cmd.colorscheme("gruvbox") + vim.o.background = "light" end, }, diff --git a/nvim/lazy-lock.json b/nvim/lazy-lock.json index 396615f..81c89a4 100644 --- a/nvim/lazy-lock.json +++ b/nvim/lazy-lock.json @@ -3,20 +3,18 @@ "coq.artifacts": { "branch": "artifacts", "commit": "ef5f21d638ccc456cfa5b8d0ab37093cefe48c8b" }, "coq.thirdparty": { "branch": "3p", "commit": "2bd969a2bcd2624f9c260b1000957c7e665e308e" }, "coq_nvim": { "branch": "coq", "commit": "d939a34ceb2b57d2937890337a4aa75eb55e18a8" }, - "gruvbox.nvim": { "branch": "main", "commit": "561126520034a1dac2f78ab063db025d12555998" }, - "julia-vim": { "branch": "master", "commit": "edd3512748bd07252fa79f3c01b759921192a319" }, - "lazy.nvim": { "branch": "main", "commit": "85c7ff3711b730b4030d03144f6db6375044ae82" }, + "fzf-lua": { "branch": "main", "commit": "d9508cc1d05ffcdc91a32dfd38fc1013a56b20da" }, + "gruvbox.nvim": { "branch": "main", "commit": "334d5fd49fc8033f26408425366c66c6390c57bb" }, + "julia-vim": { "branch": "master", "commit": "52b30547346b21bc93acda28d626795667f9e087" }, + "lazy.nvim": { "branch": "main", "commit": "306a05526ada86a7b30af95c5cc81ffba93fef97" }, "lualine.nvim": { "branch": "master", "commit": "47f91c416daef12db467145e16bed5bbfe00add8" }, "nvim-autopairs": { "branch": "master", "commit": "59bce2eef357189c3305e25bc6dd2d138c1683f5" }, "nvim-bqf": { "branch": "main", "commit": "f65fba733268ffcf9c5b8ac381287eca7c223422" }, - "nvim-lspconfig": { "branch": "master", "commit": "44acfe887d4056f704ccc4f17513ed41c9e2b2e6" }, - "nvim-tree.lua": { "branch": "master", "commit": "e11ce83ed9a00f065bf676ae4e6c261c766989ba" }, - "nvim-web-devicons": { "branch": "master", "commit": "746ffbb17975ebd6c40142362eee1b0249969c5c" }, - "plenary.nvim": { "branch": "master", "commit": "b9fd5226c2f76c951fc8ed5923d85e4de065e509" }, - "telescope-fzf-native.nvim": { "branch": "main", "commit": "6fea601bd2b694c6f2ae08a6c6fab14930c60e2c" }, - "telescope.nvim": { "branch": "master", "commit": "5255aa27c422de944791318024167ad5d40aad20" }, - "vim-fugitive": { "branch": "master", "commit": "61b51c09b7c9ce04e821f6cf76ea4f6f903e3cf4" }, + "nvim-lspconfig": { "branch": "master", "commit": "0203a9608d63eda57679b01e69f33a7b4c34b0d1" }, + "nvim-tree.lua": { "branch": "master", "commit": "4b30847c91d498446cb8440c03031359b045e050" }, + "nvim-web-devicons": { "branch": "master", "commit": "d7462543c9e366c0d196c7f67a945eaaf5d99414" }, + "vim-fugitive": { "branch": "master", "commit": "3b753cf8c6a4dcde6edee8827d464ba9b8c4a6f0" }, "vim-ime": { "branch": "master", "commit": "79e3b02eb50a57305113550be7ca163b267b5e30" }, "viml-surround": { "branch": "master", "commit": "98358bad347aa2b8a180c2edde84c3bd8a51fdd1" }, - "vimtex": { "branch": "master", "commit": "95b93a24740f7b89dd8331326b41bdd1337d79f6" } + "vimtex": { "branch": "master", "commit": "82d2305ff71dfb3bd91602534cc9bb9a195bcb38" } } diff --git a/wezterm/wezterm.lua b/wezterm/wezterm.lua index 1b43c4c..d8d3d30 100644 --- a/wezterm/wezterm.lua +++ b/wezterm/wezterm.lua @@ -3,11 +3,11 @@ local config = wezterm.config_builder() -- Font config.font = wezterm.font '0xProto Nerd Font' -config.font_size = 13 +config.font_size = 14 -- Appearance -config.color_scheme = 'Tokyo Night' +config.color_scheme = 'Gruvbox Material (Gogh)' config.enable_tab_bar = false config.window_padding = { left = 4, right = 4, top = 4, bottom = 4, From c5ac8a6d050ba27f9518f71f024104e0f735c2a2 Mon Sep 17 00:00:00 2001 From: nnduc Date: Sat, 6 Jun 2026 15:04:31 +0700 Subject: [PATCH 14/23] fixed gap --- i3/config | 16 +++++++--------- polybar/config.ini | 2 +- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/i3/config b/i3/config index fddeb65..26d66ed 100644 --- a/i3/config +++ b/i3/config @@ -11,7 +11,7 @@ set $mod Mod1 set $wallpaper '/home/nnduc/sync/images/wallpapers/suse.png' -set $terminal 'xfce4-terminal' +set $terminal 'wezterm' # Font for window titles. Will also be used by the bar unless a different font # is used in the bar {} block below. font pango:NotoSans 12 @@ -29,10 +29,12 @@ exec --no-startup-id dex --autostart --environment i3 #exec --no-startup-id /usr/bin/gnome-keyring-daemon --start --components=gpg,pkcs11,secrets,ssh # xss-lock grabs a logind suspend inhibit lock and will use i3lock to lock the # screen before suspend. Use systemctl lock-session to lock your screen. -exec --no-startup-id xrand --output HDMI-0 --mode 1920x1080 --rate 120 -bindsym $mod+l exec i3lock --ignore-empty-password -i $wallpaper +exec --no-startup-id xrandr --output HDMI-0 --mode 1920x1080 --rate 120 +bindsym $mod+l exec i3lock --ignore-empty-password -i $wallpaper +bindsym $mod+Shift+o exec systemctl suspend bindsym $mod+Shift+p exec systemctl poweroff + bindsym Print exec flameshot gui -c # NetworkManager is the most popular way to manage wireless networks on Linux, # and nm-applet is a desktop environment-independent system tray GUI for it. @@ -41,9 +43,8 @@ bindsym Print exec flameshot gui -c exec --no-startup-id fcitx5 -d exec --no-startup-id nm-applet exec --no-startup-id blueman-applet -exec --no-startup-id kwalletd6 +exec --no-startup-id /usr/bin/gnome-keyring-daemon --start --components=ssh,pkcs11 exec --no-startup-id feh --bg-fill $wallpaper -exec --no-startup-id owncloud exec --no-startup-id pasystray exec --no-startup-id polybar @@ -247,12 +248,9 @@ bindsym $mod+r mode "resize" #floating for_window [class="Signal"] floating enable -for_window [class="Fluffychat"] floating enable -for_window [class="Proton VPN"] floating enable for_window [class="Dino"] floating enable -for_window [class="ownCloud"] floating enable for_window [class="firefox"] move container to workspace 1 for_window [class="thunderbird"] move container to workspace 4 -for_window [class="Dolphin"] move container to workspace 3 for_window [class="Thunar"] move container to workspace 3 +for_window [class="steam_app_1364781"] border none, fullscreen enable diff --git a/polybar/config.ini b/polybar/config.ini index a3790b7..ddb2256 100644 --- a/polybar/config.ini +++ b/polybar/config.ini @@ -40,7 +40,7 @@ foreground = ${colors.foreground} tray-position = right line-size = 2pt -border-size = 2.5pt +border-size = 0 border-color = #00000000 padding-left = 1 From e55ebcc8ed2787e77307cd13c788140985ec96a7 Mon Sep 17 00:00:00 2001 From: nnduc Date: Mon, 15 Jun 2026 02:07:53 +0700 Subject: [PATCH 15/23] change wallpaper --- .zshrc | 4 +- i3/config | 12 +- i3/i3blocks.conf | 182 ++++++++++++ i3/i3status.conf | 0 i3/keybindings | 106 +++++++ i3/scripts/audio-device-switch | 100 +++++++ i3/scripts/bandwidth2 | 109 +++++++ i3/scripts/battery | 106 +++++++ i3/scripts/battery-pinebook-pro | 20 ++ i3/scripts/blur-lock | 14 + i3/scripts/cpu_usage | 62 ++++ i3/scripts/cputemp | 17 ++ i3/scripts/disk | 48 ++++ i3/scripts/empty_workspace | 16 ++ i3/scripts/gputemp | 17 ++ i3/scripts/import-gsettings | 16 ++ i3/scripts/keyhint | 27 ++ i3/scripts/keyhint-2 | 10 + i3/scripts/memory | 69 +++++ i3/scripts/openweather | 471 +++++++++++++++++++++++++++++++ i3/scripts/power-profiles | 64 +++++ i3/scripts/powermenu | 81 ++++++ i3/scripts/ppd-status | 25 ++ i3/scripts/temperature | 75 +++++ i3/scripts/volume | 46 +++ i3/scripts/volume_brightness.sh | 95 +++++++ i3/scripts/volume_brightness2.sh | 168 +++++++++++ i3/scripts/vpn | 25 ++ polybar/config.ini | 17 +- 29 files changed, 1986 insertions(+), 16 deletions(-) mode change 100644 => 100755 i3/config create mode 100644 i3/i3blocks.conf mode change 100644 => 100755 i3/i3status.conf create mode 100644 i3/keybindings create mode 100755 i3/scripts/audio-device-switch create mode 100755 i3/scripts/bandwidth2 create mode 100755 i3/scripts/battery create mode 100755 i3/scripts/battery-pinebook-pro create mode 100755 i3/scripts/blur-lock create mode 100755 i3/scripts/cpu_usage create mode 100755 i3/scripts/cputemp create mode 100755 i3/scripts/disk create mode 100755 i3/scripts/empty_workspace create mode 100755 i3/scripts/gputemp create mode 100755 i3/scripts/import-gsettings create mode 100755 i3/scripts/keyhint create mode 100755 i3/scripts/keyhint-2 create mode 100755 i3/scripts/memory create mode 100755 i3/scripts/openweather create mode 100755 i3/scripts/power-profiles create mode 100755 i3/scripts/powermenu create mode 100755 i3/scripts/ppd-status create mode 100755 i3/scripts/temperature create mode 100755 i3/scripts/volume create mode 100755 i3/scripts/volume_brightness.sh create mode 100755 i3/scripts/volume_brightness2.sh create mode 100755 i3/scripts/vpn mode change 100644 => 100755 polybar/config.ini diff --git a/.zshrc b/.zshrc index 4ea8e93..727bb9e 100644 --- a/.zshrc +++ b/.zshrc @@ -19,7 +19,7 @@ zstyle ':completion:*' menu select source /home/nnduc/git/powerlevel10k/powerlevel10k.zsh-theme - +source /home/nnduc/git/zsh-autosuggestions/zsh-autosuggestions.zsh zshaddhistory() { whence ${${(z)1}[1]} >/dev/null || return 2 @@ -34,4 +34,4 @@ export PATH="$HOME/.local/bin:$PATH" alias ls='ls --color=auto' alias doc='docker-compose' -source ~/git/zsh-autosuggestions/zsh-autosuggestions.zsh + diff --git a/i3/config b/i3/config old mode 100644 new mode 100755 index 26d66ed..9886845 --- a/i3/config +++ b/i3/config @@ -10,7 +10,7 @@ # Please see https://i3wm.org/docs/userguide.html for a complete reference! set $mod Mod1 -set $wallpaper '/home/nnduc/sync/images/wallpapers/suse.png' +set $wallpaper '/sync/images/wallpapers/pexels-lumn.jpg' set $terminal 'wezterm' # Font for window titles. Will also be used by the bar unless a different font # is used in the bar {} block below. @@ -45,7 +45,7 @@ exec --no-startup-id nm-applet exec --no-startup-id blueman-applet exec --no-startup-id /usr/bin/gnome-keyring-daemon --start --components=ssh,pkcs11 exec --no-startup-id feh --bg-fill $wallpaper -exec --no-startup-id pasystray +#exec --no-startup-id pasystray exec --no-startup-id polybar set $refresh_i3status killall -SIGUSR1 i3status @@ -237,10 +237,10 @@ bindsym $mod+r mode "resize" bindsym $mod+Tab workspace back_and_forth # class border bground text indicator child_border - client.focused #05707E #05707E #FFFFFF #000000 #05707E - client.placeholder #000000 #F1E3D3 #FFFFFF #000000 #0d100f - client.unfocused #000000 #1B4D3E #FFFFFF #000000 #0d100f - client.focused_inactive #333333 #C8C9C9 #7A858D #484E50 #5F676A + client.focused #3A7CA5 #3A7CA5 #E2EBF0 #0D1B27 #3A7CA5 + client.placeholder #0D1B27 #0D1B27 #BDD5E4 #0D1B27 #0D1B27 + client.unfocused #0D1B27 #152535 #6A8DA0 #0D1B27 #152535 + client.focused_inactive #1A3347 #1A3347 #6A8DA0 #1A3347 #1A3347 #focused_workspace #4c7899 #285577 #ffff # (No) Title Bars diff --git a/i3/i3blocks.conf b/i3/i3blocks.conf new file mode 100644 index 0000000..c9d1d3c --- /dev/null +++ b/i3/i3blocks.conf @@ -0,0 +1,182 @@ +# i3blocks config file changed for EndeavourOS-i3 setup + +# source is available here: +# https://raw.githubusercontent.com/endeavouros-team/endeavouros-i3wm-setup/main/etc/skel/.config/i3/i3blocks.conf +# Maintainer: joekamprad [joekamprad //a_t// endeavouros.com] +# Former Visual Designer: Florent Valetti [@FLVAL EndeavourOS] +# created for i3wm setup on EndeavourOS +# https://endeavouros.com + +# cheatsheet for icon fonts used on the block-bar: +# https://fontawesome.com/v4.7/cheatsheet/ + +# --> to update this run the following command: +# wget --backups=1 https://raw.githubusercontent.com/endeavouros-team/endeavouros-i3wm-setup/main/etc/skel/.config/i3/i3blocks.conf -P ~/.config/i3/ + +# Please see man i3blocks for a complete reference! +# The man page is also hosted at http://vivien.github.io/i3blocks + + +# List of valid properties: +# +# align +# color +# command +# full_text +# instance +# interval +# label +# min_width +# name +# separator +# separator_block_width +# short_text +# signal +# urgent + +# Global properties +# +# The top properties below are applied to every block, but can be overridden. +separator=false +markup=pango + +#[Weather] +#command=~/.config/i3/scripts/openweather +#interval=1800 +#color=#7275b3 + +[terminal] +full_text=  +color=#807dfe +command=i3-msg -q exec xfce4-terminal + +[browser] +full_text=  +color=#ff7f81 +command=i3-msg -q exec firefox + +[files] +full_text=  +color=#7f3fbf +command=i3-msg -q exec thunar ~/ + +#[mail] +#full_text=  +#color=#dbcb75 +#command=i3-msg -q exec thunderbird + +[simple-2] +full_text=: : +color=#717171 + +# Disk usage +# +# The directory defaults to $HOME if the instance is not specified. +# The script may be called with a optional argument to set the alert +# (defaults to 10 for 10%). +[disk] +label= +instance=/ +command=~/.config/i3/scripts/disk +interval=30 + +# Memory usage +# +# The type defaults to "mem" if the instance is not specified. +[memory] +label= +command=~/.config/i3/scripts/memory +interval=2 + +[cpu_usage] +label= +command=~/.config/i3/scripts/cpu_usage +#min_width=CPU: 100.00% +interval=2 + +[CPU-temperature] +label= +command=~/.config/i3/scripts/temperature +interval=30 +#T_WARN=70 +#T_CRIT=90 +#SENSOR_CHIP="" +# where SENSOR_CHIP can be find with sensors output +# can be used also for GPU temperature or other temperature sensors lm-sensors detects. + +# showing name of connected network (enable for wifi use) +#[net] +#label= +#command=echo "$(LANG=C nmcli d | grep connected | awk '{print $4}')" +#interval=30 + +[bandwidth] +command=~/.config/i3/scripts/bandwidth2 +interval=persist + +#[vpn] +#command=~/.config/i3/scripts/vpn +#init_color=#FFFF00 +#on_color=#00FF00 +#label=VPN: +#interval=5 + +# Battery indicator +[battery] +command=~/.config/i3/scripts/battery +# change this to battery-pinebook-pro if you are running on pinebook-pro +label= +interval=30 + +[simple-2] +full_text=: : +color=#717171 + +[pavucontrol] +full_text=♪ +command=pavucontrol + +[volume] +command=~/.config/i3/scripts/volume +interval=2 + +# display keyboard layout name +# for keyboard layouts switcher +# see i3 config file +# this needs xkblayout-state installed from the AUR: +# https://aur.archlinux.org/packages/xkblayout-state-git +#[keyboard-layout] +#command=~/.config/i3/scripts/keyboard-layout +#interval=2 + +[keybindings] +full_text= +command=~/.config/i3/scripts/keyhint + +# power-profiles-daemon implementation: +# needs package power-profiles-daemon installed and the service running see here: +# https://wiki.archlinux.org/title/CPU_frequency_scaling#power-profiles-daemon + +#set power-profile +[ppd_menu] +full_text= +command=~/.config/i3/scripts/power-profiles +color=#407437 + +#Show the current power-profile +[ppd-status] +command=~/.config/i3/scripts/ppd-status +interval=5 + +[time] +#label= +command=date '+%a %d %b %H:%M:%S' +interval=1 + +[shutdown_menu] +full_text= +command=~/.config/i3/scripts/powermenu + +[simple-2] +full_text=: : +color=#717171 diff --git a/i3/i3status.conf b/i3/i3status.conf old mode 100644 new mode 100755 diff --git a/i3/keybindings b/i3/keybindings new file mode 100644 index 0000000..f5edbc6 --- /dev/null +++ b/i3/keybindings @@ -0,0 +1,106 @@ +EndeavourOS i3wm Keybindings cheat sheet: + +--> to update this run the following command: +wget --backups=1 https://raw.githubusercontent.com/endeavouros-team/endeavouros-i3wm-setup/main/.config/i3/keybindings -P ~/.config/i3/ + +All sources and updates are available at GitHub: +https://github.com/endeavouros-team/endeavouros-i3wm-setup + +For reference consult our WIKI: +https://discovery.endeavouros.com/window-tiling-managers/i3-wm/ + + = windows key + +# start xfce4-terminal ++Return + +# kill focused window ++q + +# Application menu search by typing (fancy Rofi menu): ++d + +# Window switcher menu (fancy Rofi menu): ++t + +# fancy exit-menu on bottom right: ++Shift+e + +# Lock the system +# lock with a picture or blurring the screen (options in config) ++l + +# reload the configuration file ++Shift+c + +# restart i3 inplace (preserves your layout/session, can be used to upgrade i3) ++Shift+r + +# keybinding in fancy rofi (automated) +F1 + +# full keybinding list in editor: ++F1 + +# change window focus ++j focus left ++k focus down ++b focus up ++o focus right + +# alternatively, you can use the cursor keys: ++Left focus left ++Down focus down ++Up focus up ++Right focus right + +# move a focused window ++Shift+j move left ++Shift+k move down ++Shift+b move up ++Shift+o move right + +# alternatively, you can use the cursor keys: ++Shift+Left move left ++Shift+Down move down ++Shift+Up move up ++Shift+Right move right + +# split in horizontal orientation ++h split h + +# split in vertical orientation ++v split v + +# enter fullscreen mode for the focused container ++f fullscreen toggle + +# change container layout (stacked, tabbed, toggle split) ++s layout stacking ++g layout tabbed ++e layout toggle split + +# toggle tiling / floating ++Shift+space floating toggle + +# change focus between tiling / floating windows ++space focus mode_toggle + +# focus the parent container ++a focus parent + +# focus the child container +#+d focus child + +# resize floating window ++right mouse button + +## Multimedia Keys + +# Redirect sound to headphones ++p + +## App shortcuts ++w starts Firefox ++n starts Thunar + Button screenshot diff --git a/i3/scripts/audio-device-switch b/i3/scripts/audio-device-switch new file mode 100755 index 0000000..6077d38 --- /dev/null +++ b/i3/scripts/audio-device-switch @@ -0,0 +1,100 @@ +#!/usr/bin/env bash + +# audio-device-switch - audio device switch with a keybind +# Adapted from this: +# https://gist.githubusercontent.com/kbravh/1117a974f89cc53664e55823a55ac320/raw/9d04a10ae925074536047ae8100c6b0dbfc303d6/audio-device-switch.sh +# Readme: https://gist.github.com/kbravh/1117a974f89cc53664e55823a55ac320 +# Creator: https://github.com/kbravh + +# Audio Output Switcher +# This script will cycle to the next available audio output device. +# It can be tied to a hotkey to easily be triggered. +# This is handy, for example, for swapping between speakers and headphones. +# This script will work on systems running PulseAudio or Pipewire services. + + + +# Check which sound server is running +if pgrep pulseaudio >/dev/null; then + sound_server="pulseaudio" +elif pgrep pipewire >/dev/null; then + sound_server="pipewire" +else + echo "Neither PulseAudio nor PipeWire is running." + exit 1 +fi + +# Grab a count of how many audio sinks we have +if [[ "$sound_server" == "pulseaudio" ]]; then + sink_count=$(pacmd list-sinks | grep -c "index:[[:space:]][[:digit:]]") + # Create an array of the actual sink IDs + sinks=() + mapfile -t sinks < <(pacmd list-sinks | grep 'index:[[:space:]][[:digit:]]' | sed -n -e 's/.*index:[[:space:]]\([[:digit:]]\)/\1/p') + # Get the ID of the active sink + active_sink=$(pacmd list-sinks | sed -n -e 's/[[:space:]]*\*[[:space:]]index:[[:space:]]\([[:digit:]]\)/\1/p') + +elif [[ "$sound_server" == "pipewire" ]]; then + sink_count=$(pactl list sinks | grep -c "Sink #[[:digit:]]") + # Create an array of the actual sink IDs + sinks=() + mapfile -t sinks < <(pactl list sinks | grep 'Sink #[[:digit:]]' | sed -n -e 's/.*Sink #\([[:digit:]]\)/\1/p') + # Get the ID of the active sink + active_sink_name=$(pactl info | grep 'Default Sink:' | sed -n -e 's/.*Default Sink:[[:space:]]\+\(.*\)/\1/p') + active_sink=$(pactl list sinks | grep -B 2 "$active_sink_name" | sed -n -e 's/Sink #\([[:digit:]]\)/\1/p' | head -n 1) +fi + +# Get the ID of the last sink in the array +final_sink=${sinks[$((sink_count - 1))]} + +# Find the index of the active sink +for index in "${!sinks[@]}"; do + if [[ "${sinks[$index]}" == "$active_sink" ]]; then + active_sink_index=$index + fi +done + +# Default to the first sink in the list +next_sink=${sinks[0]} +next_sink_index=0 + +# If we're not at the end of the list, move up the list +if [[ $active_sink -ne $final_sink ]]; then + next_sink_index=$((active_sink_index + 1)) + next_sink=${sinks[$next_sink_index]} +fi + +#change the default sink +if [[ "$sound_server" == "pulseaudio" ]]; then + pacmd "set-default-sink ${next_sink}" +elif [[ "$sound_server" == "pipewire" ]]; then + # Get the name of the next sink + next_sink_name=$(pactl list sinks | grep -C 2 "Sink #$next_sink" | sed -n -e 's/.*Name:[[:space:]]\+\(.*\)/\1/p' | head -n 1) + pactl set-default-sink "$next_sink_name" +fi + +#move all inputs to the new sink +if [[ "$sound_server" == "pulseaudio" ]]; then + for app in $(pacmd list-sink-inputs | sed -n -e 's/index:[[:space:]]\([[:digit:]]\)/\1/p'); do + pacmd "move-sink-input $app $next_sink" + done +elif [[ "$sound_server" == "pipewire" ]]; then + for app in $(pactl list sink-inputs | sed -n -e 's/.*Sink Input #\([[:digit:]]\)/\1/p'); do + pactl "move-sink-input $app $next_sink" + done +fi + +# Create a list of the sink descriptions +sink_descriptions=() +if [[ "$sound_server" == "pulseaudio" ]]; then + mapfile -t sink_descriptions < <(pacmd list-sinks | sed -n -e 's/.*alsa.name[[:space:]]=[[:space:]]"\(.*\)"/\1/p') +elif [[ "$sound_server" == "pipewire" ]]; then + mapfile -t sink_descriptions < <(pactl list sinks | sed -n -e 's/.*Description:[[:space:]]\+\(.*\)/\1/p') +fi + +# Find the index that matches our new active sink +for sink_index in "${!sink_descriptions[@]}"; do + if [[ "$sink_index" == "$next_sink_index" ]]; then + notify-send -i audio-volume-high "Sound output switched to:" "${sink_descriptions[$sink_index]}" + exit + fi +done diff --git a/i3/scripts/bandwidth2 b/i3/scripts/bandwidth2 new file mode 100755 index 0000000..bd79e1a --- /dev/null +++ b/i3/scripts/bandwidth2 @@ -0,0 +1,109 @@ +#!/usr/bin/env bash +# +# Copyright (C) 2015 James Murphy +# Licensed under the terms of the GNU GPL v2 only. +# +# i3blocks blocklet script to monitor bandwidth usage +# detecting active device device +# option to set used unit + +iface="${BLOCK_INSTANCE}" +iface="${IFACE:-$iface}" +dt="${DT:-3}" +unit="${UNIT:-MB}" +LABEL="${LABEL:-}" # down arrow up arrow +printf_command="${PRINTF_COMMAND:-"printf \"${LABEL}%1.0f/%1.0f %s/s\\n\", rx, wx, unit;"}" + +function default_interface { + ip route | awk '/^default via/ {print $5; exit}' +} + +function check_proc_net_dev { + if [ ! -f "/proc/net/dev" ]; then + echo "/proc/net/dev not found" + exit 1 + fi +} + +function list_interfaces { + check_proc_net_dev + echo "Interfaces in /proc/net/dev:" + grep -o "^[^:]\\+:" /proc/net/dev | tr -d " :" +} + +while getopts i:t:u:p:lh opt; do + case "$opt" in + i) iface="$OPTARG" ;; + t) dt="$OPTARG" ;; + u) unit="$OPTARG" ;; + p) printf_command="$OPTARG" ;; + l) list_interfaces && exit 0 ;; + h) printf \ +"Usage: bandwidth3 [-i interface] [-t time] [-u unit] [-p printf_command] [-l] [-h] +Options: +-i\tNetwork interface to measure. Default determined using \`ip route\`. +-t\tTime interval in seconds between measurements. Default: 3 +-u\tUnits to measure bytes in. Default: Mb +\tAllowed units: Kb, KB, Mb, MB, Gb, GB, Tb, TB +\tUnits may have optional it/its/yte/ytes on the end, e.g. Mbits, KByte +-p\tAwk command to be called after a measurement is made. +\tDefault: printf \"%%-5.1f/%%5.1f %%s/s\\\\n\", rx, wx, unit; +\tExposed variables: rx, wx, tx, unit, iface +-l\tList available interfaces in /proc/net/dev +-h\tShow this help text +" && exit 0;; + esac +done + +check_proc_net_dev + +iface="${iface:-$(default_interface)}" +while [ -z "$iface" ]; do + echo No default interface + sleep "$dt" + iface=$(default_interface) +done + +case "$unit" in + Kb|Kbit|Kbits) bytes_per_unit=$((1024 / 8));; + KB|KByte|KBytes) bytes_per_unit=$((1024));; + Mb|Mbit|Mbits) bytes_per_unit=$((1024 * 1024 / 8));; + MB|MByte|MBytes) bytes_per_unit=$((1024 * 1024));; + Gb|Gbit|Gbits) bytes_per_unit=$((1024 * 1024 * 1024 / 8));; + GB|GByte|GBytes) bytes_per_unit=$((1024 * 1024 * 1024));; + Tb|Tbit|Tbits) bytes_per_unit=$((1024 * 1024 * 1024 * 1024 / 8));; + TB|TByte|TBytes) bytes_per_unit=$((1024 * 1024 * 1024 * 1024));; + *) echo Bad unit "$unit" && exit 1;; +esac + +scalar=$((bytes_per_unit * dt)) +init_line=$(cat /proc/net/dev | grep "^[ ]*$iface:") +if [ -z "$init_line" ]; then + echo Interface not found in /proc/net/dev: "$iface" + exit 1 +fi + +init_received=$(awk '{print $2}' <<< $init_line) +init_sent=$(awk '{print $10}' <<< $init_line) + +(while true; do cat /proc/net/dev; sleep "$dt"; done) |\ + stdbuf -oL grep "^[ ]*$iface:" |\ + awk -v scalar="$scalar" -v unit="$unit" -v iface="$iface" ' +BEGIN { + old_received='"$init_received"' + old_sent='"$init_sent"' +} +{ + received=$2 + sent=$10 + rx=(received-old_received)/scalar + wx=(sent-old_sent)/scalar + tx=rx+wx + old_received=received + old_sent=sent + if (rx >= 0 && wx >= 0) { + '"$printf_command"' + fflush(stdout) + } +} +' diff --git a/i3/scripts/battery b/i3/scripts/battery new file mode 100755 index 0000000..2d55dab --- /dev/null +++ b/i3/scripts/battery @@ -0,0 +1,106 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 2016 James Murphy +# Licensed under the GPL version 2 only +# +# A battery indicator blocklet script for i3blocks + +from subprocess import check_output +import os +import re + +config = dict(os.environ) +status = check_output(['acpi'], universal_newlines=True) + +if not status: + # stands for no battery found + color = config.get("color_10", "red") + fulltext = "\uf00d \uf240".format(color) + percentleft = 100 +else: + # if there is more than one battery in one laptop, the percentage left is + # available for each battery separately, although state and remaining + # time for overall block is shown in the status of the first battery + batteries = status.split("\n") + state_batteries=[] + commasplitstatus_batteries=[] + percentleft_batteries=[] + time = "" + for battery in batteries: + if battery!='': + state_batteries.append(battery.split(": ")[1].split(", ")[0]) + commasplitstatus = battery.split(", ") + if not time: + time = commasplitstatus[-1].strip() + # check if it matches a time + time = re.match(r"(\d+):(\d+)", time) + if time: + time = ":".join(time.groups()) + timeleft = " ({})".format(time) + else: + timeleft = "" + + p = int(commasplitstatus[1].rstrip("%\n")) + if p>0: + percentleft_batteries.append(p) + commasplitstatus_batteries.append(commasplitstatus) + state = state_batteries[0] + commasplitstatus = commasplitstatus_batteries[0] + if percentleft_batteries: + percentleft = int(sum(percentleft_batteries)/len(percentleft_batteries)) + else: + percentleft = 0 + + # stands for charging + color = config.get("color_charging", "yellow") + FA_LIGHTNING = "\uf0e7".format(color) + + # stands for plugged in + FA_PLUG = "\uf1e6" + + # stands for using battery + FA_BATTERY = "\uf240" + + # stands for unknown status of battery + FA_QUESTION = "\uf128" + + + if state == "Discharging": + fulltext = FA_BATTERY + " " + elif state == "Full": + fulltext = FA_PLUG + " " + timeleft = "" + elif state == "Unknown": + fulltext = FA_QUESTION + " " + FA_BATTERY + " " + timeleft = "" + else: + fulltext = FA_LIGHTNING + " " + FA_PLUG + " " + + def color(percent): + if percent < 10: + # exit code 33 will turn background red + return config.get("color_10", "#FFFFFF") + if percent < 20: + return config.get("color_20", "#FF3300") + if percent < 30: + return config.get("color_30", "#FF6600") + if percent < 40: + return config.get("color_40", "#FF9900") + if percent < 50: + return config.get("color_50", "#FFCC00") + if percent < 60: + return config.get("color_60", "#FFFF00") + if percent < 70: + return config.get("color_70", "#FFFF33") + if percent < 80: + return config.get("color_80", "#FFFF66") + return config.get("color_full", "#FFFFFF") + + form = '{}%' + fulltext += form.format(color(percentleft), percentleft) + #fulltext += timeleft + +print(fulltext) +print(fulltext) +if percentleft < 10: + exit(33) diff --git a/i3/scripts/battery-pinebook-pro b/i3/scripts/battery-pinebook-pro new file mode 100755 index 0000000..45317d5 --- /dev/null +++ b/i3/scripts/battery-pinebook-pro @@ -0,0 +1,20 @@ +#!/usr/bin/env bash + +# simple Shellscript for i3blocks on Pinebook pro +# 05012020 geri123 //at// gmx.net Gerhard S. +# battery-symbols: you need the awesome-terminal-font package installed + +PERCENT=$(cat /sys/class/power_supply/cw2015-battery/capacity) +STATUS=$(cat /sys/class/power_supply/cw2015-battery/status) +case $(( + $PERCENT >= 0 && $PERCENT <= 20 ? 1 : + $PERCENT > 20 && $PERCENT <= 40 ? 2 : + $PERCENT > 40 && $PERCENT <= 60 ? 3 : + $PERCENT > 60 && $PERCENT <= 80 ? 4 : 5)) in +# + (1) echo $STATUS:"" :$PERCENT%;; + (2) echo $STATUS:"" :$PERCENT%;; + (3) echo $STATUS:"" :$PERCENT%;; + (4) echo $STATUS:"" :$PERCENT%;; + (5) echo $STATUS:"" :$PERCENT%;; +esac diff --git a/i3/scripts/blur-lock b/i3/scripts/blur-lock new file mode 100755 index 0000000..2f6cc31 --- /dev/null +++ b/i3/scripts/blur-lock @@ -0,0 +1,14 @@ +#!/usr/bin/env bash + +# simple screenlocker using i3lock that creates ablurred screenshot to overlay + +PICTURE=/tmp/i3lock.png +SCREENSHOT="scrot -z $PICTURE" + +BLUR="5x4" + +$SCREENSHOT +magick $PICTURE -blur $BLUR $PICTURE +i3lock -i $PICTURE +shred $PICTURE +rm $PICTURE diff --git a/i3/scripts/cpu_usage b/i3/scripts/cpu_usage new file mode 100755 index 0000000..8d8a267 --- /dev/null +++ b/i3/scripts/cpu_usage @@ -0,0 +1,62 @@ +#!/usr/bin/perl +# +# Copyright 2014 Pierre Mavro +# Copyright 2014 Vivien Didelot +# Copyright 2014 Andreas Guldstrand +# +# Licensed under the terms of the GNU GPL v3, or any later version. + +use strict; +use warnings; +use utf8; +use Getopt::Long; + +# default values +my $t_warn = $ENV{T_WARN} // 50; +my $t_crit = $ENV{T_CRIT} // 80; +my $cpu_usage = -1; +my $decimals = $ENV{DECIMALS} // 0; +my $label = $ENV{LABEL} // ""; + +sub help { + print "Usage: cpu_usage [-w ] [-c ] [-d ]\n"; + print "-w : warning threshold to become yellow\n"; + print "-c : critical threshold to become red\n"; + print "-d : Use decimals for percentage (default is $decimals) \n"; + exit 0; +} + +GetOptions("help|h" => \&help, + "w=i" => \$t_warn, + "c=i" => \$t_crit, + "d=i" => \$decimals, +); + +# Get CPU usage +$ENV{LC_ALL}="en_US"; # if mpstat is not run under en_US locale, things may break, so make sure it is +open (MPSTAT, 'mpstat 1 1 |') or die; +while () { + if (/^.*\s+(\d+\.\d+)[\s\x00]?$/) { + $cpu_usage = 100 - $1; # 100% - %idle + last; + } +} +close(MPSTAT); + +$cpu_usage eq -1 and die 'Can\'t find CPU information'; + +# Print short_text, full_text +print "${label}"; +printf "%02.${decimals}f%%\n", $cpu_usage; +print "${label}"; +printf "%02.${decimals}f%%\n", $cpu_usage; + +# Print color, if needed +if ($cpu_usage >= $t_crit) { + print "#FF0000\n"; + exit 33; +} elsif ($cpu_usage >= $t_warn) { + print "#FFFC00\n"; +} + +exit 0; diff --git a/i3/scripts/cputemp b/i3/scripts/cputemp new file mode 100755 index 0000000..8a7d821 --- /dev/null +++ b/i3/scripts/cputemp @@ -0,0 +1,17 @@ +#!/usr/bin/env bash + +# script to monitor temperatures in waybar/i3blocks e.t.c. +# example only use `sensors` to find your names to replace `Tdie|Tctl|Package` +# example output part from sensors: +# zenpower-pci-00c3 +# Adapter: PCI adapter +# SVI2_Core: 1.03 V +# SVI2_SoC: 994.00 mV +# Tdie: +53.1°C +# Tctl: +53.1°C +# Tccd1: +42.5°C +# Tccd2: +43.2°C + +temp=$(sensors 2>/dev/null | grep -E 'Tdie|Tctl|Package id 0' | grep -oP '\+?[0-9]+\.\d+(?=°C)' | tr -d '+' | head -n1) + +echo "${temp}°C" diff --git a/i3/scripts/disk b/i3/scripts/disk new file mode 100755 index 0000000..e18c7aa --- /dev/null +++ b/i3/scripts/disk @@ -0,0 +1,48 @@ +#!/usr/bin/env bash +# Copyright (C) 2014 Julien Bonjean + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +DIR="${DIR:-$BLOCK_INSTANCE}" +DIR="${DIR:-$HOME}" +ALERT_LOW="${ALERT_LOW:-$1}" +ALERT_LOW="${ALERT_LOW:-10}" # color will turn red under this value (default: 10%) + +LOCAL_FLAG="-l" +if [ "$1" = "-n" ] || [ "$2" = "-n" ]; then + LOCAL_FLAG="" +fi + +df -h -P $LOCAL_FLAG "$DIR" | awk -v label="$LABEL" -v alert_low=$ALERT_LOW ' +/\/.*/ { + # full text + print label $4 + + # short text + print label $4 + + use=$5 + + # no need to continue parsing + exit 0 +} + +END { + gsub(/%$/,"",use) + if (100 - use < alert_low) { + # color + print "#FF0000" + } +} +' diff --git a/i3/scripts/empty_workspace b/i3/scripts/empty_workspace new file mode 100755 index 0000000..fd21131 --- /dev/null +++ b/i3/scripts/empty_workspace @@ -0,0 +1,16 @@ +#!/usr/bin/env bash + +# Copyright (C) 2025 Johannes Kamprad +# SPDX-License-Identifier: GPL-3.0-or-later + +# empty_workspace - open a new workspace automatically named with next number on i3 + + +MAX_DESKTOPS=20 + +WORKSPACES=$(seq -s '\n' 1 1 ${MAX_DESKTOPS}) + +EMPTY_WORKSPACE=$( (i3-msg -t get_workspaces | tr ',' '\n' | grep num | awk -F: '{print int($2)}' ; \ + echo -e ${WORKSPACES} ) | sort -n | uniq -u | head -n 1) + +i3-msg workspace ${EMPTY_WORKSPACE} diff --git a/i3/scripts/gputemp b/i3/scripts/gputemp new file mode 100755 index 0000000..a63166c --- /dev/null +++ b/i3/scripts/gputemp @@ -0,0 +1,17 @@ +#!/usr/bin/env bash + +# script to monitor temperatures in waybar/i3blocks e.t.c. +# example only use `sensors` to find your sensor to replace `i915-pci-0600` +# example output part from sensors: +# i915-pci-0600 +# Adapter: PCI adapter +# in0: 630.00 mV +# fan1: 0 RPM +# temp1: +55.0°C +# energy1: 1.26 MJ + +# examples using Nvidia tools: +#echo "$(nvidia-smi --format=csv,noheader --query-gpu=temperature.gpu) °C" +#echo "$(nvidia-settings -q gpucoretemp -t) °C" +# example using sensor name: +sensors 2>/dev/null | awk '/i915-pci-0600/{flag=1} flag && /temp1/ {gsub("\\+", "", $2); print $2, $3; exit}' diff --git a/i3/scripts/import-gsettings b/i3/scripts/import-gsettings new file mode 100755 index 0000000..b848168 --- /dev/null +++ b/i3/scripts/import-gsettings @@ -0,0 +1,16 @@ +#!/bin/sh + +# needed for nwg-looks +# usage: import-gsettings +config="${XDG_CONFIG_HOME:-$HOME/.config}/gtk-3.0/settings.ini" +if [ ! -f "$config" ]; then exit 1; fi + +gnome_schema="org.gnome.desktop.interface" +gtk_theme="$(grep 'gtk-theme-name' "$config" | cut -d'=' -f2)" +icon_theme="$(grep 'gtk-icon-theme-name' "$config" | cut -d'=' -f2)" +cursor_theme="$(grep 'gtk-cursor-theme-name' "$config" | cut -d'=' -f2)" +font_name="$(grep 'gtk-font-name' "$config" | cut -d'=' -f2)" +gsettings set "$gnome_schema" gtk-theme "$gtk_theme" +gsettings set "$gnome_schema" icon-theme "$icon_theme" +gsettings set "$gnome_schema" cursor-theme "$cursor_theme" +gsettings set "$gnome_schema" font-name "$font_name" \ No newline at end of file diff --git a/i3/scripts/keyhint b/i3/scripts/keyhint new file mode 100755 index 0000000..34a123a --- /dev/null +++ b/i3/scripts/keyhint @@ -0,0 +1,27 @@ +#!/usr/bin/env bash + +# simple yad gui to show default keybindings + +Main() { + source /usr/share/endeavouros/scripts/eos-script-lib-yad || return 1 + + local command=( + eos_yad --title="EndeavourOS i3-wm keybindings:" --no-buttons --geometry=400x345-15-400 --list + --column=key: --column=description: --column=command: + "ESC" "close this app" "" + "=" "modkey" "(set mod Mod4)" + "+enter" "open a terminal" "" + "+Shift+n" "new empty workspace" "" + "+w" "open Browser" "" + "+n" "open Filebrowser" "" + "+d" "app menu" "" + "+q" "close focused app" "" + "Print-key" "screenshot" "" + "+Shift+e" "logout menu" "" + "F1" "open keybinding helper" "" + ) + + "${command[@]}" +} + +Main "$@" diff --git a/i3/scripts/keyhint-2 b/i3/scripts/keyhint-2 new file mode 100755 index 0000000..a5fd92f --- /dev/null +++ b/i3/scripts/keyhint-2 @@ -0,0 +1,10 @@ +#!/bin/sh + +# keyhint rofi tool to search used keybindings in i3wm + +I3_CONFIG=$HOME/.config/i3/config +mod_key=$(sed -nre 's/^set \$mod (.*)/\1/p' ${I3_CONFIG}) +grep "^bindsym" ${I3_CONFIG} \ + | sed "s/-\(-\w\+\)\+//g;s/\$mod/${mod_key}/g;s/Mod1/Alt/g;s/exec //;s/bindsym //;s/^\s\+//;s/^\([^ ]\+\) \(.\+\)$/\2: \1/;s/^\s\+//" \ + | tr -s ' ' \ + | rofi -dmenu -theme ~/.config/rofi/rofikeyhint.rasi diff --git a/i3/scripts/memory b/i3/scripts/memory new file mode 100755 index 0000000..e60be50 --- /dev/null +++ b/i3/scripts/memory @@ -0,0 +1,69 @@ +#!/usr/bin/env bash +# Copyright (C) 2014 Julien Bonjean + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +TYPE="${BLOCK_INSTANCE:-mem}" + +awk -v type=$TYPE ' +/^MemTotal:/ { + mem_total=$2 +} +/^MemFree:/ { + mem_free=$2 +} +/^Buffers:/ { + mem_free+=$2 +} +/^Cached:/ { + mem_free+=$2 +} +/^SwapTotal:/ { + swap_total=$2 +} +/^SwapFree:/ { + swap_free=$2 +} +END { + if (type == "swap") { + free=swap_free/1024/1024 + used=(swap_total-swap_free)/1024/1024 + total=swap_total/1024/1024 + } else { + free=mem_free/1024/1024 + used=(mem_total-mem_free)/1024/1024 + total=mem_total/1024/1024 + } + + pct=0 + if (total > 0) { + pct=used/total*100 + } + + # full text + # printf("%.1fG/%.1fG (%.f%%)\n", used, total, pct) + + # short text + printf("%02.f%%\n", pct) + + # color + if (pct > 90) { + print("#FF0000") + } else if (pct > 80) { + print("#FFAE00") + } else if (pct > 70) { + print("#FFF600") + } +} +' /proc/meminfo diff --git a/i3/scripts/openweather b/i3/scripts/openweather new file mode 100755 index 0000000..e41b833 --- /dev/null +++ b/i3/scripts/openweather @@ -0,0 +1,471 @@ +#!/usr/bin/env bash + +# openweater - OpenWeatherMap Weather Fetcher for Waybar/Status Bars +# +# Copyright (C) 2025 Johannes Kamprad +# +# SPDX-License-Identifier: GPL-3.0-or-later + + +# openweater - OpenWeatherMap Weather Fetcher for Waybar/Status Bars +# Secure API key handling with configurable locations +# including setup script and help +# Options: +# -h, --help Show this help message +# -c, --city-id ID Override city ID (required if not in config) +# -k, --api-key KEY Override API key (not recommended, use config file) +# -u, --units UNITS Units: metric, imperial, kelvin (default: $DEFAULT_UNITS) +# -f, --force-refresh Force refresh (ignore cache) +# --setup Interactive setup wizard +# --show-config Show current configuration + +set -euo pipefail + +# Set C locale to avoid German decimal formatting issues +export LC_NUMERIC=C +export LC_ALL=C + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +NC='\033[0m' # No Color + +# Default configuration (no default location) +DEFAULT_UNITS="metric" +CONFIG_DIR="${XDG_CONFIG_HOME:-$HOME/.config}" +CONFIG_FILE="$CONFIG_DIR/openweather/config" +CACHE_DIR="${XDG_CACHE_HOME:-$HOME/.cache}/openweather" +CACHE_FILE="$CACHE_DIR/weather_data" +CACHE_DURATION=600 # 10 minutes + +# Logging functions +log_error() { + echo -e "${RED}[ERROR]${NC} $*" >&2 +} + +log_warn() { + echo -e "${YELLOW}[WARN]${NC} $*" >&2 +} + +# Show help +show_help() { + cat << EOF +Usage: $(basename "$0") [OPTIONS] + +Secure OpenWeatherMap weather fetcher with configurable locations. + +Options: + -h, --help Show this help message + -c, --city-id ID Override city ID (required if not in config) + -k, --api-key KEY Override API key (not recommended, use config file) + -u, --units UNITS Units: metric, imperial, kelvin (default: $DEFAULT_UNITS) + -f, --force-refresh Force refresh (ignore cache) + --setup Interactive setup wizard + --show-config Show current configuration + +Configuration: + Config file: $CONFIG_FILE + + Create config file with: + OPENWEATHER_API_KEY="your_api_key_here" + OPENWEATHER_CITY_ID="your_city_id" # Required + OPENWEATHER_UNITS="metric" # Optional + +Examples: + $(basename "$0") # Use config file settings + $(basename "$0") --city-id 5128581 # New York + $(basename "$0") --units imperial # Fahrenheit + $(basename "$0") --setup # Run setup wizard + +Get your free API key at: https://openweathermap.org/api +Find city IDs at: https://openweathermap.org/find + +EOF +} + +# Check dependencies +check_dependencies() { + local missing_deps=() + + for cmd in jq curl; do + if ! command -v "$cmd" >/dev/null 2>&1; then + missing_deps+=("$cmd") + fi + done + + if [[ ${#missing_deps[@]} -gt 0 ]]; then + log_error "Missing required dependencies: ${missing_deps[*]}" + echo "Install with: sudo pacman -S ${missing_deps[*]}" + exit 1 + fi +} + +# Load configuration +load_config() { + # Set defaults (no default city ID) + OPENWEATHER_CITY_ID="" + OPENWEATHER_UNITS="$DEFAULT_UNITS" + + # Load from config file if it exists + if [[ -f "$CONFIG_FILE" ]]; then + source "$CONFIG_FILE" + fi + + # Override with environment variables if set + OPENWEATHER_API_KEY="${OPENWEATHER_API_KEY:-}" + OPENWEATHER_CITY_ID="${OPENWEATHER_CITY_ID:-}" + OPENWEATHER_UNITS="${OPENWEATHER_UNITS:-$DEFAULT_UNITS}" +} + +# Validate API key +validate_api_key() { + if [[ -z "$OPENWEATHER_API_KEY" ]]; then + log_error "No API key found!" + echo + echo "To fix this:" + echo "1. Get free API key: https://openweathermap.org/api" + echo "2. Run setup wizard: $0 --setup" + echo "3. Or set environment variable: export OPENWEATHER_API_KEY=your_key" + echo "4. Or create config file: $CONFIG_FILE" + exit 1 + fi + + # Basic validation (OpenWeatherMap keys are typically 32 chars) + if [[ ${#OPENWEATHER_API_KEY} -ne 32 ]]; then + log_warn "API key length seems incorrect (expected 32 characters, got ${#OPENWEATHER_API_KEY})" + fi +} + +# Validate city ID +validate_city_id() { + if [[ -z "$OPENWEATHER_CITY_ID" ]]; then + log_error "No city ID found!" + echo + echo "To fix this:" + echo "1. Run setup wizard: $0 --setup" + echo "2. Or set environment variable: export OPENWEATHER_CITY_ID=your_city_id" + echo "3. Or add OPENWEATHER_CITY_ID=\"your_city_id\" to: $CONFIG_FILE" + echo "4. Or provide city ID via command line: $0 --city-id your_city_id" + echo + echo "Find city IDs at: https://openweathermap.org/find" + exit 1 + fi + + # Basic validation (city IDs are typically numeric) + if [[ ! "$OPENWEATHER_CITY_ID" =~ ^[0-9]+$ ]]; then + log_warn "City ID format seems incorrect (expected numeric, got: $OPENWEATHER_CITY_ID)" + fi +} + +# Setup wizard +run_setup() { + echo -e "${GREEN}=== OpenWeatherMap Setup Wizard ===${NC}" + echo + + # Create config directory + mkdir -p "$(dirname "$CONFIG_FILE")" + + # Get API key + echo "Get your free API key at: https://openweathermap.org/api" + echo + echo -n "Enter your OpenWeatherMap API key: " + read -r api_key + + if [[ -z "$api_key" ]]; then + log_error "API key cannot be empty" + exit 1 + fi + + # Get city ID (required) + echo + echo "Find your city ID at: https://openweathermap.org/find" + echo -n "Enter city ID: " + read -r city_id + + if [[ -z "$city_id" ]]; then + log_error "City ID cannot be empty" + exit 1 + fi + + # Get units (optional) + echo + echo "Available units: metric (°C), imperial (°F), kelvin (K)" + echo -n "Enter units [metric]: " + read -r units + units="${units:-metric}" + + # Write config file + cat > "$CONFIG_FILE" << EOF +# OpenWeatherMap Configuration +# Generated by $(basename "$0") setup wizard on $(date) + +# Your API key from https://openweathermap.org/api +OPENWEATHER_API_KEY="$api_key" + +# City ID from https://openweathermap.org/find +OPENWEATHER_CITY_ID="$city_id" + +# Units: metric, imperial, kelvin +OPENWEATHER_UNITS="$units" +EOF + + # Set secure permissions + chmod 600 "$CONFIG_FILE" + + echo + echo -e "${GREEN}✅ Configuration saved to: $CONFIG_FILE${NC}" + echo -e "${GREEN}✅ File permissions set to 600 (user read/write only)${NC}" + echo + echo "Testing configuration..." + + # Test the configuration + OPENWEATHER_API_KEY="$api_key" + OPENWEATHER_CITY_ID="$city_id" + OPENWEATHER_UNITS="$units" + + if fetch_weather_data; then + echo -e "${GREEN}✅ Configuration test successful!${NC}" + else + log_error "Configuration test failed. Please check your API key and city ID." + exit 1 + fi +} + +# Show current configuration +show_config() { + echo "=== Current Configuration ===" + echo "Config file: $CONFIG_FILE" + echo "Cache file: $CACHE_FILE" + echo "Cache duration: ${CACHE_DURATION}s" + echo + + if [[ -f "$CONFIG_FILE" ]]; then + echo "Configuration:" + echo " API Key: ${OPENWEATHER_API_KEY:0:8}... (${#OPENWEATHER_API_KEY} chars)" + echo " City ID: $OPENWEATHER_CITY_ID" + echo " Units: $OPENWEATHER_UNITS" + else + echo "❌ No configuration file found at: $CONFIG_FILE" + echo "Run: $0 --setup" + fi +} + +# Check cache validity +is_cache_valid() { + [[ -f "$CACHE_FILE" ]] && \ + [[ $(($(date +%s) - $(stat -c %Y "$CACHE_FILE" 2>/dev/null || echo 0))) -lt $CACHE_DURATION ]] +} + +# Fetch weather data from API +fetch_weather_data() { + local url="https://api.openweathermap.org/data/2.5/weather?id=${OPENWEATHER_CITY_ID}&units=${OPENWEATHER_UNITS}&appid=${OPENWEATHER_API_KEY}" + + local response + if ! response=$(curl -sf "$url" 2>/dev/null); then + log_error "Failed to fetch weather data from API" + return 1 + fi + + # Validate JSON response + if ! echo "$response" | jq . >/dev/null 2>&1; then + log_error "Invalid JSON response from API" + return 1 + fi + + # Check for API error + local api_code + api_code=$(echo "$response" | jq -r '.cod // empty') + if [[ "$api_code" != "200" ]]; then + local api_message + api_message=$(echo "$response" | jq -r '.message // "Unknown API error"') + log_error "API Error ($api_code): $api_message" + return 1 + fi + + # Cache the response + mkdir -p "$CACHE_DIR" + echo "$response" > "$CACHE_FILE" + + return 0 +} + +# Get weather data (from cache or API) +get_weather_data() { + local force_refresh="${1:-false}" + + if [[ "$force_refresh" != "true" ]] && is_cache_valid; then + cat "$CACHE_FILE" + else + if fetch_weather_data; then + cat "$CACHE_FILE" + else + # Fallback to cache if available + if [[ -f "$CACHE_FILE" ]]; then + log_warn "Using stale cache data due to API failure" + cat "$CACHE_FILE" + else + return 1 + fi + fi + fi +} + +# Calculate wind direction +get_wind_direction() { + local degrees="$1" + local directions=(N NNE NE ENE E ESE SE SSE S SSW SW WSW W WNW NW NNW) + local index + index=$(awk "BEGIN {print int(($degrees % 360) / 22.5)}") + echo "${directions[$index]}" +} + +# Get weather icon +get_weather_icon() { + local condition="$1" + case "$condition" in + 'Clear') echo "☀" ;; # Clear sky + 'Clouds') echo "☁" ;; # Cloudy + 'Rain'|'Drizzle') echo "🌧" ;; # Rain + 'Snow') echo "❄" ;; # Snow + 'Thunderstorm') echo "⛈" ;; # Thunder + 'Mist'|'Fog') echo "🌫" ;; # Fog + *) echo "🌤" ;; # Default + esac +} + +# Safe number formatting (handles locale issues) +safe_printf() { + local format="$1" + local number="$2" + + # Validate number is actually numeric + if [[ ! "$number" =~ ^-?[0-9]+(\.[0-9]+)?$ ]]; then + echo "0.0" + return 1 + fi + + # Use awk for reliable formatting regardless of locale + awk "BEGIN {printf \"$format\", $number}" +} + +# Format weather output +format_weather() { + local weather_data="$1" + + # Parse weather data with error checking + local condition temp wind_speed_ms wind_deg + condition=$(echo "$weather_data" | jq -r '.weather[0].main // "Unknown"') + temp=$(echo "$weather_data" | jq -r '.main.temp // "0"') + wind_speed_ms=$(echo "$weather_data" | jq -r '.wind.speed // "0"') + wind_deg=$(echo "$weather_data" | jq -r '.wind.deg // "0"') + + # Validate parsed data + [[ "$condition" == "null" ]] && condition="Unknown" + [[ "$temp" == "null" ]] && temp="0" + [[ "$wind_speed_ms" == "null" ]] && wind_speed_ms="0" + [[ "$wind_deg" == "null" ]] && wind_deg="0" + + # Format temperature with safe formatting + local temp_formatted + temp_formatted=$(safe_printf "%.1f" "$temp") + + # Convert wind speed to km/h with safe formatting + local wind_speed_kmh + wind_speed_kmh=$(awk "BEGIN {printf \"%.1f\", ($wind_speed_ms + 0) * 3.6}") + + # Get wind direction + local wind_dir + wind_dir=$(get_wind_direction "$wind_deg") + + # Get weather icon + local icon + icon=$(get_weather_icon "$condition") + + # Format unit symbol + local unit_symbol + case "$OPENWEATHER_UNITS" in + "imperial") unit_symbol="°F" ;; + "kelvin") unit_symbol="K" ;; + *) unit_symbol="°C" ;; + esac + + # Output formatted weather + echo "${icon} ${temp_formatted}${unit_symbol}, ${wind_speed_kmh} km/h ${wind_dir}" +} + +# Main function +main() { + local city_id_override="" + local api_key_override="" + local units_override="" + local force_refresh="false" + + # Parse command line arguments + while [[ $# -gt 0 ]]; do + case $1 in + -h|--help) + show_help + exit 0 + ;; + -c|--city-id) + city_id_override="$2" + shift 2 + ;; + -k|--api-key) + api_key_override="$2" + shift 2 + ;; + -u|--units) + units_override="$2" + shift 2 + ;; + -f|--force-refresh) + force_refresh="true" + shift + ;; + --setup) + check_dependencies + run_setup + exit 0 + ;; + --show-config) + load_config + show_config + exit 0 + ;; + *) + log_error "Unknown option: $1" + show_help + exit 1 + ;; + esac + done + + # Check dependencies + check_dependencies + + # Load configuration + load_config + + # Apply overrides + [[ -n "$city_id_override" ]] && OPENWEATHER_CITY_ID="$city_id_override" + [[ -n "$api_key_override" ]] && OPENWEATHER_API_KEY="$api_key_override" + [[ -n "$units_override" ]] && OPENWEATHER_UNITS="$units_override" + + # Validate configuration + validate_api_key + validate_city_id + + # Get and format weather data + local weather_data + if weather_data=$(get_weather_data "$force_refresh"); then + format_weather "$weather_data" + else + echo "⚠️ Weather data unavailable" + exit 1 + fi +} + +# Run main function +main "$@" diff --git a/i3/scripts/power-profiles b/i3/scripts/power-profiles new file mode 100755 index 0000000..6c901b3 --- /dev/null +++ b/i3/scripts/power-profiles @@ -0,0 +1,64 @@ +#!/usr/bin/env bash + +# Simple power-profiles-daemon switcher using rofi and static theme, with notification +# +# Copyright (C) 2025 Johannes Kamprad +# +# SPDX-License-Identifier: GPL-3.0-or-later + +# needs rofi config: +# $HOME/.config/rofi/powermenu.rasi + +ROFI_THEME="${HOME}/.config/rofi/power-profiles.rasi" + +# Dependency checks +command -v powerprofilesctl >/dev/null 2>&1 || { echo "powerprofilesctl not found"; exit 1; } +command -v rofi >/dev/null 2>&1 || { echo "rofi not found"; exit 1; } +if ! command -v notify-send >/dev/null 2>&1; then + notify_send_missing=true +fi + +current_profile="$(powerprofilesctl get 2>/dev/null)" +ROFI_ARGS=(-dmenu -i -theme "$ROFI_THEME" -p "Change Profile" -mesg "Current used: $current_profile" -markup-rows) + +# Menu entries +cancel=" Cancel" +perf=" Performance" +balanced=" Balanced" +powersave=" Power Saver" +# sets chancel to be on top +options="$cancel" + +if powerprofilesctl list | grep -q "performance"; then + options="$options\n$perf" +fi +if powerprofilesctl list | grep -q "balanced"; then + options="$options\n$balanced" +fi +if powerprofilesctl list | grep -q "power-saver"; then + options="$options\n$powersave" +fi + +# Show menu +chosen="$(echo -e "$options" | rofi "${ROFI_ARGS[@]}")" + +# Run selection +case $chosen in + "$perf") + powerprofilesctl set performance + ;; + "$balanced") + powerprofilesctl set balanced + ;; + "$powersave") + powerprofilesctl set power-saver + ;; + "$cancel"|"") + exit 0 + ;; +esac + +# Send notification if available +if [[ "$chosen" != "$cancel" && -z "${notify_send_missing}" ]]; then + notify-send -i dialog-information "Power Profile Changed" "New profile: ${chosen}" +fi diff --git a/i3/scripts/powermenu b/i3/scripts/powermenu new file mode 100755 index 0000000..6111806 --- /dev/null +++ b/i3/scripts/powermenu @@ -0,0 +1,81 @@ +#!/usr/bin/env bash + +# +# powermenu - a very simple rofi powermenu +# +# Copyright (C) 2025 Johannes Kamprad +# +# SPDX-License-Identifier: GPL-3.0-or-later + +# needs rofi config: +# $HOME/.config/rofi/powermenu.rasi +# set to be used in i3wm + +ROFI_THEME="${HOME}/.config/rofi/powermenu.rasi" +# Define possible lock scripts/commands (edit this list as you like) +LOCK_SCRIPTS=("${HOME}/.config/i3/scripts/blur-lock" "i3lock") + +# Find available lock script +find_lock_script() { + for script in "${LOCK_SCRIPTS[@]}"; do + # Handle command names vs full paths + if [[ "$script" =~ ^[a-zA-Z0-9_-]+$ ]]; then + # It's a command name, check if available + if command -v "$script" >/dev/null 2>&1; then + echo "$script" + return 0 + fi + else + # It's a path, check if file exists and is executable + if [[ -x "$script" ]]; then + echo "$script" + return 0 + fi + fi + done + return 1 +} + +# Menu entries +chancel=" Cancel" +lock=" Lock" +logout=" Logout" +reboot=" Reboot" +shutdown=" Shutdown" +suspend=" Suspend" +hibernate=" Hibernate" + + +# Add lock only if script is found +if lockcmd="$(find_lock_script)"; then + options="$chancel\n$lock\n$logout\n$reboot\n$shutdown\n$suspend\n$hibernate" +else + options="$chancel\n$logout\n$reboot\n$shutdown\n$suspend\n$hibernate" +fi + +chosen="$(echo -e "$options" | rofi -dmenu -i -p "Power Menu" \ + -theme $ROFI_THEME)" + +case $chosen in + "$lock") + $lockcmd + ;; + "$cancel"|"") + exit 0 + ;; + "$logout") + i3-msg exit + ;; + "$reboot") + systemctl reboot + ;; + "$shutdown") + systemctl poweroff + ;; + "$suspend") + systemctl suspend + ;; + "$hibernate") + systemctl hibernate + ;; +esac diff --git a/i3/scripts/ppd-status b/i3/scripts/ppd-status new file mode 100755 index 0000000..92ab169 --- /dev/null +++ b/i3/scripts/ppd-status @@ -0,0 +1,25 @@ +#!/usr/bin/env bash + + +# power-profiles-daemon implementation: +# needs package power-profiles-daemon installed and the service running see here: +# https://wiki.archlinux.org/title/CPU_frequency_scaling#power-profiles-daemon +# used in i3-blocks: ~/.config/i3/i3blocks.conf together with: ~/.config/i3/scripts/power-profiles + + +# assign tags or translations to each profile +declare -A tags +tags=( + [performance]="Performance" + [balanced]="Balanced" + [power-saver]="Power saver" +) + +# Get current profile +current_profile=$(/usr/bin/powerprofilesctl get) + +# Get tag from the array +profile_tag=${tags[$current_profile]} + +# Show tag on i3block +echo "${profile_tag:-$current_profile}" diff --git a/i3/scripts/temperature b/i3/scripts/temperature new file mode 100755 index 0000000..69dcc63 --- /dev/null +++ b/i3/scripts/temperature @@ -0,0 +1,75 @@ +#!/usr/bin/env perl + +# Copyright 2014 Pierre Mavro +# Copyright 2014 Vivien Didelot +# Copyright 2014 Andreas Guldstrand +# Copyright 2014 Benjamin Chretien +# SPDX-License-Identifier: GPL-3.0-or-later + +# Edited by Andreas Lindlbauer + +use strict; +use warnings; +use utf8; +use Getopt::Long; + +binmode(STDOUT, ":utf8"); + +# default values +my $t_warn = $ENV{T_WARN} || 70; +my $t_crit = $ENV{T_CRIT} || 90; +my $chip = $ENV{SENSOR_CHIP} || ""; +my $temperature = -9999; +my $label = "😀 "; + +sub help { + print "Usage: temperature [-w ] [-c ] [--chip ]\n"; + print "-w : warning threshold to become yellow\n"; + print "-c : critical threshold to become red\n"; + print "--chip : sensor chip\n"; + exit 0; +} + +GetOptions("help|h" => \&help, + "w=i" => \$t_warn, + "c=i" => \$t_crit, + "chip=s" => \$chip); + +# Get chip temperature +open (SENSORS, "sensors -u $chip |") or die; +while () { + if (/^\s+temp1_input:\s+[\+]*([\-]*\d+\.\d)/) { + $temperature = $1; + last; + } +} +close(SENSORS); + +$temperature eq -9999 and die 'Cannot find temperature'; + +if ($temperature < 45) { + $label = ''; +} elsif ($temperature < 55) { + $label = ''; +} elsif ($temperature < 65) { + $label = ''; +} elsif ($temperature < 75) { + $label = ''; +} else { + $label = ''; +} +# Print short_text, full_text +print "${label}"; +print " $temperature°C\n"; +print "${label}"; +print " $temperature°C\n"; + +# Print color, if needed +if ($temperature >= $t_crit) { + print "#FF0000\n"; + exit 33; +} elsif ($temperature >= $t_warn) { + print "#FFFC00\n"; +} + +exit 0; diff --git a/i3/scripts/volume b/i3/scripts/volume new file mode 100755 index 0000000..97f2693 --- /dev/null +++ b/i3/scripts/volume @@ -0,0 +1,46 @@ +#!/usr/bin/env bash +# i3blocks volume block for PipeWire (PulseAudio compatible) + +STEP=${1:-5%} + +# Default sink +SINK=$(pactl info | awk '/Default Sink/ {print $3}') +[[ -z "$SINK" ]] && { echo "No audio"; exit 0; } + +# Handle scroll/middle-click +case "$BLOCK_BUTTON" in + 3) pactl set-sink-mute "$SINK" toggle ;; # right click = mute/unmute + 4) pactl set-sink-volume "$SINK" +$STEP ;; # scroll up + 5) pactl set-sink-volume "$SINK" -$STEP ;; # scroll down +esac + +# Get current volume (front-left channel) +VOL=$(pactl list sinks | awk -v s="$SINK" ' + $0 ~ "Name: " s {found=1} + found && /Volume:/ {gsub("%","",$5); print $5; exit} +') + +# Get mute state +MUTED=$(pactl list sinks | awk -v s="$SINK" ' + $0 ~ "Name: " s {found=1} + found && /Mute:/ {print $2; exit} +') + +# Choose symbol +AUDIO_HIGH='' +AUDIO_MED='' +AUDIO_LOW='' +AUDIO_MUTED='' +MED_THRESH=50 +LOW_THRESH=0 + +if [[ "$MUTED" == "no" ]]; then + SYMB=$AUDIO_HIGH + [[ $VOL -le $MED_THRESH ]] && SYMB=$AUDIO_MED + [[ $VOL -le $LOW_THRESH ]] && SYMB=$AUDIO_LOW +else + SYMB=$AUDIO_MUTED +fi + +# Single-line output for i3blocks +echo "${SYMB} ${VOL}%" diff --git a/i3/scripts/volume_brightness.sh b/i3/scripts/volume_brightness.sh new file mode 100755 index 0000000..676c6d3 --- /dev/null +++ b/i3/scripts/volume_brightness.sh @@ -0,0 +1,95 @@ +#!/usr/bin/env bash + +# original source: https://gitlab.com/Nmoleo/i3-volume-brightness-indicator +# changed to use brightnessctl [xbacklight is non functional on modern hardware] +# by joekamprad [Aug 2025] + +bar_color="#7f7fff" +volume_step=1 +brightness_step=5 +max_volume=100 +notification_timeout=1000 # in ms + +# Uses regex to get volume from pactl +function get_volume { + pactl get-sink-volume @DEFAULT_SINK@ | grep -Po '[0-9]{1,3}(?=%)' | head -1 +} + +# Uses regex to get mute status from pactl +function get_mute { + pactl get-sink-mute @DEFAULT_SINK@ | grep -Po '(?<=Mute: )(yes|no)' +} + +# Uses brightnessctl instead of xbacklight +function get_brightness { + brightnessctl g | awk '{print int($1)}' + # You could also use: brightnessctl info | grep -Po '(?<=Current brightness: )[0-9]+' +} + +# Calculates brightness percentage +function get_brightness_percent { + current=$(brightnessctl g) + max=$(brightnessctl m) + percent=$(( 100 * current / max )) + echo $percent +} + +function get_volume_icon { + volume=$(get_volume) + mute=$(get_mute) + if [ "$volume" -eq 0 ] || [ "$mute" == "yes" ] ; then + volume_icon="" + elif [ "$volume" -lt 50 ]; then + volume_icon="" + else + volume_icon="" + fi +} + +function get_brightness_icon { + brightness_icon="" +} + +function show_volume_notif { + volume=$(get_volume) + get_volume_icon + notify-send -i volume_icon -t 1000 "Volume" "$volume_icon $volume%" -h int:value:$volume -h string:x-canonical-private-synchronous:volume +} + + +function show_brightness_notif { + get_brightness_icon + brightness=$(get_brightness_percent) + notify-send -i brightness_icon -t $notification_timeout -h string:x-dunst-stack-tag:brightness_notif -h int:value:$brightness "$brightness_icon $brightness%" +} + + + +case $1 in + volume_up) + pactl set-sink-mute @DEFAULT_SINK@ 0 + volume=$(get_volume) + if [ $(( "$volume" + "$volume_step" )) -gt $max_volume ]; then + pactl set-sink-volume @DEFAULT_SINK@ $max_volume% + else + pactl set-sink-volume @DEFAULT_SINK@ +$volume_step% + fi + show_volume_notif + ;; + volume_down) + pactl set-sink-volume @DEFAULT_SINK@ -$volume_step% + show_volume_notif + ;; + volume_mute) + pactl set-sink-mute @DEFAULT_SINK@ toggle + show_volume_notif + ;; + brightness_up) + brightnessctl s +$brightness_step% > /dev/null + show_brightness_notif + ;; + brightness_down) + brightnessctl s $brightness_step%- > /dev/null + show_brightness_notif + ;; +esac diff --git a/i3/scripts/volume_brightness2.sh b/i3/scripts/volume_brightness2.sh new file mode 100755 index 0000000..cd78d77 --- /dev/null +++ b/i3/scripts/volume_brightness2.sh @@ -0,0 +1,168 @@ +#!/usr/bin/env bash + +# original source: https://gitlab.com/Nmoleo/i3-volume-brightness-indicator +# alternative to volume_brightness.sh that uses brightnessctl for both keyboard & screen brightness + +# See README.md for usage instructions +volume_step=1 +keyboard_brightness_step=20 +screen_brightness_step=1 +max_volume=100 +notification_timeout=1000 + +# Specify Icon Theme here: +volume_theme_icon="audio-volume-high" +screen_brightness_theme_icon="display-brightness" +keyboard_brightness_theme_icon="display-brightness" + +# Keyboard Backlight device detection here: +device_cache="/tmp/kbd_backlight_device" + +if [ -f "$device_cache" ]; then + # If there is cache, load it into device + device=$(cat "$device_cache") +else + # If there is no cache, create one + device=$(brightnessctl --list | grep -Po '\w+::kbd_backlight') + echo "$device" > "$device_cache" +fi + +# Uses regex to get volume from pactl +function get_volume { + pactl get-sink-volume @DEFAULT_SINK@ | grep -Po '[0-9]{1,3}(?=%)' | head -1 +} + +# Uses regex to get mute status from pactl +function get_mute { + pactl get-sink-mute @DEFAULT_SINK@ | grep -Po '(?<=Mute: )(yes|no)' +} + +# Get keyboard_brightness from brightnessctl +function get_keyboard_brightness { + if [ -n "$device" ]; then + keyboard_curr=$(brightnessctl -d "$device" get) + keyboard_max=$(brightnessctl -d "$device" max) + echo $(( keyboard_curr * 100 / keyboard_max)) + fi +} + + +# Grabs screen brightness and formats it out of 100 +function get_screen_brightness { + screen_curr=$(brightnessctl -q get) + screen_max=$(brightnessctl -q max) + echo $(( screen_curr * 100 / screen_max )) +} + +# Returns a mute icon, a volume-low icon, or a volume-high icon, depending on the volume +function get_volume_icon { + volume=$(get_volume) + mute=$(get_mute) + if [ "$volume" -eq 0 ] || [ "$mute" == "yes" ] ; then + volume_icon="" + elif [ "$volume" -lt 50 ] ; then + volume_icon="" + else + volume_icon="" + fi +} + +# Always returns the same icon - I couldn't get the brightness-low icon to work with fontawesome +function get_keyboard_brightness_icon { + kb_brightness=$(get_keyboard_brightness) + if [ "$kb_brightness" -eq 0 ] ; then + keyboard_brightness_icon="" # unfilled circle + elif [ "$kb_brightness" -lt 50 ] ; then + keyboard_brightness_icon="" # fa-adjust (low brightness) + else + keyboard_brightness_icon="" # full circle (high brightness) + fi +} + +function get_screen_brightness_icon { + sc_brightness=$(get_screen_brightness) + if [ "$sc_brightness" -eq 0 ] ; then + screen_brightness_icon="" # unfilled circle + elif [ "$sc_brightness" -lt 50 ] ; then + screen_brightness_icon="" # fa-adjust (low brightness) + else + screen_brightness_icon="" # full circle (high brightness) + fi +} + +# Displays a volume notification using notify-send +function show_volume_notif { + mute=$(get_mute) + volume=$(get_volume) + get_volume_icon + notify-send -i $volume_theme_icon -t $notification_timeout "Volume" "$volume_icon $volume%" -h int:value:$volume -h string:x-canonical-private-synchronous:volume +} + +# Displays a keyboard_brightness notification +function show_keyboard_brightness_notif { + keyboard_brightness=$(get_keyboard_brightness) + # Debug Purposes: + # echo $keyboard_brightness + get_keyboard_brightness_icon + notify-send -i $keyboard_brightness_theme_icon -t $notification_timeout "Keyboard Brightness" -h string:x-dunst-stack-tag:keyboard_brightness_notif -h int:value:$keyboard_brightness "$keyboard_brightness_icon $keyboard_brightness%" +} + +# Displays a screen_brightness notification +function show_screen_brightness_notif { + screen_brightness=$(get_screen_brightness) + # Debug Purposes: + # echo $screen_brightness + get_screen_brightness_icon + notify-send -i $screen_brightness_theme_icon -t $notification_timeout "Screen Brightness" -h string:x-dunst-stack-tag:screen_brightness_notif -h int:value:$screen_brightness "$screen_brightness_icon $screen_brightness%" +} + +# Main function - Takes user input, "volume_up", "volume_down", "keyboard_brightness_up", "keyboard_brightness_down", "brightness_up", or "brightness_down" +case $1 in + volume_up) + # Unmutes and increases volume, then displays the notification + pactl set-sink-mute @DEFAULT_SINK@ 0 + volume=$(get_volume) + if [ $(( "$volume" + "$volume_step" )) -gt $max_volume ]; then + pactl set-sink-volume @DEFAULT_SINK@ $max_volume% + else + pactl set-sink-volume @DEFAULT_SINK@ +$volume_step% + fi + show_volume_notif + ;; + + volume_down) + # Raises volume and displays the notification + pactl set-sink-volume @DEFAULT_SINK@ -$volume_step% + show_volume_notif + ;; + + volume_mute) + # Toggles mute and displays the notification + pactl set-sink-mute @DEFAULT_SINK@ toggle + show_volume_notif + ;; + + keyboard_brightness_up) + # Increases keyboard brightness and displays the notification + brightnessctl -d "$device" set ${keyboard_brightness_step}+ + show_keyboard_brightness_notif + ;; + + keyboard_brightness_down) + # Decreases keyboard brightness and displays the notification + brightnessctl -d "$device" set ${keyboard_brightness_step}- + show_keyboard_brightness_notif + ;; + + screen_brightness_up) + # Increases screen brightness and displays the notification + brightnessctl -q set ${screen_brightness_step}%+ + show_screen_brightness_notif + ;; + + screen_brightness_down) + # Decreases screen brightness and displays the notification + brightnessctl -q set ${screen_brightness_step}%- + show_screen_brightness_notif + ;; +esac diff --git a/i3/scripts/vpn b/i3/scripts/vpn new file mode 100755 index 0000000..bcf54ee --- /dev/null +++ b/i3/scripts/vpn @@ -0,0 +1,25 @@ +#!/usr/bin/env sh + +# Parses output from nmcli to show the current connected VPN name/status for i3block +# Source: https://github.com/vivien/i3blocks-contrib/tree/master/nm-vpn +# uncomment in $HOME/.config/i3/i3blocks.conf if you want to use it + +init_color=${init_color:-#FFFF00} +on_color=${on_color:-#00FF00} +export init_color on_color +nmcli -t connection show --active | awk -F ':' ' +BEGIN { + init_color=ENVIRON["init_color"] + on_color=ENVIRON["on_color"] +} +$3=="vpn" { + name=$1 + status="INIT" + color=init_color +} +$3=="tun" || ($4~/^tap/ || $3~/^tap/) { + if(!name) name=$1 + status="ON" + color=on_color +} +END {if(status) printf("%s\n%s\n%s\n", name, status, color)}' diff --git a/polybar/config.ini b/polybar/config.ini old mode 100644 new mode 100755 index ddb2256..13eaf9c --- a/polybar/config.ini +++ b/polybar/config.ini @@ -18,13 +18,13 @@ [colors] background-alt = #00000000 -foreground = A3D1C6 -primary = #B3D8A8 -altprime = #B3D8A8 -secondary = #FBFFE4 -altsecondary = #BEABA7EF -alert = #A54242 -disabled = FBFFE4 +foreground = #1A2533 +primary = #2D6A8A +altprime = #2D6A8A +secondary = #0D1B27 +altsecondary = #3A7CA5EF +alert = #A52020 +disabled = #4A6878 [bar/example] bottom = false @@ -34,10 +34,11 @@ radius = 8 ; dpi = 96 -background = #1B4D3E +background = #00000000 foreground = ${colors.foreground} tray-position = right +tray-background = #C8D8E8 line-size = 2pt border-size = 0 From b9e75b0ff725b8d350a315daf4c26a6fb141239f Mon Sep 17 00:00:00 2001 From: nnduc Date: Mon, 15 Jun 2026 02:10:09 +0700 Subject: [PATCH 16/23] remove distro script --- i3/scripts/audio-device-switch | 100 ------- i3/scripts/bandwidth2 | 109 ------- i3/scripts/battery | 106 ------- i3/scripts/battery-pinebook-pro | 20 -- i3/scripts/blur-lock | 14 - i3/scripts/cpu_usage | 62 ---- i3/scripts/cputemp | 17 -- i3/scripts/disk | 48 ---- i3/scripts/empty_workspace | 16 -- i3/scripts/gputemp | 17 -- i3/scripts/import-gsettings | 16 -- i3/scripts/keyhint | 27 -- i3/scripts/keyhint-2 | 10 - i3/scripts/memory | 69 ----- i3/scripts/openweather | 471 ------------------------------- i3/scripts/power-profiles | 64 ----- i3/scripts/powermenu | 81 ------ i3/scripts/ppd-status | 25 -- i3/scripts/temperature | 75 ----- i3/scripts/volume | 46 --- i3/scripts/volume_brightness.sh | 95 ------- i3/scripts/volume_brightness2.sh | 168 ----------- i3/scripts/vpn | 25 -- 23 files changed, 1681 deletions(-) delete mode 100755 i3/scripts/audio-device-switch delete mode 100755 i3/scripts/bandwidth2 delete mode 100755 i3/scripts/battery delete mode 100755 i3/scripts/battery-pinebook-pro delete mode 100755 i3/scripts/blur-lock delete mode 100755 i3/scripts/cpu_usage delete mode 100755 i3/scripts/cputemp delete mode 100755 i3/scripts/disk delete mode 100755 i3/scripts/empty_workspace delete mode 100755 i3/scripts/gputemp delete mode 100755 i3/scripts/import-gsettings delete mode 100755 i3/scripts/keyhint delete mode 100755 i3/scripts/keyhint-2 delete mode 100755 i3/scripts/memory delete mode 100755 i3/scripts/openweather delete mode 100755 i3/scripts/power-profiles delete mode 100755 i3/scripts/powermenu delete mode 100755 i3/scripts/ppd-status delete mode 100755 i3/scripts/temperature delete mode 100755 i3/scripts/volume delete mode 100755 i3/scripts/volume_brightness.sh delete mode 100755 i3/scripts/volume_brightness2.sh delete mode 100755 i3/scripts/vpn diff --git a/i3/scripts/audio-device-switch b/i3/scripts/audio-device-switch deleted file mode 100755 index 6077d38..0000000 --- a/i3/scripts/audio-device-switch +++ /dev/null @@ -1,100 +0,0 @@ -#!/usr/bin/env bash - -# audio-device-switch - audio device switch with a keybind -# Adapted from this: -# https://gist.githubusercontent.com/kbravh/1117a974f89cc53664e55823a55ac320/raw/9d04a10ae925074536047ae8100c6b0dbfc303d6/audio-device-switch.sh -# Readme: https://gist.github.com/kbravh/1117a974f89cc53664e55823a55ac320 -# Creator: https://github.com/kbravh - -# Audio Output Switcher -# This script will cycle to the next available audio output device. -# It can be tied to a hotkey to easily be triggered. -# This is handy, for example, for swapping between speakers and headphones. -# This script will work on systems running PulseAudio or Pipewire services. - - - -# Check which sound server is running -if pgrep pulseaudio >/dev/null; then - sound_server="pulseaudio" -elif pgrep pipewire >/dev/null; then - sound_server="pipewire" -else - echo "Neither PulseAudio nor PipeWire is running." - exit 1 -fi - -# Grab a count of how many audio sinks we have -if [[ "$sound_server" == "pulseaudio" ]]; then - sink_count=$(pacmd list-sinks | grep -c "index:[[:space:]][[:digit:]]") - # Create an array of the actual sink IDs - sinks=() - mapfile -t sinks < <(pacmd list-sinks | grep 'index:[[:space:]][[:digit:]]' | sed -n -e 's/.*index:[[:space:]]\([[:digit:]]\)/\1/p') - # Get the ID of the active sink - active_sink=$(pacmd list-sinks | sed -n -e 's/[[:space:]]*\*[[:space:]]index:[[:space:]]\([[:digit:]]\)/\1/p') - -elif [[ "$sound_server" == "pipewire" ]]; then - sink_count=$(pactl list sinks | grep -c "Sink #[[:digit:]]") - # Create an array of the actual sink IDs - sinks=() - mapfile -t sinks < <(pactl list sinks | grep 'Sink #[[:digit:]]' | sed -n -e 's/.*Sink #\([[:digit:]]\)/\1/p') - # Get the ID of the active sink - active_sink_name=$(pactl info | grep 'Default Sink:' | sed -n -e 's/.*Default Sink:[[:space:]]\+\(.*\)/\1/p') - active_sink=$(pactl list sinks | grep -B 2 "$active_sink_name" | sed -n -e 's/Sink #\([[:digit:]]\)/\1/p' | head -n 1) -fi - -# Get the ID of the last sink in the array -final_sink=${sinks[$((sink_count - 1))]} - -# Find the index of the active sink -for index in "${!sinks[@]}"; do - if [[ "${sinks[$index]}" == "$active_sink" ]]; then - active_sink_index=$index - fi -done - -# Default to the first sink in the list -next_sink=${sinks[0]} -next_sink_index=0 - -# If we're not at the end of the list, move up the list -if [[ $active_sink -ne $final_sink ]]; then - next_sink_index=$((active_sink_index + 1)) - next_sink=${sinks[$next_sink_index]} -fi - -#change the default sink -if [[ "$sound_server" == "pulseaudio" ]]; then - pacmd "set-default-sink ${next_sink}" -elif [[ "$sound_server" == "pipewire" ]]; then - # Get the name of the next sink - next_sink_name=$(pactl list sinks | grep -C 2 "Sink #$next_sink" | sed -n -e 's/.*Name:[[:space:]]\+\(.*\)/\1/p' | head -n 1) - pactl set-default-sink "$next_sink_name" -fi - -#move all inputs to the new sink -if [[ "$sound_server" == "pulseaudio" ]]; then - for app in $(pacmd list-sink-inputs | sed -n -e 's/index:[[:space:]]\([[:digit:]]\)/\1/p'); do - pacmd "move-sink-input $app $next_sink" - done -elif [[ "$sound_server" == "pipewire" ]]; then - for app in $(pactl list sink-inputs | sed -n -e 's/.*Sink Input #\([[:digit:]]\)/\1/p'); do - pactl "move-sink-input $app $next_sink" - done -fi - -# Create a list of the sink descriptions -sink_descriptions=() -if [[ "$sound_server" == "pulseaudio" ]]; then - mapfile -t sink_descriptions < <(pacmd list-sinks | sed -n -e 's/.*alsa.name[[:space:]]=[[:space:]]"\(.*\)"/\1/p') -elif [[ "$sound_server" == "pipewire" ]]; then - mapfile -t sink_descriptions < <(pactl list sinks | sed -n -e 's/.*Description:[[:space:]]\+\(.*\)/\1/p') -fi - -# Find the index that matches our new active sink -for sink_index in "${!sink_descriptions[@]}"; do - if [[ "$sink_index" == "$next_sink_index" ]]; then - notify-send -i audio-volume-high "Sound output switched to:" "${sink_descriptions[$sink_index]}" - exit - fi -done diff --git a/i3/scripts/bandwidth2 b/i3/scripts/bandwidth2 deleted file mode 100755 index bd79e1a..0000000 --- a/i3/scripts/bandwidth2 +++ /dev/null @@ -1,109 +0,0 @@ -#!/usr/bin/env bash -# -# Copyright (C) 2015 James Murphy -# Licensed under the terms of the GNU GPL v2 only. -# -# i3blocks blocklet script to monitor bandwidth usage -# detecting active device device -# option to set used unit - -iface="${BLOCK_INSTANCE}" -iface="${IFACE:-$iface}" -dt="${DT:-3}" -unit="${UNIT:-MB}" -LABEL="${LABEL:-}" # down arrow up arrow -printf_command="${PRINTF_COMMAND:-"printf \"${LABEL}%1.0f/%1.0f %s/s\\n\", rx, wx, unit;"}" - -function default_interface { - ip route | awk '/^default via/ {print $5; exit}' -} - -function check_proc_net_dev { - if [ ! -f "/proc/net/dev" ]; then - echo "/proc/net/dev not found" - exit 1 - fi -} - -function list_interfaces { - check_proc_net_dev - echo "Interfaces in /proc/net/dev:" - grep -o "^[^:]\\+:" /proc/net/dev | tr -d " :" -} - -while getopts i:t:u:p:lh opt; do - case "$opt" in - i) iface="$OPTARG" ;; - t) dt="$OPTARG" ;; - u) unit="$OPTARG" ;; - p) printf_command="$OPTARG" ;; - l) list_interfaces && exit 0 ;; - h) printf \ -"Usage: bandwidth3 [-i interface] [-t time] [-u unit] [-p printf_command] [-l] [-h] -Options: --i\tNetwork interface to measure. Default determined using \`ip route\`. --t\tTime interval in seconds between measurements. Default: 3 --u\tUnits to measure bytes in. Default: Mb -\tAllowed units: Kb, KB, Mb, MB, Gb, GB, Tb, TB -\tUnits may have optional it/its/yte/ytes on the end, e.g. Mbits, KByte --p\tAwk command to be called after a measurement is made. -\tDefault: printf \"%%-5.1f/%%5.1f %%s/s\\\\n\", rx, wx, unit; -\tExposed variables: rx, wx, tx, unit, iface --l\tList available interfaces in /proc/net/dev --h\tShow this help text -" && exit 0;; - esac -done - -check_proc_net_dev - -iface="${iface:-$(default_interface)}" -while [ -z "$iface" ]; do - echo No default interface - sleep "$dt" - iface=$(default_interface) -done - -case "$unit" in - Kb|Kbit|Kbits) bytes_per_unit=$((1024 / 8));; - KB|KByte|KBytes) bytes_per_unit=$((1024));; - Mb|Mbit|Mbits) bytes_per_unit=$((1024 * 1024 / 8));; - MB|MByte|MBytes) bytes_per_unit=$((1024 * 1024));; - Gb|Gbit|Gbits) bytes_per_unit=$((1024 * 1024 * 1024 / 8));; - GB|GByte|GBytes) bytes_per_unit=$((1024 * 1024 * 1024));; - Tb|Tbit|Tbits) bytes_per_unit=$((1024 * 1024 * 1024 * 1024 / 8));; - TB|TByte|TBytes) bytes_per_unit=$((1024 * 1024 * 1024 * 1024));; - *) echo Bad unit "$unit" && exit 1;; -esac - -scalar=$((bytes_per_unit * dt)) -init_line=$(cat /proc/net/dev | grep "^[ ]*$iface:") -if [ -z "$init_line" ]; then - echo Interface not found in /proc/net/dev: "$iface" - exit 1 -fi - -init_received=$(awk '{print $2}' <<< $init_line) -init_sent=$(awk '{print $10}' <<< $init_line) - -(while true; do cat /proc/net/dev; sleep "$dt"; done) |\ - stdbuf -oL grep "^[ ]*$iface:" |\ - awk -v scalar="$scalar" -v unit="$unit" -v iface="$iface" ' -BEGIN { - old_received='"$init_received"' - old_sent='"$init_sent"' -} -{ - received=$2 - sent=$10 - rx=(received-old_received)/scalar - wx=(sent-old_sent)/scalar - tx=rx+wx - old_received=received - old_sent=sent - if (rx >= 0 && wx >= 0) { - '"$printf_command"' - fflush(stdout) - } -} -' diff --git a/i3/scripts/battery b/i3/scripts/battery deleted file mode 100755 index 2d55dab..0000000 --- a/i3/scripts/battery +++ /dev/null @@ -1,106 +0,0 @@ -#!/usr/bin/env python3 -# -# Copyright (C) 2016 James Murphy -# Licensed under the GPL version 2 only -# -# A battery indicator blocklet script for i3blocks - -from subprocess import check_output -import os -import re - -config = dict(os.environ) -status = check_output(['acpi'], universal_newlines=True) - -if not status: - # stands for no battery found - color = config.get("color_10", "red") - fulltext = "\uf00d \uf240".format(color) - percentleft = 100 -else: - # if there is more than one battery in one laptop, the percentage left is - # available for each battery separately, although state and remaining - # time for overall block is shown in the status of the first battery - batteries = status.split("\n") - state_batteries=[] - commasplitstatus_batteries=[] - percentleft_batteries=[] - time = "" - for battery in batteries: - if battery!='': - state_batteries.append(battery.split(": ")[1].split(", ")[0]) - commasplitstatus = battery.split(", ") - if not time: - time = commasplitstatus[-1].strip() - # check if it matches a time - time = re.match(r"(\d+):(\d+)", time) - if time: - time = ":".join(time.groups()) - timeleft = " ({})".format(time) - else: - timeleft = "" - - p = int(commasplitstatus[1].rstrip("%\n")) - if p>0: - percentleft_batteries.append(p) - commasplitstatus_batteries.append(commasplitstatus) - state = state_batteries[0] - commasplitstatus = commasplitstatus_batteries[0] - if percentleft_batteries: - percentleft = int(sum(percentleft_batteries)/len(percentleft_batteries)) - else: - percentleft = 0 - - # stands for charging - color = config.get("color_charging", "yellow") - FA_LIGHTNING = "\uf0e7".format(color) - - # stands for plugged in - FA_PLUG = "\uf1e6" - - # stands for using battery - FA_BATTERY = "\uf240" - - # stands for unknown status of battery - FA_QUESTION = "\uf128" - - - if state == "Discharging": - fulltext = FA_BATTERY + " " - elif state == "Full": - fulltext = FA_PLUG + " " - timeleft = "" - elif state == "Unknown": - fulltext = FA_QUESTION + " " + FA_BATTERY + " " - timeleft = "" - else: - fulltext = FA_LIGHTNING + " " + FA_PLUG + " " - - def color(percent): - if percent < 10: - # exit code 33 will turn background red - return config.get("color_10", "#FFFFFF") - if percent < 20: - return config.get("color_20", "#FF3300") - if percent < 30: - return config.get("color_30", "#FF6600") - if percent < 40: - return config.get("color_40", "#FF9900") - if percent < 50: - return config.get("color_50", "#FFCC00") - if percent < 60: - return config.get("color_60", "#FFFF00") - if percent < 70: - return config.get("color_70", "#FFFF33") - if percent < 80: - return config.get("color_80", "#FFFF66") - return config.get("color_full", "#FFFFFF") - - form = '{}%' - fulltext += form.format(color(percentleft), percentleft) - #fulltext += timeleft - -print(fulltext) -print(fulltext) -if percentleft < 10: - exit(33) diff --git a/i3/scripts/battery-pinebook-pro b/i3/scripts/battery-pinebook-pro deleted file mode 100755 index 45317d5..0000000 --- a/i3/scripts/battery-pinebook-pro +++ /dev/null @@ -1,20 +0,0 @@ -#!/usr/bin/env bash - -# simple Shellscript for i3blocks on Pinebook pro -# 05012020 geri123 //at// gmx.net Gerhard S. -# battery-symbols: you need the awesome-terminal-font package installed - -PERCENT=$(cat /sys/class/power_supply/cw2015-battery/capacity) -STATUS=$(cat /sys/class/power_supply/cw2015-battery/status) -case $(( - $PERCENT >= 0 && $PERCENT <= 20 ? 1 : - $PERCENT > 20 && $PERCENT <= 40 ? 2 : - $PERCENT > 40 && $PERCENT <= 60 ? 3 : - $PERCENT > 60 && $PERCENT <= 80 ? 4 : 5)) in -# - (1) echo $STATUS:"" :$PERCENT%;; - (2) echo $STATUS:"" :$PERCENT%;; - (3) echo $STATUS:"" :$PERCENT%;; - (4) echo $STATUS:"" :$PERCENT%;; - (5) echo $STATUS:"" :$PERCENT%;; -esac diff --git a/i3/scripts/blur-lock b/i3/scripts/blur-lock deleted file mode 100755 index 2f6cc31..0000000 --- a/i3/scripts/blur-lock +++ /dev/null @@ -1,14 +0,0 @@ -#!/usr/bin/env bash - -# simple screenlocker using i3lock that creates ablurred screenshot to overlay - -PICTURE=/tmp/i3lock.png -SCREENSHOT="scrot -z $PICTURE" - -BLUR="5x4" - -$SCREENSHOT -magick $PICTURE -blur $BLUR $PICTURE -i3lock -i $PICTURE -shred $PICTURE -rm $PICTURE diff --git a/i3/scripts/cpu_usage b/i3/scripts/cpu_usage deleted file mode 100755 index 8d8a267..0000000 --- a/i3/scripts/cpu_usage +++ /dev/null @@ -1,62 +0,0 @@ -#!/usr/bin/perl -# -# Copyright 2014 Pierre Mavro -# Copyright 2014 Vivien Didelot -# Copyright 2014 Andreas Guldstrand -# -# Licensed under the terms of the GNU GPL v3, or any later version. - -use strict; -use warnings; -use utf8; -use Getopt::Long; - -# default values -my $t_warn = $ENV{T_WARN} // 50; -my $t_crit = $ENV{T_CRIT} // 80; -my $cpu_usage = -1; -my $decimals = $ENV{DECIMALS} // 0; -my $label = $ENV{LABEL} // ""; - -sub help { - print "Usage: cpu_usage [-w ] [-c ] [-d ]\n"; - print "-w : warning threshold to become yellow\n"; - print "-c : critical threshold to become red\n"; - print "-d : Use decimals for percentage (default is $decimals) \n"; - exit 0; -} - -GetOptions("help|h" => \&help, - "w=i" => \$t_warn, - "c=i" => \$t_crit, - "d=i" => \$decimals, -); - -# Get CPU usage -$ENV{LC_ALL}="en_US"; # if mpstat is not run under en_US locale, things may break, so make sure it is -open (MPSTAT, 'mpstat 1 1 |') or die; -while () { - if (/^.*\s+(\d+\.\d+)[\s\x00]?$/) { - $cpu_usage = 100 - $1; # 100% - %idle - last; - } -} -close(MPSTAT); - -$cpu_usage eq -1 and die 'Can\'t find CPU information'; - -# Print short_text, full_text -print "${label}"; -printf "%02.${decimals}f%%\n", $cpu_usage; -print "${label}"; -printf "%02.${decimals}f%%\n", $cpu_usage; - -# Print color, if needed -if ($cpu_usage >= $t_crit) { - print "#FF0000\n"; - exit 33; -} elsif ($cpu_usage >= $t_warn) { - print "#FFFC00\n"; -} - -exit 0; diff --git a/i3/scripts/cputemp b/i3/scripts/cputemp deleted file mode 100755 index 8a7d821..0000000 --- a/i3/scripts/cputemp +++ /dev/null @@ -1,17 +0,0 @@ -#!/usr/bin/env bash - -# script to monitor temperatures in waybar/i3blocks e.t.c. -# example only use `sensors` to find your names to replace `Tdie|Tctl|Package` -# example output part from sensors: -# zenpower-pci-00c3 -# Adapter: PCI adapter -# SVI2_Core: 1.03 V -# SVI2_SoC: 994.00 mV -# Tdie: +53.1°C -# Tctl: +53.1°C -# Tccd1: +42.5°C -# Tccd2: +43.2°C - -temp=$(sensors 2>/dev/null | grep -E 'Tdie|Tctl|Package id 0' | grep -oP '\+?[0-9]+\.\d+(?=°C)' | tr -d '+' | head -n1) - -echo "${temp}°C" diff --git a/i3/scripts/disk b/i3/scripts/disk deleted file mode 100755 index e18c7aa..0000000 --- a/i3/scripts/disk +++ /dev/null @@ -1,48 +0,0 @@ -#!/usr/bin/env bash -# Copyright (C) 2014 Julien Bonjean - -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. - -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. - -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -DIR="${DIR:-$BLOCK_INSTANCE}" -DIR="${DIR:-$HOME}" -ALERT_LOW="${ALERT_LOW:-$1}" -ALERT_LOW="${ALERT_LOW:-10}" # color will turn red under this value (default: 10%) - -LOCAL_FLAG="-l" -if [ "$1" = "-n" ] || [ "$2" = "-n" ]; then - LOCAL_FLAG="" -fi - -df -h -P $LOCAL_FLAG "$DIR" | awk -v label="$LABEL" -v alert_low=$ALERT_LOW ' -/\/.*/ { - # full text - print label $4 - - # short text - print label $4 - - use=$5 - - # no need to continue parsing - exit 0 -} - -END { - gsub(/%$/,"",use) - if (100 - use < alert_low) { - # color - print "#FF0000" - } -} -' diff --git a/i3/scripts/empty_workspace b/i3/scripts/empty_workspace deleted file mode 100755 index fd21131..0000000 --- a/i3/scripts/empty_workspace +++ /dev/null @@ -1,16 +0,0 @@ -#!/usr/bin/env bash - -# Copyright (C) 2025 Johannes Kamprad -# SPDX-License-Identifier: GPL-3.0-or-later - -# empty_workspace - open a new workspace automatically named with next number on i3 - - -MAX_DESKTOPS=20 - -WORKSPACES=$(seq -s '\n' 1 1 ${MAX_DESKTOPS}) - -EMPTY_WORKSPACE=$( (i3-msg -t get_workspaces | tr ',' '\n' | grep num | awk -F: '{print int($2)}' ; \ - echo -e ${WORKSPACES} ) | sort -n | uniq -u | head -n 1) - -i3-msg workspace ${EMPTY_WORKSPACE} diff --git a/i3/scripts/gputemp b/i3/scripts/gputemp deleted file mode 100755 index a63166c..0000000 --- a/i3/scripts/gputemp +++ /dev/null @@ -1,17 +0,0 @@ -#!/usr/bin/env bash - -# script to monitor temperatures in waybar/i3blocks e.t.c. -# example only use `sensors` to find your sensor to replace `i915-pci-0600` -# example output part from sensors: -# i915-pci-0600 -# Adapter: PCI adapter -# in0: 630.00 mV -# fan1: 0 RPM -# temp1: +55.0°C -# energy1: 1.26 MJ - -# examples using Nvidia tools: -#echo "$(nvidia-smi --format=csv,noheader --query-gpu=temperature.gpu) °C" -#echo "$(nvidia-settings -q gpucoretemp -t) °C" -# example using sensor name: -sensors 2>/dev/null | awk '/i915-pci-0600/{flag=1} flag && /temp1/ {gsub("\\+", "", $2); print $2, $3; exit}' diff --git a/i3/scripts/import-gsettings b/i3/scripts/import-gsettings deleted file mode 100755 index b848168..0000000 --- a/i3/scripts/import-gsettings +++ /dev/null @@ -1,16 +0,0 @@ -#!/bin/sh - -# needed for nwg-looks -# usage: import-gsettings -config="${XDG_CONFIG_HOME:-$HOME/.config}/gtk-3.0/settings.ini" -if [ ! -f "$config" ]; then exit 1; fi - -gnome_schema="org.gnome.desktop.interface" -gtk_theme="$(grep 'gtk-theme-name' "$config" | cut -d'=' -f2)" -icon_theme="$(grep 'gtk-icon-theme-name' "$config" | cut -d'=' -f2)" -cursor_theme="$(grep 'gtk-cursor-theme-name' "$config" | cut -d'=' -f2)" -font_name="$(grep 'gtk-font-name' "$config" | cut -d'=' -f2)" -gsettings set "$gnome_schema" gtk-theme "$gtk_theme" -gsettings set "$gnome_schema" icon-theme "$icon_theme" -gsettings set "$gnome_schema" cursor-theme "$cursor_theme" -gsettings set "$gnome_schema" font-name "$font_name" \ No newline at end of file diff --git a/i3/scripts/keyhint b/i3/scripts/keyhint deleted file mode 100755 index 34a123a..0000000 --- a/i3/scripts/keyhint +++ /dev/null @@ -1,27 +0,0 @@ -#!/usr/bin/env bash - -# simple yad gui to show default keybindings - -Main() { - source /usr/share/endeavouros/scripts/eos-script-lib-yad || return 1 - - local command=( - eos_yad --title="EndeavourOS i3-wm keybindings:" --no-buttons --geometry=400x345-15-400 --list - --column=key: --column=description: --column=command: - "ESC" "close this app" "" - "=" "modkey" "(set mod Mod4)" - "+enter" "open a terminal" "" - "+Shift+n" "new empty workspace" "" - "+w" "open Browser" "" - "+n" "open Filebrowser" "" - "+d" "app menu" "" - "+q" "close focused app" "" - "Print-key" "screenshot" "" - "+Shift+e" "logout menu" "" - "F1" "open keybinding helper" "" - ) - - "${command[@]}" -} - -Main "$@" diff --git a/i3/scripts/keyhint-2 b/i3/scripts/keyhint-2 deleted file mode 100755 index a5fd92f..0000000 --- a/i3/scripts/keyhint-2 +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/sh - -# keyhint rofi tool to search used keybindings in i3wm - -I3_CONFIG=$HOME/.config/i3/config -mod_key=$(sed -nre 's/^set \$mod (.*)/\1/p' ${I3_CONFIG}) -grep "^bindsym" ${I3_CONFIG} \ - | sed "s/-\(-\w\+\)\+//g;s/\$mod/${mod_key}/g;s/Mod1/Alt/g;s/exec //;s/bindsym //;s/^\s\+//;s/^\([^ ]\+\) \(.\+\)$/\2: \1/;s/^\s\+//" \ - | tr -s ' ' \ - | rofi -dmenu -theme ~/.config/rofi/rofikeyhint.rasi diff --git a/i3/scripts/memory b/i3/scripts/memory deleted file mode 100755 index e60be50..0000000 --- a/i3/scripts/memory +++ /dev/null @@ -1,69 +0,0 @@ -#!/usr/bin/env bash -# Copyright (C) 2014 Julien Bonjean - -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. - -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. - -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -TYPE="${BLOCK_INSTANCE:-mem}" - -awk -v type=$TYPE ' -/^MemTotal:/ { - mem_total=$2 -} -/^MemFree:/ { - mem_free=$2 -} -/^Buffers:/ { - mem_free+=$2 -} -/^Cached:/ { - mem_free+=$2 -} -/^SwapTotal:/ { - swap_total=$2 -} -/^SwapFree:/ { - swap_free=$2 -} -END { - if (type == "swap") { - free=swap_free/1024/1024 - used=(swap_total-swap_free)/1024/1024 - total=swap_total/1024/1024 - } else { - free=mem_free/1024/1024 - used=(mem_total-mem_free)/1024/1024 - total=mem_total/1024/1024 - } - - pct=0 - if (total > 0) { - pct=used/total*100 - } - - # full text - # printf("%.1fG/%.1fG (%.f%%)\n", used, total, pct) - - # short text - printf("%02.f%%\n", pct) - - # color - if (pct > 90) { - print("#FF0000") - } else if (pct > 80) { - print("#FFAE00") - } else if (pct > 70) { - print("#FFF600") - } -} -' /proc/meminfo diff --git a/i3/scripts/openweather b/i3/scripts/openweather deleted file mode 100755 index e41b833..0000000 --- a/i3/scripts/openweather +++ /dev/null @@ -1,471 +0,0 @@ -#!/usr/bin/env bash - -# openweater - OpenWeatherMap Weather Fetcher for Waybar/Status Bars -# -# Copyright (C) 2025 Johannes Kamprad -# -# SPDX-License-Identifier: GPL-3.0-or-later - - -# openweater - OpenWeatherMap Weather Fetcher for Waybar/Status Bars -# Secure API key handling with configurable locations -# including setup script and help -# Options: -# -h, --help Show this help message -# -c, --city-id ID Override city ID (required if not in config) -# -k, --api-key KEY Override API key (not recommended, use config file) -# -u, --units UNITS Units: metric, imperial, kelvin (default: $DEFAULT_UNITS) -# -f, --force-refresh Force refresh (ignore cache) -# --setup Interactive setup wizard -# --show-config Show current configuration - -set -euo pipefail - -# Set C locale to avoid German decimal formatting issues -export LC_NUMERIC=C -export LC_ALL=C - -# Colors for output -RED='\033[0;31m' -GREEN='\033[0;32m' -YELLOW='\033[1;33m' -NC='\033[0m' # No Color - -# Default configuration (no default location) -DEFAULT_UNITS="metric" -CONFIG_DIR="${XDG_CONFIG_HOME:-$HOME/.config}" -CONFIG_FILE="$CONFIG_DIR/openweather/config" -CACHE_DIR="${XDG_CACHE_HOME:-$HOME/.cache}/openweather" -CACHE_FILE="$CACHE_DIR/weather_data" -CACHE_DURATION=600 # 10 minutes - -# Logging functions -log_error() { - echo -e "${RED}[ERROR]${NC} $*" >&2 -} - -log_warn() { - echo -e "${YELLOW}[WARN]${NC} $*" >&2 -} - -# Show help -show_help() { - cat << EOF -Usage: $(basename "$0") [OPTIONS] - -Secure OpenWeatherMap weather fetcher with configurable locations. - -Options: - -h, --help Show this help message - -c, --city-id ID Override city ID (required if not in config) - -k, --api-key KEY Override API key (not recommended, use config file) - -u, --units UNITS Units: metric, imperial, kelvin (default: $DEFAULT_UNITS) - -f, --force-refresh Force refresh (ignore cache) - --setup Interactive setup wizard - --show-config Show current configuration - -Configuration: - Config file: $CONFIG_FILE - - Create config file with: - OPENWEATHER_API_KEY="your_api_key_here" - OPENWEATHER_CITY_ID="your_city_id" # Required - OPENWEATHER_UNITS="metric" # Optional - -Examples: - $(basename "$0") # Use config file settings - $(basename "$0") --city-id 5128581 # New York - $(basename "$0") --units imperial # Fahrenheit - $(basename "$0") --setup # Run setup wizard - -Get your free API key at: https://openweathermap.org/api -Find city IDs at: https://openweathermap.org/find - -EOF -} - -# Check dependencies -check_dependencies() { - local missing_deps=() - - for cmd in jq curl; do - if ! command -v "$cmd" >/dev/null 2>&1; then - missing_deps+=("$cmd") - fi - done - - if [[ ${#missing_deps[@]} -gt 0 ]]; then - log_error "Missing required dependencies: ${missing_deps[*]}" - echo "Install with: sudo pacman -S ${missing_deps[*]}" - exit 1 - fi -} - -# Load configuration -load_config() { - # Set defaults (no default city ID) - OPENWEATHER_CITY_ID="" - OPENWEATHER_UNITS="$DEFAULT_UNITS" - - # Load from config file if it exists - if [[ -f "$CONFIG_FILE" ]]; then - source "$CONFIG_FILE" - fi - - # Override with environment variables if set - OPENWEATHER_API_KEY="${OPENWEATHER_API_KEY:-}" - OPENWEATHER_CITY_ID="${OPENWEATHER_CITY_ID:-}" - OPENWEATHER_UNITS="${OPENWEATHER_UNITS:-$DEFAULT_UNITS}" -} - -# Validate API key -validate_api_key() { - if [[ -z "$OPENWEATHER_API_KEY" ]]; then - log_error "No API key found!" - echo - echo "To fix this:" - echo "1. Get free API key: https://openweathermap.org/api" - echo "2. Run setup wizard: $0 --setup" - echo "3. Or set environment variable: export OPENWEATHER_API_KEY=your_key" - echo "4. Or create config file: $CONFIG_FILE" - exit 1 - fi - - # Basic validation (OpenWeatherMap keys are typically 32 chars) - if [[ ${#OPENWEATHER_API_KEY} -ne 32 ]]; then - log_warn "API key length seems incorrect (expected 32 characters, got ${#OPENWEATHER_API_KEY})" - fi -} - -# Validate city ID -validate_city_id() { - if [[ -z "$OPENWEATHER_CITY_ID" ]]; then - log_error "No city ID found!" - echo - echo "To fix this:" - echo "1. Run setup wizard: $0 --setup" - echo "2. Or set environment variable: export OPENWEATHER_CITY_ID=your_city_id" - echo "3. Or add OPENWEATHER_CITY_ID=\"your_city_id\" to: $CONFIG_FILE" - echo "4. Or provide city ID via command line: $0 --city-id your_city_id" - echo - echo "Find city IDs at: https://openweathermap.org/find" - exit 1 - fi - - # Basic validation (city IDs are typically numeric) - if [[ ! "$OPENWEATHER_CITY_ID" =~ ^[0-9]+$ ]]; then - log_warn "City ID format seems incorrect (expected numeric, got: $OPENWEATHER_CITY_ID)" - fi -} - -# Setup wizard -run_setup() { - echo -e "${GREEN}=== OpenWeatherMap Setup Wizard ===${NC}" - echo - - # Create config directory - mkdir -p "$(dirname "$CONFIG_FILE")" - - # Get API key - echo "Get your free API key at: https://openweathermap.org/api" - echo - echo -n "Enter your OpenWeatherMap API key: " - read -r api_key - - if [[ -z "$api_key" ]]; then - log_error "API key cannot be empty" - exit 1 - fi - - # Get city ID (required) - echo - echo "Find your city ID at: https://openweathermap.org/find" - echo -n "Enter city ID: " - read -r city_id - - if [[ -z "$city_id" ]]; then - log_error "City ID cannot be empty" - exit 1 - fi - - # Get units (optional) - echo - echo "Available units: metric (°C), imperial (°F), kelvin (K)" - echo -n "Enter units [metric]: " - read -r units - units="${units:-metric}" - - # Write config file - cat > "$CONFIG_FILE" << EOF -# OpenWeatherMap Configuration -# Generated by $(basename "$0") setup wizard on $(date) - -# Your API key from https://openweathermap.org/api -OPENWEATHER_API_KEY="$api_key" - -# City ID from https://openweathermap.org/find -OPENWEATHER_CITY_ID="$city_id" - -# Units: metric, imperial, kelvin -OPENWEATHER_UNITS="$units" -EOF - - # Set secure permissions - chmod 600 "$CONFIG_FILE" - - echo - echo -e "${GREEN}✅ Configuration saved to: $CONFIG_FILE${NC}" - echo -e "${GREEN}✅ File permissions set to 600 (user read/write only)${NC}" - echo - echo "Testing configuration..." - - # Test the configuration - OPENWEATHER_API_KEY="$api_key" - OPENWEATHER_CITY_ID="$city_id" - OPENWEATHER_UNITS="$units" - - if fetch_weather_data; then - echo -e "${GREEN}✅ Configuration test successful!${NC}" - else - log_error "Configuration test failed. Please check your API key and city ID." - exit 1 - fi -} - -# Show current configuration -show_config() { - echo "=== Current Configuration ===" - echo "Config file: $CONFIG_FILE" - echo "Cache file: $CACHE_FILE" - echo "Cache duration: ${CACHE_DURATION}s" - echo - - if [[ -f "$CONFIG_FILE" ]]; then - echo "Configuration:" - echo " API Key: ${OPENWEATHER_API_KEY:0:8}... (${#OPENWEATHER_API_KEY} chars)" - echo " City ID: $OPENWEATHER_CITY_ID" - echo " Units: $OPENWEATHER_UNITS" - else - echo "❌ No configuration file found at: $CONFIG_FILE" - echo "Run: $0 --setup" - fi -} - -# Check cache validity -is_cache_valid() { - [[ -f "$CACHE_FILE" ]] && \ - [[ $(($(date +%s) - $(stat -c %Y "$CACHE_FILE" 2>/dev/null || echo 0))) -lt $CACHE_DURATION ]] -} - -# Fetch weather data from API -fetch_weather_data() { - local url="https://api.openweathermap.org/data/2.5/weather?id=${OPENWEATHER_CITY_ID}&units=${OPENWEATHER_UNITS}&appid=${OPENWEATHER_API_KEY}" - - local response - if ! response=$(curl -sf "$url" 2>/dev/null); then - log_error "Failed to fetch weather data from API" - return 1 - fi - - # Validate JSON response - if ! echo "$response" | jq . >/dev/null 2>&1; then - log_error "Invalid JSON response from API" - return 1 - fi - - # Check for API error - local api_code - api_code=$(echo "$response" | jq -r '.cod // empty') - if [[ "$api_code" != "200" ]]; then - local api_message - api_message=$(echo "$response" | jq -r '.message // "Unknown API error"') - log_error "API Error ($api_code): $api_message" - return 1 - fi - - # Cache the response - mkdir -p "$CACHE_DIR" - echo "$response" > "$CACHE_FILE" - - return 0 -} - -# Get weather data (from cache or API) -get_weather_data() { - local force_refresh="${1:-false}" - - if [[ "$force_refresh" != "true" ]] && is_cache_valid; then - cat "$CACHE_FILE" - else - if fetch_weather_data; then - cat "$CACHE_FILE" - else - # Fallback to cache if available - if [[ -f "$CACHE_FILE" ]]; then - log_warn "Using stale cache data due to API failure" - cat "$CACHE_FILE" - else - return 1 - fi - fi - fi -} - -# Calculate wind direction -get_wind_direction() { - local degrees="$1" - local directions=(N NNE NE ENE E ESE SE SSE S SSW SW WSW W WNW NW NNW) - local index - index=$(awk "BEGIN {print int(($degrees % 360) / 22.5)}") - echo "${directions[$index]}" -} - -# Get weather icon -get_weather_icon() { - local condition="$1" - case "$condition" in - 'Clear') echo "☀" ;; # Clear sky - 'Clouds') echo "☁" ;; # Cloudy - 'Rain'|'Drizzle') echo "🌧" ;; # Rain - 'Snow') echo "❄" ;; # Snow - 'Thunderstorm') echo "⛈" ;; # Thunder - 'Mist'|'Fog') echo "🌫" ;; # Fog - *) echo "🌤" ;; # Default - esac -} - -# Safe number formatting (handles locale issues) -safe_printf() { - local format="$1" - local number="$2" - - # Validate number is actually numeric - if [[ ! "$number" =~ ^-?[0-9]+(\.[0-9]+)?$ ]]; then - echo "0.0" - return 1 - fi - - # Use awk for reliable formatting regardless of locale - awk "BEGIN {printf \"$format\", $number}" -} - -# Format weather output -format_weather() { - local weather_data="$1" - - # Parse weather data with error checking - local condition temp wind_speed_ms wind_deg - condition=$(echo "$weather_data" | jq -r '.weather[0].main // "Unknown"') - temp=$(echo "$weather_data" | jq -r '.main.temp // "0"') - wind_speed_ms=$(echo "$weather_data" | jq -r '.wind.speed // "0"') - wind_deg=$(echo "$weather_data" | jq -r '.wind.deg // "0"') - - # Validate parsed data - [[ "$condition" == "null" ]] && condition="Unknown" - [[ "$temp" == "null" ]] && temp="0" - [[ "$wind_speed_ms" == "null" ]] && wind_speed_ms="0" - [[ "$wind_deg" == "null" ]] && wind_deg="0" - - # Format temperature with safe formatting - local temp_formatted - temp_formatted=$(safe_printf "%.1f" "$temp") - - # Convert wind speed to km/h with safe formatting - local wind_speed_kmh - wind_speed_kmh=$(awk "BEGIN {printf \"%.1f\", ($wind_speed_ms + 0) * 3.6}") - - # Get wind direction - local wind_dir - wind_dir=$(get_wind_direction "$wind_deg") - - # Get weather icon - local icon - icon=$(get_weather_icon "$condition") - - # Format unit symbol - local unit_symbol - case "$OPENWEATHER_UNITS" in - "imperial") unit_symbol="°F" ;; - "kelvin") unit_symbol="K" ;; - *) unit_symbol="°C" ;; - esac - - # Output formatted weather - echo "${icon} ${temp_formatted}${unit_symbol}, ${wind_speed_kmh} km/h ${wind_dir}" -} - -# Main function -main() { - local city_id_override="" - local api_key_override="" - local units_override="" - local force_refresh="false" - - # Parse command line arguments - while [[ $# -gt 0 ]]; do - case $1 in - -h|--help) - show_help - exit 0 - ;; - -c|--city-id) - city_id_override="$2" - shift 2 - ;; - -k|--api-key) - api_key_override="$2" - shift 2 - ;; - -u|--units) - units_override="$2" - shift 2 - ;; - -f|--force-refresh) - force_refresh="true" - shift - ;; - --setup) - check_dependencies - run_setup - exit 0 - ;; - --show-config) - load_config - show_config - exit 0 - ;; - *) - log_error "Unknown option: $1" - show_help - exit 1 - ;; - esac - done - - # Check dependencies - check_dependencies - - # Load configuration - load_config - - # Apply overrides - [[ -n "$city_id_override" ]] && OPENWEATHER_CITY_ID="$city_id_override" - [[ -n "$api_key_override" ]] && OPENWEATHER_API_KEY="$api_key_override" - [[ -n "$units_override" ]] && OPENWEATHER_UNITS="$units_override" - - # Validate configuration - validate_api_key - validate_city_id - - # Get and format weather data - local weather_data - if weather_data=$(get_weather_data "$force_refresh"); then - format_weather "$weather_data" - else - echo "⚠️ Weather data unavailable" - exit 1 - fi -} - -# Run main function -main "$@" diff --git a/i3/scripts/power-profiles b/i3/scripts/power-profiles deleted file mode 100755 index 6c901b3..0000000 --- a/i3/scripts/power-profiles +++ /dev/null @@ -1,64 +0,0 @@ -#!/usr/bin/env bash - -# Simple power-profiles-daemon switcher using rofi and static theme, with notification -# -# Copyright (C) 2025 Johannes Kamprad -# -# SPDX-License-Identifier: GPL-3.0-or-later - -# needs rofi config: -# $HOME/.config/rofi/powermenu.rasi - -ROFI_THEME="${HOME}/.config/rofi/power-profiles.rasi" - -# Dependency checks -command -v powerprofilesctl >/dev/null 2>&1 || { echo "powerprofilesctl not found"; exit 1; } -command -v rofi >/dev/null 2>&1 || { echo "rofi not found"; exit 1; } -if ! command -v notify-send >/dev/null 2>&1; then - notify_send_missing=true -fi - -current_profile="$(powerprofilesctl get 2>/dev/null)" -ROFI_ARGS=(-dmenu -i -theme "$ROFI_THEME" -p "Change Profile" -mesg "Current used: $current_profile" -markup-rows) - -# Menu entries -cancel=" Cancel" -perf=" Performance" -balanced=" Balanced" -powersave=" Power Saver" -# sets chancel to be on top -options="$cancel" - -if powerprofilesctl list | grep -q "performance"; then - options="$options\n$perf" -fi -if powerprofilesctl list | grep -q "balanced"; then - options="$options\n$balanced" -fi -if powerprofilesctl list | grep -q "power-saver"; then - options="$options\n$powersave" -fi - -# Show menu -chosen="$(echo -e "$options" | rofi "${ROFI_ARGS[@]}")" - -# Run selection -case $chosen in - "$perf") - powerprofilesctl set performance - ;; - "$balanced") - powerprofilesctl set balanced - ;; - "$powersave") - powerprofilesctl set power-saver - ;; - "$cancel"|"") - exit 0 - ;; -esac - -# Send notification if available -if [[ "$chosen" != "$cancel" && -z "${notify_send_missing}" ]]; then - notify-send -i dialog-information "Power Profile Changed" "New profile: ${chosen}" -fi diff --git a/i3/scripts/powermenu b/i3/scripts/powermenu deleted file mode 100755 index 6111806..0000000 --- a/i3/scripts/powermenu +++ /dev/null @@ -1,81 +0,0 @@ -#!/usr/bin/env bash - -# -# powermenu - a very simple rofi powermenu -# -# Copyright (C) 2025 Johannes Kamprad -# -# SPDX-License-Identifier: GPL-3.0-or-later - -# needs rofi config: -# $HOME/.config/rofi/powermenu.rasi -# set to be used in i3wm - -ROFI_THEME="${HOME}/.config/rofi/powermenu.rasi" -# Define possible lock scripts/commands (edit this list as you like) -LOCK_SCRIPTS=("${HOME}/.config/i3/scripts/blur-lock" "i3lock") - -# Find available lock script -find_lock_script() { - for script in "${LOCK_SCRIPTS[@]}"; do - # Handle command names vs full paths - if [[ "$script" =~ ^[a-zA-Z0-9_-]+$ ]]; then - # It's a command name, check if available - if command -v "$script" >/dev/null 2>&1; then - echo "$script" - return 0 - fi - else - # It's a path, check if file exists and is executable - if [[ -x "$script" ]]; then - echo "$script" - return 0 - fi - fi - done - return 1 -} - -# Menu entries -chancel=" Cancel" -lock=" Lock" -logout=" Logout" -reboot=" Reboot" -shutdown=" Shutdown" -suspend=" Suspend" -hibernate=" Hibernate" - - -# Add lock only if script is found -if lockcmd="$(find_lock_script)"; then - options="$chancel\n$lock\n$logout\n$reboot\n$shutdown\n$suspend\n$hibernate" -else - options="$chancel\n$logout\n$reboot\n$shutdown\n$suspend\n$hibernate" -fi - -chosen="$(echo -e "$options" | rofi -dmenu -i -p "Power Menu" \ - -theme $ROFI_THEME)" - -case $chosen in - "$lock") - $lockcmd - ;; - "$cancel"|"") - exit 0 - ;; - "$logout") - i3-msg exit - ;; - "$reboot") - systemctl reboot - ;; - "$shutdown") - systemctl poweroff - ;; - "$suspend") - systemctl suspend - ;; - "$hibernate") - systemctl hibernate - ;; -esac diff --git a/i3/scripts/ppd-status b/i3/scripts/ppd-status deleted file mode 100755 index 92ab169..0000000 --- a/i3/scripts/ppd-status +++ /dev/null @@ -1,25 +0,0 @@ -#!/usr/bin/env bash - - -# power-profiles-daemon implementation: -# needs package power-profiles-daemon installed and the service running see here: -# https://wiki.archlinux.org/title/CPU_frequency_scaling#power-profiles-daemon -# used in i3-blocks: ~/.config/i3/i3blocks.conf together with: ~/.config/i3/scripts/power-profiles - - -# assign tags or translations to each profile -declare -A tags -tags=( - [performance]="Performance" - [balanced]="Balanced" - [power-saver]="Power saver" -) - -# Get current profile -current_profile=$(/usr/bin/powerprofilesctl get) - -# Get tag from the array -profile_tag=${tags[$current_profile]} - -# Show tag on i3block -echo "${profile_tag:-$current_profile}" diff --git a/i3/scripts/temperature b/i3/scripts/temperature deleted file mode 100755 index 69dcc63..0000000 --- a/i3/scripts/temperature +++ /dev/null @@ -1,75 +0,0 @@ -#!/usr/bin/env perl - -# Copyright 2014 Pierre Mavro -# Copyright 2014 Vivien Didelot -# Copyright 2014 Andreas Guldstrand -# Copyright 2014 Benjamin Chretien -# SPDX-License-Identifier: GPL-3.0-or-later - -# Edited by Andreas Lindlbauer - -use strict; -use warnings; -use utf8; -use Getopt::Long; - -binmode(STDOUT, ":utf8"); - -# default values -my $t_warn = $ENV{T_WARN} || 70; -my $t_crit = $ENV{T_CRIT} || 90; -my $chip = $ENV{SENSOR_CHIP} || ""; -my $temperature = -9999; -my $label = "😀 "; - -sub help { - print "Usage: temperature [-w ] [-c ] [--chip ]\n"; - print "-w : warning threshold to become yellow\n"; - print "-c : critical threshold to become red\n"; - print "--chip : sensor chip\n"; - exit 0; -} - -GetOptions("help|h" => \&help, - "w=i" => \$t_warn, - "c=i" => \$t_crit, - "chip=s" => \$chip); - -# Get chip temperature -open (SENSORS, "sensors -u $chip |") or die; -while () { - if (/^\s+temp1_input:\s+[\+]*([\-]*\d+\.\d)/) { - $temperature = $1; - last; - } -} -close(SENSORS); - -$temperature eq -9999 and die 'Cannot find temperature'; - -if ($temperature < 45) { - $label = ''; -} elsif ($temperature < 55) { - $label = ''; -} elsif ($temperature < 65) { - $label = ''; -} elsif ($temperature < 75) { - $label = ''; -} else { - $label = ''; -} -# Print short_text, full_text -print "${label}"; -print " $temperature°C\n"; -print "${label}"; -print " $temperature°C\n"; - -# Print color, if needed -if ($temperature >= $t_crit) { - print "#FF0000\n"; - exit 33; -} elsif ($temperature >= $t_warn) { - print "#FFFC00\n"; -} - -exit 0; diff --git a/i3/scripts/volume b/i3/scripts/volume deleted file mode 100755 index 97f2693..0000000 --- a/i3/scripts/volume +++ /dev/null @@ -1,46 +0,0 @@ -#!/usr/bin/env bash -# i3blocks volume block for PipeWire (PulseAudio compatible) - -STEP=${1:-5%} - -# Default sink -SINK=$(pactl info | awk '/Default Sink/ {print $3}') -[[ -z "$SINK" ]] && { echo "No audio"; exit 0; } - -# Handle scroll/middle-click -case "$BLOCK_BUTTON" in - 3) pactl set-sink-mute "$SINK" toggle ;; # right click = mute/unmute - 4) pactl set-sink-volume "$SINK" +$STEP ;; # scroll up - 5) pactl set-sink-volume "$SINK" -$STEP ;; # scroll down -esac - -# Get current volume (front-left channel) -VOL=$(pactl list sinks | awk -v s="$SINK" ' - $0 ~ "Name: " s {found=1} - found && /Volume:/ {gsub("%","",$5); print $5; exit} -') - -# Get mute state -MUTED=$(pactl list sinks | awk -v s="$SINK" ' - $0 ~ "Name: " s {found=1} - found && /Mute:/ {print $2; exit} -') - -# Choose symbol -AUDIO_HIGH='' -AUDIO_MED='' -AUDIO_LOW='' -AUDIO_MUTED='' -MED_THRESH=50 -LOW_THRESH=0 - -if [[ "$MUTED" == "no" ]]; then - SYMB=$AUDIO_HIGH - [[ $VOL -le $MED_THRESH ]] && SYMB=$AUDIO_MED - [[ $VOL -le $LOW_THRESH ]] && SYMB=$AUDIO_LOW -else - SYMB=$AUDIO_MUTED -fi - -# Single-line output for i3blocks -echo "${SYMB} ${VOL}%" diff --git a/i3/scripts/volume_brightness.sh b/i3/scripts/volume_brightness.sh deleted file mode 100755 index 676c6d3..0000000 --- a/i3/scripts/volume_brightness.sh +++ /dev/null @@ -1,95 +0,0 @@ -#!/usr/bin/env bash - -# original source: https://gitlab.com/Nmoleo/i3-volume-brightness-indicator -# changed to use brightnessctl [xbacklight is non functional on modern hardware] -# by joekamprad [Aug 2025] - -bar_color="#7f7fff" -volume_step=1 -brightness_step=5 -max_volume=100 -notification_timeout=1000 # in ms - -# Uses regex to get volume from pactl -function get_volume { - pactl get-sink-volume @DEFAULT_SINK@ | grep -Po '[0-9]{1,3}(?=%)' | head -1 -} - -# Uses regex to get mute status from pactl -function get_mute { - pactl get-sink-mute @DEFAULT_SINK@ | grep -Po '(?<=Mute: )(yes|no)' -} - -# Uses brightnessctl instead of xbacklight -function get_brightness { - brightnessctl g | awk '{print int($1)}' - # You could also use: brightnessctl info | grep -Po '(?<=Current brightness: )[0-9]+' -} - -# Calculates brightness percentage -function get_brightness_percent { - current=$(brightnessctl g) - max=$(brightnessctl m) - percent=$(( 100 * current / max )) - echo $percent -} - -function get_volume_icon { - volume=$(get_volume) - mute=$(get_mute) - if [ "$volume" -eq 0 ] || [ "$mute" == "yes" ] ; then - volume_icon="" - elif [ "$volume" -lt 50 ]; then - volume_icon="" - else - volume_icon="" - fi -} - -function get_brightness_icon { - brightness_icon="" -} - -function show_volume_notif { - volume=$(get_volume) - get_volume_icon - notify-send -i volume_icon -t 1000 "Volume" "$volume_icon $volume%" -h int:value:$volume -h string:x-canonical-private-synchronous:volume -} - - -function show_brightness_notif { - get_brightness_icon - brightness=$(get_brightness_percent) - notify-send -i brightness_icon -t $notification_timeout -h string:x-dunst-stack-tag:brightness_notif -h int:value:$brightness "$brightness_icon $brightness%" -} - - - -case $1 in - volume_up) - pactl set-sink-mute @DEFAULT_SINK@ 0 - volume=$(get_volume) - if [ $(( "$volume" + "$volume_step" )) -gt $max_volume ]; then - pactl set-sink-volume @DEFAULT_SINK@ $max_volume% - else - pactl set-sink-volume @DEFAULT_SINK@ +$volume_step% - fi - show_volume_notif - ;; - volume_down) - pactl set-sink-volume @DEFAULT_SINK@ -$volume_step% - show_volume_notif - ;; - volume_mute) - pactl set-sink-mute @DEFAULT_SINK@ toggle - show_volume_notif - ;; - brightness_up) - brightnessctl s +$brightness_step% > /dev/null - show_brightness_notif - ;; - brightness_down) - brightnessctl s $brightness_step%- > /dev/null - show_brightness_notif - ;; -esac diff --git a/i3/scripts/volume_brightness2.sh b/i3/scripts/volume_brightness2.sh deleted file mode 100755 index cd78d77..0000000 --- a/i3/scripts/volume_brightness2.sh +++ /dev/null @@ -1,168 +0,0 @@ -#!/usr/bin/env bash - -# original source: https://gitlab.com/Nmoleo/i3-volume-brightness-indicator -# alternative to volume_brightness.sh that uses brightnessctl for both keyboard & screen brightness - -# See README.md for usage instructions -volume_step=1 -keyboard_brightness_step=20 -screen_brightness_step=1 -max_volume=100 -notification_timeout=1000 - -# Specify Icon Theme here: -volume_theme_icon="audio-volume-high" -screen_brightness_theme_icon="display-brightness" -keyboard_brightness_theme_icon="display-brightness" - -# Keyboard Backlight device detection here: -device_cache="/tmp/kbd_backlight_device" - -if [ -f "$device_cache" ]; then - # If there is cache, load it into device - device=$(cat "$device_cache") -else - # If there is no cache, create one - device=$(brightnessctl --list | grep -Po '\w+::kbd_backlight') - echo "$device" > "$device_cache" -fi - -# Uses regex to get volume from pactl -function get_volume { - pactl get-sink-volume @DEFAULT_SINK@ | grep -Po '[0-9]{1,3}(?=%)' | head -1 -} - -# Uses regex to get mute status from pactl -function get_mute { - pactl get-sink-mute @DEFAULT_SINK@ | grep -Po '(?<=Mute: )(yes|no)' -} - -# Get keyboard_brightness from brightnessctl -function get_keyboard_brightness { - if [ -n "$device" ]; then - keyboard_curr=$(brightnessctl -d "$device" get) - keyboard_max=$(brightnessctl -d "$device" max) - echo $(( keyboard_curr * 100 / keyboard_max)) - fi -} - - -# Grabs screen brightness and formats it out of 100 -function get_screen_brightness { - screen_curr=$(brightnessctl -q get) - screen_max=$(brightnessctl -q max) - echo $(( screen_curr * 100 / screen_max )) -} - -# Returns a mute icon, a volume-low icon, or a volume-high icon, depending on the volume -function get_volume_icon { - volume=$(get_volume) - mute=$(get_mute) - if [ "$volume" -eq 0 ] || [ "$mute" == "yes" ] ; then - volume_icon="" - elif [ "$volume" -lt 50 ] ; then - volume_icon="" - else - volume_icon="" - fi -} - -# Always returns the same icon - I couldn't get the brightness-low icon to work with fontawesome -function get_keyboard_brightness_icon { - kb_brightness=$(get_keyboard_brightness) - if [ "$kb_brightness" -eq 0 ] ; then - keyboard_brightness_icon="" # unfilled circle - elif [ "$kb_brightness" -lt 50 ] ; then - keyboard_brightness_icon="" # fa-adjust (low brightness) - else - keyboard_brightness_icon="" # full circle (high brightness) - fi -} - -function get_screen_brightness_icon { - sc_brightness=$(get_screen_brightness) - if [ "$sc_brightness" -eq 0 ] ; then - screen_brightness_icon="" # unfilled circle - elif [ "$sc_brightness" -lt 50 ] ; then - screen_brightness_icon="" # fa-adjust (low brightness) - else - screen_brightness_icon="" # full circle (high brightness) - fi -} - -# Displays a volume notification using notify-send -function show_volume_notif { - mute=$(get_mute) - volume=$(get_volume) - get_volume_icon - notify-send -i $volume_theme_icon -t $notification_timeout "Volume" "$volume_icon $volume%" -h int:value:$volume -h string:x-canonical-private-synchronous:volume -} - -# Displays a keyboard_brightness notification -function show_keyboard_brightness_notif { - keyboard_brightness=$(get_keyboard_brightness) - # Debug Purposes: - # echo $keyboard_brightness - get_keyboard_brightness_icon - notify-send -i $keyboard_brightness_theme_icon -t $notification_timeout "Keyboard Brightness" -h string:x-dunst-stack-tag:keyboard_brightness_notif -h int:value:$keyboard_brightness "$keyboard_brightness_icon $keyboard_brightness%" -} - -# Displays a screen_brightness notification -function show_screen_brightness_notif { - screen_brightness=$(get_screen_brightness) - # Debug Purposes: - # echo $screen_brightness - get_screen_brightness_icon - notify-send -i $screen_brightness_theme_icon -t $notification_timeout "Screen Brightness" -h string:x-dunst-stack-tag:screen_brightness_notif -h int:value:$screen_brightness "$screen_brightness_icon $screen_brightness%" -} - -# Main function - Takes user input, "volume_up", "volume_down", "keyboard_brightness_up", "keyboard_brightness_down", "brightness_up", or "brightness_down" -case $1 in - volume_up) - # Unmutes and increases volume, then displays the notification - pactl set-sink-mute @DEFAULT_SINK@ 0 - volume=$(get_volume) - if [ $(( "$volume" + "$volume_step" )) -gt $max_volume ]; then - pactl set-sink-volume @DEFAULT_SINK@ $max_volume% - else - pactl set-sink-volume @DEFAULT_SINK@ +$volume_step% - fi - show_volume_notif - ;; - - volume_down) - # Raises volume and displays the notification - pactl set-sink-volume @DEFAULT_SINK@ -$volume_step% - show_volume_notif - ;; - - volume_mute) - # Toggles mute and displays the notification - pactl set-sink-mute @DEFAULT_SINK@ toggle - show_volume_notif - ;; - - keyboard_brightness_up) - # Increases keyboard brightness and displays the notification - brightnessctl -d "$device" set ${keyboard_brightness_step}+ - show_keyboard_brightness_notif - ;; - - keyboard_brightness_down) - # Decreases keyboard brightness and displays the notification - brightnessctl -d "$device" set ${keyboard_brightness_step}- - show_keyboard_brightness_notif - ;; - - screen_brightness_up) - # Increases screen brightness and displays the notification - brightnessctl -q set ${screen_brightness_step}%+ - show_screen_brightness_notif - ;; - - screen_brightness_down) - # Decreases screen brightness and displays the notification - brightnessctl -q set ${screen_brightness_step}%- - show_screen_brightness_notif - ;; -esac diff --git a/i3/scripts/vpn b/i3/scripts/vpn deleted file mode 100755 index bcf54ee..0000000 --- a/i3/scripts/vpn +++ /dev/null @@ -1,25 +0,0 @@ -#!/usr/bin/env sh - -# Parses output from nmcli to show the current connected VPN name/status for i3block -# Source: https://github.com/vivien/i3blocks-contrib/tree/master/nm-vpn -# uncomment in $HOME/.config/i3/i3blocks.conf if you want to use it - -init_color=${init_color:-#FFFF00} -on_color=${on_color:-#00FF00} -export init_color on_color -nmcli -t connection show --active | awk -F ':' ' -BEGIN { - init_color=ENVIRON["init_color"] - on_color=ENVIRON["on_color"] -} -$3=="vpn" { - name=$1 - status="INIT" - color=init_color -} -$3=="tun" || ($4~/^tap/ || $3~/^tap/) { - if(!name) name=$1 - status="ON" - color=on_color -} -END {if(status) printf("%s\n%s\n%s\n", name, status, color)}' From 3ed4afab7393a765b326cc75419cd655fbd28ea7 Mon Sep 17 00:00:00 2001 From: nnduc Date: Thu, 25 Jun 2026 11:33:22 +0700 Subject: [PATCH 17/23] change manythings --- i3/config | 12 +- i3/scripts/audio-device-switch | 100 +++++++ i3/scripts/bandwidth2 | 109 +++++++ i3/scripts/battery | 106 +++++++ i3/scripts/battery-pinebook-pro | 20 ++ i3/scripts/blur-lock | 14 + i3/scripts/cpu_usage | 62 ++++ i3/scripts/cputemp | 17 ++ i3/scripts/disk | 48 ++++ i3/scripts/empty_workspace | 16 ++ i3/scripts/gputemp | 17 ++ i3/scripts/import-gsettings | 16 ++ i3/scripts/keyhint | 27 ++ i3/scripts/keyhint-2 | 10 + i3/scripts/lock | 10 + i3/scripts/lock-now | 10 + i3/scripts/memory | 69 +++++ i3/scripts/openweather | 471 +++++++++++++++++++++++++++++++ i3/scripts/power-profiles | 64 +++++ i3/scripts/powermenu | 81 ++++++ i3/scripts/ppd-status | 25 ++ i3/scripts/temperature | 75 +++++ i3/scripts/volume | 46 +++ i3/scripts/volume_brightness.sh | 95 +++++++ i3/scripts/volume_brightness2.sh | 168 +++++++++++ i3/scripts/vpn | 25 ++ i3/scripts/wallpaper-rotate | 7 + picom/picom.conf | 15 + polybar/config.ini | 24 +- 29 files changed, 1745 insertions(+), 14 deletions(-) create mode 100755 i3/scripts/audio-device-switch create mode 100755 i3/scripts/bandwidth2 create mode 100755 i3/scripts/battery create mode 100755 i3/scripts/battery-pinebook-pro create mode 100755 i3/scripts/blur-lock create mode 100755 i3/scripts/cpu_usage create mode 100755 i3/scripts/cputemp create mode 100755 i3/scripts/disk create mode 100755 i3/scripts/empty_workspace create mode 100755 i3/scripts/gputemp create mode 100755 i3/scripts/import-gsettings create mode 100755 i3/scripts/keyhint create mode 100755 i3/scripts/keyhint-2 create mode 100755 i3/scripts/lock create mode 100755 i3/scripts/lock-now create mode 100755 i3/scripts/memory create mode 100755 i3/scripts/openweather create mode 100755 i3/scripts/power-profiles create mode 100755 i3/scripts/powermenu create mode 100755 i3/scripts/ppd-status create mode 100755 i3/scripts/temperature create mode 100755 i3/scripts/volume create mode 100755 i3/scripts/volume_brightness.sh create mode 100755 i3/scripts/volume_brightness2.sh create mode 100755 i3/scripts/vpn create mode 100755 i3/scripts/wallpaper-rotate create mode 100644 picom/picom.conf diff --git a/i3/config b/i3/config index 9886845..dad74e7 100755 --- a/i3/config +++ b/i3/config @@ -31,7 +31,12 @@ exec --no-startup-id dex --autostart --environment i3 # screen before suspend. Use systemctl lock-session to lock your screen. exec --no-startup-id xrandr --output HDMI-0 --mode 1920x1080 --rate 120 -bindsym $mod+l exec i3lock --ignore-empty-password -i $wallpaper +# burn-in prevention: blank after 5min, DPMS off after 10min, skip lock if fullscreen +exec --no-startup-id xset s 300 300 +exec --no-startup-id xset dpms 300 600 900 +exec --no-startup-id xss-lock -- ~/.config/i3/scripts/lock + +bindsym $mod+l exec ~/.config/i3/scripts/lock-now bindsym $mod+Shift+o exec systemctl suspend bindsym $mod+Shift+p exec systemctl poweroff @@ -40,11 +45,12 @@ bindsym Print exec flameshot gui -c # and nm-applet is a desktop environment-independent system tray GUI for it. # applets +exec --no-startup-id picom --config ~/.config/picom/picom.conf exec --no-startup-id fcitx5 -d exec --no-startup-id nm-applet exec --no-startup-id blueman-applet exec --no-startup-id /usr/bin/gnome-keyring-daemon --start --components=ssh,pkcs11 -exec --no-startup-id feh --bg-fill $wallpaper +exec --no-startup-id ~/.config/i3/scripts/wallpaper-rotate #exec --no-startup-id pasystray exec --no-startup-id polybar @@ -247,7 +253,7 @@ bindsym $mod+r mode "resize" for_window [class="^.*"] border pixel 1 #floating -for_window [class="Signal"] floating enable +for_window [class="signal"] floating enable for_window [class="Dino"] floating enable for_window [class="firefox"] move container to workspace 1 for_window [class="thunderbird"] move container to workspace 4 diff --git a/i3/scripts/audio-device-switch b/i3/scripts/audio-device-switch new file mode 100755 index 0000000..6077d38 --- /dev/null +++ b/i3/scripts/audio-device-switch @@ -0,0 +1,100 @@ +#!/usr/bin/env bash + +# audio-device-switch - audio device switch with a keybind +# Adapted from this: +# https://gist.githubusercontent.com/kbravh/1117a974f89cc53664e55823a55ac320/raw/9d04a10ae925074536047ae8100c6b0dbfc303d6/audio-device-switch.sh +# Readme: https://gist.github.com/kbravh/1117a974f89cc53664e55823a55ac320 +# Creator: https://github.com/kbravh + +# Audio Output Switcher +# This script will cycle to the next available audio output device. +# It can be tied to a hotkey to easily be triggered. +# This is handy, for example, for swapping between speakers and headphones. +# This script will work on systems running PulseAudio or Pipewire services. + + + +# Check which sound server is running +if pgrep pulseaudio >/dev/null; then + sound_server="pulseaudio" +elif pgrep pipewire >/dev/null; then + sound_server="pipewire" +else + echo "Neither PulseAudio nor PipeWire is running." + exit 1 +fi + +# Grab a count of how many audio sinks we have +if [[ "$sound_server" == "pulseaudio" ]]; then + sink_count=$(pacmd list-sinks | grep -c "index:[[:space:]][[:digit:]]") + # Create an array of the actual sink IDs + sinks=() + mapfile -t sinks < <(pacmd list-sinks | grep 'index:[[:space:]][[:digit:]]' | sed -n -e 's/.*index:[[:space:]]\([[:digit:]]\)/\1/p') + # Get the ID of the active sink + active_sink=$(pacmd list-sinks | sed -n -e 's/[[:space:]]*\*[[:space:]]index:[[:space:]]\([[:digit:]]\)/\1/p') + +elif [[ "$sound_server" == "pipewire" ]]; then + sink_count=$(pactl list sinks | grep -c "Sink #[[:digit:]]") + # Create an array of the actual sink IDs + sinks=() + mapfile -t sinks < <(pactl list sinks | grep 'Sink #[[:digit:]]' | sed -n -e 's/.*Sink #\([[:digit:]]\)/\1/p') + # Get the ID of the active sink + active_sink_name=$(pactl info | grep 'Default Sink:' | sed -n -e 's/.*Default Sink:[[:space:]]\+\(.*\)/\1/p') + active_sink=$(pactl list sinks | grep -B 2 "$active_sink_name" | sed -n -e 's/Sink #\([[:digit:]]\)/\1/p' | head -n 1) +fi + +# Get the ID of the last sink in the array +final_sink=${sinks[$((sink_count - 1))]} + +# Find the index of the active sink +for index in "${!sinks[@]}"; do + if [[ "${sinks[$index]}" == "$active_sink" ]]; then + active_sink_index=$index + fi +done + +# Default to the first sink in the list +next_sink=${sinks[0]} +next_sink_index=0 + +# If we're not at the end of the list, move up the list +if [[ $active_sink -ne $final_sink ]]; then + next_sink_index=$((active_sink_index + 1)) + next_sink=${sinks[$next_sink_index]} +fi + +#change the default sink +if [[ "$sound_server" == "pulseaudio" ]]; then + pacmd "set-default-sink ${next_sink}" +elif [[ "$sound_server" == "pipewire" ]]; then + # Get the name of the next sink + next_sink_name=$(pactl list sinks | grep -C 2 "Sink #$next_sink" | sed -n -e 's/.*Name:[[:space:]]\+\(.*\)/\1/p' | head -n 1) + pactl set-default-sink "$next_sink_name" +fi + +#move all inputs to the new sink +if [[ "$sound_server" == "pulseaudio" ]]; then + for app in $(pacmd list-sink-inputs | sed -n -e 's/index:[[:space:]]\([[:digit:]]\)/\1/p'); do + pacmd "move-sink-input $app $next_sink" + done +elif [[ "$sound_server" == "pipewire" ]]; then + for app in $(pactl list sink-inputs | sed -n -e 's/.*Sink Input #\([[:digit:]]\)/\1/p'); do + pactl "move-sink-input $app $next_sink" + done +fi + +# Create a list of the sink descriptions +sink_descriptions=() +if [[ "$sound_server" == "pulseaudio" ]]; then + mapfile -t sink_descriptions < <(pacmd list-sinks | sed -n -e 's/.*alsa.name[[:space:]]=[[:space:]]"\(.*\)"/\1/p') +elif [[ "$sound_server" == "pipewire" ]]; then + mapfile -t sink_descriptions < <(pactl list sinks | sed -n -e 's/.*Description:[[:space:]]\+\(.*\)/\1/p') +fi + +# Find the index that matches our new active sink +for sink_index in "${!sink_descriptions[@]}"; do + if [[ "$sink_index" == "$next_sink_index" ]]; then + notify-send -i audio-volume-high "Sound output switched to:" "${sink_descriptions[$sink_index]}" + exit + fi +done diff --git a/i3/scripts/bandwidth2 b/i3/scripts/bandwidth2 new file mode 100755 index 0000000..bd79e1a --- /dev/null +++ b/i3/scripts/bandwidth2 @@ -0,0 +1,109 @@ +#!/usr/bin/env bash +# +# Copyright (C) 2015 James Murphy +# Licensed under the terms of the GNU GPL v2 only. +# +# i3blocks blocklet script to monitor bandwidth usage +# detecting active device device +# option to set used unit + +iface="${BLOCK_INSTANCE}" +iface="${IFACE:-$iface}" +dt="${DT:-3}" +unit="${UNIT:-MB}" +LABEL="${LABEL:-}" # down arrow up arrow +printf_command="${PRINTF_COMMAND:-"printf \"${LABEL}%1.0f/%1.0f %s/s\\n\", rx, wx, unit;"}" + +function default_interface { + ip route | awk '/^default via/ {print $5; exit}' +} + +function check_proc_net_dev { + if [ ! -f "/proc/net/dev" ]; then + echo "/proc/net/dev not found" + exit 1 + fi +} + +function list_interfaces { + check_proc_net_dev + echo "Interfaces in /proc/net/dev:" + grep -o "^[^:]\\+:" /proc/net/dev | tr -d " :" +} + +while getopts i:t:u:p:lh opt; do + case "$opt" in + i) iface="$OPTARG" ;; + t) dt="$OPTARG" ;; + u) unit="$OPTARG" ;; + p) printf_command="$OPTARG" ;; + l) list_interfaces && exit 0 ;; + h) printf \ +"Usage: bandwidth3 [-i interface] [-t time] [-u unit] [-p printf_command] [-l] [-h] +Options: +-i\tNetwork interface to measure. Default determined using \`ip route\`. +-t\tTime interval in seconds between measurements. Default: 3 +-u\tUnits to measure bytes in. Default: Mb +\tAllowed units: Kb, KB, Mb, MB, Gb, GB, Tb, TB +\tUnits may have optional it/its/yte/ytes on the end, e.g. Mbits, KByte +-p\tAwk command to be called after a measurement is made. +\tDefault: printf \"%%-5.1f/%%5.1f %%s/s\\\\n\", rx, wx, unit; +\tExposed variables: rx, wx, tx, unit, iface +-l\tList available interfaces in /proc/net/dev +-h\tShow this help text +" && exit 0;; + esac +done + +check_proc_net_dev + +iface="${iface:-$(default_interface)}" +while [ -z "$iface" ]; do + echo No default interface + sleep "$dt" + iface=$(default_interface) +done + +case "$unit" in + Kb|Kbit|Kbits) bytes_per_unit=$((1024 / 8));; + KB|KByte|KBytes) bytes_per_unit=$((1024));; + Mb|Mbit|Mbits) bytes_per_unit=$((1024 * 1024 / 8));; + MB|MByte|MBytes) bytes_per_unit=$((1024 * 1024));; + Gb|Gbit|Gbits) bytes_per_unit=$((1024 * 1024 * 1024 / 8));; + GB|GByte|GBytes) bytes_per_unit=$((1024 * 1024 * 1024));; + Tb|Tbit|Tbits) bytes_per_unit=$((1024 * 1024 * 1024 * 1024 / 8));; + TB|TByte|TBytes) bytes_per_unit=$((1024 * 1024 * 1024 * 1024));; + *) echo Bad unit "$unit" && exit 1;; +esac + +scalar=$((bytes_per_unit * dt)) +init_line=$(cat /proc/net/dev | grep "^[ ]*$iface:") +if [ -z "$init_line" ]; then + echo Interface not found in /proc/net/dev: "$iface" + exit 1 +fi + +init_received=$(awk '{print $2}' <<< $init_line) +init_sent=$(awk '{print $10}' <<< $init_line) + +(while true; do cat /proc/net/dev; sleep "$dt"; done) |\ + stdbuf -oL grep "^[ ]*$iface:" |\ + awk -v scalar="$scalar" -v unit="$unit" -v iface="$iface" ' +BEGIN { + old_received='"$init_received"' + old_sent='"$init_sent"' +} +{ + received=$2 + sent=$10 + rx=(received-old_received)/scalar + wx=(sent-old_sent)/scalar + tx=rx+wx + old_received=received + old_sent=sent + if (rx >= 0 && wx >= 0) { + '"$printf_command"' + fflush(stdout) + } +} +' diff --git a/i3/scripts/battery b/i3/scripts/battery new file mode 100755 index 0000000..2d55dab --- /dev/null +++ b/i3/scripts/battery @@ -0,0 +1,106 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 2016 James Murphy +# Licensed under the GPL version 2 only +# +# A battery indicator blocklet script for i3blocks + +from subprocess import check_output +import os +import re + +config = dict(os.environ) +status = check_output(['acpi'], universal_newlines=True) + +if not status: + # stands for no battery found + color = config.get("color_10", "red") + fulltext = "\uf00d \uf240".format(color) + percentleft = 100 +else: + # if there is more than one battery in one laptop, the percentage left is + # available for each battery separately, although state and remaining + # time for overall block is shown in the status of the first battery + batteries = status.split("\n") + state_batteries=[] + commasplitstatus_batteries=[] + percentleft_batteries=[] + time = "" + for battery in batteries: + if battery!='': + state_batteries.append(battery.split(": ")[1].split(", ")[0]) + commasplitstatus = battery.split(", ") + if not time: + time = commasplitstatus[-1].strip() + # check if it matches a time + time = re.match(r"(\d+):(\d+)", time) + if time: + time = ":".join(time.groups()) + timeleft = " ({})".format(time) + else: + timeleft = "" + + p = int(commasplitstatus[1].rstrip("%\n")) + if p>0: + percentleft_batteries.append(p) + commasplitstatus_batteries.append(commasplitstatus) + state = state_batteries[0] + commasplitstatus = commasplitstatus_batteries[0] + if percentleft_batteries: + percentleft = int(sum(percentleft_batteries)/len(percentleft_batteries)) + else: + percentleft = 0 + + # stands for charging + color = config.get("color_charging", "yellow") + FA_LIGHTNING = "\uf0e7".format(color) + + # stands for plugged in + FA_PLUG = "\uf1e6" + + # stands for using battery + FA_BATTERY = "\uf240" + + # stands for unknown status of battery + FA_QUESTION = "\uf128" + + + if state == "Discharging": + fulltext = FA_BATTERY + " " + elif state == "Full": + fulltext = FA_PLUG + " " + timeleft = "" + elif state == "Unknown": + fulltext = FA_QUESTION + " " + FA_BATTERY + " " + timeleft = "" + else: + fulltext = FA_LIGHTNING + " " + FA_PLUG + " " + + def color(percent): + if percent < 10: + # exit code 33 will turn background red + return config.get("color_10", "#FFFFFF") + if percent < 20: + return config.get("color_20", "#FF3300") + if percent < 30: + return config.get("color_30", "#FF6600") + if percent < 40: + return config.get("color_40", "#FF9900") + if percent < 50: + return config.get("color_50", "#FFCC00") + if percent < 60: + return config.get("color_60", "#FFFF00") + if percent < 70: + return config.get("color_70", "#FFFF33") + if percent < 80: + return config.get("color_80", "#FFFF66") + return config.get("color_full", "#FFFFFF") + + form = '{}%' + fulltext += form.format(color(percentleft), percentleft) + #fulltext += timeleft + +print(fulltext) +print(fulltext) +if percentleft < 10: + exit(33) diff --git a/i3/scripts/battery-pinebook-pro b/i3/scripts/battery-pinebook-pro new file mode 100755 index 0000000..45317d5 --- /dev/null +++ b/i3/scripts/battery-pinebook-pro @@ -0,0 +1,20 @@ +#!/usr/bin/env bash + +# simple Shellscript for i3blocks on Pinebook pro +# 05012020 geri123 //at// gmx.net Gerhard S. +# battery-symbols: you need the awesome-terminal-font package installed + +PERCENT=$(cat /sys/class/power_supply/cw2015-battery/capacity) +STATUS=$(cat /sys/class/power_supply/cw2015-battery/status) +case $(( + $PERCENT >= 0 && $PERCENT <= 20 ? 1 : + $PERCENT > 20 && $PERCENT <= 40 ? 2 : + $PERCENT > 40 && $PERCENT <= 60 ? 3 : + $PERCENT > 60 && $PERCENT <= 80 ? 4 : 5)) in +# + (1) echo $STATUS:"" :$PERCENT%;; + (2) echo $STATUS:"" :$PERCENT%;; + (3) echo $STATUS:"" :$PERCENT%;; + (4) echo $STATUS:"" :$PERCENT%;; + (5) echo $STATUS:"" :$PERCENT%;; +esac diff --git a/i3/scripts/blur-lock b/i3/scripts/blur-lock new file mode 100755 index 0000000..2f6cc31 --- /dev/null +++ b/i3/scripts/blur-lock @@ -0,0 +1,14 @@ +#!/usr/bin/env bash + +# simple screenlocker using i3lock that creates ablurred screenshot to overlay + +PICTURE=/tmp/i3lock.png +SCREENSHOT="scrot -z $PICTURE" + +BLUR="5x4" + +$SCREENSHOT +magick $PICTURE -blur $BLUR $PICTURE +i3lock -i $PICTURE +shred $PICTURE +rm $PICTURE diff --git a/i3/scripts/cpu_usage b/i3/scripts/cpu_usage new file mode 100755 index 0000000..8d8a267 --- /dev/null +++ b/i3/scripts/cpu_usage @@ -0,0 +1,62 @@ +#!/usr/bin/perl +# +# Copyright 2014 Pierre Mavro +# Copyright 2014 Vivien Didelot +# Copyright 2014 Andreas Guldstrand +# +# Licensed under the terms of the GNU GPL v3, or any later version. + +use strict; +use warnings; +use utf8; +use Getopt::Long; + +# default values +my $t_warn = $ENV{T_WARN} // 50; +my $t_crit = $ENV{T_CRIT} // 80; +my $cpu_usage = -1; +my $decimals = $ENV{DECIMALS} // 0; +my $label = $ENV{LABEL} // ""; + +sub help { + print "Usage: cpu_usage [-w ] [-c ] [-d ]\n"; + print "-w : warning threshold to become yellow\n"; + print "-c : critical threshold to become red\n"; + print "-d : Use decimals for percentage (default is $decimals) \n"; + exit 0; +} + +GetOptions("help|h" => \&help, + "w=i" => \$t_warn, + "c=i" => \$t_crit, + "d=i" => \$decimals, +); + +# Get CPU usage +$ENV{LC_ALL}="en_US"; # if mpstat is not run under en_US locale, things may break, so make sure it is +open (MPSTAT, 'mpstat 1 1 |') or die; +while () { + if (/^.*\s+(\d+\.\d+)[\s\x00]?$/) { + $cpu_usage = 100 - $1; # 100% - %idle + last; + } +} +close(MPSTAT); + +$cpu_usage eq -1 and die 'Can\'t find CPU information'; + +# Print short_text, full_text +print "${label}"; +printf "%02.${decimals}f%%\n", $cpu_usage; +print "${label}"; +printf "%02.${decimals}f%%\n", $cpu_usage; + +# Print color, if needed +if ($cpu_usage >= $t_crit) { + print "#FF0000\n"; + exit 33; +} elsif ($cpu_usage >= $t_warn) { + print "#FFFC00\n"; +} + +exit 0; diff --git a/i3/scripts/cputemp b/i3/scripts/cputemp new file mode 100755 index 0000000..8a7d821 --- /dev/null +++ b/i3/scripts/cputemp @@ -0,0 +1,17 @@ +#!/usr/bin/env bash + +# script to monitor temperatures in waybar/i3blocks e.t.c. +# example only use `sensors` to find your names to replace `Tdie|Tctl|Package` +# example output part from sensors: +# zenpower-pci-00c3 +# Adapter: PCI adapter +# SVI2_Core: 1.03 V +# SVI2_SoC: 994.00 mV +# Tdie: +53.1°C +# Tctl: +53.1°C +# Tccd1: +42.5°C +# Tccd2: +43.2°C + +temp=$(sensors 2>/dev/null | grep -E 'Tdie|Tctl|Package id 0' | grep -oP '\+?[0-9]+\.\d+(?=°C)' | tr -d '+' | head -n1) + +echo "${temp}°C" diff --git a/i3/scripts/disk b/i3/scripts/disk new file mode 100755 index 0000000..e18c7aa --- /dev/null +++ b/i3/scripts/disk @@ -0,0 +1,48 @@ +#!/usr/bin/env bash +# Copyright (C) 2014 Julien Bonjean + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +DIR="${DIR:-$BLOCK_INSTANCE}" +DIR="${DIR:-$HOME}" +ALERT_LOW="${ALERT_LOW:-$1}" +ALERT_LOW="${ALERT_LOW:-10}" # color will turn red under this value (default: 10%) + +LOCAL_FLAG="-l" +if [ "$1" = "-n" ] || [ "$2" = "-n" ]; then + LOCAL_FLAG="" +fi + +df -h -P $LOCAL_FLAG "$DIR" | awk -v label="$LABEL" -v alert_low=$ALERT_LOW ' +/\/.*/ { + # full text + print label $4 + + # short text + print label $4 + + use=$5 + + # no need to continue parsing + exit 0 +} + +END { + gsub(/%$/,"",use) + if (100 - use < alert_low) { + # color + print "#FF0000" + } +} +' diff --git a/i3/scripts/empty_workspace b/i3/scripts/empty_workspace new file mode 100755 index 0000000..fd21131 --- /dev/null +++ b/i3/scripts/empty_workspace @@ -0,0 +1,16 @@ +#!/usr/bin/env bash + +# Copyright (C) 2025 Johannes Kamprad +# SPDX-License-Identifier: GPL-3.0-or-later + +# empty_workspace - open a new workspace automatically named with next number on i3 + + +MAX_DESKTOPS=20 + +WORKSPACES=$(seq -s '\n' 1 1 ${MAX_DESKTOPS}) + +EMPTY_WORKSPACE=$( (i3-msg -t get_workspaces | tr ',' '\n' | grep num | awk -F: '{print int($2)}' ; \ + echo -e ${WORKSPACES} ) | sort -n | uniq -u | head -n 1) + +i3-msg workspace ${EMPTY_WORKSPACE} diff --git a/i3/scripts/gputemp b/i3/scripts/gputemp new file mode 100755 index 0000000..a63166c --- /dev/null +++ b/i3/scripts/gputemp @@ -0,0 +1,17 @@ +#!/usr/bin/env bash + +# script to monitor temperatures in waybar/i3blocks e.t.c. +# example only use `sensors` to find your sensor to replace `i915-pci-0600` +# example output part from sensors: +# i915-pci-0600 +# Adapter: PCI adapter +# in0: 630.00 mV +# fan1: 0 RPM +# temp1: +55.0°C +# energy1: 1.26 MJ + +# examples using Nvidia tools: +#echo "$(nvidia-smi --format=csv,noheader --query-gpu=temperature.gpu) °C" +#echo "$(nvidia-settings -q gpucoretemp -t) °C" +# example using sensor name: +sensors 2>/dev/null | awk '/i915-pci-0600/{flag=1} flag && /temp1/ {gsub("\\+", "", $2); print $2, $3; exit}' diff --git a/i3/scripts/import-gsettings b/i3/scripts/import-gsettings new file mode 100755 index 0000000..b848168 --- /dev/null +++ b/i3/scripts/import-gsettings @@ -0,0 +1,16 @@ +#!/bin/sh + +# needed for nwg-looks +# usage: import-gsettings +config="${XDG_CONFIG_HOME:-$HOME/.config}/gtk-3.0/settings.ini" +if [ ! -f "$config" ]; then exit 1; fi + +gnome_schema="org.gnome.desktop.interface" +gtk_theme="$(grep 'gtk-theme-name' "$config" | cut -d'=' -f2)" +icon_theme="$(grep 'gtk-icon-theme-name' "$config" | cut -d'=' -f2)" +cursor_theme="$(grep 'gtk-cursor-theme-name' "$config" | cut -d'=' -f2)" +font_name="$(grep 'gtk-font-name' "$config" | cut -d'=' -f2)" +gsettings set "$gnome_schema" gtk-theme "$gtk_theme" +gsettings set "$gnome_schema" icon-theme "$icon_theme" +gsettings set "$gnome_schema" cursor-theme "$cursor_theme" +gsettings set "$gnome_schema" font-name "$font_name" \ No newline at end of file diff --git a/i3/scripts/keyhint b/i3/scripts/keyhint new file mode 100755 index 0000000..34a123a --- /dev/null +++ b/i3/scripts/keyhint @@ -0,0 +1,27 @@ +#!/usr/bin/env bash + +# simple yad gui to show default keybindings + +Main() { + source /usr/share/endeavouros/scripts/eos-script-lib-yad || return 1 + + local command=( + eos_yad --title="EndeavourOS i3-wm keybindings:" --no-buttons --geometry=400x345-15-400 --list + --column=key: --column=description: --column=command: + "ESC" "close this app" "" + "=" "modkey" "(set mod Mod4)" + "+enter" "open a terminal" "" + "+Shift+n" "new empty workspace" "" + "+w" "open Browser" "" + "+n" "open Filebrowser" "" + "+d" "app menu" "" + "+q" "close focused app" "" + "Print-key" "screenshot" "" + "+Shift+e" "logout menu" "" + "F1" "open keybinding helper" "" + ) + + "${command[@]}" +} + +Main "$@" diff --git a/i3/scripts/keyhint-2 b/i3/scripts/keyhint-2 new file mode 100755 index 0000000..a5fd92f --- /dev/null +++ b/i3/scripts/keyhint-2 @@ -0,0 +1,10 @@ +#!/bin/sh + +# keyhint rofi tool to search used keybindings in i3wm + +I3_CONFIG=$HOME/.config/i3/config +mod_key=$(sed -nre 's/^set \$mod (.*)/\1/p' ${I3_CONFIG}) +grep "^bindsym" ${I3_CONFIG} \ + | sed "s/-\(-\w\+\)\+//g;s/\$mod/${mod_key}/g;s/Mod1/Alt/g;s/exec //;s/bindsym //;s/^\s\+//;s/^\([^ ]\+\) \(.\+\)$/\2: \1/;s/^\s\+//" \ + | tr -s ' ' \ + | rofi -dmenu -theme ~/.config/rofi/rofikeyhint.rasi diff --git a/i3/scripts/lock b/i3/scripts/lock new file mode 100755 index 0000000..611f9a6 --- /dev/null +++ b/i3/scripts/lock @@ -0,0 +1,10 @@ +#!/bin/bash +# Skip lock if a fullscreen window is active (game, video, etc.) +active=$(xprop -root _NET_ACTIVE_WINDOW 2>/dev/null | awk '{print $NF}') +if [ -n "$active" ] && [ "$active" != "0x0" ]; then + state=$(xprop -id "$active" _NET_WM_STATE 2>/dev/null) + if echo "$state" | grep -q "_NET_WM_STATE_FULLSCREEN"; then + exit 0 + fi +fi +exec ~/.config/i3/scripts/lock-now diff --git a/i3/scripts/lock-now b/i3/scripts/lock-now new file mode 100755 index 0000000..e5f04dc --- /dev/null +++ b/i3/scripts/lock-now @@ -0,0 +1,10 @@ +#!/bin/bash +img=$(find /sync/images/wallpapers/ -type f \( -iname "*.jpg" -o -iname "*.jpeg" -o -iname "*.png" \) | shuf -n1) +tmp=/tmp/lockscreen.png +res=$(xrandr --current | awk '/ connected/ {getline; print $1; exit}') +: "${res:=1920x1080}" +if [ -n "$img" ] && convert "$img" -resize "${res}^" -gravity Center -extent "$res" "$tmp" 2>/dev/null; then + exec i3lock -i "$tmp" --nofork +else + exec i3lock -c 000000 --nofork +fi diff --git a/i3/scripts/memory b/i3/scripts/memory new file mode 100755 index 0000000..e60be50 --- /dev/null +++ b/i3/scripts/memory @@ -0,0 +1,69 @@ +#!/usr/bin/env bash +# Copyright (C) 2014 Julien Bonjean + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +TYPE="${BLOCK_INSTANCE:-mem}" + +awk -v type=$TYPE ' +/^MemTotal:/ { + mem_total=$2 +} +/^MemFree:/ { + mem_free=$2 +} +/^Buffers:/ { + mem_free+=$2 +} +/^Cached:/ { + mem_free+=$2 +} +/^SwapTotal:/ { + swap_total=$2 +} +/^SwapFree:/ { + swap_free=$2 +} +END { + if (type == "swap") { + free=swap_free/1024/1024 + used=(swap_total-swap_free)/1024/1024 + total=swap_total/1024/1024 + } else { + free=mem_free/1024/1024 + used=(mem_total-mem_free)/1024/1024 + total=mem_total/1024/1024 + } + + pct=0 + if (total > 0) { + pct=used/total*100 + } + + # full text + # printf("%.1fG/%.1fG (%.f%%)\n", used, total, pct) + + # short text + printf("%02.f%%\n", pct) + + # color + if (pct > 90) { + print("#FF0000") + } else if (pct > 80) { + print("#FFAE00") + } else if (pct > 70) { + print("#FFF600") + } +} +' /proc/meminfo diff --git a/i3/scripts/openweather b/i3/scripts/openweather new file mode 100755 index 0000000..e41b833 --- /dev/null +++ b/i3/scripts/openweather @@ -0,0 +1,471 @@ +#!/usr/bin/env bash + +# openweater - OpenWeatherMap Weather Fetcher for Waybar/Status Bars +# +# Copyright (C) 2025 Johannes Kamprad +# +# SPDX-License-Identifier: GPL-3.0-or-later + + +# openweater - OpenWeatherMap Weather Fetcher for Waybar/Status Bars +# Secure API key handling with configurable locations +# including setup script and help +# Options: +# -h, --help Show this help message +# -c, --city-id ID Override city ID (required if not in config) +# -k, --api-key KEY Override API key (not recommended, use config file) +# -u, --units UNITS Units: metric, imperial, kelvin (default: $DEFAULT_UNITS) +# -f, --force-refresh Force refresh (ignore cache) +# --setup Interactive setup wizard +# --show-config Show current configuration + +set -euo pipefail + +# Set C locale to avoid German decimal formatting issues +export LC_NUMERIC=C +export LC_ALL=C + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +NC='\033[0m' # No Color + +# Default configuration (no default location) +DEFAULT_UNITS="metric" +CONFIG_DIR="${XDG_CONFIG_HOME:-$HOME/.config}" +CONFIG_FILE="$CONFIG_DIR/openweather/config" +CACHE_DIR="${XDG_CACHE_HOME:-$HOME/.cache}/openweather" +CACHE_FILE="$CACHE_DIR/weather_data" +CACHE_DURATION=600 # 10 minutes + +# Logging functions +log_error() { + echo -e "${RED}[ERROR]${NC} $*" >&2 +} + +log_warn() { + echo -e "${YELLOW}[WARN]${NC} $*" >&2 +} + +# Show help +show_help() { + cat << EOF +Usage: $(basename "$0") [OPTIONS] + +Secure OpenWeatherMap weather fetcher with configurable locations. + +Options: + -h, --help Show this help message + -c, --city-id ID Override city ID (required if not in config) + -k, --api-key KEY Override API key (not recommended, use config file) + -u, --units UNITS Units: metric, imperial, kelvin (default: $DEFAULT_UNITS) + -f, --force-refresh Force refresh (ignore cache) + --setup Interactive setup wizard + --show-config Show current configuration + +Configuration: + Config file: $CONFIG_FILE + + Create config file with: + OPENWEATHER_API_KEY="your_api_key_here" + OPENWEATHER_CITY_ID="your_city_id" # Required + OPENWEATHER_UNITS="metric" # Optional + +Examples: + $(basename "$0") # Use config file settings + $(basename "$0") --city-id 5128581 # New York + $(basename "$0") --units imperial # Fahrenheit + $(basename "$0") --setup # Run setup wizard + +Get your free API key at: https://openweathermap.org/api +Find city IDs at: https://openweathermap.org/find + +EOF +} + +# Check dependencies +check_dependencies() { + local missing_deps=() + + for cmd in jq curl; do + if ! command -v "$cmd" >/dev/null 2>&1; then + missing_deps+=("$cmd") + fi + done + + if [[ ${#missing_deps[@]} -gt 0 ]]; then + log_error "Missing required dependencies: ${missing_deps[*]}" + echo "Install with: sudo pacman -S ${missing_deps[*]}" + exit 1 + fi +} + +# Load configuration +load_config() { + # Set defaults (no default city ID) + OPENWEATHER_CITY_ID="" + OPENWEATHER_UNITS="$DEFAULT_UNITS" + + # Load from config file if it exists + if [[ -f "$CONFIG_FILE" ]]; then + source "$CONFIG_FILE" + fi + + # Override with environment variables if set + OPENWEATHER_API_KEY="${OPENWEATHER_API_KEY:-}" + OPENWEATHER_CITY_ID="${OPENWEATHER_CITY_ID:-}" + OPENWEATHER_UNITS="${OPENWEATHER_UNITS:-$DEFAULT_UNITS}" +} + +# Validate API key +validate_api_key() { + if [[ -z "$OPENWEATHER_API_KEY" ]]; then + log_error "No API key found!" + echo + echo "To fix this:" + echo "1. Get free API key: https://openweathermap.org/api" + echo "2. Run setup wizard: $0 --setup" + echo "3. Or set environment variable: export OPENWEATHER_API_KEY=your_key" + echo "4. Or create config file: $CONFIG_FILE" + exit 1 + fi + + # Basic validation (OpenWeatherMap keys are typically 32 chars) + if [[ ${#OPENWEATHER_API_KEY} -ne 32 ]]; then + log_warn "API key length seems incorrect (expected 32 characters, got ${#OPENWEATHER_API_KEY})" + fi +} + +# Validate city ID +validate_city_id() { + if [[ -z "$OPENWEATHER_CITY_ID" ]]; then + log_error "No city ID found!" + echo + echo "To fix this:" + echo "1. Run setup wizard: $0 --setup" + echo "2. Or set environment variable: export OPENWEATHER_CITY_ID=your_city_id" + echo "3. Or add OPENWEATHER_CITY_ID=\"your_city_id\" to: $CONFIG_FILE" + echo "4. Or provide city ID via command line: $0 --city-id your_city_id" + echo + echo "Find city IDs at: https://openweathermap.org/find" + exit 1 + fi + + # Basic validation (city IDs are typically numeric) + if [[ ! "$OPENWEATHER_CITY_ID" =~ ^[0-9]+$ ]]; then + log_warn "City ID format seems incorrect (expected numeric, got: $OPENWEATHER_CITY_ID)" + fi +} + +# Setup wizard +run_setup() { + echo -e "${GREEN}=== OpenWeatherMap Setup Wizard ===${NC}" + echo + + # Create config directory + mkdir -p "$(dirname "$CONFIG_FILE")" + + # Get API key + echo "Get your free API key at: https://openweathermap.org/api" + echo + echo -n "Enter your OpenWeatherMap API key: " + read -r api_key + + if [[ -z "$api_key" ]]; then + log_error "API key cannot be empty" + exit 1 + fi + + # Get city ID (required) + echo + echo "Find your city ID at: https://openweathermap.org/find" + echo -n "Enter city ID: " + read -r city_id + + if [[ -z "$city_id" ]]; then + log_error "City ID cannot be empty" + exit 1 + fi + + # Get units (optional) + echo + echo "Available units: metric (°C), imperial (°F), kelvin (K)" + echo -n "Enter units [metric]: " + read -r units + units="${units:-metric}" + + # Write config file + cat > "$CONFIG_FILE" << EOF +# OpenWeatherMap Configuration +# Generated by $(basename "$0") setup wizard on $(date) + +# Your API key from https://openweathermap.org/api +OPENWEATHER_API_KEY="$api_key" + +# City ID from https://openweathermap.org/find +OPENWEATHER_CITY_ID="$city_id" + +# Units: metric, imperial, kelvin +OPENWEATHER_UNITS="$units" +EOF + + # Set secure permissions + chmod 600 "$CONFIG_FILE" + + echo + echo -e "${GREEN}✅ Configuration saved to: $CONFIG_FILE${NC}" + echo -e "${GREEN}✅ File permissions set to 600 (user read/write only)${NC}" + echo + echo "Testing configuration..." + + # Test the configuration + OPENWEATHER_API_KEY="$api_key" + OPENWEATHER_CITY_ID="$city_id" + OPENWEATHER_UNITS="$units" + + if fetch_weather_data; then + echo -e "${GREEN}✅ Configuration test successful!${NC}" + else + log_error "Configuration test failed. Please check your API key and city ID." + exit 1 + fi +} + +# Show current configuration +show_config() { + echo "=== Current Configuration ===" + echo "Config file: $CONFIG_FILE" + echo "Cache file: $CACHE_FILE" + echo "Cache duration: ${CACHE_DURATION}s" + echo + + if [[ -f "$CONFIG_FILE" ]]; then + echo "Configuration:" + echo " API Key: ${OPENWEATHER_API_KEY:0:8}... (${#OPENWEATHER_API_KEY} chars)" + echo " City ID: $OPENWEATHER_CITY_ID" + echo " Units: $OPENWEATHER_UNITS" + else + echo "❌ No configuration file found at: $CONFIG_FILE" + echo "Run: $0 --setup" + fi +} + +# Check cache validity +is_cache_valid() { + [[ -f "$CACHE_FILE" ]] && \ + [[ $(($(date +%s) - $(stat -c %Y "$CACHE_FILE" 2>/dev/null || echo 0))) -lt $CACHE_DURATION ]] +} + +# Fetch weather data from API +fetch_weather_data() { + local url="https://api.openweathermap.org/data/2.5/weather?id=${OPENWEATHER_CITY_ID}&units=${OPENWEATHER_UNITS}&appid=${OPENWEATHER_API_KEY}" + + local response + if ! response=$(curl -sf "$url" 2>/dev/null); then + log_error "Failed to fetch weather data from API" + return 1 + fi + + # Validate JSON response + if ! echo "$response" | jq . >/dev/null 2>&1; then + log_error "Invalid JSON response from API" + return 1 + fi + + # Check for API error + local api_code + api_code=$(echo "$response" | jq -r '.cod // empty') + if [[ "$api_code" != "200" ]]; then + local api_message + api_message=$(echo "$response" | jq -r '.message // "Unknown API error"') + log_error "API Error ($api_code): $api_message" + return 1 + fi + + # Cache the response + mkdir -p "$CACHE_DIR" + echo "$response" > "$CACHE_FILE" + + return 0 +} + +# Get weather data (from cache or API) +get_weather_data() { + local force_refresh="${1:-false}" + + if [[ "$force_refresh" != "true" ]] && is_cache_valid; then + cat "$CACHE_FILE" + else + if fetch_weather_data; then + cat "$CACHE_FILE" + else + # Fallback to cache if available + if [[ -f "$CACHE_FILE" ]]; then + log_warn "Using stale cache data due to API failure" + cat "$CACHE_FILE" + else + return 1 + fi + fi + fi +} + +# Calculate wind direction +get_wind_direction() { + local degrees="$1" + local directions=(N NNE NE ENE E ESE SE SSE S SSW SW WSW W WNW NW NNW) + local index + index=$(awk "BEGIN {print int(($degrees % 360) / 22.5)}") + echo "${directions[$index]}" +} + +# Get weather icon +get_weather_icon() { + local condition="$1" + case "$condition" in + 'Clear') echo "☀" ;; # Clear sky + 'Clouds') echo "☁" ;; # Cloudy + 'Rain'|'Drizzle') echo "🌧" ;; # Rain + 'Snow') echo "❄" ;; # Snow + 'Thunderstorm') echo "⛈" ;; # Thunder + 'Mist'|'Fog') echo "🌫" ;; # Fog + *) echo "🌤" ;; # Default + esac +} + +# Safe number formatting (handles locale issues) +safe_printf() { + local format="$1" + local number="$2" + + # Validate number is actually numeric + if [[ ! "$number" =~ ^-?[0-9]+(\.[0-9]+)?$ ]]; then + echo "0.0" + return 1 + fi + + # Use awk for reliable formatting regardless of locale + awk "BEGIN {printf \"$format\", $number}" +} + +# Format weather output +format_weather() { + local weather_data="$1" + + # Parse weather data with error checking + local condition temp wind_speed_ms wind_deg + condition=$(echo "$weather_data" | jq -r '.weather[0].main // "Unknown"') + temp=$(echo "$weather_data" | jq -r '.main.temp // "0"') + wind_speed_ms=$(echo "$weather_data" | jq -r '.wind.speed // "0"') + wind_deg=$(echo "$weather_data" | jq -r '.wind.deg // "0"') + + # Validate parsed data + [[ "$condition" == "null" ]] && condition="Unknown" + [[ "$temp" == "null" ]] && temp="0" + [[ "$wind_speed_ms" == "null" ]] && wind_speed_ms="0" + [[ "$wind_deg" == "null" ]] && wind_deg="0" + + # Format temperature with safe formatting + local temp_formatted + temp_formatted=$(safe_printf "%.1f" "$temp") + + # Convert wind speed to km/h with safe formatting + local wind_speed_kmh + wind_speed_kmh=$(awk "BEGIN {printf \"%.1f\", ($wind_speed_ms + 0) * 3.6}") + + # Get wind direction + local wind_dir + wind_dir=$(get_wind_direction "$wind_deg") + + # Get weather icon + local icon + icon=$(get_weather_icon "$condition") + + # Format unit symbol + local unit_symbol + case "$OPENWEATHER_UNITS" in + "imperial") unit_symbol="°F" ;; + "kelvin") unit_symbol="K" ;; + *) unit_symbol="°C" ;; + esac + + # Output formatted weather + echo "${icon} ${temp_formatted}${unit_symbol}, ${wind_speed_kmh} km/h ${wind_dir}" +} + +# Main function +main() { + local city_id_override="" + local api_key_override="" + local units_override="" + local force_refresh="false" + + # Parse command line arguments + while [[ $# -gt 0 ]]; do + case $1 in + -h|--help) + show_help + exit 0 + ;; + -c|--city-id) + city_id_override="$2" + shift 2 + ;; + -k|--api-key) + api_key_override="$2" + shift 2 + ;; + -u|--units) + units_override="$2" + shift 2 + ;; + -f|--force-refresh) + force_refresh="true" + shift + ;; + --setup) + check_dependencies + run_setup + exit 0 + ;; + --show-config) + load_config + show_config + exit 0 + ;; + *) + log_error "Unknown option: $1" + show_help + exit 1 + ;; + esac + done + + # Check dependencies + check_dependencies + + # Load configuration + load_config + + # Apply overrides + [[ -n "$city_id_override" ]] && OPENWEATHER_CITY_ID="$city_id_override" + [[ -n "$api_key_override" ]] && OPENWEATHER_API_KEY="$api_key_override" + [[ -n "$units_override" ]] && OPENWEATHER_UNITS="$units_override" + + # Validate configuration + validate_api_key + validate_city_id + + # Get and format weather data + local weather_data + if weather_data=$(get_weather_data "$force_refresh"); then + format_weather "$weather_data" + else + echo "⚠️ Weather data unavailable" + exit 1 + fi +} + +# Run main function +main "$@" diff --git a/i3/scripts/power-profiles b/i3/scripts/power-profiles new file mode 100755 index 0000000..6c901b3 --- /dev/null +++ b/i3/scripts/power-profiles @@ -0,0 +1,64 @@ +#!/usr/bin/env bash + +# Simple power-profiles-daemon switcher using rofi and static theme, with notification +# +# Copyright (C) 2025 Johannes Kamprad +# +# SPDX-License-Identifier: GPL-3.0-or-later + +# needs rofi config: +# $HOME/.config/rofi/powermenu.rasi + +ROFI_THEME="${HOME}/.config/rofi/power-profiles.rasi" + +# Dependency checks +command -v powerprofilesctl >/dev/null 2>&1 || { echo "powerprofilesctl not found"; exit 1; } +command -v rofi >/dev/null 2>&1 || { echo "rofi not found"; exit 1; } +if ! command -v notify-send >/dev/null 2>&1; then + notify_send_missing=true +fi + +current_profile="$(powerprofilesctl get 2>/dev/null)" +ROFI_ARGS=(-dmenu -i -theme "$ROFI_THEME" -p "Change Profile" -mesg "Current used: $current_profile" -markup-rows) + +# Menu entries +cancel=" Cancel" +perf=" Performance" +balanced=" Balanced" +powersave=" Power Saver" +# sets chancel to be on top +options="$cancel" + +if powerprofilesctl list | grep -q "performance"; then + options="$options\n$perf" +fi +if powerprofilesctl list | grep -q "balanced"; then + options="$options\n$balanced" +fi +if powerprofilesctl list | grep -q "power-saver"; then + options="$options\n$powersave" +fi + +# Show menu +chosen="$(echo -e "$options" | rofi "${ROFI_ARGS[@]}")" + +# Run selection +case $chosen in + "$perf") + powerprofilesctl set performance + ;; + "$balanced") + powerprofilesctl set balanced + ;; + "$powersave") + powerprofilesctl set power-saver + ;; + "$cancel"|"") + exit 0 + ;; +esac + +# Send notification if available +if [[ "$chosen" != "$cancel" && -z "${notify_send_missing}" ]]; then + notify-send -i dialog-information "Power Profile Changed" "New profile: ${chosen}" +fi diff --git a/i3/scripts/powermenu b/i3/scripts/powermenu new file mode 100755 index 0000000..6111806 --- /dev/null +++ b/i3/scripts/powermenu @@ -0,0 +1,81 @@ +#!/usr/bin/env bash + +# +# powermenu - a very simple rofi powermenu +# +# Copyright (C) 2025 Johannes Kamprad +# +# SPDX-License-Identifier: GPL-3.0-or-later + +# needs rofi config: +# $HOME/.config/rofi/powermenu.rasi +# set to be used in i3wm + +ROFI_THEME="${HOME}/.config/rofi/powermenu.rasi" +# Define possible lock scripts/commands (edit this list as you like) +LOCK_SCRIPTS=("${HOME}/.config/i3/scripts/blur-lock" "i3lock") + +# Find available lock script +find_lock_script() { + for script in "${LOCK_SCRIPTS[@]}"; do + # Handle command names vs full paths + if [[ "$script" =~ ^[a-zA-Z0-9_-]+$ ]]; then + # It's a command name, check if available + if command -v "$script" >/dev/null 2>&1; then + echo "$script" + return 0 + fi + else + # It's a path, check if file exists and is executable + if [[ -x "$script" ]]; then + echo "$script" + return 0 + fi + fi + done + return 1 +} + +# Menu entries +chancel=" Cancel" +lock=" Lock" +logout=" Logout" +reboot=" Reboot" +shutdown=" Shutdown" +suspend=" Suspend" +hibernate=" Hibernate" + + +# Add lock only if script is found +if lockcmd="$(find_lock_script)"; then + options="$chancel\n$lock\n$logout\n$reboot\n$shutdown\n$suspend\n$hibernate" +else + options="$chancel\n$logout\n$reboot\n$shutdown\n$suspend\n$hibernate" +fi + +chosen="$(echo -e "$options" | rofi -dmenu -i -p "Power Menu" \ + -theme $ROFI_THEME)" + +case $chosen in + "$lock") + $lockcmd + ;; + "$cancel"|"") + exit 0 + ;; + "$logout") + i3-msg exit + ;; + "$reboot") + systemctl reboot + ;; + "$shutdown") + systemctl poweroff + ;; + "$suspend") + systemctl suspend + ;; + "$hibernate") + systemctl hibernate + ;; +esac diff --git a/i3/scripts/ppd-status b/i3/scripts/ppd-status new file mode 100755 index 0000000..92ab169 --- /dev/null +++ b/i3/scripts/ppd-status @@ -0,0 +1,25 @@ +#!/usr/bin/env bash + + +# power-profiles-daemon implementation: +# needs package power-profiles-daemon installed and the service running see here: +# https://wiki.archlinux.org/title/CPU_frequency_scaling#power-profiles-daemon +# used in i3-blocks: ~/.config/i3/i3blocks.conf together with: ~/.config/i3/scripts/power-profiles + + +# assign tags or translations to each profile +declare -A tags +tags=( + [performance]="Performance" + [balanced]="Balanced" + [power-saver]="Power saver" +) + +# Get current profile +current_profile=$(/usr/bin/powerprofilesctl get) + +# Get tag from the array +profile_tag=${tags[$current_profile]} + +# Show tag on i3block +echo "${profile_tag:-$current_profile}" diff --git a/i3/scripts/temperature b/i3/scripts/temperature new file mode 100755 index 0000000..69dcc63 --- /dev/null +++ b/i3/scripts/temperature @@ -0,0 +1,75 @@ +#!/usr/bin/env perl + +# Copyright 2014 Pierre Mavro +# Copyright 2014 Vivien Didelot +# Copyright 2014 Andreas Guldstrand +# Copyright 2014 Benjamin Chretien +# SPDX-License-Identifier: GPL-3.0-or-later + +# Edited by Andreas Lindlbauer + +use strict; +use warnings; +use utf8; +use Getopt::Long; + +binmode(STDOUT, ":utf8"); + +# default values +my $t_warn = $ENV{T_WARN} || 70; +my $t_crit = $ENV{T_CRIT} || 90; +my $chip = $ENV{SENSOR_CHIP} || ""; +my $temperature = -9999; +my $label = "😀 "; + +sub help { + print "Usage: temperature [-w ] [-c ] [--chip ]\n"; + print "-w : warning threshold to become yellow\n"; + print "-c : critical threshold to become red\n"; + print "--chip : sensor chip\n"; + exit 0; +} + +GetOptions("help|h" => \&help, + "w=i" => \$t_warn, + "c=i" => \$t_crit, + "chip=s" => \$chip); + +# Get chip temperature +open (SENSORS, "sensors -u $chip |") or die; +while () { + if (/^\s+temp1_input:\s+[\+]*([\-]*\d+\.\d)/) { + $temperature = $1; + last; + } +} +close(SENSORS); + +$temperature eq -9999 and die 'Cannot find temperature'; + +if ($temperature < 45) { + $label = ''; +} elsif ($temperature < 55) { + $label = ''; +} elsif ($temperature < 65) { + $label = ''; +} elsif ($temperature < 75) { + $label = ''; +} else { + $label = ''; +} +# Print short_text, full_text +print "${label}"; +print " $temperature°C\n"; +print "${label}"; +print " $temperature°C\n"; + +# Print color, if needed +if ($temperature >= $t_crit) { + print "#FF0000\n"; + exit 33; +} elsif ($temperature >= $t_warn) { + print "#FFFC00\n"; +} + +exit 0; diff --git a/i3/scripts/volume b/i3/scripts/volume new file mode 100755 index 0000000..97f2693 --- /dev/null +++ b/i3/scripts/volume @@ -0,0 +1,46 @@ +#!/usr/bin/env bash +# i3blocks volume block for PipeWire (PulseAudio compatible) + +STEP=${1:-5%} + +# Default sink +SINK=$(pactl info | awk '/Default Sink/ {print $3}') +[[ -z "$SINK" ]] && { echo "No audio"; exit 0; } + +# Handle scroll/middle-click +case "$BLOCK_BUTTON" in + 3) pactl set-sink-mute "$SINK" toggle ;; # right click = mute/unmute + 4) pactl set-sink-volume "$SINK" +$STEP ;; # scroll up + 5) pactl set-sink-volume "$SINK" -$STEP ;; # scroll down +esac + +# Get current volume (front-left channel) +VOL=$(pactl list sinks | awk -v s="$SINK" ' + $0 ~ "Name: " s {found=1} + found && /Volume:/ {gsub("%","",$5); print $5; exit} +') + +# Get mute state +MUTED=$(pactl list sinks | awk -v s="$SINK" ' + $0 ~ "Name: " s {found=1} + found && /Mute:/ {print $2; exit} +') + +# Choose symbol +AUDIO_HIGH='' +AUDIO_MED='' +AUDIO_LOW='' +AUDIO_MUTED='' +MED_THRESH=50 +LOW_THRESH=0 + +if [[ "$MUTED" == "no" ]]; then + SYMB=$AUDIO_HIGH + [[ $VOL -le $MED_THRESH ]] && SYMB=$AUDIO_MED + [[ $VOL -le $LOW_THRESH ]] && SYMB=$AUDIO_LOW +else + SYMB=$AUDIO_MUTED +fi + +# Single-line output for i3blocks +echo "${SYMB} ${VOL}%" diff --git a/i3/scripts/volume_brightness.sh b/i3/scripts/volume_brightness.sh new file mode 100755 index 0000000..676c6d3 --- /dev/null +++ b/i3/scripts/volume_brightness.sh @@ -0,0 +1,95 @@ +#!/usr/bin/env bash + +# original source: https://gitlab.com/Nmoleo/i3-volume-brightness-indicator +# changed to use brightnessctl [xbacklight is non functional on modern hardware] +# by joekamprad [Aug 2025] + +bar_color="#7f7fff" +volume_step=1 +brightness_step=5 +max_volume=100 +notification_timeout=1000 # in ms + +# Uses regex to get volume from pactl +function get_volume { + pactl get-sink-volume @DEFAULT_SINK@ | grep -Po '[0-9]{1,3}(?=%)' | head -1 +} + +# Uses regex to get mute status from pactl +function get_mute { + pactl get-sink-mute @DEFAULT_SINK@ | grep -Po '(?<=Mute: )(yes|no)' +} + +# Uses brightnessctl instead of xbacklight +function get_brightness { + brightnessctl g | awk '{print int($1)}' + # You could also use: brightnessctl info | grep -Po '(?<=Current brightness: )[0-9]+' +} + +# Calculates brightness percentage +function get_brightness_percent { + current=$(brightnessctl g) + max=$(brightnessctl m) + percent=$(( 100 * current / max )) + echo $percent +} + +function get_volume_icon { + volume=$(get_volume) + mute=$(get_mute) + if [ "$volume" -eq 0 ] || [ "$mute" == "yes" ] ; then + volume_icon="" + elif [ "$volume" -lt 50 ]; then + volume_icon="" + else + volume_icon="" + fi +} + +function get_brightness_icon { + brightness_icon="" +} + +function show_volume_notif { + volume=$(get_volume) + get_volume_icon + notify-send -i volume_icon -t 1000 "Volume" "$volume_icon $volume%" -h int:value:$volume -h string:x-canonical-private-synchronous:volume +} + + +function show_brightness_notif { + get_brightness_icon + brightness=$(get_brightness_percent) + notify-send -i brightness_icon -t $notification_timeout -h string:x-dunst-stack-tag:brightness_notif -h int:value:$brightness "$brightness_icon $brightness%" +} + + + +case $1 in + volume_up) + pactl set-sink-mute @DEFAULT_SINK@ 0 + volume=$(get_volume) + if [ $(( "$volume" + "$volume_step" )) -gt $max_volume ]; then + pactl set-sink-volume @DEFAULT_SINK@ $max_volume% + else + pactl set-sink-volume @DEFAULT_SINK@ +$volume_step% + fi + show_volume_notif + ;; + volume_down) + pactl set-sink-volume @DEFAULT_SINK@ -$volume_step% + show_volume_notif + ;; + volume_mute) + pactl set-sink-mute @DEFAULT_SINK@ toggle + show_volume_notif + ;; + brightness_up) + brightnessctl s +$brightness_step% > /dev/null + show_brightness_notif + ;; + brightness_down) + brightnessctl s $brightness_step%- > /dev/null + show_brightness_notif + ;; +esac diff --git a/i3/scripts/volume_brightness2.sh b/i3/scripts/volume_brightness2.sh new file mode 100755 index 0000000..cd78d77 --- /dev/null +++ b/i3/scripts/volume_brightness2.sh @@ -0,0 +1,168 @@ +#!/usr/bin/env bash + +# original source: https://gitlab.com/Nmoleo/i3-volume-brightness-indicator +# alternative to volume_brightness.sh that uses brightnessctl for both keyboard & screen brightness + +# See README.md for usage instructions +volume_step=1 +keyboard_brightness_step=20 +screen_brightness_step=1 +max_volume=100 +notification_timeout=1000 + +# Specify Icon Theme here: +volume_theme_icon="audio-volume-high" +screen_brightness_theme_icon="display-brightness" +keyboard_brightness_theme_icon="display-brightness" + +# Keyboard Backlight device detection here: +device_cache="/tmp/kbd_backlight_device" + +if [ -f "$device_cache" ]; then + # If there is cache, load it into device + device=$(cat "$device_cache") +else + # If there is no cache, create one + device=$(brightnessctl --list | grep -Po '\w+::kbd_backlight') + echo "$device" > "$device_cache" +fi + +# Uses regex to get volume from pactl +function get_volume { + pactl get-sink-volume @DEFAULT_SINK@ | grep -Po '[0-9]{1,3}(?=%)' | head -1 +} + +# Uses regex to get mute status from pactl +function get_mute { + pactl get-sink-mute @DEFAULT_SINK@ | grep -Po '(?<=Mute: )(yes|no)' +} + +# Get keyboard_brightness from brightnessctl +function get_keyboard_brightness { + if [ -n "$device" ]; then + keyboard_curr=$(brightnessctl -d "$device" get) + keyboard_max=$(brightnessctl -d "$device" max) + echo $(( keyboard_curr * 100 / keyboard_max)) + fi +} + + +# Grabs screen brightness and formats it out of 100 +function get_screen_brightness { + screen_curr=$(brightnessctl -q get) + screen_max=$(brightnessctl -q max) + echo $(( screen_curr * 100 / screen_max )) +} + +# Returns a mute icon, a volume-low icon, or a volume-high icon, depending on the volume +function get_volume_icon { + volume=$(get_volume) + mute=$(get_mute) + if [ "$volume" -eq 0 ] || [ "$mute" == "yes" ] ; then + volume_icon="" + elif [ "$volume" -lt 50 ] ; then + volume_icon="" + else + volume_icon="" + fi +} + +# Always returns the same icon - I couldn't get the brightness-low icon to work with fontawesome +function get_keyboard_brightness_icon { + kb_brightness=$(get_keyboard_brightness) + if [ "$kb_brightness" -eq 0 ] ; then + keyboard_brightness_icon="" # unfilled circle + elif [ "$kb_brightness" -lt 50 ] ; then + keyboard_brightness_icon="" # fa-adjust (low brightness) + else + keyboard_brightness_icon="" # full circle (high brightness) + fi +} + +function get_screen_brightness_icon { + sc_brightness=$(get_screen_brightness) + if [ "$sc_brightness" -eq 0 ] ; then + screen_brightness_icon="" # unfilled circle + elif [ "$sc_brightness" -lt 50 ] ; then + screen_brightness_icon="" # fa-adjust (low brightness) + else + screen_brightness_icon="" # full circle (high brightness) + fi +} + +# Displays a volume notification using notify-send +function show_volume_notif { + mute=$(get_mute) + volume=$(get_volume) + get_volume_icon + notify-send -i $volume_theme_icon -t $notification_timeout "Volume" "$volume_icon $volume%" -h int:value:$volume -h string:x-canonical-private-synchronous:volume +} + +# Displays a keyboard_brightness notification +function show_keyboard_brightness_notif { + keyboard_brightness=$(get_keyboard_brightness) + # Debug Purposes: + # echo $keyboard_brightness + get_keyboard_brightness_icon + notify-send -i $keyboard_brightness_theme_icon -t $notification_timeout "Keyboard Brightness" -h string:x-dunst-stack-tag:keyboard_brightness_notif -h int:value:$keyboard_brightness "$keyboard_brightness_icon $keyboard_brightness%" +} + +# Displays a screen_brightness notification +function show_screen_brightness_notif { + screen_brightness=$(get_screen_brightness) + # Debug Purposes: + # echo $screen_brightness + get_screen_brightness_icon + notify-send -i $screen_brightness_theme_icon -t $notification_timeout "Screen Brightness" -h string:x-dunst-stack-tag:screen_brightness_notif -h int:value:$screen_brightness "$screen_brightness_icon $screen_brightness%" +} + +# Main function - Takes user input, "volume_up", "volume_down", "keyboard_brightness_up", "keyboard_brightness_down", "brightness_up", or "brightness_down" +case $1 in + volume_up) + # Unmutes and increases volume, then displays the notification + pactl set-sink-mute @DEFAULT_SINK@ 0 + volume=$(get_volume) + if [ $(( "$volume" + "$volume_step" )) -gt $max_volume ]; then + pactl set-sink-volume @DEFAULT_SINK@ $max_volume% + else + pactl set-sink-volume @DEFAULT_SINK@ +$volume_step% + fi + show_volume_notif + ;; + + volume_down) + # Raises volume and displays the notification + pactl set-sink-volume @DEFAULT_SINK@ -$volume_step% + show_volume_notif + ;; + + volume_mute) + # Toggles mute and displays the notification + pactl set-sink-mute @DEFAULT_SINK@ toggle + show_volume_notif + ;; + + keyboard_brightness_up) + # Increases keyboard brightness and displays the notification + brightnessctl -d "$device" set ${keyboard_brightness_step}+ + show_keyboard_brightness_notif + ;; + + keyboard_brightness_down) + # Decreases keyboard brightness and displays the notification + brightnessctl -d "$device" set ${keyboard_brightness_step}- + show_keyboard_brightness_notif + ;; + + screen_brightness_up) + # Increases screen brightness and displays the notification + brightnessctl -q set ${screen_brightness_step}%+ + show_screen_brightness_notif + ;; + + screen_brightness_down) + # Decreases screen brightness and displays the notification + brightnessctl -q set ${screen_brightness_step}%- + show_screen_brightness_notif + ;; +esac diff --git a/i3/scripts/vpn b/i3/scripts/vpn new file mode 100755 index 0000000..bcf54ee --- /dev/null +++ b/i3/scripts/vpn @@ -0,0 +1,25 @@ +#!/usr/bin/env sh + +# Parses output from nmcli to show the current connected VPN name/status for i3block +# Source: https://github.com/vivien/i3blocks-contrib/tree/master/nm-vpn +# uncomment in $HOME/.config/i3/i3blocks.conf if you want to use it + +init_color=${init_color:-#FFFF00} +on_color=${on_color:-#00FF00} +export init_color on_color +nmcli -t connection show --active | awk -F ':' ' +BEGIN { + init_color=ENVIRON["init_color"] + on_color=ENVIRON["on_color"] +} +$3=="vpn" { + name=$1 + status="INIT" + color=init_color +} +$3=="tun" || ($4~/^tap/ || $3~/^tap/) { + if(!name) name=$1 + status="ON" + color=on_color +} +END {if(status) printf("%s\n%s\n%s\n", name, status, color)}' diff --git a/i3/scripts/wallpaper-rotate b/i3/scripts/wallpaper-rotate new file mode 100755 index 0000000..6215a67 --- /dev/null +++ b/i3/scripts/wallpaper-rotate @@ -0,0 +1,7 @@ +#!/bin/bash +# Rotate wallpaper every 20 minutes from /sync/images/wallpapers/ +while true; do + img=$(find /sync/images/wallpapers/ -type f \( -iname "*.jpg" -o -iname "*.jpeg" -o -iname "*.png" \) | shuf -n1) + [ -n "$img" ] && feh --bg-fill "$img" + sleep 1200 +done diff --git a/picom/picom.conf b/picom/picom.conf new file mode 100644 index 0000000..b777b3e --- /dev/null +++ b/picom/picom.conf @@ -0,0 +1,15 @@ +backend = "xrender"; +vsync = true; +use-damage = true; + +# games bypass picom entirely when fullscreen +unredir-if-possible = true; + +# no effects — featherweight +shadow = false; +fading = false; +blur-background = false; +corner-radius = 0; + +detect-transient = true; +detect-client-leader = true; diff --git a/polybar/config.ini b/polybar/config.ini index 13eaf9c..a00f088 100755 --- a/polybar/config.ini +++ b/polybar/config.ini @@ -17,14 +17,15 @@ ;========================================================== [colors] -background-alt = #00000000 -foreground = #1A2533 -primary = #2D6A8A -altprime = #2D6A8A -secondary = #0D1B27 -altsecondary = #3A7CA5EF -alert = #A52020 -disabled = #4A6878 +background = #BB111111 +background-alt = #BB111111 +foreground = #D0D0D0 +primary = #5294E2 +altprime = #6AAFE6 +secondary = #1A1A1A +altsecondary = #5294E2EF +alert = #CC3333 +disabled = #707070 [bar/example] bottom = false @@ -34,11 +35,11 @@ radius = 8 ; dpi = 96 -background = #00000000 +background = ${colors.background} foreground = ${colors.foreground} tray-position = right -tray-background = #C8D8E8 +tray-background = ${colors.background-alt} line-size = 2pt border-size = 0 @@ -52,7 +53,8 @@ module-margin = 1 separator = | separator-foreground = ${colors.disabled} -font-0 = 0xProto Nerd Font:pixelsize=14;3 +font-0 = JetBrainsMono Nerd Font:size=14;3 +#font-0 = 0xProto Nerd Font:pixelsize=14;3 modules-left = xworkspaces xwindow modules-right = polytiramisu memory cpu date battery xkeyboard From 99dc13136ef08e6848ef8f8faacfc10294a62fea Mon Sep 17 00:00:00 2001 From: nnduc Date: Thu, 25 Jun 2026 16:15:58 +0700 Subject: [PATCH 18/23] refine --- i3/config | 8 ++++---- i3/scripts/lock | 2 +- i3/scripts/lock-now | 3 ++- i3/scripts/wallpaper-rotate | 4 ++-- polybar/config.ini | 15 ++++++++------- 5 files changed, 17 insertions(+), 15 deletions(-) diff --git a/i3/config b/i3/config index dad74e7..f73b5dd 100755 --- a/i3/config +++ b/i3/config @@ -10,7 +10,7 @@ # Please see https://i3wm.org/docs/userguide.html for a complete reference! set $mod Mod1 -set $wallpaper '/sync/images/wallpapers/pexels-lumn.jpg' +set $wallpaper_dir /sync/images/wallpapers set $terminal 'wezterm' # Font for window titles. Will also be used by the bar unless a different font # is used in the bar {} block below. @@ -34,9 +34,9 @@ exec --no-startup-id xrandr --output HDMI-0 --mode 1920x1080 --rate 120 # burn-in prevention: blank after 5min, DPMS off after 10min, skip lock if fullscreen exec --no-startup-id xset s 300 300 exec --no-startup-id xset dpms 300 600 900 -exec --no-startup-id xss-lock -- ~/.config/i3/scripts/lock +exec --no-startup-id xss-lock -- ~/.config/i3/scripts/lock $wallpaper_dir -bindsym $mod+l exec ~/.config/i3/scripts/lock-now +bindsym $mod+l exec ~/.config/i3/scripts/lock-now $wallpaper_dir bindsym $mod+Shift+o exec systemctl suspend bindsym $mod+Shift+p exec systemctl poweroff @@ -50,7 +50,7 @@ exec --no-startup-id fcitx5 -d exec --no-startup-id nm-applet exec --no-startup-id blueman-applet exec --no-startup-id /usr/bin/gnome-keyring-daemon --start --components=ssh,pkcs11 -exec --no-startup-id ~/.config/i3/scripts/wallpaper-rotate +exec --no-startup-id ~/.config/i3/scripts/wallpaper-rotate $wallpaper_dir #exec --no-startup-id pasystray exec --no-startup-id polybar diff --git a/i3/scripts/lock b/i3/scripts/lock index 611f9a6..3b43364 100755 --- a/i3/scripts/lock +++ b/i3/scripts/lock @@ -7,4 +7,4 @@ if [ -n "$active" ] && [ "$active" != "0x0" ]; then exit 0 fi fi -exec ~/.config/i3/scripts/lock-now +exec ~/.config/i3/scripts/lock-now "$1" diff --git a/i3/scripts/lock-now b/i3/scripts/lock-now index e5f04dc..d7b8f91 100755 --- a/i3/scripts/lock-now +++ b/i3/scripts/lock-now @@ -1,5 +1,6 @@ #!/bin/bash -img=$(find /sync/images/wallpapers/ -type f \( -iname "*.jpg" -o -iname "*.jpeg" -o -iname "*.png" \) | shuf -n1) +wall_dir="${1:?wallpaper directory required}" +img=$(find "$wall_dir" -type f \( -iname "*.jpg" -o -iname "*.jpeg" -o -iname "*.png" \) | shuf -n1) tmp=/tmp/lockscreen.png res=$(xrandr --current | awk '/ connected/ {getline; print $1; exit}') : "${res:=1920x1080}" diff --git a/i3/scripts/wallpaper-rotate b/i3/scripts/wallpaper-rotate index 6215a67..f77e365 100755 --- a/i3/scripts/wallpaper-rotate +++ b/i3/scripts/wallpaper-rotate @@ -1,7 +1,7 @@ #!/bin/bash -# Rotate wallpaper every 20 minutes from /sync/images/wallpapers/ +wall_dir="${1:?wallpaper directory required}" while true; do - img=$(find /sync/images/wallpapers/ -type f \( -iname "*.jpg" -o -iname "*.jpeg" -o -iname "*.png" \) | shuf -n1) + img=$(find "$wall_dir" -type f \( -iname "*.jpg" -o -iname "*.jpeg" -o -iname "*.png" \) | shuf -n1) [ -n "$img" ] && feh --bg-fill "$img" sleep 1200 done diff --git a/polybar/config.ini b/polybar/config.ini index a00f088..5a9258d 100755 --- a/polybar/config.ini +++ b/polybar/config.ini @@ -31,15 +31,13 @@ disabled = #707070 bottom = false width = 100% height = 20pt -radius = 8 +radius = 0 ; dpi = 96 background = ${colors.background} foreground = ${colors.foreground} -tray-position = right -tray-background = ${colors.background-alt} line-size = 2pt border-size = 0 @@ -48,7 +46,7 @@ border-color = #00000000 padding-left = 1 padding-right = 1 -module-margin = 1 +;module-margin = 1 separator = | separator-foreground = ${colors.disabled} @@ -57,15 +55,13 @@ font-0 = JetBrainsMono Nerd Font:size=14;3 #font-0 = 0xProto Nerd Font:pixelsize=14;3 modules-left = xworkspaces xwindow -modules-right = polytiramisu memory cpu date battery xkeyboard +modules-right = date polytiramisu memory cpu battery xkeyboard tray cursor-click = pointer cursor-scroll = ns-resize enable-ipc = true -; tray-position = right - ; wm-restack = generic ; wm-restack = bspwm ; wm-restack = i3 @@ -185,6 +181,11 @@ exec = ~/.config/polybar/scripts/polytiramisu.sh format =