├── .gitignore ├── README.md ├── bin └── zellij │ ├── runner │ ├── CHANGELOG.md │ ├── Cargo.lock │ ├── Cargo.toml │ ├── README.md │ ├── screen.png │ └── src │ │ ├── action.rs │ │ ├── dir.rs │ │ ├── log.rs │ │ ├── main.rs │ │ ├── options.rs │ │ ├── runner.rs │ │ ├── ui.rs │ │ └── zellij.rs │ └── statusbar │ ├── .cargo │ └── config.toml │ ├── Cargo.lock │ ├── Cargo.toml │ ├── README.md │ └── src │ ├── color.rs │ ├── datetime.rs │ ├── main.rs │ ├── session.rs │ ├── tabs.rs │ └── view.rs ├── home ├── .bash_profile ├── .bashrc ├── .config │ ├── alacritty │ │ └── alacritty.toml │ ├── btop │ │ └── btop.conf │ ├── direnv │ │ └── direnv.toml │ ├── git │ │ ├── config │ │ └── ignore │ ├── hammerspoon │ │ └── init.lua │ ├── karabiner.edn │ ├── lazygit │ │ └── config.yml │ ├── nix │ │ └── nix.conf │ ├── nixpkgs │ │ └── config.nix │ ├── nvim │ │ ├── .gitignore │ │ ├── .neoconf.json │ │ ├── init.lua │ │ ├── lazy-lock.json │ │ ├── lazyvim.json │ │ ├── lua │ │ │ ├── config │ │ │ │ ├── autocmds.lua │ │ │ │ ├── keymaps.lua │ │ │ │ ├── lazy.lua │ │ │ │ └── options.lua │ │ │ ├── editor.lua │ │ │ ├── editor │ │ │ │ ├── buffers.lua │ │ │ │ ├── clipboard.lua │ │ │ │ ├── cursor.lua │ │ │ │ ├── debug.lua │ │ │ │ ├── editing.lua │ │ │ │ ├── formatting.lua │ │ │ │ ├── fs.lua │ │ │ │ ├── help.lua │ │ │ │ ├── icons.lua │ │ │ │ ├── keys.lua │ │ │ │ ├── lsp.lua │ │ │ │ ├── navigation.lua │ │ │ │ ├── search.lua │ │ │ │ ├── terminal.lua │ │ │ │ └── windows.lua │ │ │ ├── keymaps.lua │ │ │ ├── plugins │ │ │ │ ├── _disabled.lua │ │ │ │ ├── _theme.lua │ │ │ │ ├── cmp.lua │ │ │ │ ├── diffview.lua │ │ │ │ ├── flash.lua │ │ │ │ ├── gitsigns.lua │ │ │ │ ├── lazy.lua │ │ │ │ ├── lualine.lua │ │ │ │ ├── mini-pairs.lua │ │ │ │ ├── mini-starter.lua │ │ │ │ ├── mini-surround.lua │ │ │ │ ├── neo-tree.lua │ │ │ │ ├── no-neck-pain.lua │ │ │ │ ├── noice.lua │ │ │ │ ├── nvim-lspconfig.lua │ │ │ │ ├── nvim-notify.lua │ │ │ │ ├── persistence.lua │ │ │ │ ├── telescope.lua │ │ │ │ ├── tinygit.lua │ │ │ │ ├── trouble.lua │ │ │ │ └── zen-mode.lua │ │ │ ├── screen.lua │ │ │ ├── theme │ │ │ │ ├── colors │ │ │ │ │ └── theme.lua │ │ │ │ └── lua │ │ │ │ │ └── theme.lua │ │ │ └── utils │ │ │ │ ├── class.lua │ │ │ │ ├── init.lua │ │ │ │ └── log.lua │ │ └── stylua.toml │ ├── prettier.yml │ ├── raycast │ │ └── scripts │ │ │ └── youtube.sh │ ├── shell │ │ ├── apps │ │ │ ├── cargo.sh │ │ │ ├── devbox.sh │ │ │ ├── direnv.sh │ │ │ ├── docker.sh │ │ │ ├── git.sh │ │ │ ├── neovim.sh │ │ │ ├── nix.sh │ │ │ ├── node.sh │ │ │ ├── starship.sh │ │ │ └── zellij.sh │ │ ├── bash │ │ │ └── options.sh │ │ ├── init.sh │ │ ├── shortcuts.sh │ │ ├── variables.sh │ │ └── zsh │ │ │ ├── completions │ │ │ ├── _cargo │ │ │ └── _devbox │ │ │ └── options.sh │ ├── starship.toml │ ├── vimium │ │ └── vimium-options.json │ ├── yamlfmt │ │ └── .yamlfmt │ ├── zed │ │ ├── keymap.json │ │ ├── settings.json │ │ └── themes │ │ │ └── 35mil.json │ └── zellij │ │ ├── banners │ │ └── 01.banner │ │ ├── config.kdl │ │ ├── layouts │ │ └── terminal.kdl │ │ └── themes │ │ └── default.kdl ├── .editorconfig ├── .local │ └── share │ │ └── devbox │ │ └── global │ │ └── default │ │ ├── devbox.json │ │ └── devbox.lock ├── .profile ├── .zprofile ├── .zshenv └── .zshrc └── script ├── cargo.sh ├── font ├── original │ └── .gitkeep ├── patch.sh └── patched │ └── .gitkeep └── install.sh /.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | /.lsp/ 3 | /.clj-kondo/ 4 | /home/.config/zellij/plugins/** 5 | /script/font/original/**/* 6 | /script/font/patched/**/* 7 | !/script/font/original/**/.gitkeep 8 | !/script/font/patched/**/.gitkeep 9 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

dotfiles

2 | 3 |

4 | $EDITOR 5 | 6 | $EDITOR 7 | 8 |

9 | 10 |

Notes

11 |

12 | Primary tools: Zsh, Alacritty (with Zellij), Neovim (with Neovide). 13 |

14 | 15 |

16 | Packages are managed via Nix + Devbox. 17 |

18 | 19 |

20 | 21 |

22 | Quick links
23 | Neovim config
24 | NeoHub
25 | Zellij config
26 | Zellij session switcher
27 | Zellij statusbar
28 |

29 | 30 |

Screenshots

31 |

Terminal

32 | 33 |

34 | Session switcher 35 | Session selector 36 |

37 | 38 |

 

39 | 40 |

41 | Terminal multiplexer 42 | Session panes 43 |

44 | 45 |

 

46 | 47 |

Editor

48 | 49 |

50 | Single buffer 51 | Single buffer 52 |

53 | 54 |

 

55 | 56 |

57 | Buffer selector 58 | Buffer selector 59 |

60 | 61 |

 

62 | 63 |

64 | Multiple splits 65 | Multiple splits 66 |

67 | 68 |

69 | 70 |

🏴‍☠️

71 | -------------------------------------------------------------------------------- /bin/zellij/runner/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## 0.4.0 4 | - Update to Zellij v0.10. 5 | - Use `~` as a default session name for a session at `HOME` directory. 6 | 7 | ## 0.3.0 8 | - When changing a current directory for the new session, lowercase both dir and input during a filtering of the directory list. 9 | 10 | ## 0.2.0 11 | - On session selector screen, `Ctrl-N` starts creating a new session. 12 | - When creating a new session, `Esc` cancels it and takes to the session selector screen. 13 | - `Ctrl-C` exits the runner from any screen. 14 | 15 | ## 0.1.0 16 | Initial release. 17 | -------------------------------------------------------------------------------- /bin/zellij/runner/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "zellij-runner" 3 | description = "Session runner/switcher for Zellij" 4 | authors = ["Alex Fedoseev "] 5 | version = "0.4.0" 6 | readme = "README.md" 7 | documentation = "https://docs.rs/zellij-runner" 8 | repository = "https://github.com/alex35mil/dotfiles" 9 | keywords = ["zellij"] 10 | license = "MIT" 11 | edition = "2021" 12 | 13 | [dependencies] 14 | tui = "0.19.0" 15 | crossterm = "0.25" 16 | console = "0.15.5" 17 | dirs = "4.0.0" 18 | ignore = "0.4.20" 19 | unicode-width = "0.1" 20 | once_cell = "1.17.0" 21 | fastrand = "1.9.0" 22 | -------------------------------------------------------------------------------- /bin/zellij/runner/README.md: -------------------------------------------------------------------------------- 1 | # zellij-runner 2 | 3 | 4 | Ad-hoc replacement of Zellij session switcher (which doesn't exist yet). 5 | 6 | screen 7 | 8 | ## Installation 9 | ```sh 10 | cargo install zellij-runner 11 | ``` 12 | 13 | ## Usage 14 | ```sh 15 | # run switcher in interactive mode 16 | zellij-runner 17 | 18 | # create/connect to specified session 19 | zellij-runner my-session 20 | 21 | # create session with specified layout 22 | zellij-runner my-session my-layout 23 | ``` 24 | 25 | To exit the runner, hit `Esc` on session selector screen, or `Ctrl-C` on any screen. 26 | 27 | ## Configuration 28 | ### Layouts 29 | The runner can include layout selector when creating a new session. 30 | To activate it, set an environment variable with a path to the layouts folder: 31 | 32 | ```sh 33 | ZELLIJ_RUNNER_LAYOUTS_DIR=.config/zellij/layouts 34 | ``` 35 | 36 | ### Banner 37 | To show a banner, provide a path to the directory with ASCII art. 38 | 39 | ```sh 40 | ZELLIJ_RUNNER_BANNERS_DIR=.config/zellij/banners 41 | ``` 42 | 43 | Each file with ASCII art must have `.banner` extension. 44 | 45 | Runner would pick a random banner each time you switch sessions. 46 | 47 | ### Paths autocompletion 48 | To optimize autocompletion when switching working dir, set the following environment variables: 49 | 50 | ```sh 51 | # directory with the projects, relative to the HOME dir 52 | ZELLIJ_RUNNER_ROOT_DIR=Projects 53 | 54 | # switcher already respects gitignore, but it's still useful in case there's no git 55 | ZELLIJ_RUNNER_IGNORE_DIRS=node_modules,target 56 | 57 | # traverse dirs 3 level max from ZELLIJ_RUNNER_ROOT_DIR 58 | ZELLIJ_RUNNER_MAX_DIRS_DEPTH=3 59 | ``` 60 | 61 | 62 | -------------------------------------------------------------------------------- /bin/zellij/runner/screen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alex35mil/dotfiles/98c4539994572df10c4b941b04d43a14c6024ccc/bin/zellij/runner/screen.png -------------------------------------------------------------------------------- /bin/zellij/runner/src/action.rs: -------------------------------------------------------------------------------- 1 | use std::{io, process}; 2 | 3 | use crate::{dir::Dir, log, zellij}; 4 | 5 | pub(crate) enum Action { 6 | AttachToSession(String), 7 | CreateNewSession { 8 | session: String, 9 | layout: Option, 10 | dir: Option, 11 | }, 12 | Exit(Result<(), io::Error>), 13 | } 14 | 15 | impl Action { 16 | pub(crate) fn exec(self) { 17 | let action = self; 18 | 19 | let status = match action { 20 | Action::CreateNewSession { 21 | session, 22 | layout, 23 | dir: wd, 24 | } => zellij::create(&session, &layout, &wd), 25 | Action::AttachToSession(session) => zellij::attach(&session), 26 | Action::Exit(Ok(())) => process::exit(0), 27 | Action::Exit(Err(error)) => Self::exit_with_error(error), 28 | }; 29 | 30 | match status { 31 | Ok(status) => { 32 | if !status.success() { 33 | process::exit(status.code().unwrap_or(1)); 34 | } 35 | } 36 | Err(err) => Self::exit_with_error(err), 37 | } 38 | } 39 | 40 | fn exit_with_error(error: io::Error) -> ! { 41 | log::error(error); 42 | process::exit(1); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /bin/zellij/runner/src/dir.rs: -------------------------------------------------------------------------------- 1 | use std::{ 2 | env, fmt, 3 | ops::{Deref, DerefMut}, 4 | path::{Path, PathBuf}, 5 | }; 6 | 7 | #[derive(PartialEq, Clone, Debug)] 8 | pub(crate) struct Dir(PathBuf); 9 | 10 | impl Dir { 11 | pub fn home() -> Self { 12 | dirs::home_dir() 13 | .expect("Failed to get HOME directory.") 14 | .into() 15 | } 16 | 17 | pub fn cwd() -> Self { 18 | env::current_dir() 19 | .expect("Failed to get current directory of the process") 20 | .into() 21 | } 22 | 23 | pub fn filename(&self) -> Option { 24 | self.file_name() 25 | .and_then(|x| x.to_str().map(|x| x.to_string())) 26 | } 27 | 28 | pub fn join>(&self, path: P) -> Self { 29 | Self(self.as_path().join(path)) 30 | } 31 | } 32 | 33 | impl AsRef for Dir { 34 | fn as_ref(&self) -> &Path { 35 | &self.0 36 | } 37 | } 38 | 39 | impl From<&Path> for Dir { 40 | fn from(path: &Path) -> Self { 41 | Self(path.to_path_buf()) 42 | } 43 | } 44 | 45 | impl From for Dir { 46 | fn from(path: PathBuf) -> Self { 47 | Self(path) 48 | } 49 | } 50 | 51 | impl From for Dir { 52 | fn from(path: String) -> Self { 53 | Self(PathBuf::from(path)) 54 | } 55 | } 56 | 57 | impl Deref for Dir { 58 | type Target = PathBuf; 59 | 60 | fn deref(&self) -> &Self::Target { 61 | &self.0 62 | } 63 | } 64 | 65 | impl DerefMut for Dir { 66 | fn deref_mut(&mut self) -> &mut Self::Target { 67 | &mut self.0 68 | } 69 | } 70 | 71 | impl fmt::Display for Dir { 72 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 73 | let path = &self.0; 74 | let display = path.strip_prefix(Dir::home()).unwrap_or(path); 75 | write!(f, "~/{}", display.to_str().unwrap()) 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /bin/zellij/runner/src/log.rs: -------------------------------------------------------------------------------- 1 | use std::fmt; 2 | 3 | pub(crate) fn warn(msg: impl fmt::Display) { 4 | eprintln!("{}", console::style(format!("[WARNING] {}", msg)).yellow()); 5 | } 6 | 7 | pub(crate) fn error(msg: impl fmt::Display) { 8 | eprintln!("{}", console::style(format!("[ERROR] {}", msg)).red()); 9 | } 10 | -------------------------------------------------------------------------------- /bin/zellij/runner/src/main.rs: -------------------------------------------------------------------------------- 1 | //! Ad-hoc replacement of Zellij session switcher (which doesn't exist yet). 2 | //! 3 | //! screen 4 | //! 5 | //! ## Installation 6 | //! ```sh 7 | //! cargo install zellij-runner 8 | //! ``` 9 | //! 10 | //! ## Usage 11 | //! ```sh 12 | //! # run switcher in interactive mode 13 | //! zellij-runner 14 | //! 15 | //! # create/connect to specified session 16 | //! zellij-runner my-session 17 | //! 18 | //! # create session with specified layout 19 | //! zellij-runner my-session my-layout 20 | //! ``` 21 | //! 22 | //! To exit the runner, hit `Esc` at any point. 23 | //! 24 | //! ## Configuration 25 | //! ### Layouts 26 | //! The runner can include layout selector when creating a new session. 27 | //! To activate it, set an environment variable with a path to the layouts folder: 28 | //! 29 | //! ```sh 30 | //! ZELLIJ_RUNNER_LAYOUTS_DIR=.config/zellij/layouts 31 | //! ``` 32 | //! 33 | //! ### Banner 34 | //! To show a banner, provide a path to the directory with ASCII art. 35 | //! 36 | //! ```sh 37 | //! ZELLIJ_RUNNER_BANNERS_DIR=.config/zellij/banners 38 | //! ``` 39 | //! 40 | //! Each file with ASCII art must have `.banner` extension. 41 | //! 42 | //! Runner would pick a random banner each time you switch sessions. 43 | //! 44 | //! ### Paths autocompletion 45 | //! To optimize autocompletion when switching working dir, set the following environment variables: 46 | //! 47 | //! ```sh 48 | //! # directory with the projects, relative to the HOME dir 49 | //! ZELLIJ_RUNNER_ROOT_DIR=Projects 50 | //! 51 | //! # switcher already respects gitignore, but it's still useful in case there's no git 52 | //! ZELLIJ_RUNNER_IGNORE_DIRS=node_modules,target 53 | //! 54 | //! # traverse dirs 3 level max from ZELLIJ_RUNNER_ROOT_DIR 55 | //! ZELLIJ_RUNNER_MAX_DIRS_DEPTH=3 56 | //! ``` 57 | 58 | mod action; 59 | mod dir; 60 | mod log; 61 | mod options; 62 | mod runner; 63 | mod ui; 64 | mod zellij; 65 | 66 | fn main() { 67 | runner::init(); 68 | 69 | loop { 70 | runner::switch(); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /bin/zellij/runner/src/options.rs: -------------------------------------------------------------------------------- 1 | use once_cell::sync::Lazy; 2 | 3 | use crate::dir::Dir; 4 | 5 | pub(crate) static OPTIONS: Lazy = Lazy::new(Options::new); 6 | 7 | #[derive(Debug)] 8 | pub(crate) struct Options { 9 | pub root: Dir, 10 | pub ignore: Vec, 11 | pub depth: Option, 12 | pub layouts: Option, 13 | pub banners: Option, 14 | } 15 | 16 | impl Options { 17 | pub fn new() -> Self { 18 | Self { 19 | root: Self::root(), 20 | ignore: Self::ignore(), 21 | depth: Self::depth(), 22 | layouts: Self::layouts(), 23 | banners: Self::banners(), 24 | } 25 | } 26 | 27 | fn root() -> Dir { 28 | let home = Dir::home(); 29 | let root = env::ZELLIJ_RUNNER_ROOT_DIR(); 30 | 31 | root.map(|p| home.join(p)).unwrap_or(home) 32 | } 33 | 34 | fn ignore() -> Vec { 35 | let dirs = env::ZELLIJ_RUNNER_IGNORE_DIRS(); 36 | match dirs { 37 | Some(dirs) => dirs.split(',').map(|d| d.trim().to_string()).collect(), 38 | None => vec![], 39 | } 40 | } 41 | 42 | fn depth() -> Option { 43 | let dirs = env::ZELLIJ_RUNNER_MAX_DIRS_DEPTH(); 44 | match dirs { 45 | Some(n) => match n.parse() { 46 | Ok(n) => Some(n), 47 | Err(err) => { 48 | panic!("Invalid value of ZELLIJ_RUNNER_MAX_DIR_DEPTH. Must be positive int. Found: {}. {}", n, err) 49 | } 50 | }, 51 | None => None, 52 | } 53 | } 54 | 55 | fn layouts() -> Option { 56 | let home = Dir::home(); 57 | let dir = env::ZELLIJ_RUNNER_LAYOUTS_DIR(); 58 | 59 | dir.map(|p| home.join(p)) 60 | } 61 | 62 | fn banners() -> Option { 63 | let home = Dir::home(); 64 | let dir = env::ZELLIJ_RUNNER_BANNERS_DIR(); 65 | 66 | dir.map(|p| home.join(p)) 67 | } 68 | } 69 | 70 | mod env { 71 | use std::env::{self, VarError}; 72 | 73 | fn var(name: &str) -> Option { 74 | match env::var(name) { 75 | Ok(value) => Some(value), 76 | Err(VarError::NotPresent) => None, 77 | Err(VarError::NotUnicode(_)) => { 78 | panic!("Failed to read {} environment variable. ", name); 79 | } 80 | } 81 | } 82 | 83 | #[allow(non_snake_case)] 84 | pub(crate) fn ZELLIJ_RUNNER_ROOT_DIR() -> Option { 85 | var("ZELLIJ_RUNNER_ROOT_DIR") 86 | } 87 | 88 | #[allow(non_snake_case)] 89 | pub(crate) fn ZELLIJ_RUNNER_IGNORE_DIRS() -> Option { 90 | var("ZELLIJ_RUNNER_IGNORE_DIRS") 91 | } 92 | 93 | #[allow(non_snake_case)] 94 | pub(crate) fn ZELLIJ_RUNNER_MAX_DIRS_DEPTH() -> Option { 95 | var("ZELLIJ_RUNNER_MAX_DIRS_DEPTH") 96 | } 97 | 98 | #[allow(non_snake_case)] 99 | pub(crate) fn ZELLIJ_RUNNER_LAYOUTS_DIR() -> Option { 100 | var("ZELLIJ_RUNNER_LAYOUTS_DIR") 101 | } 102 | 103 | #[allow(non_snake_case)] 104 | pub(crate) fn ZELLIJ_RUNNER_BANNERS_DIR() -> Option { 105 | var("ZELLIJ_RUNNER_BANNERS_DIR") 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /bin/zellij/runner/src/runner.rs: -------------------------------------------------------------------------------- 1 | use std::env; 2 | 3 | use crate::{action::Action, ui, zellij}; 4 | 5 | struct Args { 6 | session: String, 7 | layout: Option, 8 | } 9 | 10 | impl Args { 11 | fn from_args() -> Option { 12 | let mut args = env::args(); 13 | 14 | match args.nth(1) { 15 | None => None, 16 | Some(session) => match args.nth(2) { 17 | None => Some(Self { 18 | session, 19 | layout: None, 20 | }), 21 | Some(layout) => Some(Self { 22 | session, 23 | layout: Some(layout), 24 | }), 25 | }, 26 | } 27 | } 28 | } 29 | 30 | pub(crate) fn init() { 31 | let input = Args::from_args(); 32 | 33 | let action = match zellij::list_sessions() { 34 | Err(error) => Action::Exit(Err(error)), 35 | Ok(sessions) => match (input, sessions.is_empty()) { 36 | (Some(Args { session, layout }), true) => Action::CreateNewSession { 37 | session, 38 | layout, 39 | dir: None, 40 | }, 41 | (None, true) => ui::new_session_prompt(sessions), 42 | (Some(Args { session, layout }), _) => { 43 | if sessions.contains(&session) { 44 | Action::AttachToSession(session) 45 | } else { 46 | Action::CreateNewSession { 47 | session, 48 | layout, 49 | dir: None, 50 | } 51 | } 52 | } 53 | (None, _) => ui::action_selector(sessions), 54 | }, 55 | }; 56 | 57 | action.exec() 58 | } 59 | 60 | pub(crate) fn switch() { 61 | let action = match zellij::list_sessions() { 62 | Err(error) => Action::Exit(Err(error)), 63 | Ok(sessions) => { 64 | if sessions.is_empty() { 65 | ui::new_session_prompt(sessions) 66 | } else { 67 | ui::action_selector(sessions) 68 | } 69 | } 70 | }; 71 | 72 | action.exec() 73 | } 74 | -------------------------------------------------------------------------------- /bin/zellij/runner/src/zellij.rs: -------------------------------------------------------------------------------- 1 | use std::{ 2 | cmp::Ordering, 3 | fs, io, 4 | process::{Command, ExitStatus}, 5 | slice, vec, 6 | }; 7 | 8 | use crate::dir::Dir; 9 | 10 | const BIN: &str = "zellij"; 11 | 12 | #[derive(Eq, PartialEq, Clone)] 13 | pub struct Session { 14 | pub name: String, 15 | pub is_exited: bool, 16 | } 17 | 18 | impl Ord for Session { 19 | fn cmp(&self, other: &Self) -> Ordering { 20 | match (self.is_exited, other.is_exited) { 21 | (true, false) => Ordering::Greater, 22 | (false, true) => Ordering::Less, 23 | _ => self.name.cmp(&other.name), 24 | } 25 | } 26 | } 27 | 28 | impl PartialOrd for Session { 29 | fn partial_cmp(&self, other: &Self) -> Option { 30 | Some(self.cmp(other)) 31 | } 32 | } 33 | 34 | #[derive(Clone)] 35 | pub struct Sessions(Vec); 36 | 37 | impl IntoIterator for Sessions { 38 | type Item = Session; 39 | type IntoIter = vec::IntoIter; 40 | 41 | fn into_iter(self) -> Self::IntoIter { 42 | self.0.into_iter() 43 | } 44 | } 45 | 46 | impl FromIterator for Sessions { 47 | fn from_iter>(iter: I) -> Self { 48 | Sessions(iter.into_iter().collect()) 49 | } 50 | } 51 | 52 | impl Sessions { 53 | pub fn empty() -> Self { 54 | Self(vec![]) 55 | } 56 | 57 | pub fn from_output(output: Vec<&str>) -> Self { 58 | let mut sessions = Vec::with_capacity(output.len()); 59 | 60 | for line in &output { 61 | let end = line.find('[').unwrap_or(0) - 1; 62 | let name = &line[..end]; 63 | let is_exited = line.contains("EXITED"); 64 | let session = Session { 65 | name: name.to_string(), 66 | is_exited, 67 | }; 68 | sessions.push(session); 69 | } 70 | 71 | sessions.sort(); 72 | 73 | Self(sessions) 74 | } 75 | 76 | pub fn iter(&self) -> slice::Iter { 77 | self.0.iter() 78 | } 79 | 80 | pub fn split(self) -> (Vec, Vec) { 81 | self.0.into_iter().partition(|s| !s.is_exited) 82 | } 83 | 84 | pub fn is_empty(&self) -> bool { 85 | self.0.is_empty() 86 | } 87 | 88 | pub fn contains(&self, session: &str) -> bool { 89 | self.0.iter().any(|s| s.name == session) 90 | } 91 | } 92 | 93 | pub(crate) fn list_sessions() -> io::Result { 94 | let output = Command::new(BIN) 95 | .args(["list-sessions", "--no-formatting"]) 96 | .output()?; 97 | 98 | if output.status.success() { 99 | let stdout = String::from_utf8(output.stdout).unwrap(); 100 | 101 | let lines: Vec<&str> = stdout.lines().collect(); 102 | 103 | Ok(Sessions::from_output(lines)) 104 | } else { 105 | let exit_code = match output.status.code() { 106 | Some(code) => code.to_string(), 107 | None => "-".to_string(), 108 | }; 109 | 110 | let stderr = String::from_utf8(output.stderr); 111 | 112 | match stderr { 113 | Ok(err) => { 114 | if err.contains("No") && err.contains("sessions found") { 115 | Ok(Sessions::empty()) 116 | } else { 117 | Err(io::Error::new( 118 | io::ErrorKind::Other, 119 | format!( 120 | "Failed to get Zellij sessions. Exit code: {}. {}", 121 | exit_code, err 122 | ), 123 | )) 124 | } 125 | } 126 | Err(_) => Err(io::Error::new( 127 | io::ErrorKind::Other, 128 | format!("Failed to get Zellij sessions. Exit code: {}", exit_code), 129 | )), 130 | } 131 | } 132 | } 133 | 134 | pub(crate) fn list_layouts(dir: &Dir) -> io::Result> { 135 | let layouts = match fs::read_dir(dir) { 136 | Ok(entries) => { 137 | let size = entries.size_hint().1; 138 | let mut layouts = match size { 139 | Some(size) => Vec::with_capacity(size), 140 | None => vec![], 141 | }; 142 | for entry in entries { 143 | match entry { 144 | Ok(entry) => { 145 | let path = entry.path(); 146 | if let Some(ext) = path.extension() { 147 | if ext.to_string_lossy() == "kdl" { 148 | let layout = 149 | path.file_stem().unwrap().to_string_lossy().to_string(); 150 | layouts.push(layout); 151 | } 152 | } 153 | } 154 | Err(err) => return Err(err), 155 | } 156 | } 157 | layouts 158 | } 159 | Err(err) => return Err(err), 160 | }; 161 | 162 | Ok(layouts) 163 | } 164 | 165 | pub(crate) fn create( 166 | session: &str, 167 | layout: &Option, 168 | dir: &Option, 169 | ) -> Result { 170 | let mut args = vec!["--session", session]; 171 | 172 | if let Some(layout) = layout { 173 | args.extend_from_slice(&["--layout", layout]); 174 | } 175 | 176 | let mut cmd = Command::new(BIN); 177 | 178 | if let Some(dir) = dir { 179 | cmd.current_dir(dir); 180 | } 181 | 182 | cmd.args(&args).status() 183 | } 184 | 185 | pub(crate) fn attach(session: &str) -> Result { 186 | Command::new(BIN).args(["attach", session]).status() 187 | } 188 | -------------------------------------------------------------------------------- /bin/zellij/statusbar/.cargo/config.toml: -------------------------------------------------------------------------------- 1 | [build] 2 | target = "wasm32-wasi" 3 | -------------------------------------------------------------------------------- /bin/zellij/statusbar/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "zellij-statusbar" 3 | version = "0.1.0" 4 | authors = ["Alex Fedoseev "] 5 | edition = "2021" 6 | 7 | [[bin]] 8 | name = "statusbar" 9 | path = "src/main.rs" 10 | 11 | [dependencies] 12 | zellij-tile = "0.38.2" 13 | zellij-tile-utils = "0.38.2" 14 | chrono = "0.4.26" 15 | colored = "2" 16 | ansi_term = "0.12" 17 | unicode-width = "0.1.8" 18 | -------------------------------------------------------------------------------- /bin/zellij/statusbar/README.md: -------------------------------------------------------------------------------- 1 | # zellij-statusbar 2 | Minimal statusbar plugin for Zellij. 3 | 4 | Terminal multiplexer 5 | 6 | ## Installation 7 | I didn't publish it anywhere, so you can pull this repo and build it from source. 8 | 9 | Checkout [my install script](../../../script/install.sh) and [zellij config](../../../home/.config/zellij/) for details. 10 | 11 | NOTE: On the first run, `zellij` asks the permission to run the plugin. Navigate to the plugin pane (it should be selectable) and hit `y`. You might need to restart the session for plugin to function properly. 12 | Make sure to have rust and the `wasm32-wasi` target installed. 13 | You can run this command `rustup target add wasm32-wasi` to install it. 14 | -------------------------------------------------------------------------------- /bin/zellij/statusbar/src/color.rs: -------------------------------------------------------------------------------- 1 | use zellij_tile::prelude::{InputMode, Palette, PaletteColor, ThemeHue}; 2 | 3 | pub const LIGHTER_GRAY: PaletteColor = PaletteColor::Rgb((62, 68, 82)); 4 | pub const DARKER_GRAY: PaletteColor = PaletteColor::Rgb((44, 50, 60)); 5 | 6 | pub struct ModeColor { 7 | pub fg: PaletteColor, 8 | pub bg: PaletteColor, 9 | } 10 | 11 | impl ModeColor { 12 | pub fn new(mode: InputMode, palette: Palette) -> Self { 13 | let fg = match palette.theme_hue { 14 | ThemeHue::Dark => palette.black, 15 | ThemeHue::Light => palette.white, 16 | }; 17 | 18 | let bg = match mode { 19 | InputMode::Locked => palette.cyan, 20 | InputMode::Normal => palette.green, 21 | _ => palette.orange, 22 | }; 23 | 24 | Self { fg, bg } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /bin/zellij/statusbar/src/datetime.rs: -------------------------------------------------------------------------------- 1 | use chrono::{FixedOffset, Utc}; 2 | 3 | use zellij_tile::prelude::*; 4 | use zellij_tile_utils::style; 5 | 6 | use crate::{ 7 | color::{self, ModeColor}, 8 | view::{Block, Separator, View}, 9 | }; 10 | 11 | #[derive(PartialEq)] 12 | pub struct DateTime { 13 | pub date: String, 14 | pub time: String, 15 | } 16 | 17 | impl DateTime { 18 | // NOTE: `time` crate can't get UTC offset in multithreaded binaries on macos: 19 | // https://github.com/time-rs/time/issues/293 20 | // so using chrono (which is also broken here) :shrugs: 21 | pub fn now() -> Self { 22 | // FIXME: UTC offset is always +00:00. Hardcoding TZ, for now. 23 | // let now = Local::now(); 24 | let utc = Utc::now(); 25 | let offset = FixedOffset::east_opt(4 * 3600 /* hours */).unwrap(); 26 | let now = utc.with_timezone(&offset); 27 | 28 | let datetime = now.format("%d/%m/%Y %H:%M").to_string(); 29 | 30 | let (date, time) = match datetime.split_once(' ') { 31 | Some(dt) => dt, 32 | None => return Self::na(), 33 | }; 34 | 35 | Self { 36 | date: date.to_owned(), 37 | time: time.to_owned(), 38 | } 39 | } 40 | 41 | fn na() -> Self { 42 | Self { 43 | date: "-".to_string(), 44 | time: "-".to_string(), 45 | } 46 | } 47 | 48 | pub fn render(&self, mode: InputMode, palette: Palette) -> View { 49 | use unicode_width::UnicodeWidthStr; 50 | 51 | let mut blocks = vec![]; 52 | let mut total_len = 0; 53 | 54 | let ModeColor { 55 | fg: mode_fg, 56 | bg: mode_bg, 57 | } = ModeColor::new(mode, palette); 58 | 59 | // separator 60 | { 61 | let separator = Separator::render(&color::LIGHTER_GRAY, &palette.bg); 62 | 63 | total_len += separator.len; 64 | blocks.push(separator); 65 | } 66 | 67 | // date 68 | { 69 | let text = format!(" {} ", self.date); 70 | let len = text.width(); 71 | let body = style!(palette.white, color::LIGHTER_GRAY).paint(text); 72 | 73 | total_len += len; 74 | blocks.push(Block { 75 | body: body.to_string(), 76 | len, 77 | tab_index: None, 78 | }); 79 | } 80 | 81 | // separator 82 | { 83 | let separator = Separator::render(&mode_bg, &color::LIGHTER_GRAY); 84 | 85 | total_len += separator.len; 86 | blocks.push(separator); 87 | } 88 | 89 | // time 90 | { 91 | let text = format!(" {} ", self.time); 92 | let len = text.width(); 93 | let body = style!(mode_fg, mode_bg).bold().paint(text); 94 | 95 | total_len += len; 96 | blocks.push(Block { 97 | body: body.to_string(), 98 | len, 99 | tab_index: None, 100 | }); 101 | } 102 | 103 | View { 104 | blocks, 105 | len: total_len, 106 | } 107 | } 108 | } 109 | 110 | impl Default for DateTime { 111 | fn default() -> Self { 112 | Self::now() 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /bin/zellij/statusbar/src/main.rs: -------------------------------------------------------------------------------- 1 | mod color; 2 | mod datetime; 3 | mod session; 4 | mod tabs; 5 | mod view; 6 | 7 | use std::{ 8 | cmp::{max, min}, 9 | collections::BTreeMap, 10 | }; 11 | 12 | use view::Error; 13 | use zellij_tile::prelude::*; 14 | 15 | use crate::{ 16 | datetime::DateTime, 17 | session::Session, 18 | tabs::Tabs, 19 | view::{Bg, Spacer}, 20 | }; 21 | 22 | #[derive(Default)] 23 | struct State { 24 | tabs: Vec, 25 | active_tab_idx: usize, 26 | mode_info: ModeInfo, 27 | mouse_click_pos: usize, 28 | should_change_tab: bool, 29 | now: DateTime, 30 | } 31 | 32 | register_plugin!(State); 33 | 34 | impl ZellijPlugin for State { 35 | fn load(&mut self, configuration: BTreeMap) { 36 | eprintln!("Loaded with configuration: {:#?}", configuration); 37 | 38 | request_permission(&[PermissionType::ReadApplicationState]); 39 | 40 | set_selectable(true); // selectable b/c we need a user input to grant the permissions 41 | set_timeout(1.0); 42 | subscribe(&[ 43 | EventType::TabUpdate, 44 | EventType::ModeUpdate, 45 | EventType::Mouse, 46 | EventType::Timer, 47 | ]); 48 | } 49 | 50 | fn update(&mut self, event: Event) -> bool { 51 | let mut should_render = false; 52 | 53 | match event { 54 | Event::PermissionRequestResult(status) => match status { 55 | PermissionStatus::Granted => { 56 | set_selectable(false); 57 | } 58 | PermissionStatus::Denied => { 59 | eprintln!("Permission denied."); 60 | } 61 | }, 62 | Event::ModeUpdate(mode_info) => { 63 | should_render = self.mode_info != mode_info; 64 | self.mode_info = mode_info; 65 | } 66 | Event::TabUpdate(tabs) => { 67 | if let Some(active_tab_index) = tabs.iter().position(|t| t.active) { 68 | // tabs are indexed starting from 1 so we need to add 1 69 | let active_tab_idx = active_tab_index + 1; 70 | 71 | should_render = self.active_tab_idx != active_tab_idx || self.tabs != tabs; 72 | self.active_tab_idx = active_tab_idx; 73 | self.tabs = tabs; 74 | } else { 75 | eprintln!("Could not find active tab."); 76 | } 77 | } 78 | Event::Mouse(event) => match event { 79 | Mouse::LeftClick(_, col) => { 80 | if self.mouse_click_pos != col { 81 | should_render = true; 82 | self.should_change_tab = true; 83 | } 84 | self.mouse_click_pos = col; 85 | } 86 | Mouse::ScrollUp(_) => { 87 | should_render = true; 88 | switch_tab_to(min(self.active_tab_idx + 1, self.tabs.len()) as u32); 89 | } 90 | Mouse::ScrollDown(_) => { 91 | should_render = true; 92 | switch_tab_to(max(self.active_tab_idx.saturating_sub(1), 1) as u32); 93 | } 94 | _ => {} 95 | }, 96 | Event::Timer(_) => { 97 | let now = DateTime::now(); 98 | should_render = now != self.now; 99 | self.now = now; 100 | set_timeout(1.0); 101 | } 102 | _ => { 103 | eprintln!("Unexpected event: {:?}", event); 104 | } 105 | }; 106 | 107 | should_render 108 | } 109 | 110 | fn render(&mut self, _rows: usize, cols: usize) { 111 | if self.tabs.is_empty() { 112 | return; 113 | } 114 | 115 | let session_name = &self.mode_info.session_name; 116 | let mode = self.mode_info.mode; 117 | let palette = self.mode_info.style.colors; 118 | 119 | let mut session = Session::render(session_name.as_deref(), mode, palette); 120 | let tabs = Tabs::render(&self.tabs, mode, palette); 121 | let mut datetime = self.now.render(mode, palette); 122 | let pad = Bg::render(2, self.mode_info.style.colors); 123 | 124 | let mut blocks = Vec::with_capacity(cols); 125 | 126 | let occupied = session.len + tabs.len + datetime.len + (pad.len * 2); 127 | 128 | blocks.append(&mut session.blocks); 129 | blocks.push(pad.clone()); 130 | 131 | let (mut mid, spacer) = if occupied > cols { 132 | let error = Error::render( 133 | "WHOA, YOU LIKE TABS DON'T YOU. IT'S TIME TO HANDLE IT.", 134 | palette, 135 | ); 136 | 137 | let parts_len = (session.len + pad.len, error.len, datetime.len + pad.len); 138 | 139 | let spacer = Spacer::render(cols, parts_len, palette); 140 | 141 | (vec![error], spacer) 142 | } else { 143 | let parts_len = (session.len + pad.len, tabs.len, datetime.len + pad.len); 144 | 145 | let spacer = Spacer::render(cols, parts_len, palette); 146 | 147 | (tabs.blocks, spacer) 148 | }; 149 | 150 | match spacer { 151 | Spacer { 152 | left: Some(left), 153 | right: Some(right), 154 | } => { 155 | blocks.push(left); 156 | blocks.append(&mut mid); 157 | blocks.push(right); 158 | } 159 | Spacer { 160 | left: Some(left), 161 | right: None, 162 | } => { 163 | blocks.push(left); 164 | blocks.append(&mut mid); 165 | } 166 | Spacer { 167 | left: None, 168 | right: Some(right), 169 | } => { 170 | blocks.append(&mut mid); 171 | blocks.push(right); 172 | } 173 | Spacer { 174 | left: None, 175 | right: None, 176 | } => { 177 | // come what may 178 | blocks.append(&mut mid); 179 | } 180 | } 181 | 182 | blocks.push(pad); 183 | blocks.append(&mut datetime.blocks); 184 | 185 | let mut bar = String::new(); 186 | let mut cursor = 0; 187 | 188 | for block in blocks { 189 | bar = format!("{}{}", bar, block.body); 190 | 191 | if let Some(idx) = block.tab_index { 192 | if self.should_change_tab 193 | && self.mouse_click_pos >= cursor 194 | && self.mouse_click_pos < cursor + block.len 195 | { 196 | // Tabs are indexed starting from 1, therefore we need add 1 to idx 197 | let tab_index = idx + 1; 198 | switch_tab_to(tab_index as u32); 199 | } 200 | } 201 | 202 | cursor += block.len; 203 | } 204 | 205 | let bg = match palette.theme_hue { 206 | ThemeHue::Dark => palette.black, 207 | ThemeHue::Light => palette.white, 208 | }; 209 | 210 | match bg { 211 | PaletteColor::Rgb((r, g, b)) => { 212 | print!("{}\u{1b}[48;2;{};{};{}m\u{1b}[0K", bar, r, g, b); 213 | } 214 | PaletteColor::EightBit(color) => { 215 | print!("{}\u{1b}[48;5;{}m\u{1b}[0K", bar, color); 216 | } 217 | } 218 | 219 | self.should_change_tab = false; 220 | } 221 | } 222 | -------------------------------------------------------------------------------- /bin/zellij/statusbar/src/session.rs: -------------------------------------------------------------------------------- 1 | use unicode_width::UnicodeWidthStr; 2 | 3 | use zellij_tile::prelude::*; 4 | use zellij_tile_utils::style; 5 | 6 | use crate::{ 7 | color::{self, ModeColor}, 8 | view::{Block, View}, 9 | }; 10 | 11 | pub struct Session; 12 | 13 | impl Session { 14 | pub fn render(name: Option<&str>, mode: InputMode, palette: Palette) -> View { 15 | let mut blocks = vec![]; 16 | let mut total_len = 0; 17 | 18 | // name 19 | if let Some(name) = name { 20 | let ModeColor { fg, bg } = ModeColor::new(mode, palette); 21 | 22 | let text = format!(" {} ", name.to_uppercase()); 23 | let len = text.width(); 24 | let body = style!(fg, bg).bold().paint(text); 25 | 26 | total_len += len; 27 | blocks.push(Block { 28 | body: body.to_string(), 29 | len, 30 | tab_index: None, 31 | }) 32 | } 33 | 34 | // mode 35 | { 36 | let text = { 37 | let sym = match mode { 38 | InputMode::Locked => "".to_string(), 39 | InputMode::Normal => "".to_string(), 40 | InputMode::Pane => "".to_string(), 41 | _ => format!("{:?}", mode).to_uppercase(), 42 | }; 43 | 44 | format!(" {} ", sym) 45 | }; 46 | let len = text.width(); 47 | let body = style!(palette.white, color::LIGHTER_GRAY).paint(text); 48 | 49 | total_len += len; 50 | blocks.push(Block { 51 | body: body.to_string(), 52 | len, 53 | tab_index: None, 54 | }) 55 | } 56 | 57 | View { 58 | blocks, 59 | len: total_len, 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /bin/zellij/statusbar/src/tabs.rs: -------------------------------------------------------------------------------- 1 | use unicode_width::UnicodeWidthStr; 2 | 3 | use zellij_tile::prelude::*; 4 | use zellij_tile_utils::style; 5 | 6 | use crate::{ 7 | color, 8 | view::{Block, View}, 9 | }; 10 | 11 | pub struct Tabs; 12 | 13 | impl Tabs { 14 | pub fn render(tabs: &[TabInfo], mode: InputMode, palette: Palette) -> View { 15 | let mut blocks: Vec = Vec::with_capacity(tabs.len()); 16 | let mut total_len = 0; 17 | 18 | for tab in tabs { 19 | let block = Tab::render(tab, mode, palette); 20 | 21 | total_len += block.len; 22 | blocks.push(block); 23 | } 24 | 25 | View { 26 | blocks, 27 | len: total_len, 28 | } 29 | } 30 | } 31 | 32 | pub struct Tab; 33 | 34 | impl Tab { 35 | pub fn render(tab: &TabInfo, mode: InputMode, palette: Palette) -> Block { 36 | let mut text = tab.name.clone(); 37 | 38 | if tab.active && mode == InputMode::RenameTab && text.is_empty() { 39 | text = String::from("Enter name..."); 40 | } 41 | 42 | if tab.is_sync_panes_active { 43 | text.push_str(" [sync]"); 44 | } 45 | 46 | if text.len() < 16 { 47 | text = format!("{:^16}", text); 48 | } else { 49 | text = format!(" {} ", text); 50 | } 51 | 52 | let len = text.width(); 53 | 54 | let fg = match palette.theme_hue { 55 | ThemeHue::Dark => palette.white, 56 | ThemeHue::Light => palette.black, 57 | }; 58 | 59 | let bg = if tab.active { 60 | color::LIGHTER_GRAY 61 | } else { 62 | color::DARKER_GRAY 63 | }; 64 | 65 | let body = style!(fg, bg).bold().paint(text); 66 | 67 | Block { 68 | body: body.to_string(), 69 | len, 70 | tab_index: Some(tab.position), 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /bin/zellij/statusbar/src/view.rs: -------------------------------------------------------------------------------- 1 | use unicode_width::UnicodeWidthStr; 2 | 3 | use zellij_tile::prelude::*; 4 | use zellij_tile_utils::style; 5 | 6 | pub struct View { 7 | pub blocks: Vec, 8 | pub len: usize, 9 | } 10 | 11 | #[derive(Default, Clone, Debug)] 12 | pub struct Block { 13 | pub body: String, 14 | pub len: usize, 15 | pub tab_index: Option, 16 | } 17 | 18 | pub struct Bg; 19 | 20 | impl Bg { 21 | pub fn render(cols: usize, palette: Palette) -> Block { 22 | let text = format!("{: <1$}", "", cols); 23 | let body = style!(palette.fg, palette.bg).paint(text); 24 | 25 | Block { 26 | body: body.to_string(), 27 | len: cols, 28 | tab_index: None, 29 | } 30 | } 31 | } 32 | 33 | pub struct Separator; 34 | 35 | impl Separator { 36 | const CHAR: &'static str = ""; 37 | 38 | pub fn render(fg: &PaletteColor, bg: &PaletteColor) -> Block { 39 | let text = Self::CHAR; 40 | let len = text.width(); 41 | let body = style!(*fg, *bg).paint(text); 42 | 43 | Block { 44 | body: body.to_string(), 45 | len, 46 | tab_index: None, 47 | } 48 | } 49 | } 50 | 51 | pub struct Spacer { 52 | pub left: Option, 53 | pub right: Option, 54 | } 55 | 56 | impl Spacer { 57 | pub fn render( 58 | total_len: usize, 59 | (left_len, mid_len, right_len): (usize, usize, usize), 60 | palette: Palette, 61 | ) -> Self { 62 | let room = total_len - mid_len; 63 | let (clean_left, clean_right) = Self::center(room); 64 | 65 | if clean_left > left_len && clean_right > right_len { 66 | let left = clean_left - left_len; 67 | let right = clean_right - right_len; 68 | Self { 69 | left: Some(Bg::render(left, palette)), 70 | right: Some(Bg::render(right, palette)), 71 | } 72 | } else if clean_left < left_len && clean_right - left_len - clean_left > right_len { 73 | let diff = left_len - clean_left; 74 | let right = clean_right - diff - right_len; 75 | 76 | Self { 77 | left: None, 78 | right: Some(Bg::render(right, palette)), 79 | } 80 | } else if clean_right < right_len && clean_left - right_len - clean_right > left_len { 81 | let diff = right_len - clean_right; 82 | let left = clean_left - diff - left_len; 83 | 84 | Self { 85 | left: Some(Bg::render(left, palette)), 86 | right: None, 87 | } 88 | } else { 89 | // We ran out of space 90 | Self { 91 | left: None, 92 | right: None, 93 | } 94 | } 95 | } 96 | 97 | fn center(room: usize) -> (usize, usize) { 98 | let quot = room / 2; 99 | let rem = room % 2; 100 | (quot, quot + rem) 101 | } 102 | } 103 | 104 | pub struct Error; 105 | 106 | impl Error { 107 | pub fn render(message: &str, palette: Palette) -> Block { 108 | let text = message; 109 | let len = text.width(); 110 | let body = style!(palette.white, palette.red).bold().paint(text); 111 | 112 | Block { 113 | body: body.to_string(), 114 | len, 115 | tab_index: None, 116 | } 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /home/.bash_profile: -------------------------------------------------------------------------------- 1 | source ~/.config/shell/init.sh 2 | source ~/.config/shell/variables.sh 3 | -------------------------------------------------------------------------------- /home/.bashrc: -------------------------------------------------------------------------------- 1 | [[ -n $PS1 ]] && source ~/.bash_profile 2 | 3 | source ~/.config/shell/bash/options.sh 4 | source ~/.config/shell/shortcuts.sh 5 | source ~/.config/shell/apps/cargo.sh 6 | source ~/.config/shell/apps/devbox.sh 7 | source ~/.config/shell/apps/direnv.sh 8 | source ~/.config/shell/apps/docker.sh 9 | source ~/.config/shell/apps/git.sh 10 | source ~/.config/shell/apps/neovim.sh 11 | source ~/.config/shell/apps/nix.sh 12 | source ~/.config/shell/apps/node.sh 13 | source ~/.config/shell/apps/starship.sh 14 | source ~/.config/shell/apps/zellij.sh 15 | -------------------------------------------------------------------------------- /home/.config/alacritty/alacritty.toml: -------------------------------------------------------------------------------- 1 | [env] 2 | TERM = "alacritty" 3 | 4 | [window] 5 | opacity = 1.0 6 | startup_mode = "Windowed" 7 | decorations = "Buttonless" 8 | padding = { x = 20, y = 20 } 9 | 10 | [font] 11 | size = 16.0 12 | normal = { family = "BerkeleyMono Nerd Font", style = "Regular" } 13 | bold = { family = "BerkeleyMono Nerd Font", style = "Bold" } 14 | italic = { family = "BerkeleyMono Nerd Font", style = "Italic" } 15 | bold_italic = { family = "BerkeleyMono Nerd Font", style = "Bold Italic" } 16 | 17 | [colors.primary] 18 | background = "#272b30" 19 | foreground = "#afb4c3" 20 | 21 | [colors.normal] 22 | black = "#272b30" 23 | red = "#cc6666" 24 | green = "#bdb968" 25 | yellow = "#f0c674" 26 | blue = "#81a2be" 27 | magenta = "#b08cba" 28 | cyan = "#7fb2c8" 29 | white = "#afb4c3" 30 | 31 | [selection] 32 | save_to_clipboard = true 33 | 34 | [keyboard] 35 | bindings = [ 36 | ### Zellij 37 | 38 | # Print char: `printf '\uE021'` 39 | 40 | { key = "T", mods = "Command", chars = "\uF429" }, 41 | { key = "N", mods = "Control", chars = "\uF89C" }, 42 | { key = "N", mods = "Command|Shift", chars = "\uF0FE" }, 43 | { key = "R", mods = "Command", chars = "\uF1FC" }, 44 | { key = "B", mods = "Command", chars = "\uF5CC" }, 45 | { key = "M", mods = "Command", chars = "\uF792" }, 46 | { key = "O", mods = "Command", chars = "\uF826" }, 47 | { key = "F", mods = "Command", chars = "\uF422" }, 48 | { key = "W", mods = "Control", chars = "\uF2D3" }, 49 | { key = "Q", mods = "Control", chars = "\uF090" }, 50 | 51 | { key = "Left", mods = "Shift", chars = "\uFC2F" }, 52 | { key = "Right", mods = "Shift", chars = "\uFC32" }, 53 | { key = "Up", mods = "Shift", chars = "\uFC35" }, 54 | { key = "Down", mods = "Shift", chars = "\uFC2C" }, 55 | 56 | { key = "Left", mods = "Control|Shift", chars = "\uEA9B" }, 57 | { key = "Right", mods = "Control|Shift", chars = "\uEA9C" }, 58 | { key = "Up", mods = "Control|Shift", chars = "\uEAA1" }, 59 | { key = "Down", mods = "Control|Shift", chars = "\uEA9A" }, 60 | 61 | { key = "Left", mods = "Option|Shift", chars = "\uF0D9" }, 62 | { key = "Right", mods = "Option|Shift", chars = "\uF0DA" }, 63 | { key = "Up", mods = "Option|Shift", chars = "\uF0D8" }, 64 | { key = "Down", mods = "Option|Shift", chars = "\uF0D7" }, 65 | 66 | { key = "Up", mods = "Option", chars = "\uF271" }, 67 | { key = "R", mods = "Option", chars = "\uF448" }, 68 | { key = "W", mods = "Option", chars = "\uF273" }, 69 | { key = "Left", mods = "Option", chars = "\uF04A" }, 70 | { key = "Right", mods = "Option", chars = "\uF04E" }, 71 | { key = "Left", mods = "Option|Shift", chars = "\uF049" }, 72 | { key = "Right", mods = "Option|Shift", chars = "\uF050" }, 73 | 74 | { key = "Up", mods = "Command", chars = "\uF106" }, 75 | { key = "Down", mods = "Command", chars = "\uF107" }, 76 | { key = "Up", mods = "Command|Shift", chars = "\uF102" }, 77 | { key = "Down", mods = "Command|Shift", chars = "\uF103" }, 78 | { key = "Up", mods = "Command|Option|Shift", chars = "\uF6BB" }, 79 | { key = "Down", mods = "Command|Option|Shift", chars = "\uF6BA" }, 80 | ] 81 | -------------------------------------------------------------------------------- /home/.config/btop/btop.conf: -------------------------------------------------------------------------------- 1 | #? Config file for btop v. 1.2.13 2 | 3 | #* Name of a btop++/bpytop/bashtop formatted ".theme" file, "Default" and "TTY" for builtin themes. 4 | #* Themes should be placed in "../share/btop/themes" relative to binary or "$HOME/.config/btop/themes" 5 | color_theme = "TTY" 6 | 7 | #* If the theme set background should be shown, set to False if you want terminal background transparency. 8 | theme_background = False 9 | 10 | #* Sets if 24-bit truecolor should be used, will convert 24-bit colors to 256 color (6x6x6 color cube) if false. 11 | truecolor = True 12 | 13 | #* Set to true to force tty mode regardless if a real tty has been detected or not. 14 | #* Will force 16-color mode and TTY theme, set all graph symbols to "tty" and swap out other non tty friendly symbols. 15 | force_tty = False 16 | 17 | #* Define presets for the layout of the boxes. Preset 0 is always all boxes shown with default settings. Max 9 presets. 18 | #* Format: "box_name:P:G,box_name:P:G" P=(0 or 1) for alternate positions, G=graph symbol to use for box. 19 | #* Use whitespace " " as separator between different presets. 20 | #* Example: "cpu:0:default,mem:0:tty,proc:1:default cpu:0:braille,proc:0:tty" 21 | presets = "cpu:1:default,proc:0:default cpu:0:default,mem:0:default,net:0:default cpu:0:block,net:0:tty" 22 | 23 | #* Set to True to enable "h,j,k,l,g,G" keys for directional control in lists. 24 | #* Conflicting keys for h:"help" and k:"kill" is accessible while holding shift. 25 | vim_keys = False 26 | 27 | #* Rounded corners on boxes, is ignored if TTY mode is ON. 28 | rounded_corners = True 29 | 30 | #* Default symbols to use for graph creation, "braille", "block" or "tty". 31 | #* "braille" offers the highest resolution but might not be included in all fonts. 32 | #* "block" has half the resolution of braille but uses more common characters. 33 | #* "tty" uses only 3 different symbols but will work with most fonts and should work in a real TTY. 34 | #* Note that "tty" only has half the horizontal resolution of the other two, so will show a shorter historical view. 35 | graph_symbol = "braille" 36 | 37 | # Graph symbol to use for graphs in cpu box, "default", "braille", "block" or "tty". 38 | graph_symbol_cpu = "default" 39 | 40 | # Graph symbol to use for graphs in cpu box, "default", "braille", "block" or "tty". 41 | graph_symbol_mem = "default" 42 | 43 | # Graph symbol to use for graphs in cpu box, "default", "braille", "block" or "tty". 44 | graph_symbol_net = "default" 45 | 46 | # Graph symbol to use for graphs in cpu box, "default", "braille", "block" or "tty". 47 | graph_symbol_proc = "default" 48 | 49 | #* Manually set which boxes to show. Available values are "cpu mem net proc", separate values with whitespace. 50 | shown_boxes = "cpu mem proc net" 51 | 52 | #* Update time in milliseconds, recommended 2000 ms or above for better sample times for graphs. 53 | update_ms = 2000 54 | 55 | #* Processes sorting, "pid" "program" "arguments" "threads" "user" "memory" "cpu lazy" "cpu direct", 56 | #* "cpu lazy" sorts top process over time (easier to follow), "cpu direct" updates top process directly. 57 | proc_sorting = "cpu lazy" 58 | 59 | #* Reverse sorting order, True or False. 60 | proc_reversed = False 61 | 62 | #* Show processes as a tree. 63 | proc_tree = False 64 | 65 | #* Use the cpu graph colors in the process list. 66 | proc_colors = True 67 | 68 | #* Use a darkening gradient in the process list. 69 | proc_gradient = True 70 | 71 | #* If process cpu usage should be of the core it's running on or usage of the total available cpu power. 72 | proc_per_core = False 73 | 74 | #* Show process memory as bytes instead of percent. 75 | proc_mem_bytes = True 76 | 77 | #* Show cpu graph for each process. 78 | proc_cpu_graphs = True 79 | 80 | #* Use /proc/[pid]/smaps for memory information in the process info box (very slow but more accurate) 81 | proc_info_smaps = False 82 | 83 | #* Show proc box on left side of screen instead of right. 84 | proc_left = False 85 | 86 | #* (Linux) Filter processes tied to the Linux kernel(similar behavior to htop). 87 | proc_filter_kernel = False 88 | 89 | #* Sets the CPU stat shown in upper half of the CPU graph, "total" is always available. 90 | #* Select from a list of detected attributes from the options menu. 91 | cpu_graph_upper = "total" 92 | 93 | #* Sets the CPU stat shown in lower half of the CPU graph, "total" is always available. 94 | #* Select from a list of detected attributes from the options menu. 95 | cpu_graph_lower = "total" 96 | 97 | #* Toggles if the lower CPU graph should be inverted. 98 | cpu_invert_lower = True 99 | 100 | #* Set to True to completely disable the lower CPU graph. 101 | cpu_single_graph = False 102 | 103 | #* Show cpu box at bottom of screen instead of top. 104 | cpu_bottom = False 105 | 106 | #* Shows the system uptime in the CPU box. 107 | show_uptime = True 108 | 109 | #* Show cpu temperature. 110 | check_temp = True 111 | 112 | #* Which sensor to use for cpu temperature, use options menu to select from list of available sensors. 113 | cpu_sensor = "Auto" 114 | 115 | #* Show temperatures for cpu cores also if check_temp is True and sensors has been found. 116 | show_coretemp = True 117 | 118 | #* Set a custom mapping between core and coretemp, can be needed on certain cpus to get correct temperature for correct core. 119 | #* Use lm-sensors or similar to see which cores are reporting temperatures on your machine. 120 | #* Format "x:y" x=core with wrong temp, y=core with correct temp, use space as separator between multiple entries. 121 | #* Example: "4:0 5:1 6:3" 122 | cpu_core_map = "" 123 | 124 | #* Which temperature scale to use, available values: "celsius", "fahrenheit", "kelvin" and "rankine". 125 | temp_scale = "celsius" 126 | 127 | #* Use base 10 for bits/bytes sizes, KB = 1000 instead of KiB = 1024. 128 | base_10_sizes = False 129 | 130 | #* Show CPU frequency. 131 | show_cpu_freq = True 132 | 133 | #* Draw a clock at top of screen, formatting according to strftime, empty string to disable. 134 | #* Special formatting: /host = hostname | /user = username | /uptime = system uptime 135 | clock_format = "%X" 136 | 137 | #* Update main ui in background when menus are showing, set this to false if the menus is flickering too much for comfort. 138 | background_update = True 139 | 140 | #* Custom cpu model name, empty string to disable. 141 | custom_cpu_name = "" 142 | 143 | #* Optional filter for shown disks, should be full path of a mountpoint, separate multiple values with whitespace " ". 144 | #* Begin line with "exclude=" to change to exclude filter, otherwise defaults to "most include" filter. Example: disks_filter="exclude=/boot /home/user". 145 | disks_filter = "" 146 | 147 | #* Show graphs instead of meters for memory values. 148 | mem_graphs = True 149 | 150 | #* Show mem box below net box instead of above. 151 | mem_below_net = False 152 | 153 | #* Count ZFS ARC in cached and available memory. 154 | zfs_arc_cached = True 155 | 156 | #* If swap memory should be shown in memory box. 157 | show_swap = True 158 | 159 | #* Show swap as a disk, ignores show_swap value above, inserts itself after first disk. 160 | swap_disk = True 161 | 162 | #* If mem box should be split to also show disks info. 163 | show_disks = True 164 | 165 | #* Filter out non physical disks. Set this to False to include network disks, RAM disks and similar. 166 | only_physical = True 167 | 168 | #* Read disks list from /etc/fstab. This also disables only_physical. 169 | use_fstab = True 170 | 171 | #* Setting this to True will hide all datasets, and only show ZFS pools. (IO stats will be calculated per-pool) 172 | zfs_hide_datasets = False 173 | 174 | #* Set to true to show available disk space for privileged users. 175 | disk_free_priv = False 176 | 177 | #* Toggles if io activity % (disk busy time) should be shown in regular disk usage view. 178 | show_io_stat = True 179 | 180 | #* Toggles io mode for disks, showing big graphs for disk read/write speeds. 181 | io_mode = False 182 | 183 | #* Set to True to show combined read/write io graphs in io mode. 184 | io_graph_combined = False 185 | 186 | #* Set the top speed for the io graphs in MiB/s (100 by default), use format "mountpoint:speed" separate disks with whitespace " ". 187 | #* Example: "/mnt/media:100 /:20 /boot:1". 188 | io_graph_speeds = "" 189 | 190 | #* Set fixed values for network graphs in Mebibits. Is only used if net_auto is also set to False. 191 | net_download = 100 192 | 193 | net_upload = 100 194 | 195 | #* Use network graphs auto rescaling mode, ignores any values set above and rescales down to 10 Kibibytes at the lowest. 196 | net_auto = True 197 | 198 | #* Sync the auto scaling for download and upload to whichever currently has the highest scale. 199 | net_sync = True 200 | 201 | #* Starts with the Network Interface specified here. 202 | net_iface = "en0" 203 | 204 | #* Show battery stats in top right if battery is present. 205 | show_battery = True 206 | 207 | #* Which battery to use if multiple are present. "Auto" for auto detection. 208 | selected_battery = "Auto" 209 | 210 | #* Set loglevel for "~/.config/btop/btop.log" levels are: "ERROR" "WARNING" "INFO" "DEBUG". 211 | #* The level set includes all lower levels, i.e. "DEBUG" will show all logging info. 212 | log_level = "WARNING" -------------------------------------------------------------------------------- /home/.config/direnv/direnv.toml: -------------------------------------------------------------------------------- 1 | [global] 2 | load_dotenv = false 3 | -------------------------------------------------------------------------------- /home/.config/git/config: -------------------------------------------------------------------------------- 1 | [user] 2 | name = "Alex Fedoseev" 3 | email = "alex@35mil.me" 4 | 5 | [core] 6 | editor = "nvim" 7 | ignorecase = false 8 | 9 | [color] 10 | ui = "auto" 11 | 12 | [http] 13 | postBuffer = 524288000 14 | 15 | [init] 16 | defaultBranch = "main" 17 | 18 | [branch] 19 | sort = "-committerdate" 20 | 21 | [push] 22 | default = "simple" 23 | followTags = true 24 | 25 | [pull] 26 | rebase = true 27 | 28 | [diff] 29 | algorithm = "histogram" 30 | 31 | [merge] 32 | conflictStyle = "zdiff3" 33 | 34 | [rerere] 35 | enabled = true 36 | 37 | [alias] 38 | # Delete all merged branches except for the currently checked out one. 39 | dm = "!git branch --merged | grep -v '\\*' | xargs -n 1 git branch -d" 40 | 41 | # Show parent branch 42 | parent = "!git show-branch | grep '*' | grep -v \"$(git rev-parse --abbrev-ref HEAD)\" | head -n1 | sed 's/.*\\[\\(.*\\)\\].*/\\1/' | sed 's/[\\^~].*//' #" 43 | 44 | # Show log in a pretty format with relative dates, commit hash, message, author, and date. 45 | # The '%h' is the abbreviated hash, '%s' is the subject, '%ad' is the author date, and '%an' is the author name. 46 | history = "log --pretty=format:'%C(yellow)%h%C(reset) - %s %C(dim)%ad <%an>' --date=relative" 47 | 48 | # Interactive rebase on the last n commits, where n is provided as an argument to the alias. 49 | # For example, 'git irebase 5' would start an interactive rebase for the last 5 commits. 50 | irebase = "!r() { git rebase -i HEAD~$1; }; r" 51 | -------------------------------------------------------------------------------- /home/.config/git/ignore: -------------------------------------------------------------------------------- 1 | .envrc 2 | .direnv 3 | .devbox 4 | .idea 5 | .DS_Store 6 | default.profraw 7 | neovide_backtraces.log 8 | SIDENOTES-*.md 9 | -------------------------------------------------------------------------------- /home/.config/karabiner.edn: -------------------------------------------------------------------------------- 1 | { 2 | :applications { 3 | :alacritty ["^org.alacritty$"] 4 | :neovide [:paths "^.*\\.cargo/bin/neovide$"] 5 | :zed ["^dev.zed.Zed$"] 6 | :xcode ["^com.apple.dt.Xcode$"] 7 | :things ["^com.culturedcode.ThingsMac$"] 8 | :notion ["^notion.id$"] 9 | } 10 | 11 | :input-sources { 12 | :ru { :language "ru" } 13 | } 14 | 15 | :main [ 16 | 17 | ;; ! | mandatory 18 | ;; # | optional 19 | ;; C | left_command 20 | ;; T | left_control 21 | ;; O | left_option 22 | ;; S | left_shift 23 | ;; F | fn 24 | ;; Q | right_command 25 | ;; W | right_control 26 | ;; E | right_option 27 | ;; R | right_shift 28 | ;; P | caps_lock 29 | ;; !! | mandatory hyper 30 | ;; ## | optional any 31 | 32 | ;; !CTSequal_sign | mandatory Cmd Ctrl Shift = (or Cmd Ctrl +) 33 | ;; !O#Sright_arrow | mandatory Opt optional Shift right_arrow 34 | 35 | ;; Karabiner definition of mandatory and optional 36 | ;; https://karabiner-elements.pqrs.org/docs/json/complex-modifications-manipulator-definition/from/modifiers/ 37 | 38 | ;; Goku keys 39 | ;; https://github.com/yqrashawn/GokuRakuJoudo/blob/master/src/karabiner_configurator/keys_info.clj 40 | 41 | { 42 | :des "Global configuration" 43 | :rules [ 44 | ; F21 -> Ctrl+Fn+F8: toggle menubar no macOS 45 | [:f21 :!TFf8] 46 | ] 47 | } 48 | 49 | { 50 | :des "Dvorak configuration" 51 | :rules [ 52 | ; Homerow mods safety belt for Dvorak layout 53 | [:!Qh [:t :h]] 54 | [:!Qn [:t :n]] 55 | [:!Eh [:s :h]] 56 | [:!Et [:s :t]] 57 | [:!Wt [:n :t]] 58 | [:!Wd [:n :d]] 59 | [:!Wh [:n :h]] 60 | [:!Wg [:n :g]] 61 | [:!Cu [:e :u]] 62 | [:!Co [:e :o]] 63 | [:!Ca [:e :a]] 64 | [:!Ci [:e :i]] 65 | [:!Se [:u :e]] 66 | [:!So [:u :o]] 67 | [:!Sa [:u :a]] 68 | [:!Tu [:o :u]] 69 | [:!Te [:o :e]] 70 | [:!Ti [:o :i]] 71 | [:!Rt [:h :t]] 72 | [:!Rn [:h :n]] 73 | [:!Rs [:h :s]] 74 | [:!Ou [:a :u]] 75 | 76 | ; RU 77 | ; Specific to my keyboard 78 | [:!Squote :!S7 [:ru]] ; period 79 | ; General mappings 80 | [:#SOERPquote :q [:ru]] 81 | [:#SOERPcomma :w [:ru]] 82 | [:#SOERPperiod :e [:ru]] 83 | [:#SOERPp :r [:ru]] 84 | [:#SOERPy :t [:ru]] 85 | [:#SOERPf :y [:ru]] 86 | [:#SOERPg :u [:ru]] 87 | [:#SOERPc :i [:ru]] 88 | [:#SOERPr :o [:ru]] 89 | [:#SOERPl :p [:ru]] 90 | [:#SOERPo :s [:ru]] 91 | [:#SOERPe :d [:ru]] 92 | [:#SOERPu :f [:ru]] 93 | [:#SOERPi :g [:ru]] 94 | [:#SOERPd :h [:ru]] 95 | [:#SOERPh :j [:ru]] 96 | [:#SOERPt :k [:ru]] 97 | [:#SOERPn :l [:ru]] 98 | [:#SOERPs :semicolon [:ru]] 99 | [:#SOERPsemicolon :z [:ru]] 100 | [:#SOERPq :x [:ru]] 101 | [:#SOERPj :c [:ru]] 102 | [:#SOERPk :v [:ru]] 103 | [:#SOERPx :b [:ru]] 104 | [:#SOERPb :n [:ru]] 105 | [:#SOERPw :comma [:ru]] 106 | [:#SOERPv :period [:ru]] 107 | [:#SOERPz :quote [:ru]] 108 | ] 109 | } 110 | 111 | { 112 | :des "Scrolla configuration" 113 | :rules [ 114 | ; Enabling/disabling is done via CLI from Hammerspoon 115 | [:down_arrow :j ["scrolla" 1]] 116 | [:up_arrow :k ["scrolla" 1]] 117 | [:left_arrow :h ["scrolla" 1]] 118 | [:right_arrow :l ["scrolla" 1]] 119 | [:!Odown_arrow :d ["scrolla" 1]] 120 | [:!Oup_arrow :u ["scrolla" 1]] 121 | [:!Sright_arrow :tab ["scrolla" 1]] 122 | [:!Sleft_arrow :!Stab ["scrolla" 1]] 123 | ] 124 | } 125 | 126 | { 127 | :des "Alacritty configuration" 128 | :rules [ 129 | ; Cmd+C -> Ctrl+C 130 | [:!Cc :!Tc [:alacritty]] 131 | 132 | ; Cmd+N <-> Ctrl+N 133 | [:!Cn :!Tn [:alacritty]] 134 | [:!Tn :!Cn [:alacritty]] 135 | 136 | ; Cmd+W <-> Ctrl+W 137 | [:!Cw :!Tw [:alacritty]] 138 | [:!Tw :!Cw [:alacritty]] 139 | 140 | ; Cmd+Q <-> Ctrl+Q 141 | [:!Qq :!Wq [:alacritty]] 142 | [:!Wq :!Qq [:alacritty]] 143 | ] 144 | } 145 | 146 | { 147 | :des "Neovide configuration" 148 | :rules [ 149 | [:!Th :!TOSh [:neovide]] ; Ctrl+H -> Ctrl+Opt+Shift+H 150 | [:!Cm :!TOSm [:neovide]] ; Cmd+M -> Ctrl+Opt+Shift+M 151 | ] 152 | } 153 | 154 | { 155 | :des "Zed configuration" 156 | :rules [ 157 | [:!Cs [:escape :!Cs] [:zed]] ; Cmd+S -> Esc Cmd+S 158 | [:!CTOh :slash [:zed]] ; Whooshy -> / 159 | ] 160 | } 161 | 162 | { 163 | :des "Xcode configuration" 164 | :rules [ 165 | [:!Ct :!CSo [:xcode]] 166 | ; [:!Ch :page_down [:xcode]] 167 | ] 168 | } 169 | 170 | { 171 | :des "Things configuration" 172 | :rules [ 173 | [:!Cg :!Ck [:things]] ; Complete 174 | [:!CSg :!COk [:things]] ; Cancel 175 | [:!Cp :!Cl [:things]] ; Show in Project 176 | [:!Cw :escape [:things]] ; Close 177 | ] 178 | } 179 | 180 | { 181 | :des "Notion configuration" 182 | :rules [ 183 | [:!Ct :!Cp [:notion]] 184 | [:!Cw :escape [:notion]] 185 | ] 186 | } 187 | ] 188 | } 189 | -------------------------------------------------------------------------------- /home/.config/lazygit/config.yml: -------------------------------------------------------------------------------- 1 | keybinding: 2 | universal: 3 | quit: "w" 4 | scrollUpMain: "" 5 | scrollDownMain: "" 6 | files: 7 | commitChangesWithoutHook: "" 8 | commits: 9 | moveUpCommit: "" 10 | moveDownCommit: "" 11 | -------------------------------------------------------------------------------- /home/.config/nix/nix.conf: -------------------------------------------------------------------------------- 1 | keep-derivations = true 2 | keep-outputs = true 3 | experimental-features = nix-command flakes 4 | -------------------------------------------------------------------------------- /home/.config/nixpkgs/config.nix: -------------------------------------------------------------------------------- 1 | { 2 | allowUnfree = true; 3 | } 4 | -------------------------------------------------------------------------------- /home/.config/nvim/.gitignore: -------------------------------------------------------------------------------- 1 | tt.* 2 | .tests 3 | doc/tags 4 | debug 5 | .repro 6 | foo.* 7 | *.log 8 | data 9 | -------------------------------------------------------------------------------- /home/.config/nvim/.neoconf.json: -------------------------------------------------------------------------------- 1 | { 2 | "neodev": { 3 | "library": { 4 | "enabled": true, 5 | "plugins": true 6 | } 7 | }, 8 | "neoconf": { 9 | "plugins": { 10 | "lua_ls": { 11 | "enabled": true 12 | } 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /home/.config/nvim/init.lua: -------------------------------------------------------------------------------- 1 | require("utils") 2 | require("screen") 3 | require("keymaps") 4 | require("editor") 5 | require("config.lazy") 6 | -------------------------------------------------------------------------------- /home/.config/nvim/lazy-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "LazyVim": { "branch": "main", "commit": "d5a4ced75acadb6ae151c0d2960a531c691c88b9" }, 3 | "SchemaStore.nvim": { "branch": "main", "commit": "08618c584e38933731a1ef210b323a7588403dd2" }, 4 | "cmp-buffer": { "branch": "main", "commit": "3022dbc9166796b644a841a02de8dd1cc1d311fa" }, 5 | "cmp-git": { "branch": "main", "commit": "50d526dff0f6bc441b51fc269d9fdc99a50c76af" }, 6 | "cmp-nvim-lsp": { "branch": "main", "commit": "39e2eda76828d88b773cc27a3f61d2ad782c922d" }, 7 | "cmp-path": { "branch": "main", "commit": "91ff86cd9c29299a64f968ebb45846c485725f23" }, 8 | "conform.nvim": { "branch": "master", "commit": "1a99fdc1d3aa9ccdf3021e67982a679a8c5c740c" }, 9 | "crates.nvim": { "branch": "main", "commit": "8bf8358ee326d5d8c11dcd7ac0bcc9ff97dbc785" }, 10 | "diffview.nvim": { "branch": "main", "commit": "4516612fe98ff56ae0415a259ff6361a89419b0a" }, 11 | "dressing.nvim": { "branch": "master", "commit": "1b7921eecc65af1baf8ac1dc06f0794934cbcfb2" }, 12 | "flash.nvim": { "branch": "main", "commit": "34c7be146a91fec3555c33fe89c7d643f6ef5cf1" }, 13 | "friendly-snippets": { "branch": "main", "commit": "00ba9dd3df89509f95437b8d595553707c46d5ea" }, 14 | "gitsigns.nvim": { "branch": "main", "commit": "863903631e676b33e8be2acb17512fdc1b80b4fb" }, 15 | "grug-far.nvim": { "branch": "main", "commit": "b7c2b28e49d55ff71cd9bb3ad19a2021316510d8" }, 16 | "lazy.nvim": { "branch": "main", "commit": "077102c5bfc578693f12377846d427f49bc50076" }, 17 | "lazydev.nvim": { "branch": "main", "commit": "491452cf1ca6f029e90ad0d0368848fac717c6d2" }, 18 | "lualine.nvim": { "branch": "master", "commit": "b431d228b7bbcdaea818bdc3e25b8cdbe861f056" }, 19 | "lush.nvim": { "branch": "main", "commit": "45a79ec4acb5af783a6a29673a999ce37f00497e" }, 20 | "luvit-meta": { "branch": "main", "commit": "ce76f6f6cdc9201523a5875a4471dcfe0186eb60" }, 21 | "markdown-preview.nvim": { "branch": "master", "commit": "a923f5fc5ba36a3b17e289dc35dc17f66d0548ee" }, 22 | "mason-lspconfig.nvim": { "branch": "main", "commit": "25c11854aa25558ee6c03432edfa0df0217324be" }, 23 | "mason.nvim": { "branch": "main", "commit": "e2f7f9044ec30067bc11800a9e266664b88cda22" }, 24 | "mini.ai": { "branch": "main", "commit": "9b9b7cfa38b4871c3e44cfe89cf6d53fd40684d9" }, 25 | "mini.icons": { "branch": "main", "commit": "a2742459f0ee32806c2438ca06b4d8b331f3f4d4" }, 26 | "mini.pairs": { "branch": "main", "commit": "919a89ed3c9f4142215a44c9fffca72fa8c8e792" }, 27 | "mini.starter": { "branch": "main", "commit": "3e0af795938ee800846708bed92fbe4e8583141a" }, 28 | "mini.surround": { "branch": "main", "commit": "e1ac1ce5c7499aa4cc2ca9fb1adec9e730dd9394" }, 29 | "neo-tree.nvim": { "branch": "main", "commit": "a77af2e764c5ed4038d27d1c463fa49cd4794e07" }, 30 | "no-neck-pain.nvim": { "branch": "main", "commit": "c0d8061f18bccceff0991e096c8f864a720e1ebf" }, 31 | "noice.nvim": { "branch": "main", "commit": "86c3ab04eaddeed901a5495bc350a0235a2a11bc" }, 32 | "nui.nvim": { "branch": "main", "commit": "b58e2bfda5cea347c9d58b7f11cf3012c7b3953f" }, 33 | "nvim-cmp": { "branch": "main", "commit": "ae644feb7b67bf1ce4260c231d1d4300b19c6f30" }, 34 | "nvim-lint": { "branch": "master", "commit": "968a35d54b3a4c1ce66609cf80b14d4ae44fe77f" }, 35 | "nvim-lspconfig": { "branch": "master", "commit": "e6569c18c21be5166e4b9cc7530e828b8285c84e" }, 36 | "nvim-notify": { "branch": "master", "commit": "fbef5d32be8466dd76544a257d3f3dce20082a07" }, 37 | "nvim-scrollbar": { "branch": "main", "commit": "d09f14aa16c9f2748e77008f9da7b1f76e4e7b85" }, 38 | "nvim-snippets": { "branch": "main", "commit": "56b4052f71220144689caaa2e5b66222ba5661eb" }, 39 | "nvim-tinygit": { "branch": "main", "commit": "f126dde3c89f8a00aa1e6ff7bd2f65d9054e7f10" }, 40 | "nvim-treesitter": { "branch": "master", "commit": "98a33cc524c85a78a1ff5a707998629b24cbf8c2" }, 41 | "nvim-treesitter-textobjects": { "branch": "master", "commit": "4a2d05ec24eaa6b655c7d19092a3b6c0219d46b9" }, 42 | "nvim-ts-autotag": { "branch": "main", "commit": "e239a560f338be31337e7abc3ee42515daf23f5e" }, 43 | "persistence.nvim": { "branch": "main", "commit": "f6aad7dde7fcf54148ccfc5f622c6d5badd0cc3d" }, 44 | "plenary.nvim": { "branch": "master", "commit": "2d9b06177a975543726ce5c73fca176cedbffe9d" }, 45 | "render-markdown.nvim": { "branch": "main", "commit": "e91b042b3865d2d040a0e21e0a3b13fb57f24094" }, 46 | "rustaceanvim": { "branch": "master", "commit": "29f42cc149f915d771c550b6dfe7c788d856cf04" }, 47 | "tailwindcss-colorizer-cmp.nvim": { "branch": "main", "commit": "3d3cd95e4a4135c250faf83dd5ed61b8e5502b86" }, 48 | "telescope-file-browser.nvim": { "branch": "master", "commit": "3b8a1e17187cfeedb31decbd625da62398a8ff34" }, 49 | "telescope-fzf-native.nvim": { "branch": "main", "commit": "cf48d4dfce44e0b9a2e19a008d6ec6ea6f01a83b" }, 50 | "telescope-terraform-doc.nvim": { "branch": "main", "commit": "ce2d39a576a68755a623982a7a88bcb3d981b15b" }, 51 | "telescope-terraform.nvim": { "branch": "main", "commit": "072c97023797ca1a874668aaa6ae0b74425335df" }, 52 | "telescope.nvim": { "branch": "master", "commit": "eae0d8fbde590b0eaa2f9481948cd6fd7dd21656" }, 53 | "todo-comments.nvim": { "branch": "main", "commit": "ae0a2afb47cf7395dc400e5dc4e05274bf4fb9e0" }, 54 | "trouble.nvim": { "branch": "main", "commit": "254145ffd528b98eb20be894338e2d5c93fa02c2" }, 55 | "ts-comments.nvim": { "branch": "main", "commit": "98d7d4dec0af1312d38e288f800bbf6ff562b6ab" }, 56 | "vim-dadbod": { "branch": "master", "commit": "7888cb7164d69783d3dce4e0283decd26b82538b" }, 57 | "vim-dadbod-completion": { "branch": "master", "commit": "880f7e9f2959e567c718d52550f9fae1aa07aa81" }, 58 | "vim-dadbod-ui": { "branch": "master", "commit": "f29c85ab42861c6ef683289b0c6a51e0d436dcf6" }, 59 | "which-key.nvim": { "branch": "main", "commit": "8badb359f7ab8711e2575ef75dfe6fbbd87e4821" }, 60 | "zen-mode.nvim": { "branch": "main", "commit": "29b292bdc58b76a6c8f294c961a8bf92c5a6ebd6" } 61 | } 62 | -------------------------------------------------------------------------------- /home/.config/nvim/lazyvim.json: -------------------------------------------------------------------------------- 1 | { 2 | "extras": [], 3 | "news": { 4 | "NEWS.md": "6520" 5 | }, 6 | "version": 6 7 | } 8 | -------------------------------------------------------------------------------- /home/.config/nvim/lua/config/autocmds.lua: -------------------------------------------------------------------------------- 1 | -- Autocmds are automatically loaded on the VeryLazy event 2 | -- Default autocmds that are always set: https://github.com/LazyVim/LazyVim/blob/main/lua/lazyvim/config/autocmds.lua 3 | -- Add any additional autocmds here 4 | 5 | NVLsp.autocmds() 6 | NVFormatting.autocmds() 7 | NVPersistence.autocmds() 8 | -------------------------------------------------------------------------------- /home/.config/nvim/lua/config/keymaps.lua: -------------------------------------------------------------------------------- 1 | -- Keymaps are automatically loaded on the VeryLazy event 2 | -- Default keymaps that are always set: https://github.com/LazyVim/LazyVim/blob/main/lua/lazyvim/config/keymaps.lua 3 | -- Add any additional keymaps here 4 | 5 | NVEditing.keymaps() 6 | NVBuffers.keymaps() 7 | NVWindows.keymaps() 8 | NVNavigation.keymaps() 9 | NVLsp.keymaps() 10 | NVDebug.keymaps() 11 | -------------------------------------------------------------------------------- /home/.config/nvim/lua/config/lazy.lua: -------------------------------------------------------------------------------- 1 | local lazypath = vim.fn.stdpath("data") .. "/lazy/lazy.nvim" 2 | if not (vim.uv or vim.loop).fs_stat(lazypath) then 3 | local lazyrepo = "https://github.com/folke/lazy.nvim.git" 4 | local out = vim.fn.system({ "git", "clone", "--filter=blob:none", "--branch=stable", lazyrepo, lazypath }) 5 | if vim.v.shell_error ~= 0 then 6 | vim.api.nvim_echo({ 7 | { "Failed to clone lazy.nvim:\n", "ErrorMsg" }, 8 | { out, "WarningMsg" }, 9 | { "\nPress any key to exit..." }, 10 | }, true, {}) 11 | vim.fn.getchar() 12 | os.exit(1) 13 | end 14 | end 15 | vim.opt.rtp:prepend(lazypath) 16 | 17 | require("lazy").setup({ 18 | spec = { 19 | -- add LazyVim and import its plugins 20 | { "LazyVim/LazyVim", import = "lazyvim.plugins" }, 21 | 22 | -- import/override with your plugins 23 | { import = "lazyvim.plugins.extras.coding.mini-surround" }, 24 | -- { import = "lazyvim.plugins.extras.coding.copilot" }, 25 | -- { import = "lazyvim.plugins.extras.coding.codeium" }, 26 | { import = "lazyvim.plugins.extras.editor.telescope" }, 27 | { import = "lazyvim.plugins.extras.ui.mini-starter" }, 28 | { import = "lazyvim.plugins.extras.lang.docker" }, 29 | { import = "lazyvim.plugins.extras.lang.git" }, 30 | { import = "lazyvim.plugins.extras.lang.json" }, 31 | { import = "lazyvim.plugins.extras.lang.markdown" }, 32 | { import = "lazyvim.plugins.extras.lang.nix" }, 33 | -- { import = "lazyvim.plugins.extras.lang.ocaml" }, -- NOTE: Ocaml LSP is broken 34 | { import = "lazyvim.plugins.extras.lang.rust" }, 35 | { import = "lazyvim.plugins.extras.lang.sql" }, 36 | { import = "lazyvim.plugins.extras.lang.tailwind" }, 37 | { import = "lazyvim.plugins.extras.lang.terraform" }, 38 | { import = "lazyvim.plugins.extras.lang.toml" }, 39 | { import = "lazyvim.plugins.extras.lang.yaml" }, 40 | { import = "plugins" }, 41 | }, 42 | defaults = { 43 | -- By default, only LazyVim plugins will be lazy-loaded. Your custom plugins will load during startup. 44 | -- If you know what you're doing, you can set this to `true` to have all your custom plugins lazy-loaded by default. 45 | lazy = false, 46 | -- It's recommended to leave version=false for now, since a lot the plugin that support versioning, 47 | -- have outdated releases, which may break your Neovim install. 48 | version = false, -- always use the latest git commit 49 | -- version = "*", -- try installing the latest stable version for plugins that support semver 50 | }, 51 | install = { 52 | missing = false, 53 | colorscheme = { "theme" }, 54 | }, 55 | rocks = { 56 | enabled = false, 57 | }, 58 | ui = { 59 | backdrop = 100, 60 | }, 61 | -- automatically check for plugin updates 62 | checker = { 63 | enabled = true, -- check for plugin updates periodically 64 | notify = false, -- notify on update 65 | }, 66 | performance = { 67 | rtp = { 68 | -- disable some rtp plugins 69 | disabled_plugins = { 70 | "gzip", 71 | -- "matchit", 72 | -- "matchparen", 73 | -- "netrwPlugin", 74 | "tarPlugin", 75 | "tohtml", 76 | "tutor", 77 | "zipPlugin", 78 | }, 79 | }, 80 | }, 81 | }) 82 | -------------------------------------------------------------------------------- /home/.config/nvim/lua/config/options.lua: -------------------------------------------------------------------------------- 1 | -- Options are automatically loaded before lazy.nvim startup 2 | -- Default options that are always set: https://github.com/LazyVim/LazyVim/blob/main/lua/lazyvim/config/options.lua 3 | -- Add any additional options here 4 | 5 | local o = vim.o 6 | local g = vim.g 7 | local opt = vim.opt 8 | 9 | opt.termguicolors = true 10 | 11 | opt.number = true 12 | opt.relativenumber = false 13 | 14 | opt.expandtab = true 15 | opt.shiftwidth = 4 16 | opt.smartindent = true 17 | opt.tabstop = 4 18 | opt.softtabstop = 4 19 | 20 | opt.list = true 21 | opt.listchars = { 22 | tab = "▸ ", 23 | trail = "·", 24 | precedes = "←", 25 | extends = "→", 26 | nbsp = "+", 27 | -- eol = "↲", 28 | } 29 | 30 | opt.fillchars:append({ 31 | vert = " ", 32 | eob = " ", 33 | diff = "", 34 | }) 35 | 36 | opt.ignorecase = true 37 | opt.smartcase = true 38 | 39 | opt.mouse = "a" 40 | 41 | opt.splitright = true 42 | opt.splitbelow = true 43 | opt.equalalways = true 44 | 45 | opt.wrap = false 46 | 47 | opt.whichwrap:append({ 48 | ["<"] = true, 49 | [">"] = true, 50 | ["["] = true, 51 | ["]"] = true, 52 | h = true, 53 | l = true, 54 | }) 55 | 56 | g.lazyvim_picker = "telescope" 57 | 58 | if g.neovide then 59 | o.guifont = "BerkeleyMono Nerd Font:h17" 60 | opt.linespace = 24 61 | 62 | vim.g.neovide_padding_top = 0 -- Set to 40 if the tabline is hidden 63 | vim.g.neovide_padding_bottom = 0 64 | vim.g.neovide_padding_right = 30 65 | vim.g.neovide_padding_left = 30 66 | 67 | vim.g.neovide_scroll_animation_length = 0.2 68 | 69 | vim.g.neovide_floating_shadow = true 70 | vim.g.neovide_floating_z_height = 1 71 | vim.g.neovide_light_angle_degrees = 45 72 | vim.g.neovide_light_radius = 1 73 | 74 | vim.g.neovide_floating_blur_amount_x = 100 75 | vim.g.neovide_floating_blur_amount_y = 100 76 | 77 | vim.g.neovide_hide_mouse_when_typing = true 78 | 79 | vim.g.neovide_remember_window_size = true 80 | vim.g.neovide_confirm_quit = true 81 | 82 | vim.g.neovide_fullscreen = false 83 | 84 | vim.g.neovide_input_use_logo = true 85 | vim.g.neovide_input_macos_option_key_is_meta = "both" 86 | 87 | vim.g.neovide_cursor_antialiasing = false 88 | vim.g.neovide_cursor_animate_in_insert_mode = true 89 | vim.g.neovide_cursor_animate_command_line = false 90 | end 91 | -------------------------------------------------------------------------------- /home/.config/nvim/lua/editor.lua: -------------------------------------------------------------------------------- 1 | require("editor.buffers") 2 | require("editor.clipboard") 3 | require("editor.cursor") 4 | require("editor.editing") 5 | require("editor.formatting") 6 | require("editor.fs") 7 | require("editor.help") 8 | require("editor.icons") 9 | require("editor.keys") 10 | require("editor.lsp") 11 | require("editor.navigation") 12 | require("editor.search") 13 | require("editor.terminal") 14 | require("editor.windows") 15 | require("editor.debug") 16 | -------------------------------------------------------------------------------- /home/.config/nvim/lua/editor/clipboard.lua: -------------------------------------------------------------------------------- 1 | NVClipboard = {} 2 | 3 | function NVClipboard.yank(text) 4 | vim.fn.setreg("+", text) 5 | end 6 | -------------------------------------------------------------------------------- /home/.config/nvim/lua/editor/cursor.lua: -------------------------------------------------------------------------------- 1 | NVCursor = {} 2 | 3 | function NVCursor.get() 4 | local win = vim.api.nvim_get_current_win() 5 | local pos = vim.api.nvim_win_get_cursor(win) 6 | 7 | return { win, pos } 8 | end 9 | 10 | function NVCursor.set(cursor) 11 | local row, col = cursor.pos[1], cursor.pos[2] 12 | 13 | vim.api.nvim_win_set_cursor(cursor.win, { row, col }) 14 | end 15 | 16 | function NVCursor.shake() 17 | local cursor = vim.api.nvim_win_get_cursor(0) 18 | 19 | local cur_line = cursor[1] 20 | local cur_col = cursor[2] 21 | 22 | local direction 23 | 24 | if cur_col > 0 then 25 | direction = "Left" 26 | elseif cur_line > 1 then 27 | direction = "Up" 28 | else 29 | local total_lines = vim.api.nvim_buf_line_count(0) 30 | 31 | if cur_line < total_lines then 32 | direction = "Down" 33 | else 34 | local lines = vim.api.nvim_buf_get_lines(0, cur_line - 1, cur_line, false) 35 | local line = lines[1] 36 | 37 | if cur_col < #line - 1 then 38 | direction = "Right" 39 | end 40 | end 41 | end 42 | 43 | if not direction then 44 | return nil 45 | end 46 | 47 | vim.cmd.execute([["normal \<]] .. direction .. [[>"]]) 48 | 49 | vim.wait(1000, function() 50 | local next_cursor = vim.api.nvim_win_get_cursor(0) 51 | local next_line = next_cursor[1] 52 | local next_col = next_cursor[2] 53 | local moved = next_line ~= cur_line or next_col ~= cur_col 54 | 55 | return moved 56 | end, 10, false) 57 | 58 | return function() 59 | vim.api.nvim_win_set_cursor(0, cursor) 60 | end 61 | end 62 | -------------------------------------------------------------------------------- /home/.config/nvim/lua/editor/debug.lua: -------------------------------------------------------------------------------- 1 | NVDebug = {} 2 | 3 | local fn = {} 4 | 5 | function NVDebug.keymaps() 6 | K.map({ "w", "DEBUG: Print current window and buffer info", fn.print_current_window_and_buffer_info, mode = "n" }) 7 | K.map({ "b", "DEBUG: Print all buffers info", fn.print_all_buffers_info, mode = "n" }) 8 | end 9 | 10 | function fn.print(data) 11 | vim.notify(data, vim.log.levels.INFO, { timeout = false }) 12 | end 13 | 14 | function fn.print_window_info(winnr) 15 | local win_info = vim.api.nvim_win_get_config(winnr) 16 | 17 | fn.print("winnr: " .. winnr) 18 | fn.print("win info: " .. vim.inspect(win_info)) 19 | end 20 | 21 | function fn.print_buffer_info(bufnr) 22 | local buf_info = vim.fn.getbufinfo(bufnr)[1] 23 | 24 | fn.print("bufnr: " .. bufnr) 25 | fn.print("buf info: " .. vim.inspect(buf_info)) 26 | end 27 | 28 | function fn.print_current_window_and_buffer_info() 29 | local winnr = vim.api.nvim_get_current_win() 30 | local bufnr = vim.api.nvim_get_current_buf() 31 | 32 | fn.print_window_info(winnr) 33 | fn.print_buffer_info(bufnr) 34 | end 35 | 36 | function fn.print_all_buffers_info() 37 | local bufs = vim.fn.getbufinfo() 38 | 39 | fn.print("bufs: " .. vim.inspect(bufs)) 40 | end 41 | -------------------------------------------------------------------------------- /home/.config/nvim/lua/editor/editing.lua: -------------------------------------------------------------------------------- 1 | NVEditing = {} 2 | 3 | local fn = {} 4 | 5 | function NVEditing.keymaps() 6 | K.map({ "", "Copy selected text", [["+y]], mode = "v" }) 7 | K.map({ "", "Paste text", "P", mode = { "n", "v" } }) 8 | K.map({ "", "Paste text", fn.paste, mode = { "i", "c" } }) 9 | 10 | K.map({ 11 | "p", 12 | "Don't replace clipboard content when pasting", 13 | function() 14 | return 'pgv"' .. vim.v.register .. "ygv" 15 | end, 16 | mode = "v", 17 | expr = true, 18 | }) 19 | 20 | K.map({ "d", "Don't replace clipboard content when deleting", [["_d]], mode = { "n", "v" } }) 21 | K.map({ "D", "Don't replace clipboard content when deleting", [["_D]], mode = { "n", "v" } }) 22 | K.map({ "s", "Don't replace clipboard content when inserting", [["xs]], mode = "v" }) 23 | K.map({ "c", "Don't replace clipboard content when changing", [["xc]], mode = { "n", "v" } }) 24 | 25 | K.map({ "", "Change inner word", [["xciw]], mode = "n" }) 26 | K.map({ "", "Change seletion", [["xc]], mode = "v" }) 27 | K.map({ "", "Change inner word", [["xciw]], mode = "i" }) 28 | K.map({ "", "Select inner word", "viw", mode = "n" }) 29 | K.map({ "", "Yank inner word", "yiw", mode = "n" }) 30 | 31 | K.map({ "", "Insert new line above", "O", mode = "n" }) 32 | K.map({ "", "Insert new line below", "o", mode = "n" }) 33 | K.map({ "", "Insert new line above", "O", mode = "i" }) 34 | K.map({ "", "Insert new line below", "o", mode = "i" }) 35 | 36 | K.map({ "", "Duplicate line", [["yyy"yp]], mode = "n" }) 37 | K.map({ "", "Duplicate line", [["yyy"ypgi]], mode = "i" }) 38 | K.map({ "", "Duplicate selection", [["yy'>"ypgv]], mode = "v" }) 39 | 40 | K.map({ "", "Move line up", "m .-2==", mode = "n" }) 41 | K.map({ "", "Move line down", "m .+1==", mode = "n" }) 42 | K.map({ "", "Move line up", "m .-2==gi", mode = "i" }) 43 | K.map({ "", "Move line down", "m .+1==gi", mode = "i" }) 44 | K.map({ "", "Move selected lines up", ":m '<-2gv=gv", mode = "v" }) 45 | K.map({ "", "Move selected lines down", ":m '>+1gv=gv", mode = "v" }) 46 | 47 | K.map({ "", "Indent", ">>", mode = "n" }) 48 | K.map({ "", "Unindent", "<<", mode = "n" }) 49 | K.map({ "", "Indent", ">gv", mode = "v" }) 50 | K.map({ "", "Unindent", "", "Jump one word to the left", "b", mode = { "n", "v" } }) 53 | K.map({ "", "Jump one word to the right", "w", mode = { "n", "v" } }) 54 | K.map({ "", "Jump one word to the left", "b", mode = "i" }) 55 | K.map({ "", "Jump one word to the right", fn.jump_to_end_of_word, mode = "i" }) 56 | K.map({ "", "Jump to the beginning of the line", "I", mode = "i" }) 57 | K.map({ "", "Jump to the end of the line", "A", mode = "i" }) 58 | K.map({ "", "Delete word to the left", "", mode = "i" }) 59 | K.map({ "", "Delete word to the right", [["_de]], mode = "i" }) 60 | K.map({ "", "Delete everything to the left", "", mode = "i" }) 61 | K.map({ "", "Delete everything to the right", [["_D]], mode = "i" }) 62 | 63 | K.map({ "", "Select all", "ggVG", mode = "n" }) 64 | K.map({ "", "Select all", "ggVG", mode = { "i", "v" } }) 65 | 66 | K.map({ "*", "Don't jump on *", "keepjumps normal! mi*`i", mode = "n" }) 67 | K.map({ 68 | "*", 69 | "Highlight selected text", 70 | [["*y:silent! let searchTerm = '\V'.substitute(escape(@*, '\/'), "\n", '\\n', "g") let @/ = searchTerm echo '/'.@/ call histadd("search", searchTerm) set hls]], 71 | mode = "v", 72 | }) 73 | 74 | K.map({ 75 | "", 76 | "Drop all the noise and Esc", 77 | "NoiceDismisssilent noh", 78 | mode = "n", 79 | silent = false, 80 | }) 81 | 82 | K.map({ "u", "Unset undo", "", mode = "n" }) 83 | K.map({ "", "Undo", "u", mode = { "n", "v" } }) 84 | K.map({ "", "Undo", "ui", mode = "i" }) 85 | K.map({ "", "Redo", "", mode = { "n", "v" } }) 86 | K.map({ "", "Redo", "i", mode = "i" }) 87 | 88 | K.map({ "", "Comment", "gcc", mode = "n", remap = true }) 89 | K.map({ "", "Comment", "gc", mode = "v", remap = true }) 90 | K.map({ "", "Comment", "normal gcc", mode = "i", remap = true }) 91 | K.map({ "", "Start comment on the next line", "gco", mode = "n", remap = true }) 92 | K.map({ "", "Start comment on the next line", "normal gco", mode = "i", remap = true }) 93 | 94 | K.map({ "", "Save files", "silent wsilent! wa", mode = "n" }) 95 | K.map({ "", "Save files", "silent wsilent! wa", mode = { "i", "v" } }) 96 | end 97 | 98 | function fn.paste() 99 | local mode = vim.fn.mode() 100 | 101 | if mode == "i" or mode == "c" then 102 | local paste = vim.o.paste 103 | local fopts = vim.o.formatoptions 104 | 105 | vim.o.paste = true 106 | vim.o.formatoptions = fopts:gsub("[crota]", "") 107 | 108 | NVKeys.send("+", { mode = "n" }) 109 | 110 | vim.defer_fn(function() 111 | vim.o.paste = paste 112 | vim.o.formatoptions = fopts 113 | end, 10) 114 | else 115 | vim.api.nvim_err_writeln("Unexpected mode") 116 | end 117 | end 118 | 119 | function fn.jump_to_end_of_word() 120 | vim.cmd("normal! e") 121 | 122 | local current_col = vim.fn.col(".") 123 | local end_col = vim.fn.col("$") 124 | 125 | if current_col == end_col - 1 then 126 | NVKeys.send("A", { mode = "n" }) 127 | elseif current_col ~= end_col then 128 | vim.cmd("normal! l") 129 | end 130 | end 131 | -------------------------------------------------------------------------------- /home/.config/nvim/lua/editor/formatting.lua: -------------------------------------------------------------------------------- 1 | NVFormatting = {} 2 | 3 | function NVFormatting.keymaps() 4 | K.map({ 5 | "f", 6 | "Format", 7 | function() 8 | LazyVim.format({ force = true }) 9 | end, 10 | mode = { "n", "v" }, 11 | }) 12 | end 13 | 14 | function NVFormatting.autocmds() 15 | vim.api.nvim_create_autocmd({ "FileType" }, { 16 | pattern = { "json", "toml", "yaml", "clojure" }, 17 | callback = function() 18 | vim.b.autoformat = false 19 | end, 20 | }) 21 | end 22 | -------------------------------------------------------------------------------- /home/.config/nvim/lua/editor/fs.lua: -------------------------------------------------------------------------------- 1 | NVFS = {} 2 | 3 | local format = vim.fn.fnamemodify 4 | 5 | function NVFS.root(options) 6 | local opts = options or { capitalize = false } 7 | 8 | local cwd = vim.fn.getcwd() 9 | local root = format(cwd, ":t") 10 | 11 | if opts.capitalize then 12 | return root:upper() 13 | else 14 | return root 15 | end 16 | end 17 | 18 | function NVFS.relative_path(loc) 19 | return format(loc, ":.") 20 | end 21 | 22 | function NVFS.filename(loc) 23 | return format(loc, ":t") 24 | end 25 | 26 | function NVFS.filestem(loc) 27 | return format(loc, ":t:r") 28 | end 29 | 30 | function NVFS.format(loc, fmt) 31 | if fmt == "absolute" then 32 | return loc 33 | elseif fmt == "relative" then 34 | return NVFS.relative_path(loc) 35 | elseif fmt == "filename" then 36 | return NVFS.filename(loc) 37 | elseif fmt == "filestem" then 38 | return NVFS.filestem(loc) 39 | else 40 | vim.api.nvim_err_writeln("Invalid path format: " .. fmt) 41 | return nil 42 | end 43 | end 44 | -------------------------------------------------------------------------------- /home/.config/nvim/lua/editor/help.lua: -------------------------------------------------------------------------------- 1 | NVHelp = {} 2 | 3 | function NVHelp.is_help(bufnr) 4 | local buf = bufnr or vim.api.nvim_get_current_buf() 5 | local filetype = vim.api.nvim_get_option_value("filetype", { buf = buf }) 6 | return filetype == "help" 7 | end 8 | -------------------------------------------------------------------------------- /home/.config/nvim/lua/editor/icons.lua: -------------------------------------------------------------------------------- 1 | NVIcons = { 2 | error = " ", 3 | warn = " ", 4 | hint = " ", 5 | info = " ", 6 | } 7 | -------------------------------------------------------------------------------- /home/.config/nvim/lua/editor/keys.lua: -------------------------------------------------------------------------------- 1 | NVKeys = {} 2 | 3 | function NVKeys.send(keys, options) 4 | local mode = options.mode 5 | 6 | if mode == nil then 7 | vim.api.nvim_err_writeln("Sending keys requires mode") 8 | return 9 | end 10 | 11 | options.mode = nil 12 | 13 | if mode == "n" then 14 | local opts = vim.tbl_extend("keep", options, { 15 | from_part = true, 16 | do_lt = true, 17 | special = true, 18 | }) 19 | 20 | local tc = vim.api.nvim_replace_termcodes(keys, opts.from_part, opts.do_lt, opts.special) 21 | 22 | vim.api.nvim_feedkeys(tc, mode, false) 23 | elseif mode == "x" then 24 | local opts = vim.tbl_extend("keep", options, { 25 | from_part = true, 26 | do_lt = false, 27 | special = true, 28 | }) 29 | 30 | local tc = vim.api.nvim_replace_termcodes(keys, opts.from_part, opts.do_lt, opts.special) 31 | 32 | vim.api.nvim_feedkeys(tc, mode, false) 33 | elseif mode == "t" then 34 | vim.api.nvim_feedkeys(keys, mode, false) 35 | else 36 | vim.api.nvim_err_writeln("Unexpected mode") 37 | end 38 | end 39 | -------------------------------------------------------------------------------- /home/.config/nvim/lua/editor/navigation.lua: -------------------------------------------------------------------------------- 1 | NVNavigation = {} 2 | 3 | local fn = {} 4 | 5 | function NVNavigation.keymaps() 6 | K.map({ 7 | NVKeymaps.scroll.up, 8 | "Scroll up", 9 | function() 10 | fn.scroll_vertical("up") 11 | end, 12 | mode = { "n", "v", "i" }, 13 | }) 14 | K.map({ 15 | NVKeymaps.scroll.down, 16 | "Scroll down", 17 | function() 18 | fn.scroll_vertical("down") 19 | end, 20 | mode = { "n", "v", "i" }, 21 | }) 22 | 23 | K.map({ "", "Scroll a bit up", "normal 2", mode = { "n", "v", "i" } }) 24 | K.map({ "", "Scroll a bit down", "normal 2", mode = { "n", "v", "i" } }) 25 | 26 | K.map({ 27 | "", 28 | "Scroll left", 29 | function() 30 | fn.scroll_horizontal("left") 31 | end, 32 | mode = { "n", "v", "i" }, 33 | }) 34 | K.map({ 35 | "", 36 | "Scroll right", 37 | function() 38 | fn.scroll_horizontal("right") 39 | end, 40 | mode = { "n", "v", "i" }, 41 | }) 42 | 43 | K.map({ "", "History: back", "", mode = "n" }) 44 | K.map({ "", "History: forward", "", mode = "n" }) 45 | end 46 | 47 | function fn.scroll_horizontal(direction) 48 | if direction == "left" then 49 | vim.cmd("normal! 7zh") 50 | elseif direction == "right" then 51 | vim.cmd("normal! 7zl") 52 | else 53 | vim.api.nvim_err_writeln("Unexpected scroll direction") 54 | end 55 | end 56 | 57 | function fn.scroll_vertical(direction) 58 | if NVLsp.scroll_popup(direction) then 59 | return 60 | elseif NVWindows.is_window_floating(vim.api.nvim_get_current_win()) and not NVZenMode.is_active() then 61 | local keymap 62 | 63 | if direction == "up" then 64 | keymap = "" 65 | elseif direction == "down" then 66 | keymap = "" 67 | else 68 | vim.api.nvim_err_writeln("Unexpected scroll direction") 69 | return 70 | end 71 | 72 | NVKeys.send(keymap, { mode = "n" }) 73 | else 74 | -- if we already at the top, place cursor on the first line 75 | if direction == "up" and vim.fn.line("w0") == 1 then 76 | vim.api.nvim_win_set_cursor(0, { 1, 0 }) 77 | return 78 | end 79 | 80 | -- if we already at the bottom, place cursor on the last line 81 | if direction == "down" and vim.fn.line("w$") == vim.fn.line("$") then 82 | local line_count = vim.api.nvim_buf_line_count(0) 83 | vim.api.nvim_win_set_cursor(0, { line_count, 0 }) 84 | return 85 | end 86 | 87 | -- otherwise, scroll 88 | local lines = 15 89 | 90 | local keymap 91 | 92 | if direction == "up" then 93 | keymap = "" 94 | elseif direction == "down" then 95 | keymap = "" 96 | else 97 | vim.api.nvim_err_writeln("Unexpected scroll direction") 98 | return 99 | end 100 | 101 | local mode = vim.fn.mode() 102 | 103 | local is_i_mode = mode == "i" 104 | 105 | if is_i_mode then 106 | NVKeys.send("", { mode = "n" }) 107 | end 108 | 109 | NVKeys.send(tostring(lines) .. keymap, { mode = "n" }) 110 | 111 | if is_i_mode then 112 | NVKeys.send("a", { mode = "n" }) 113 | end 114 | end 115 | end 116 | -------------------------------------------------------------------------------- /home/.config/nvim/lua/editor/search.lua: -------------------------------------------------------------------------------- 1 | NVSearch = { 2 | cmd = "rg", 3 | base_args = { 4 | "--follow", 5 | "--color=never", 6 | "--no-heading", 7 | "--with-filename", 8 | "--line-number", 9 | "--column", 10 | }, 11 | optional_args = { 12 | with_hidden = "--hidden", 13 | with_ignored = "--no-ignore-vcs", 14 | smart_case = "--smart-case", 15 | ignore_case = "--ignore-case", 16 | }, 17 | } 18 | -------------------------------------------------------------------------------- /home/.config/nvim/lua/editor/terminal.lua: -------------------------------------------------------------------------------- 1 | NVTerminal = {} 2 | 3 | local fn = {} 4 | 5 | function NVTerminal.keymaps() 6 | K.map({ "", "Paste text", fn.paste, mode = "t", expr = true }) 7 | K.map({ "", "Exit terminal mode", "", mode = "t" }) 8 | end 9 | 10 | function fn.paste() 11 | local content = vim.fn.getreg("*") 12 | content = vim.api.nvim_replace_termcodes(content, true, true, true) 13 | vim.api.nvim_feedkeys(content, "t", true) 14 | end 15 | -------------------------------------------------------------------------------- /home/.config/nvim/lua/editor/windows.lua: -------------------------------------------------------------------------------- 1 | NVWindows = { 2 | default_width = NVScreen.is_large() and 140 or 120, 3 | maximized_width = 1, -- 100% 4 | window_picker_keys = "UHKMETJWNSABCDFGILOPQRVXYZ1234567890", 5 | } 6 | 7 | local fn = {} 8 | 9 | -- TODO: Revisit windows keymaps 10 | 11 | function NVWindows.keymaps() 12 | K.map({ "", "Create new buffer in the current window", "enew", mode = { "n", "v", "i" } }) 13 | -- K.map({ "nh", "Create new buffer in a horizontal split", "new", mode = "n" }) 14 | -- K.map({ "nn", "Create new buffer in a vertical split", "vnew", mode = "n" }) 15 | 16 | K.map({ "", "Move to window on the left", "wincmd h", mode = { "n", "v", "t" } }) 17 | K.map({ "", "Move to window below", "wincmd j", mode = { "n", "v", "t" } }) 18 | K.map({ "", "Move to window above", "wincmd k", mode = { "n", "v", "t" } }) 19 | K.map({ "", "Move to window on the right", "wincmd l", mode = { "n", "v", "t" } }) 20 | 21 | -- K.map({ 22 | -- "", 23 | -- "Move window to the left", 24 | -- function() 25 | -- fn.reposition_windows({ action = "move_left" }) 26 | -- end, 27 | -- mode = "n", 28 | -- }) 29 | -- K.map({ 30 | -- "", 31 | -- "Move window to the right", 32 | -- function() 33 | -- fn.reposition_windows({ action = "move_right" }) 34 | -- end, 35 | -- mode = "n", 36 | -- }) 37 | -- K.map({ 38 | -- "", 39 | -- "Move window up", 40 | -- function() 41 | -- fn.reposition_windows({ action = "move_up" }) 42 | -- end, 43 | -- mode = "n", 44 | -- }) 45 | -- K.map({ 46 | -- "", 47 | -- "Move window down", 48 | -- function() 49 | -- fn.reposition_windows({ action = "move_down" }) 50 | -- end, 51 | -- mode = "n", 52 | -- }) 53 | -- 54 | -- K.map({ 55 | -- "ws", 56 | -- "Swap windows", 57 | -- function() 58 | -- fn.reposition_windows({ action = "swap" }) 59 | -- end, 60 | -- mode = "n", 61 | -- }) 62 | -- 63 | -- K.map({ 64 | -- "", 65 | -- "Increase window width", 66 | -- function() 67 | -- fn.change_window_width("up") 68 | -- end, 69 | -- mode = "n", 70 | -- }) 71 | -- K.map({ 72 | -- "", 73 | -- "Decrease window width", 74 | -- function() 75 | -- fn.change_window_width("down") 76 | -- end, 77 | -- mode = "n", 78 | -- }) 79 | -- K.map({ 80 | -- "", 81 | -- "Increase window height", 82 | -- function() 83 | -- fn.change_window_height("up") 84 | -- end, 85 | -- mode = "n", 86 | -- }) 87 | -- K.map({ 88 | -- "", 89 | -- "Decrease window height", 90 | -- function() 91 | -- fn.change_window_height("down") 92 | -- end, 93 | -- mode = "n", 94 | -- }) 95 | 96 | -- K.map({ "", "Equalize layout", fn.equalize_layout, mode = "n" }) 97 | -- K.map({ "", "Reset layout", fn.reset_layout, mode = "n" }) 98 | end 99 | 100 | function NVWindows.is_window_floating(winid) 101 | local win = vim.api.nvim_win_get_config(winid) 102 | return win.relative ~= "" 103 | end 104 | 105 | function NVWindows.get_floating_tab_windows() 106 | local windows = fn.get_tab_windows() 107 | 108 | if not windows then 109 | return nil 110 | end 111 | 112 | local result = {} 113 | 114 | for _, winnr in ipairs(windows) do 115 | if NVWindows.is_window_floating(winnr) then 116 | table.insert(result, winnr) 117 | end 118 | end 119 | 120 | return result 121 | end 122 | 123 | function NVWindows.get_tab_windows_with_listed_buffers(options) 124 | local opts = vim.tbl_extend("keep", options, { incl_help = false }) 125 | 126 | local windows = fn.get_normal_tab_windows() 127 | 128 | if not windows then 129 | return nil 130 | end 131 | 132 | local result = {} 133 | 134 | for _, win in ipairs(windows) do 135 | local buf = vim.api.nvim_win_get_buf(win) 136 | local incl_if_help = opts.incl_help and NVHelp.is_help(buf) 137 | 138 | if NVBuffers.is_buf_listed(buf) or incl_if_help then 139 | table.insert(result, win) 140 | end 141 | end 142 | 143 | return result 144 | end 145 | 146 | function fn.reposition_windows(opts) 147 | local action = opts.action 148 | 149 | local windows = fn.get_normal_tab_windows() 150 | 151 | if #windows == 2 and action == "swap" then 152 | NVNoNeckPain.update_layout_with(function() 153 | vim.cmd("wincmd r") 154 | end) 155 | elseif #windows > 1 then 156 | -- FIXME: Handle winshift 157 | local winshift = require("plugins.winshift") 158 | 159 | if action == "swap" then 160 | winshift.swap() 161 | elseif action == "move_left" then 162 | NVNoNeckPain.update_layout_with(winshift.move_left) 163 | elseif action == "move_right" then 164 | NVNoNeckPain.update_layout_with(winshift.move_right) 165 | elseif action == "move_up" then 166 | NVNoNeckPain.update_layout_with(winshift.move_up) 167 | elseif action == "move_down" then 168 | NVNoNeckPain.update_layout_with(winshift.move_down) 169 | else 170 | vim.api.nvim_err_writeln("Unexpected windows action") 171 | end 172 | else 173 | print("No windows to rotate") 174 | return 175 | end 176 | end 177 | 178 | function fn.change_window_width(direction) 179 | local sidepads_visible = NVNoNeckPain.are_sidepads_visible() 180 | 181 | if direction == "up" then 182 | if sidepads_visible then 183 | NVNoNeckPain.increase_window_width() 184 | else 185 | vim.cmd("vertical resize +5") 186 | end 187 | elseif direction == "down" then 188 | if sidepads_visible then 189 | NVNoNeckPain.decrease_window_width() 190 | else 191 | vim.cmd("vertical resize -5") 192 | end 193 | else 194 | vim.api.nvim_err_writeln("Unexpected direction") 195 | end 196 | end 197 | 198 | function fn.change_window_height(direction) 199 | if direction == "up" then 200 | vim.cmd("resize +5") 201 | elseif direction == "down" then 202 | vim.cmd("resize -5") 203 | else 204 | vim.api.nvim_err_writeln("Unexpected direction") 205 | end 206 | end 207 | 208 | function fn.equalize_layout() 209 | local sidepads_visible = NVNoNeckPain.are_sidepads_visible() 210 | 211 | if sidepads_visible then 212 | NVNoNeckPain.set_default_window_width() 213 | vim.cmd("vert wincmd =") 214 | else 215 | vim.cmd("wincmd =") 216 | end 217 | end 218 | 219 | function fn.reset_layout() 220 | fn.equalize_layout() 221 | NVNoNeckPain.reload() 222 | end 223 | 224 | function fn.get_tab_windows() 225 | local tabs = vim.fn.gettabinfo() 226 | local current_tab = vim.fn.tabpagenr() 227 | 228 | local windows 229 | 230 | for _, tab in ipairs(tabs) do 231 | if tab.tabnr == current_tab then 232 | windows = tab.windows 233 | break 234 | end 235 | end 236 | 237 | return windows 238 | end 239 | 240 | function fn.get_normal_tab_windows() 241 | local windows = fn.get_tab_windows() 242 | 243 | if not windows then 244 | return nil 245 | end 246 | 247 | local result = {} 248 | 249 | local sidepads = NVNoNeckPain.get_sidepads() 250 | 251 | for _, winid in ipairs(windows) do 252 | if not NVWindows.is_window_floating(winid) then 253 | if sidepads ~= nil then 254 | if winid ~= sidepads.left and winid ~= sidepads.right then 255 | table.insert(result, winid) 256 | end 257 | else 258 | table.insert(result, winid) 259 | end 260 | end 261 | end 262 | 263 | return result 264 | end 265 | -------------------------------------------------------------------------------- /home/.config/nvim/lua/keymaps.lua: -------------------------------------------------------------------------------- 1 | K = {} 2 | 3 | NVKeymaps = { 4 | scroll = { 5 | up = "", 6 | down = "", 7 | }, 8 | close = "", 9 | } 10 | 11 | NVKarabiner = { 12 | [""] = "", 13 | [""] = "", 14 | } 15 | 16 | local default_keymap_options = { noremap = true, silent = true } 17 | 18 | ---@class Keymap 19 | ---@field [1] string Keymap 20 | ---@field [2] string Description 21 | ---@field [3] string | function Action 22 | ---@field mode Mode | Mode[] Mode 23 | 24 | ---@alias Mode "n"|"v"|"i"|"c"|"s"|"o"|"t"|"x" 25 | 26 | ---@param mapping Keymap 27 | function K.map(mapping) 28 | -- NB!: it is important to remove items in reverse order to avoid shifting 29 | local cmd = table.remove(mapping, 3) 30 | local desc = table.remove(mapping, 2) 31 | local key = table.remove(mapping, 1) 32 | 33 | local mode = mapping["mode"] 34 | 35 | mapping["mode"] = nil 36 | mapping["desc"] = desc 37 | 38 | local options = vim.tbl_extend("force", default_keymap_options, mapping) 39 | 40 | vim.keymap.set(mode, key, cmd, options) 41 | end 42 | -------------------------------------------------------------------------------- /home/.config/nvim/lua/plugins/_disabled.lua: -------------------------------------------------------------------------------- 1 | return { 2 | { "nvimdev/dashboard-nvim", enabled = false }, 3 | { "akinsho/bufferline.nvim", enabled = false }, 4 | { "lukas-reineke/indent-blankline.nvim", enabled = false }, 5 | { "folke/tokyonight.nvim", enabled = false }, 6 | { "catppuccin/nvim", enabled = false }, 7 | } 8 | -------------------------------------------------------------------------------- /home/.config/nvim/lua/plugins/_theme.lua: -------------------------------------------------------------------------------- 1 | return { 2 | { 3 | name = "theme", 4 | dir = vim.fn.stdpath("config") .. "/lua/theme", 5 | dev = true, 6 | lazy = false, 7 | priority = 1000, 8 | dependencies = { "rktjmp/lush.nvim" }, 9 | }, 10 | 11 | { 12 | "LazyVim/LazyVim", 13 | opts = { 14 | colorscheme = "theme", 15 | icons = { 16 | diagnostics = { 17 | Error = NVIcons.error, 18 | Warn = NVIcons.warn, 19 | Hint = NVIcons.hint, 20 | Info = NVIcons.info, 21 | }, 22 | }, 23 | }, 24 | }, 25 | } 26 | -------------------------------------------------------------------------------- /home/.config/nvim/lua/plugins/cmp.lua: -------------------------------------------------------------------------------- 1 | NVCmp = { 2 | "hrsh7th/nvim-cmp", 3 | opts = function(_, opts) 4 | local cmp = require("cmp") 5 | 6 | local mapping = cmp.mapping 7 | 8 | opts.mapping = mapping.preset.insert({ 9 | [NVKeymaps.scroll.up] = mapping.scroll_docs(-4), 10 | [NVKeymaps.scroll.down] = mapping.scroll_docs(4), 11 | [""] = mapping.complete(), 12 | [""] = LazyVim.cmp.confirm({ select = true }), 13 | [NVKeymaps.close] = mapping.abort(), 14 | }) 15 | 16 | -- Don't trigger completion on { 17 | opts.completion = vim.tbl_extend("force", opts.completion or {}, { 18 | keyword_length = 2, 19 | }) 20 | 21 | -- Prioritize `crates` source 22 | opts.sources = vim.tbl_filter(function(source) 23 | return not vim.tbl_contains({ "crates" }, source.name) 24 | end, opts.sources) 25 | 26 | table.insert(opts.sources, 1, { 27 | name = "crates", 28 | priority = 1000, 29 | group_index = 0, 30 | }) 31 | 32 | return opts 33 | end, 34 | } 35 | 36 | return { NVCmp } 37 | -------------------------------------------------------------------------------- /home/.config/nvim/lua/plugins/diffview.lua: -------------------------------------------------------------------------------- 1 | local fn = {} 2 | 3 | NVDiffview = { 4 | "sindrets/diffview.nvim", 5 | keys = function() 6 | return { 7 | { "d", fn.toggle_diff, mode = { "n", "v", "i" }, desc = "Git: Toggle diff" }, 8 | } 9 | end, 10 | opts = function() 11 | local actions = require("diffview.actions") 12 | 13 | return { 14 | enhanced_diff_hl = true, 15 | show_help_hints = false, 16 | watch_index = true, 17 | file_panel = { 18 | listing_style = "tree", -- 'list' or 'tree' 19 | }, 20 | keymaps = { 21 | disable_defaults = true, 22 | view = { 23 | { "n", "", actions.select_next_entry, { desc = "Open the diff for the next file" } }, 24 | { "n", "", actions.select_prev_entry, { desc = "Open the diff for the previous file" } }, 25 | { "n", "gf", actions.goto_file_edit, { desc = "Open the file" } }, 26 | -- { "n", "", actions.focus_files, { desc = "Bring focus to the file panel" } }, 27 | { "n", "", actions.toggle_files, { desc = "Toggle the file panel." } }, 28 | -- { "n", "", actions.prev_conflict, { desc = "In the merge-tool: jump to the previous conflict" } }, 29 | -- { "n", "", actions.next_conflict, { desc = "In the merge-tool: jump to the next conflict" } }, 30 | -- { "n", "", actions.conflict_choose("ours"), { desc = "Choose the OURS version of a conflict" } }, 31 | -- { "n", "", actions.conflict_choose("theirs"), { desc = "Choose the THEIRS version of a conflict" } }, 32 | -- { "n", "", actions.conflict_choose("base"), { desc = "Choose the BASE version of a conflict" } }, 33 | -- { "n", "", actions.conflict_choose("all"), { desc = "Choose all the versions of a conflict" } }, 34 | -- { "n", "", actions.conflict_choose("none"), { desc = "Delete the conflict region" } }, 35 | }, 36 | file_panel = { 37 | { "n", "", actions.prev_entry, { desc = "Bring the cursor to the previous file entry." } }, 38 | { "n", "", actions.next_entry, { desc = "Bring the cursor to the next file entry" } }, 39 | { "n", "", actions.select_prev_entry, { desc = "Open the diff for the previous file" } }, 40 | { "n", "", actions.select_next_entry, { desc = "Open the diff for the next file" } }, 41 | { "n", "", actions.select_prev_entry, { desc = "Open the diff for the previous file" } }, 42 | { "n", "", actions.select_next_entry, { desc = "Open the diff for the next file" } }, 43 | { "n", "", actions.select_entry, { desc = "Open the diff for the selected entry." } }, 44 | { "n", "", actions.select_entry, { desc = "Open the diff for the selected entry." } }, 45 | { "n", "<2-LeftMouse>", actions.select_entry, { desc = "Open the diff for the selected entry." } }, 46 | { "n", NVKeymaps.scroll.up, actions.scroll_view(-0.25), { desc = "Scroll the view up" } }, 47 | { "n", NVKeymaps.scroll.down, actions.scroll_view(0.25), { desc = "Scroll the view down" } }, 48 | { "n", "", actions.toggle_stage_entry, { desc = "Stage / unstage the selected entry." } }, 49 | { "n", "A", actions.stage_all, { desc = "Stage all entries." } }, 50 | { "n", "U", actions.unstage_all, { desc = "Unstage all entries." } }, 51 | { "n", "X", actions.restore_entry, { desc = "Restore entry to the state on the left side." } }, 52 | { "n", "", actions.goto_file_edit, { desc = "Open the file" } }, 53 | { "n", "i", actions.listing_style, { desc = "Toggle between 'list' and 'tree' views" } }, 54 | { "n", "d", actions.toggle_flatten_dirs, { desc = "Flatten empty subdirectories." } }, 55 | { "n", "L", actions.open_commit_log, { desc = "Open the commit log panel." } }, 56 | { "n", "R", actions.refresh_files, { desc = "Update stats and entries in the file list." } }, 57 | -- { "n", "", actions.focus_files, { desc = "Bring focus to the file panel" } }, 58 | { "n", "", actions.toggle_files, { desc = "Toggle the file panel" } }, 59 | -- { "n", "", actions.prev_conflict, { desc = "Go to the previous conflict" } }, 60 | -- { "n", "", actions.next_conflict, { desc = "Go to the next conflict" } }, 61 | { "n", "?", actions.help("file_panel"), { desc = "Open the help panel" } }, 62 | }, 63 | }, 64 | hooks = { 65 | diff_buf_win_enter = function(_bufnr, _winid, ctx) 66 | if ctx.layout_name:match("^diff2") then 67 | if ctx.symbol == "a" then 68 | vim.opt_local.winhl = table.concat({ 69 | "DiffAdd:DiffviewDiffDelete", 70 | "DiffDelete:DiffviewDiffFill", 71 | "DiffChange:DiffviewDiffDelete", 72 | "DiffText:DiffviewDiffDeleteText", 73 | }, ",") 74 | elseif ctx.symbol == "b" then 75 | vim.opt_local.winhl = table.concat({ 76 | "DiffAdd:DiffviewDiffAdd", 77 | "DiffChange:DiffviewDiffAdd", 78 | "DiffText:DiffviewDiffAddText", 79 | "DiffDelete:DiffviewDiffFill", 80 | }, ",") 81 | end 82 | end 83 | end, 84 | }, 85 | } 86 | end, 87 | } 88 | 89 | function NVDiffview.ensure_current_hidden() 90 | local current_diff = fn.current_diff() 91 | 92 | if current_diff ~= nil then 93 | fn.hide_current_diff() 94 | return true 95 | else 96 | return false 97 | end 98 | end 99 | 100 | function NVDiffview.ensure_all_hidden() 101 | local current_diff = fn.current_diff() 102 | 103 | if current_diff ~= nil then 104 | fn.hide_current_diff() 105 | end 106 | 107 | local inactive_diff_tab = fn.inactive_diff() 108 | 109 | if inactive_diff_tab ~= nil then 110 | vim.api.nvim_command("tabclose " .. inactive_diff_tab) 111 | end 112 | end 113 | 114 | function fn.toggle_diff() 115 | local current_diff = fn.current_diff() 116 | 117 | if current_diff ~= nil then 118 | fn.hide_current_diff() 119 | else 120 | NVZenMode.ensure_deacitvated() 121 | 122 | local inactive_diff_tab = fn.inactive_diff() 123 | 124 | if inactive_diff_tab ~= nil then 125 | vim.api.nvim_set_current_tabpage(inactive_diff_tab) 126 | else 127 | fn.open_diff() 128 | NVLualine.rename_tab("diff") 129 | NVLualine.show_tabline() 130 | end 131 | end 132 | end 133 | 134 | function fn.open_diff() 135 | vim.cmd("DiffviewOpen") 136 | end 137 | 138 | function fn.hide_current_diff() 139 | vim.cmd("DiffviewClose") 140 | end 141 | 142 | function fn.current_diff() 143 | local dv = require("diffview.lib") 144 | 145 | local current_diff = dv.get_current_view() 146 | 147 | return current_diff 148 | end 149 | 150 | function fn.inactive_diff() 151 | local dv = require("diffview.lib") 152 | 153 | local tabs = vim.api.nvim_list_tabpages() 154 | 155 | for _, tabpage in ipairs(tabs) do 156 | for _, view in ipairs(dv.views) do 157 | if view.tabpage == tabpage then 158 | return tabpage 159 | end 160 | end 161 | end 162 | 163 | return nil 164 | end 165 | 166 | return { NVDiffview } 167 | -------------------------------------------------------------------------------- /home/.config/nvim/lua/plugins/flash.lua: -------------------------------------------------------------------------------- 1 | NVFlash = { 2 | "folke/flash.nvim", 3 | event = "VeryLazy", 4 | vscode = false, 5 | keys = { 6 | { NVKarabiner[""], mode = { "n", "x", "o" }, require("flash").jump, desc = "Search" }, 7 | }, 8 | opts = { 9 | search = { 10 | multi_window = true, 11 | forward = true, 12 | wrap = true, 13 | mode = "fuzzy", 14 | max_length = false, 15 | exclude = { 16 | "notify", 17 | "cmp_menu", 18 | "noice", 19 | "flash_prompt", 20 | function(win) 21 | return not vim.api.nvim_win_get_config(win).focusable 22 | end, 23 | }, 24 | }, 25 | jump = { 26 | nohlsearch = true, 27 | autojump = false, 28 | }, 29 | label = { 30 | uppercase = false, 31 | current = false, 32 | after = false, 33 | before = true, 34 | style = "overlay", 35 | reuse = "lowercase", 36 | distance = true, 37 | min_pattern_length = 0, 38 | }, 39 | highlight = { 40 | backdrop = true, 41 | matches = true, 42 | }, 43 | modes = { 44 | search = { 45 | enabled = false, 46 | }, 47 | char = { 48 | enabled = true, 49 | keys = { "f", "F", "t", "T" }, 50 | autohide = false, 51 | jump_labels = false, 52 | multi_line = true, 53 | char_actions = function(motion) 54 | return { 55 | [motion:lower()] = "next", 56 | [motion:upper()] = "prev", 57 | } 58 | end, 59 | search = { wrap = false }, 60 | highlight = { backdrop = true }, 61 | jump = { 62 | register = false, 63 | autojump = false, 64 | }, 65 | }, 66 | 67 | -- TODO: Review treesitter-related settings 68 | 69 | treesitter = { 70 | labels = "abcdefghijklmnopqrstuvwxyz", 71 | jump = { pos = "range", autojump = true }, 72 | search = { incremental = false }, 73 | label = { before = true, after = true, style = "inline" }, 74 | highlight = { 75 | backdrop = false, 76 | matches = false, 77 | }, 78 | }, 79 | treesitter_search = { 80 | jump = { pos = "range" }, 81 | search = { multi_window = true, wrap = true, incremental = false }, 82 | remote_op = { restore = true }, 83 | label = { before = true, after = true, style = "inline" }, 84 | }, 85 | remote = { 86 | remote_op = { restore = true, motion = true }, 87 | }, 88 | }, 89 | prompt = { 90 | enabled = true, 91 | prefix = { { "󱅥 ", "FlashPromptIcon" } }, 92 | win_config = { 93 | relative = "editor", 94 | width = 20, -- when <=1 it's a percentage of the editor width 95 | height = 1, 96 | row = 0, -- when negative it's an offset from the bottom 97 | col = math.floor(vim.go.columns / 2) - 14, -- when negative it's an offset from the right 98 | zindex = 2000, 99 | }, 100 | }, 101 | remote_op = { 102 | restore = false, 103 | motion = false, 104 | }, 105 | }, 106 | } 107 | 108 | return { NVFlash } 109 | -------------------------------------------------------------------------------- /home/.config/nvim/lua/plugins/gitsigns.lua: -------------------------------------------------------------------------------- 1 | NVGitsigns = { 2 | "lewis6991/gitsigns.nvim", 3 | opts = { 4 | preview_config = { 5 | border = "solid", 6 | style = "minimal", 7 | relative = "cursor", 8 | row = 0, 9 | col = 1, 10 | }, 11 | on_attach = function(buffer) 12 | local gs = package.loaded.gitsigns 13 | 14 | local function keymap(mapping) 15 | mapping = vim.tbl_extend("error", mapping, { buffer = buffer }) 16 | K.map(mapping) 17 | end 18 | 19 | keymap({ "", "Git: Preview hunk", gs.preview_hunk, mode = "n" }) 20 | keymap({ "", "Git: Stage/unstage hunk", gs.stage_hunk, mode = "n" }) 21 | keymap({ 22 | "", 23 | "Git: Stage/unstage hunk", 24 | function() 25 | gs.stage_hunk({ vim.fn.line("."), vim.fn.line("v") }) 26 | end, 27 | mode = "v", 28 | }) 29 | keymap({ 30 | "", 31 | "Git: Jump to next hunk", 32 | function() 33 | gs.nav_hunk("next", { navigation_message = false }) 34 | end, 35 | mode = { "n", "i" }, 36 | }) 37 | keymap({ 38 | "", 39 | "Git: Jump to previous hunk", 40 | function() 41 | gs.nav_hunk("prev", { navigation_message = false }) 42 | end, 43 | mode = { "n", "i" }, 44 | }) 45 | end, 46 | }, 47 | } 48 | 49 | ---@return boolean 50 | function NVGitsigns.ensure_preview_hidden() 51 | local popup = require("gitsigns.popup") 52 | 53 | -- https://github.com/lewis6991/gitsigns.nvim/blob/863903631e676b33e8be2acb17512fdc1b80b4fb/lua/gitsigns/actions.lua#L833 54 | local id = "hunk" 55 | 56 | if popup.is_open(id) then 57 | popup.close(id) 58 | return true 59 | else 60 | return false 61 | end 62 | end 63 | 64 | return { NVGitsigns } 65 | -------------------------------------------------------------------------------- /home/.config/nvim/lua/plugins/lazy.lua: -------------------------------------------------------------------------------- 1 | local fn = {} 2 | 3 | NVLazy = {} 4 | 5 | function NVLazy.ensure_hidden() 6 | if fn.is_active() then 7 | fn.close() 8 | return true 9 | else 10 | return false 11 | end 12 | end 13 | 14 | function NVLazy.anything_missing() 15 | local plugins = require("lazy.core.config").plugins 16 | 17 | for _, plugin in pairs(plugins) do 18 | local installed = plugin._.installed 19 | local needs_build = plugin._.build 20 | 21 | if not installed or needs_build then 22 | return true 23 | end 24 | end 25 | 26 | return false 27 | end 28 | 29 | function NVLazy.install() 30 | require("lazy").install() 31 | end 32 | 33 | function fn.is_active() 34 | return vim.bo.filetype == "lazy" 35 | end 36 | 37 | function fn.close() 38 | NVKeys.send("q", { mode = "x" }) 39 | 40 | vim.schedule(function() 41 | if NVMiniStarter.is_active() then 42 | NVMiniStarter.refresh() 43 | end 44 | end) 45 | end 46 | 47 | return {} 48 | -------------------------------------------------------------------------------- /home/.config/nvim/lua/plugins/mini-pairs.lua: -------------------------------------------------------------------------------- 1 | NVMiniPairs = { 2 | "echasnovski/mini.pairs", 3 | opts = { 4 | skip_ts = {}, 5 | }, 6 | } 7 | 8 | return { NVMiniPairs } 9 | -------------------------------------------------------------------------------- /home/.config/nvim/lua/plugins/mini-starter.lua: -------------------------------------------------------------------------------- 1 | NVMiniStarter = { 2 | "echasnovski/mini.starter", 3 | opts = function() 4 | local project = NVFS.root({ capitalize = true }) 5 | 6 | local item = function(name, action, section) 7 | return { name = name, action = action, section = section } 8 | end 9 | 10 | local items = {} 11 | 12 | table.insert(items, function() 13 | if NVLazy.anything_missing() then 14 | return item("Install plugins", NVLazy.install, project) 15 | else 16 | return nil 17 | end 18 | end) 19 | 20 | table.insert(items, function() 21 | if NVPersistence.has_session() then 22 | return item("Restore session", NVPersistence.restore, project) 23 | else 24 | return item("Browse", NVTelescope.open_file_browser, project) 25 | end 26 | end) 27 | 28 | table.insert(items, item("Quit", "qa", project)) 29 | 30 | local config = { 31 | evaluate_single = false, 32 | header = "", 33 | items = items, 34 | } 35 | 36 | return config 37 | end, 38 | config = function(_, config) 39 | -- close Lazy and re-open when starter is ready 40 | if vim.o.filetype == "lazy" then 41 | vim.cmd.close() 42 | vim.api.nvim_create_autocmd("User", { 43 | pattern = "MiniStarterOpened", 44 | callback = function() 45 | require("lazy").show() 46 | end, 47 | }) 48 | end 49 | 50 | local starter = require("mini.starter") 51 | 52 | starter.setup(config) 53 | 54 | vim.api.nvim_create_autocmd("User", { 55 | pattern = "MiniStarterOpened", 56 | callback = function() 57 | NVLualine.hide_tabline() 58 | 59 | local starter_bufid = vim.api.nvim_get_current_buf() 60 | 61 | vim.api.nvim_create_autocmd("BufWipeout", { 62 | callback = function(args) 63 | local bufid = args.buf 64 | 65 | if bufid == starter_bufid then 66 | NVLualine.rename_tab("editor") 67 | NVLualine.show_tabline() 68 | NVNoNeckPain.enable() 69 | end 70 | end, 71 | }) 72 | end, 73 | }) 74 | 75 | vim.api.nvim_create_autocmd("User", { 76 | once = true, 77 | pattern = "MiniStarterOpened", 78 | callback = NVLualine.hide_tabline, 79 | }) 80 | 81 | vim.api.nvim_create_autocmd("User", { 82 | once = true, 83 | pattern = "LazyVimStarted", 84 | callback = function(ev) 85 | local stats = require("lazy").stats() 86 | local ms = (math.floor(stats.startuptime * 100 + 0.5) / 100) 87 | starter.config.footer = " in " .. ms .. "ms" 88 | if vim.bo[ev.buf].filetype == "ministarter" then 89 | pcall(starter.refresh) 90 | end 91 | end, 92 | }) 93 | end, 94 | } 95 | 96 | function NVMiniStarter.is_active() 97 | return vim.bo.filetype == "ministarter" 98 | end 99 | 100 | function NVMiniStarter.refresh() 101 | require("mini.starter").refresh() 102 | end 103 | 104 | return { NVMiniStarter } 105 | -------------------------------------------------------------------------------- /home/.config/nvim/lua/plugins/mini-surround.lua: -------------------------------------------------------------------------------- 1 | NVMiniSurround = { 2 | "echasnovski/mini.surround", 3 | opts = { 4 | mappings = { 5 | add = "", 6 | replace = "cs", 7 | delete = "ds", 8 | }, 9 | }, 10 | } 11 | 12 | return { NVMiniSurround } 13 | -------------------------------------------------------------------------------- /home/.config/nvim/lua/plugins/neo-tree.lua: -------------------------------------------------------------------------------- 1 | -- TODO: Setup or remove neo-tree 2 | 3 | NVNeoTree = { 4 | "nvim-neo-tree/neo-tree.nvim", 5 | opts = { 6 | filesystem = { 7 | filtered_items = { 8 | hide_dotfiles = false, 9 | hide_gitignored = false, 10 | }, 11 | }, 12 | }, 13 | } 14 | 15 | return { NVNeoTree } 16 | -------------------------------------------------------------------------------- /home/.config/nvim/lua/plugins/no-neck-pain.lua: -------------------------------------------------------------------------------- 1 | local fn = {} 2 | 3 | NVNoNeckPain = { 4 | "shortcuts/no-neck-pain.nvim", 5 | opts = { 6 | width = NVWindows.default_width, 7 | autocmds = { 8 | enableOnVimEnter = false, 9 | skipEnteringNoNeckPainBuffer = true, 10 | }, 11 | }, 12 | } 13 | 14 | function NVNoNeckPain.increase_window_width() 15 | vim.cmd("NoNeckPainWidthUp") 16 | end 17 | 18 | function NVNoNeckPain.decrease_window_width() 19 | vim.cmd("NoNeckPainWidthDown") 20 | end 21 | 22 | function NVNoNeckPain.set_default_window_width() 23 | vim.cmd("NoNeckPainResize " .. NVWindows.default_width) 24 | end 25 | 26 | function NVNoNeckPain.get_sidepads() 27 | local plugin = _G.NoNeckPain 28 | 29 | if not plugin then 30 | return nil 31 | end 32 | 33 | local state = plugin.state 34 | 35 | if not state then 36 | return nil 37 | end 38 | 39 | local current_tab = vim.api.nvim_get_current_tabpage() 40 | 41 | local tab = nil 42 | 43 | if state.tabs ~= nil then 44 | for _, t in ipairs(state.tabs) do 45 | if t.id == current_tab then 46 | tab = t 47 | break 48 | end 49 | end 50 | end 51 | 52 | if not tab then 53 | return nil 54 | end 55 | 56 | local win = tab.wins.main 57 | 58 | return { 59 | left = win.left, 60 | right = win.right, 61 | } 62 | end 63 | 64 | function NVNoNeckPain.are_sidepads_visible() 65 | local sidepads = NVNoNeckPain.get_sidepads() 66 | 67 | if not sidepads then 68 | return false 69 | end 70 | 71 | return sidepads.left ~= nil or sidepads.right ~= nil 72 | end 73 | 74 | function NVNoNeckPain.ensure_sidepads_hidden() 75 | if NVNoNeckPain.are_sidepads_visible() then 76 | vim.cmd("NoNeckPain") 77 | end 78 | end 79 | 80 | function NVNoNeckPain.disable() 81 | fn.ensure_cursor_position(NoNeckPain.disable) 82 | end 83 | 84 | function NVNoNeckPain.enable() 85 | fn.ensure_cursor_position(NoNeckPain.enable) 86 | end 87 | 88 | function NVNoNeckPain.update_layout_with(fn, opts) 89 | local sidepads_visible 90 | 91 | if opts and opts.check_sidepads_visibility then 92 | sidepads_visible = NVNoNeckPain.are_sidepads_visible() 93 | else 94 | sidepads_visible = true 95 | end 96 | 97 | if sidepads_visible then 98 | NVNoNeckPain.disable() 99 | end 100 | 101 | fn() 102 | 103 | if sidepads_visible then 104 | NVNoNeckPain.enable() 105 | end 106 | end 107 | 108 | function NVNoNeckPain.reload() 109 | fn.ensure_cursor_position(function() 110 | pcall(NoNeckPain.disable) 111 | NoNeckPain.enable() 112 | end) 113 | end 114 | 115 | function fn.ensure_cursor_position(f) 116 | local current_cursor = NVCursor.get() 117 | 118 | f() 119 | 120 | pcall(NVCursor.set, current_cursor) 121 | end 122 | 123 | return { NVNoNeckPain } 124 | -------------------------------------------------------------------------------- /home/.config/nvim/lua/plugins/noice.lua: -------------------------------------------------------------------------------- 1 | local fn = {} 2 | 3 | NVNoice = { 4 | "folke/noice.nvim", 5 | dependencies = { 6 | "nvim-telescope/telescope.nvim", 7 | }, 8 | keys = function() 9 | return { 10 | { "", "NoiceHistory", mode = { "n", "i", "v" }, desc = "Open log" }, 11 | } 12 | end, 13 | opts = function() 14 | local Layout = { 15 | common = { 16 | position = { 17 | visually_centered = { 18 | row = "40%", 19 | col = "50%", 20 | }, 21 | }, 22 | border = { 23 | style = "none", 24 | padding = { top = 1, bottom = 1, left = 2, right = 2 }, 25 | }, 26 | win_options = { 27 | winhighlight = { 28 | Normal = "NormalFloat", 29 | FloatBorder = "FloatBorder", 30 | }, 31 | winbar = "", 32 | foldenable = false, 33 | }, 34 | }, 35 | cmdline_popup = { 36 | position = { 37 | row = 10, 38 | col = "50%", 39 | }, 40 | size = { 41 | width = 60, 42 | height = "auto", 43 | }, 44 | }, 45 | } 46 | 47 | return { 48 | cmdline = { 49 | format = { 50 | search_down = { view = "cmdline" }, 51 | search_up = { view = "cmdline" }, 52 | }, 53 | }, 54 | 55 | status = { 56 | lsp_progress = { 57 | event = "lsp", 58 | kind = "progress", 59 | }, 60 | }, 61 | 62 | commands = { 63 | last = { 64 | view = "popup", 65 | opts = { enter = true, format = "details" }, 66 | filter = { 67 | any = { 68 | { event = "notify" }, 69 | { error = true }, 70 | { warning = true }, 71 | { event = "msg_show", kind = { "" } }, 72 | { event = "lsp", kind = "message" }, 73 | }, 74 | }, 75 | filter_opts = { count = 1 }, 76 | }, 77 | history = { 78 | view = "popup", 79 | opts = { enter = true, format = "details" }, 80 | filter = { 81 | any = { 82 | { event = "notify" }, 83 | { error = true }, 84 | { warning = true }, 85 | { event = "msg_show", kind = { "" } }, 86 | { event = "lsp", kind = "message" }, 87 | }, 88 | }, 89 | }, 90 | errors = { 91 | view = "popup", 92 | opts = { enter = true, format = "details" }, 93 | filter = { error = true }, 94 | filter_opts = { reverse = true }, 95 | }, 96 | all = { 97 | view = "popup", 98 | opts = { enter = true, format = "details" }, 99 | filter = {}, 100 | }, 101 | }, 102 | 103 | views = { 104 | popup = { 105 | backend = "popup", 106 | relative = "editor", 107 | position = Layout.common.position.visually_centered, 108 | border = Layout.common.border, 109 | size = { 110 | width = NVWindows.default_width, 111 | height = NVScreen.is_large() and 30 or 15, 112 | }, 113 | win_options = Layout.common.win_options, 114 | close = { 115 | events = { "BufLeave" }, 116 | keys = { NVKeymaps.close }, 117 | }, 118 | }, 119 | cmdline = { 120 | position = { 121 | row = 0, 122 | col = "50%", 123 | }, 124 | size = { 125 | width = 60, 126 | height = 1, 127 | }, 128 | }, 129 | cmdline_popup = { 130 | position = Layout.cmdline_popup.position, 131 | size = Layout.cmdline_popup.size, 132 | border = Layout.common.border, 133 | win_options = Layout.common.win_options, 134 | filter_options = {}, 135 | close = { keys = { NVKeymaps.close } }, 136 | }, 137 | cmdline_popupmenu = { 138 | position = { 139 | row = Layout.cmdline_popup.position.row + 4, 140 | col = Layout.cmdline_popup.position.col, 141 | }, 142 | size = Layout.cmdline_popup.size, 143 | border = Layout.common.border, 144 | win_options = Layout.common.win_options, 145 | close = { keys = { NVKeymaps.close } }, 146 | }, 147 | cmdline_output = { 148 | enter = true, 149 | format = "details", 150 | view = "popup", 151 | }, 152 | notify = { 153 | backend = "notify", 154 | render = "wrapped-compact", 155 | }, 156 | }, 157 | 158 | routes = { 159 | { 160 | filter = { event = "lsp", kind = "progress" }, 161 | opts = { skip = true }, 162 | }, 163 | }, 164 | } 165 | end, 166 | config = function(_, opts) 167 | require("noice").setup(opts) 168 | require("telescope").load_extension("noice") 169 | end, 170 | } 171 | 172 | function NVNoice.ensure_hidden() 173 | if fn.is_cmdline_active() then 174 | fn.exit_cmdline() 175 | return true 176 | end 177 | 178 | local current_win = vim.api.nvim_get_current_win() 179 | 180 | if fn.is_win_active() then 181 | if NVWindows.is_window_floating(current_win) then 182 | fn.close_split() 183 | return true 184 | else 185 | if NVNoNeckPain.are_sidepads_visible() then 186 | NVNoNeckPain.update_layout_with(function() 187 | vim.api.nvim_set_current_win(current_win) 188 | fn.close_split() 189 | end, { check_sidepads_visibility = false }) 190 | else 191 | fn.close_split() 192 | end 193 | 194 | return true 195 | end 196 | else 197 | return false 198 | end 199 | end 200 | 201 | function fn.is_win_active() 202 | return vim.bo.filetype == "noice" 203 | end 204 | 205 | function fn.is_cmdline_active() 206 | local mode = vim.fn.mode() 207 | return mode == "c" 208 | end 209 | 210 | function fn.close_split() 211 | vim.cmd.close() 212 | end 213 | 214 | function fn.exit_cmdline() 215 | NVKeys.send("", { mode = "n" }) 216 | end 217 | 218 | return { NVNoice } 219 | -------------------------------------------------------------------------------- /home/.config/nvim/lua/plugins/nvim-lspconfig.lua: -------------------------------------------------------------------------------- 1 | NVLSPConfig = { 2 | "neovim/nvim-lspconfig", 3 | opts = function() 4 | local keys = require("lazyvim.plugins.lsp.keymaps").get() 5 | 6 | keys[#keys + 1] = { "", vim.lsp.buf.rename } 7 | keys[#keys + 1] = { "", vim.lsp.buf.code_action } 8 | end, 9 | } 10 | 11 | return { NVLSPConfig } 12 | -------------------------------------------------------------------------------- /home/.config/nvim/lua/plugins/nvim-notify.lua: -------------------------------------------------------------------------------- 1 | NVNotify = { 2 | "rcarriga/nvim-notify", 3 | opts = { 4 | icons = { 5 | ERROR = NVIcons.error, 6 | WARN = NVIcons.warn, 7 | INFO = NVIcons.info, 8 | }, 9 | }, 10 | } 11 | 12 | return { NVNotify } 13 | -------------------------------------------------------------------------------- /home/.config/nvim/lua/plugins/persistence.lua: -------------------------------------------------------------------------------- 1 | NVPersistence = {} 2 | 3 | function NVPersistence.autocmds() 4 | vim.api.nvim_create_autocmd("User", { 5 | pattern = "PersistenceSavePre", 6 | callback = function() 7 | local mode = vim.fn.mode() 8 | 9 | if mode == "i" or mode == "v" then 10 | NVKeys.send("", { mode = "x" }) 11 | end 12 | 13 | -- TODO: Complete this list 14 | NVLazy.ensure_hidden() 15 | NVNoice.ensure_hidden() 16 | NVZenMode.ensure_deacitvated() 17 | NVDiffview.ensure_all_hidden() 18 | NVNoNeckPain.disable() 19 | end, 20 | }) 21 | 22 | vim.api.nvim_create_autocmd("User", { 23 | pattern = "PersistenceLoadPost", 24 | callback = function() 25 | NVNoNeckPain.reload() 26 | end, 27 | }) 28 | end 29 | 30 | function NVPersistence.has_session() 31 | local plugin = require("persistence") 32 | 33 | local sessions = plugin.list() 34 | local current_session = plugin.current() 35 | 36 | for _, session in ipairs(sessions) do 37 | if session == current_session then 38 | return true 39 | end 40 | end 41 | 42 | return false 43 | end 44 | 45 | function NVPersistence.restore() 46 | require("persistence").load() 47 | end 48 | 49 | return {} 50 | -------------------------------------------------------------------------------- /home/.config/nvim/lua/plugins/tinygit.lua: -------------------------------------------------------------------------------- 1 | local fn = {} 2 | 3 | NVTinygit = { 4 | "chrisgrieser/nvim-tinygit", 5 | dependencies = { 6 | { 7 | "stevearc/dressing.nvim", 8 | opts = { 9 | input = { 10 | relative = "cursor", 11 | border = "solid", 12 | mappings = { 13 | n = { 14 | [NVKeymaps.close] = "Close", 15 | [""] = "Close", 16 | [""] = "Confirm", 17 | }, 18 | i = { 19 | [NVKeymaps.close] = "Close", 20 | [""] = "Confirm", 21 | [""] = "HistoryPrev", 22 | [""] = "HistoryNext", 23 | }, 24 | }, 25 | }, 26 | }, 27 | }, 28 | "nvim-telescope/telescope.nvim", 29 | "rcarriga/nvim-notify", 30 | }, 31 | keys = function() 32 | return { 33 | { "s", fn.stage, mode = { "n", "i", "v" }, desc = "Git: Stage" }, 34 | { "c", fn.commit, mode = { "n", "i", "v" }, desc = "Git: Commit" }, 35 | { "a", fn.amend, mode = { "n", "i", "v" }, desc = "Git: Amend and push" }, 36 | { "r", fn.rename_last_commit, mode = { "n", "i", "v" }, desc = "Git: Rename last commit anrd push" }, 37 | } 38 | end, 39 | opts = { 40 | backdrop = { 41 | enabled = false, 42 | }, 43 | staging = { 44 | contextSize = 1, 45 | stagedIndicator = " ", 46 | keymaps = { 47 | stagingToggle = "", 48 | gotoHunk = "", 49 | resetHunk = "", 50 | }, 51 | moveToNextHunkOnStagingToggle = true, 52 | }, 53 | commitMsg = { 54 | commitPreview = false, 55 | spellcheck = true, 56 | keepAbortedMsgSecs = 300, 57 | inputFieldWidth = 72, 58 | conventionalCommits = { 59 | enforce = false, 60 | }, 61 | insertIssuesOnHash = { 62 | enabled = false, 63 | next = "", 64 | prev = "", 65 | issuesToFetch = 20, 66 | }, 67 | }, 68 | push = { 69 | preventPushingFixupOrSquashCommits = true, 70 | confirmationSound = false, 71 | }, 72 | }, 73 | } 74 | 75 | function fn.stage() 76 | local tinygit = require("tinygit") 77 | tinygit.interactiveStaging() 78 | end 79 | 80 | function fn.commit() 81 | local tinygit = require("tinygit") 82 | tinygit.smartCommit({ pushIfClean = true }) 83 | end 84 | 85 | function fn.amend() 86 | local tinygit = require("tinygit") 87 | tinygit.amendNoEdit({ stageAllIfNothingStaged = false, forcePushIfDiverged = true }) 88 | end 89 | 90 | function fn.rename_last_commit() 91 | local tinygit = require("tinygit") 92 | tinygit.amendOnlyMsg({ forcePushIfDiverged = true }) 93 | end 94 | 95 | return { NVTinygit } 96 | -------------------------------------------------------------------------------- /home/.config/nvim/lua/plugins/trouble.lua: -------------------------------------------------------------------------------- 1 | local fn = {} 2 | 3 | NVTrouble = { 4 | "folke/trouble.nvim", 5 | keys = function() 6 | return { 7 | { "", fn.open_symbol_usage, mode = { "n", "i", "v" }, desc = "Open symbol usage" }, 8 | { "", fn.open_symbols, mode = { "n", "i", "v" }, desc = "Open symbols" }, 9 | { 10 | "", 11 | function() 12 | fn.open_diagnosics({ severity = vim.diagnostic.severity.ERROR }) 13 | end, 14 | mode = { "n", "i", "v" }, 15 | desc = "Diagnostics: ERROR [workspace]", 16 | }, 17 | { 18 | "", 19 | function() 20 | fn.open_diagnosics({ buf = 0, severity = vim.diagnostic.severity.ERROR }) 21 | end, 22 | mode = { "n", "i", "v" }, 23 | desc = "Diagnostics: ERROR [current buffer]", 24 | }, 25 | { 26 | "", 27 | function() 28 | fn.open_diagnosics({ severity = vim.diagnostic.severity.WARN }) 29 | end, 30 | mode = { "n", "i", "v" }, 31 | desc = "Diagnostics: WARN [workspace]", 32 | }, 33 | { 34 | "", 35 | function() 36 | fn.open_diagnosics({ buf = 0, severity = vim.diagnostic.severity.WARN }) 37 | end, 38 | mode = { "n", "i", "v" }, 39 | desc = "Diagnostics: WARN [current buffer]", 40 | }, 41 | } 42 | end, 43 | opts = function() 44 | return { 45 | auto_close = false, -- auto close when there are no items 46 | auto_open = false, -- auto open when there are items 47 | auto_preview = true, -- automatically open preview when on an item 48 | auto_refresh = true, -- auto refresh when open 49 | auto_jump = false, -- auto jump to the item when there's only one 50 | focus = true, -- Focus the window when opened 51 | restore = true, -- restores the last location in the list when opening 52 | follow = false, -- Follow the current item 53 | indent_guides = false, -- show indent guides 54 | max_items = 200, -- limit number of items that can be displayed per section 55 | multiline = true, -- render multi-line messages 56 | pinned = false, -- When pinned, the opened trouble window will be bound to the current buffer 57 | warn_no_results = true, -- show a warning when there are no results 58 | open_no_results = false, -- open the trouble window when there are no results 59 | keys = { 60 | [NVKeymaps.close] = "close", 61 | [""] = "jump_close", 62 | [""] = "jump_close", 63 | [""] = "fold_open", 64 | [""] = "fold_open_recursive", 65 | [""] = "fold_close", 66 | [""] = "fold_close_recursive", 67 | [""] = "fold_toggle", 68 | [""] = "fold_toggle_recursive", 69 | [""] = "jump_split_close", 70 | [""] = "jump_vsplit_close", 71 | }, 72 | } 73 | end, 74 | } 75 | 76 | function fn.win(opts) 77 | local base = { 78 | type = "float", 79 | relative = "editor", 80 | title_pos = "center", 81 | border = "solid", 82 | zindex = 1000, 83 | } 84 | 85 | return vim.tbl_extend("error", base, opts) 86 | end 87 | 88 | function fn.open_diagnosics(filter) 89 | local trouble = require("trouble") 90 | 91 | local size = { 92 | width = NVScreen.is_large() and NVWindows.default_width or 0.8, 93 | height = 0.4, 94 | } 95 | 96 | local shift = 0.4 97 | 98 | trouble.open({ 99 | mode = "diagnostics", 100 | focus = true, 101 | filter = filter, 102 | win = fn.win({ 103 | title = " Diagnostics ", 104 | size = size, 105 | position = { 0.5 - shift, 0.5 }, 106 | }), 107 | preview = fn.win({ 108 | title = " Preview ", 109 | size = size, 110 | position = { 0.5 + shift - 0.05, 0.5 }, 111 | scratch = true, 112 | }), 113 | }) 114 | end 115 | 116 | function fn.open_symbol_usage() 117 | local trouble = require("trouble") 118 | 119 | local large_screen = NVScreen.is_large() 120 | 121 | local size = { 122 | width = large_screen and 100 or 0.45, 123 | height = 0.8, 124 | } 125 | 126 | local shift = large_screen and 0.35 or 0.42 127 | 128 | trouble.open({ 129 | mode = "lsp", 130 | focus = true, 131 | win = fn.win({ 132 | title = " LSP ", 133 | size = size, 134 | position = { 0.5, 0.5 - shift }, 135 | }), 136 | preview = fn.win({ 137 | title = " Preview ", 138 | size = size, 139 | position = { 0.5, 0.5 + shift }, 140 | scratch = true, 141 | }), 142 | }) 143 | end 144 | 145 | function fn.open_symbols() 146 | local trouble = require("trouble") 147 | 148 | local large_screen = NVScreen.is_large() 149 | 150 | trouble.open({ 151 | mode = "symbols", 152 | focus = true, 153 | win = fn.win({ 154 | title = " Document Symbols ", 155 | size = { 156 | width = 100, 157 | height = 0.45, 158 | }, 159 | position = { large_screen and 0.3 or 0.4, 0.5 }, 160 | }), 161 | }) 162 | end 163 | 164 | function NVTrouble.ensure_hidden() 165 | local trouble = require("trouble") 166 | 167 | if trouble.is_open() then 168 | trouble.close() 169 | return true 170 | else 171 | return false 172 | end 173 | end 174 | 175 | return { NVTrouble } 176 | -------------------------------------------------------------------------------- /home/.config/nvim/lua/plugins/zen-mode.lua: -------------------------------------------------------------------------------- 1 | local fn = {} 2 | 3 | NVZenMode = { 4 | "folke/zen-mode.nvim", 5 | keys = function() 6 | return { 7 | { NVKarabiner[""], fn.toggle_normal, desc = "Toggle zen mode", mode = { "n", "i", "v" } }, 8 | { "", fn.toggle_maximized, desc = "Toggle maximized zen mode", mode = { "n", "i", "v" } }, 9 | { "", fn.deactivate, desc = "Quit zen mode", mode = { "n", "i", "v" } }, 10 | } 11 | end, 12 | opts = { 13 | backdrop = 1, 14 | height = 1, 15 | }, 16 | } 17 | 18 | function NVZenMode.is_active() 19 | local zenmode = require("zen-mode.view") 20 | 21 | local is_open = zenmode.is_open() 22 | 23 | if is_open == nil then 24 | return false 25 | else 26 | return is_open 27 | end 28 | end 29 | 30 | function NVZenMode.ensure_deacitvated() 31 | if NVZenMode.is_active() then 32 | fn.deactivate() 33 | return true 34 | else 35 | return false 36 | end 37 | end 38 | 39 | local ZenWinStatus = { 40 | normal = "NORMAL", 41 | maximized = "MAXIMIZED", 42 | } 43 | 44 | local ZenWinStatusKey = { 45 | current = "zen_mode_current_status", 46 | previous = "zen_mode_previous_status", 47 | } 48 | 49 | function ZenWinStatus.get(key) 50 | local winid = vim.api.nvim_get_current_win() 51 | return vim.w[winid][key] 52 | end 53 | 54 | function ZenWinStatus.set(winid, key, status) 55 | vim.w[winid][key] = status 56 | end 57 | 58 | function ZenWinStatus.width(status) 59 | if status == ZenWinStatus.normal then 60 | return NVWindows.default_width 61 | elseif status == ZenWinStatus.maximized then 62 | return NVWindows.maximized_width 63 | else 64 | vim.api.nvim_err_writeln("Unexpected zen window status: " .. status) 65 | end 66 | end 67 | 68 | function fn.toggle_normal() 69 | fn.toggle({ status = ZenWinStatus.normal }) 70 | end 71 | 72 | function fn.toggle_maximized() 73 | fn.toggle({ status = ZenWinStatus.maximized }) 74 | end 75 | 76 | function fn.toggle(opts) 77 | local plugin = require("zen-mode") 78 | 79 | if not NVZenMode.is_active() then 80 | local params = { 81 | window = { width = ZenWinStatus.width(opts.status) }, 82 | on_open = function(winid) 83 | ZenWinStatus.set(winid, ZenWinStatusKey.current, opts.status) 84 | end, 85 | } 86 | 87 | plugin.open(params) 88 | else 89 | -- Here, I want to handle a specific scenario when I open Zen mode at normal width, 90 | -- and need to maximize the buffer temporarily (e.g., to check a long line), 91 | -- then, to return to the normal-width Zen mode without leaving it. 92 | local current_status = ZenWinStatus.get(ZenWinStatusKey.current) 93 | local previous_status = ZenWinStatus.get(ZenWinStatusKey.previous) 94 | 95 | if opts.status == ZenWinStatus.maximized and current_status == ZenWinStatus.normal then 96 | fn.deactivate() 97 | 98 | local params = { 99 | window = { width = ZenWinStatus.width(ZenWinStatus.maximized) }, 100 | on_open = function(winid) 101 | ZenWinStatus.set(winid, ZenWinStatusKey.current, ZenWinStatus.maximized) 102 | ZenWinStatus.set(winid, ZenWinStatusKey.previous, ZenWinStatus.normal) 103 | end, 104 | } 105 | 106 | plugin.open(params) 107 | elseif 108 | ( 109 | (opts.status == ZenWinStatus.maximized and current_status == ZenWinStatus.maximized) 110 | or (opts.status == ZenWinStatus.normal and current_status == ZenWinStatus.maximized) 111 | ) and previous_status == ZenWinStatus.normal 112 | then 113 | fn.deactivate() 114 | 115 | local params = { 116 | window = { width = ZenWinStatus.width(ZenWinStatus.normal) }, 117 | on_open = function(winid) 118 | ZenWinStatus.set(winid, ZenWinStatusKey.current, ZenWinStatus.normal) 119 | ZenWinStatus.set(winid, ZenWinStatusKey.previous, nil) 120 | end, 121 | } 122 | 123 | plugin.open(params) 124 | else 125 | fn.deactivate() 126 | end 127 | end 128 | end 129 | 130 | function fn.activate(opts) 131 | if not NVZenMode.is_active() then 132 | local plugin = require("zen-mode") 133 | 134 | local params = { 135 | on_open = function(winid) 136 | opts.winid = winid 137 | fn.set_zen_mode_maximized_on_window(opts) 138 | end, 139 | } 140 | 141 | if opts.maximized then 142 | params.window = { width = NVWindows.maximized_width } 143 | end 144 | 145 | plugin.toggle(params) 146 | end 147 | end 148 | 149 | function fn.deactivate() 150 | if not NVZenMode.is_active() then 151 | return 152 | end 153 | 154 | local plugin = require("zen-mode") 155 | 156 | local zen_buf = vim.api.nvim_get_current_buf() 157 | 158 | plugin.toggle() 159 | 160 | local current_buf = vim.api.nvim_get_current_buf() 161 | 162 | if current_buf == zen_buf then 163 | return 164 | end 165 | 166 | vim.api.nvim_set_current_buf(zen_buf) 167 | end 168 | 169 | return { NVZenMode } 170 | -------------------------------------------------------------------------------- /home/.config/nvim/lua/screen.lua: -------------------------------------------------------------------------------- 1 | NVScreen = {} 2 | 3 | function NVScreen.is_large() 4 | return vim.o.columns >= 180 5 | end 6 | -------------------------------------------------------------------------------- /home/.config/nvim/lua/theme/colors/theme.lua: -------------------------------------------------------------------------------- 1 | require("theme").apply() 2 | -------------------------------------------------------------------------------- /home/.config/nvim/lua/utils/class.lua: -------------------------------------------------------------------------------- 1 | ---@generic T : table, B : table 2 | ---@param base_class B? 3 | ---@return T 4 | function Class(base_class) 5 | local new_class = {} 6 | 7 | new_class.__index = new_class 8 | 9 | if base_class then 10 | setmetatable(new_class, { __index = base_class }) 11 | end 12 | 13 | function new_class:new(...) 14 | local instance = setmetatable({}, self) 15 | 16 | if self.init then 17 | self.init(instance, ...) 18 | end 19 | 20 | return instance 21 | end 22 | 23 | return new_class 24 | end 25 | -------------------------------------------------------------------------------- /home/.config/nvim/lua/utils/init.lua: -------------------------------------------------------------------------------- 1 | require("utils.class") 2 | require("utils.log") 3 | -------------------------------------------------------------------------------- /home/.config/nvim/lua/utils/log.lua: -------------------------------------------------------------------------------- 1 | ---@diagnostic disable-next-line: lowercase-global 2 | log = {} 3 | 4 | local ERROR = vim.log.levels.ERROR 5 | local WARN = vim.log.levels.WARN 6 | local INFO = vim.log.levels.INFO 7 | local DEBUG = vim.log.levels.DEBUG 8 | 9 | ---@param message string 10 | function log.info(message) 11 | vim.notify(message, INFO) 12 | end 13 | 14 | ---@param message string 15 | function log.warn(message) 16 | vim.notify(message, WARN) 17 | end 18 | 19 | ---@param message string 20 | function log.error(message) 21 | vim.notify(message, ERROR) 22 | end 23 | 24 | ---@param payload string | number | any 25 | function log.debug(payload) 26 | local message 27 | 28 | local type = type(payload) 29 | 30 | if type == "string" then 31 | message = payload 32 | elseif type == "number" then 33 | message = tostring(payload) 34 | else 35 | message = vim.inspect(payload) 36 | end 37 | 38 | vim.notify(message, DEBUG) 39 | end 40 | -------------------------------------------------------------------------------- /home/.config/nvim/stylua.toml: -------------------------------------------------------------------------------- 1 | indent_type = "Spaces" 2 | indent_width = 4 3 | column_width = 140 4 | -------------------------------------------------------------------------------- /home/.config/prettier.yml: -------------------------------------------------------------------------------- 1 | tabWidth: 4 2 | printWidth: 120 3 | singleQuote: false 4 | -------------------------------------------------------------------------------- /home/.config/raycast/scripts/youtube.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Required parameters: 4 | # @raycast.schemaVersion 1 5 | # @raycast.title YouTube 6 | # @raycast.mode silent 7 | 8 | # Optional parameters: 9 | # @raycast.icon 📺 10 | 11 | # Documentation: 12 | # @raycast.description Opens YouTube PWA 13 | # @raycast.author alex35mil 14 | # @raycast.authorURL https://raycast.com/alex35mil 15 | 16 | open -a "$HOME/Applications/Chrome Apps.localized/YouTube.app" 17 | -------------------------------------------------------------------------------- /home/.config/shell/apps/cargo.sh: -------------------------------------------------------------------------------- 1 | alias cr="cargo run -- " 2 | alias crr="cargo run --release -- " 3 | -------------------------------------------------------------------------------- /home/.config/shell/apps/devbox.sh: -------------------------------------------------------------------------------- 1 | alias dx="devbox " 2 | alias dxs="devbox services " 3 | alias dxg="devbox global " 4 | alias dxgs="devbox global services " 5 | alias dxinit="devbox init && devbox generate direnv" 6 | -------------------------------------------------------------------------------- /home/.config/shell/apps/direnv.sh: -------------------------------------------------------------------------------- 1 | case "$SHELL" in 2 | */zsh) 3 | eval "$(direnv hook zsh)" 4 | ;; 5 | */bash) 6 | eval "$(direnv hook bash)" 7 | ;; 8 | esac 9 | -------------------------------------------------------------------------------- /home/.config/shell/apps/docker.sh: -------------------------------------------------------------------------------- 1 | alias d="docker " 2 | alias dps="docker ps " 3 | alias dpsa="docker ps -a " 4 | alias dsa="docker container stop $(docker ps -a -q)" 5 | alias dimg="docker image " 6 | alias dimgls="docker image ls " 7 | alias dimgrm="docker image rm " 8 | alias dimgpr="docker image prune " 9 | alias dct="docker container " 10 | alias dctls="docker container ls " 11 | alias dctrm="docker container rm " 12 | alias dctpr="docker container prune " 13 | alias dvol="docker volume " 14 | alias dvolls="docker volume ls " 15 | alias dvolrm="docker volume rm " 16 | alias dvolpr="docker volume prune " 17 | alias dnet="docker network " 18 | alias dnetls="docker network ls " 19 | alias dnetrm="docker network rm " 20 | alias dnetpr="docker network prune " 21 | alias dspr="docker system prune " 22 | alias dspra="docker system prune -a" 23 | alias dc="docker-compose " 24 | alias dcup="docker-compose up" 25 | alias dcupb="docker-compose up --build" 26 | 27 | # Prints Docker stats 28 | function dls() { 29 | echo "--- Images:\n" 30 | docker image ls 31 | echo "\n\n--- Containers:\n" 32 | docker container ls 33 | echo "\n\n--- Volumes:\n" 34 | docker volume ls 35 | echo "\n\n--- Networks:\n" 36 | docker network ls 37 | } 38 | -------------------------------------------------------------------------------- /home/.config/shell/apps/git.sh: -------------------------------------------------------------------------------- 1 | alias g="git " 2 | alias gs="git status " 3 | alias ga="git add " 4 | alias gap="git add -p " 5 | alias gb="git branch " 6 | alias gdm="git dm" 7 | alias gc="git commit " 8 | alias gcm="git commit -m " 9 | alias gca="git commit --amend --reuse-message=HEAD" 10 | alias gcam="git commit --amend" 11 | alias gcu="git reset HEAD~" 12 | alias gfr="git checkout HEAD -- " 13 | alias gd="git diff " 14 | alias gdc="git diff --cached " 15 | alias gp="git push " 16 | alias gpf="git push --force-with-lease" 17 | alias gpu="git push -u origin HEAD" 18 | alias gpt="git push --tags" 19 | alias gpft="git push --force --tags" 20 | alias gprq="git add . && git commit --amend --reuse-message=HEAD && git push --force-with-lease" 21 | alias gco="git checkout " 22 | alias gcob="git checkout -b " 23 | alias gcom="git checkout master" 24 | alias gup="git pull --rebase --prune" 25 | alias grau="git remote add upstream " 26 | alias gf="git fetch " 27 | alias gfu="git fetch upstream" 28 | alias gm="git merge " 29 | alias gmum="git merge upstream/master" 30 | alias gr="git rebase " 31 | alias grm="git rebase master" 32 | alias grc="git rebase --continue" 33 | alias gra="git rebase --abort" 34 | alias grs="git rebase --skip" 35 | alias glc="git diff --name-only --diff-filter=U" 36 | alias gri="git irebase " 37 | alias gcp="git cherry-pick " 38 | alias gcpc="git cherry-pick --continue" 39 | alias gcpa="git cherry-pick --abort" 40 | alias gcpq="git cherry-pick --quit" 41 | alias grst="git reset " 42 | alias grsthard="git reset --hard HEAD" 43 | alias gsh="git stash" 44 | alias gshl="git stash list" 45 | alias gshp="git stash pop " 46 | alias gh="git history" 47 | alias ghg="gh --graph" 48 | alias gt="git tag " 49 | alias gta="git tag -a " 50 | alias gtf="git tag -f " 51 | alias gsm="git submodule " 52 | alias gsma="git submodule add -b master " 53 | alias gsmu="git submodule update --remote --merge " 54 | alias gpsc="git push --recurse-submodules=check " 55 | alias gpsd="git push --recurse-submodules=on-demand " 56 | 57 | # Clones git repository and enters it 58 | function gcl() { 59 | git clone $1 && cd $(basename "$1" .git) 60 | } 61 | 62 | # Initializes git repository and creates initial commit 63 | function ginit() { 64 | git init && git commit -m "Initial commit" --allow-empty 65 | } 66 | -------------------------------------------------------------------------------- /home/.config/shell/apps/neovim.sh: -------------------------------------------------------------------------------- 1 | export NEOVIDE_FRAME="buttonless" 2 | export NEOVIDE_MAXIMIZED="true" 3 | export NEOVIDE_TITLE_HIDDEN="true" 4 | 5 | alias n="neohub " 6 | alias ncc="rm -rf ~/.cache/nvim/luac/" 7 | alias nsls="ls -1 ~/.local/state/nvim/swap/" 8 | 9 | # Removes Neovim swap files: all or of provided project 10 | function nsc() { 11 | if [ -z "$1" ]; then 12 | echo "Provide a project path or '!' to remove all swap files" 13 | return 1 14 | fi 15 | 16 | SWAPROOT="$HOME/.local/state/nvim/swap/" 17 | 18 | # If the input argument is !, remove all swap files 19 | if [[ "$1" == "!" ]]; then 20 | find $SWAPROOT -type f -name "*.sw[klmnop]" -delete 21 | echo "All swap files deleted" 22 | else 23 | SEARCHTERM=$(echo "%Users%Alex%Dev%$1" | tr '/' '%') 24 | find $SWAPROOT -type f -name "$SEARCHTERM*.sw[klmnop]" -delete 25 | echo "Swap files for $1 deleted" 26 | fi 27 | } 28 | -------------------------------------------------------------------------------- /home/.config/shell/apps/nix.sh: -------------------------------------------------------------------------------- 1 | alias xc="nix-env --delete-generations old && nix-store --gc" 2 | alias xup="nix-channel --update" 3 | alias xfl="nix flake lock" 4 | alias xfu="nix flake update" 5 | -------------------------------------------------------------------------------- /home/.config/shell/apps/node.sh: -------------------------------------------------------------------------------- 1 | export NPM_CONFIG_PREFIX="$HOME/.npm-global" 2 | 3 | alias j="npm " 4 | alias js="npm start" 5 | alias jt="npm test" 6 | alias jr="npm run " 7 | alias ji="npm install --save-exact " 8 | alias jid="npm install --save-dev --save-exact " 9 | alias jrm="npm remove --save " 10 | alias jrmd="npm remove --save-dev " 11 | alias jo="npm outdated" 12 | alias jup="ncu --upgrade --interactive --format group" 13 | alias jupw="ncu --workspaces --upgrade --interactive --format group" 14 | alias jlg="npm ls -g --depth=0" 15 | alias jfuck="rm -rf node_modules && npm cache clean && npm install" 16 | 17 | alias y="yarn " 18 | alias ys="yarn start " 19 | alias yt="yarn test" 20 | alias yr="yarn run " 21 | alias yi="yarn add --exact " 22 | alias yid="yarn add --dev --exact " 23 | alias yrm="yarn remove " 24 | alias yo="yarn outdated" 25 | alias yup="yarn upgrade-interactive --exact --latest" 26 | alias yar="rm -rf node_modules && yarn" 27 | alias yarr="rm -rf node_modules && yarn cache clean && yarn" 28 | -------------------------------------------------------------------------------- /home/.config/shell/apps/starship.sh: -------------------------------------------------------------------------------- 1 | case "$SHELL" in 2 | */zsh) 3 | eval "$(starship init zsh)" 4 | ;; 5 | */bash) 6 | eval "$(starship init bash)" 7 | ;; 8 | esac 9 | -------------------------------------------------------------------------------- /home/.config/shell/apps/zellij.sh: -------------------------------------------------------------------------------- 1 | export ZELLIJ_RUNNER_ROOT_DIR="Dev" 2 | export ZELLIJ_RUNNER_IGNORE_DIRS="node_modules,target" 3 | export ZELLIJ_RUNNER_MAX_DIRS_DEPTH="3" 4 | export ZELLIJ_RUNNER_LAYOUTS_DIR=".config/zellij/layouts" 5 | export ZELLIJ_RUNNER_BANNERS_DIR=".config/zellij/banners" 6 | 7 | alias t="zellij-runner" 8 | alias z="zellij" 9 | alias tls="zellij list-sessions" 10 | alias ta="zellij attach " 11 | alias tk="zellij kill-session " 12 | alias tka="zellij kill-all-sessions" 13 | alias tt="zellij --session generic --layout terminal" 14 | -------------------------------------------------------------------------------- /home/.config/shell/bash/options.sh: -------------------------------------------------------------------------------- 1 | set -o vi 2 | # ------------------------------------------ 3 | # Explanation: 4 | # - `set -o`: In Bash, this command is used to control various shell options. 5 | # 6 | # - `vi`: When you specify `set -o vi`, you're setting the command-line editing mode 7 | # to use vi keybindings in Bash. 8 | # 9 | # Once this is set, the command-line interface will operate in a manner similar to 10 | # the vi editor. For example, you will start in "normal mode" (where you can use 11 | # commands like `h`, `j`, `k`, and `l` for movement), and you can press `i` to 12 | # enter "insert mode" and make modifications. Pressing `Esc` will take you back 13 | # to normal mode. 14 | # ------------------------------------------ 15 | -------------------------------------------------------------------------------- /home/.config/shell/init.sh: -------------------------------------------------------------------------------- 1 | eval "$(devbox global shellenv --init-hook)" 2 | source "$HOME/.cargo/env" 3 | -------------------------------------------------------------------------------- /home/.config/shell/shortcuts.sh: -------------------------------------------------------------------------------- 1 | # === General 2 | alias dup="PSHELL=zsh $HOME/Dev/dotfiles/script/install.sh" 3 | 4 | case "$SHELL" in 5 | */zsh) 6 | alias reload="exec zsh -l" 7 | ;; 8 | */bash) 9 | alias reload="exec bash --login" 10 | ;; 11 | esac 12 | 13 | alias c="clear" 14 | alias q="exit" 15 | 16 | # === Navigation 17 | alias ..="cd .." 18 | alias ...="cd ../.." 19 | alias ....="cd ../../.." 20 | alias .....="cd ../../../.." 21 | 22 | alias dev="cd ~/Dev" 23 | alias devn="cd ~/Dev/null" 24 | alias icd="cd ~/Library/Mobile\\ Documents/com~apple~CloudDocs" 25 | alias ico="cd ~/Library/Mobile\\ Documents/iCloud~md~obsidian/Documents" 26 | 27 | # === System 28 | alias mymac="system_profiler SPHardwareDataType | rg -i \"Model Identifier|Chip|Memory\" | awk '{\$1=\$1; print}'" 29 | 30 | function l() { 31 | if [[ -z $1 ]]; then 32 | echo "Usage: l [rest...]" 33 | return 1 34 | fi 35 | 36 | local app="$1" 37 | shift 38 | 39 | local timeframe="30m" 40 | 41 | log show --predicate "process == \"$app\"" --last "$timeframe" --debug --info "$@" 42 | } 43 | 44 | alias dr="defaults read " 45 | alias dd="defaults delete " 46 | 47 | function dra() { 48 | if [ -z "$1" ]; then 49 | echo "Usage: dra [app]" 50 | return 1 51 | fi 52 | 53 | defaults read com.alex35mil.$1 54 | } 55 | 56 | function dda() { 57 | if [ -z "$1" ]; then 58 | echo "Usage: dda [app]" 59 | return 1 60 | fi 61 | 62 | defaults delete com.alex35mil.$1 63 | } 64 | 65 | # === Files 66 | alias lsa="ls -lhFaG" 67 | alias rmrf="rm -rf" 68 | 69 | # `i` stands for `inspect`. 70 | # With no argument, it lists the contents of the current directory via `tree`. 71 | # If given a directory, it lists the contents of that directory. 72 | # If given a file, it shows its contents via `bat`. 73 | function i() { 74 | # If no argument is provided, use the current directory 75 | local target="${1:-.}" 76 | 77 | # If target is a directory 78 | if [[ -d "$target" ]]; then 79 | # List its contents via `tree` 80 | tree -ahF --dirsfirst -L 1 "$target" 81 | # If target is a file 82 | elif [[ -f "$target" ]]; then 83 | # Show its contents via `bat` 84 | bat "$target" 85 | else 86 | echo "Error: $target is neither a directory nor a file." 87 | return 1 88 | fi 89 | } 90 | 91 | # Creates a new directory and enters it 92 | function mkd() { 93 | mkdir -p $@ && cd $_ 94 | } 95 | 96 | # `o` with no arguments opens current folder in Finder, 97 | # otherwise selects given item in Finder 98 | function o() { 99 | if [[ $# -eq 0 ]]; then 100 | open -R ./$(ls | sort -n | head -1) 101 | else 102 | open -R $@ 103 | fi 104 | } 105 | 106 | # `cleanup` removes all .DS_Store files and broken symlinks. 107 | # With no arguments it cleans up the current folder, 108 | # otherwise at the provided path. 109 | function cleanup() { 110 | # If an argument is provided, use it as the target directory 111 | # otherwise, use the current directory. 112 | local target_dir="${1:-.}" 113 | 114 | # Remove .DS_Store files 115 | find "$target_dir" -type f -name '*.DS_Store' -exec echo "Removing: {}" 1>&2 \; -delete 116 | 117 | # Remove default.profraw files 118 | find "$target_dir" -type f -name 'default.profraw' -exec echo "Removing: {}" 1>&2 \; -delete 119 | 120 | # Remove broken symlinks 121 | find "$target_dir" -type l ! -exec test -e {} \; -exec echo "Removing broken symlink: {}" 1>&2 \; -delete 122 | } 123 | 124 | # Adds fingerprint to the filename 125 | function fingerprint() { 126 | local FILENAME=$1 127 | local HASH=$(shasum -a 256 "$FILENAME" | awk '{print $1}' | xxd -r -p | base64 | head -c 10) 128 | 129 | if [[ $FILENAME == *.* ]]; then 130 | local NEXT_FILENAME="${FILENAME%.*}-${HASH}.${FILENAME##*.}" 131 | else 132 | local NEXT_FILENAME="${FILENAME}-${HASH}" 133 | fi 134 | 135 | mv "$FILENAME" "$NEXT_FILENAME" 136 | 137 | echo "$NEXT_FILENAME" 138 | } 139 | 140 | # === Network 141 | alias hosts="sudo $EDITOR /etc/hosts" 142 | alias ip="dig +short myip.opendns.com @resolver1.opendns.com" 143 | alias localip="ipconfig getifaddr en0" 144 | 145 | # Prints listners on a specific port. E.g. `p 3000` 146 | function p() { 147 | if [ -z "$1" ]; then 148 | echo "Usage: p [port]" 149 | return 1 150 | fi 151 | 152 | # Getting the protocol and the PID of the process listening on the specified port 153 | read protocol pid <<<$(lsof -n -i:$1 | awk '/LISTEN/ {print $8, $2}' | head -1) 154 | 155 | if [ -z "$pid" ]; then 156 | echo "No process found listening on port $1" 157 | return 1 158 | fi 159 | 160 | # Getting the command and time from ps 161 | # etime = elapsed time since the process was started, in the form [[DD-]hh:]mm:ss 162 | # command = command with all its arguments as a string 163 | read etime command <<<$(ps -p $pid -o etime=,command=) 164 | 165 | # Getting the working directory of the process 166 | pwd=$(lsof -p $pid | awk '$4=="cwd" {print $9}') 167 | 168 | echo "Port: $1" 169 | echo "Protocol: $protocol" 170 | echo "PID: $pid" 171 | echo "PWD: $pwd" 172 | echo "Command: $command" 173 | echo "Age: $etime" 174 | } 175 | 176 | # Generates a new ssh entity 177 | function gen-ssh() { 178 | ssh-keygen -f ~/.ssh/$@ -C "$@" 179 | echo "Host $@" >> ~/.ssh/config 180 | echo " HostName __IP__" >> ~/.ssh/config 181 | echo " ForwardAgent yes" >> ~/.ssh/config 182 | echo " PreferredAuthentications publickey" >> ~/.ssh/config 183 | echo " IdentityFile ~/.ssh/$@" >> ~/.ssh/config 184 | echo "" >> ~/.ssh/config 185 | vim ~/.ssh/config 186 | } 187 | 188 | # === Misc 189 | # `w` with no arguments lists all shell aliases, 190 | # otherwise lists aliases, that start with the given chars. 191 | # If no alias is found, it runs `which` command. 192 | function w() { 193 | local result="" 194 | 195 | if [[ $# -eq 0 ]]; then 196 | result=$(alias) 197 | else 198 | result=$(alias | rg "^$@") 199 | fi 200 | 201 | if [[ -z "$result" ]]; then 202 | which "$@" 203 | else 204 | echo "Aliases:" 205 | echo "$result" 206 | echo 207 | echo "Which:" 208 | which "$@" 209 | fi 210 | } 211 | 212 | # Prints nice color chart 213 | function colortest() { 214 | T='ﮊ ﮊ ﮊ' 215 | 216 | echo -e "\n 40m 41m 42m 43m\ 217 | 44m 45m 46m 47m"; 218 | 219 | for FGs in ' m' ' 1m' ' 30m' '1;30m' ' 31m' '1;31m' ' 32m' \ 220 | '1;32m' ' 33m' '1;33m' ' 34m' '1;34m' ' 35m' '1;35m' \ 221 | ' 36m' '1;36m' ' 37m' '1;37m'; 222 | do FG=${FGs// /} 223 | echo -en " $FGs \033[$FG $T " 224 | for BG in 40m 41m 42m 43m 44m 45m 46m 47m; 225 | do echo -en "$EINS \033[$FG\033[$BG $T \033[0m"; 226 | done 227 | echo; 228 | done 229 | echo 230 | } 231 | -------------------------------------------------------------------------------- /home/.config/shell/variables.sh: -------------------------------------------------------------------------------- 1 | export LANG="en_US.UTF-8" 2 | 3 | export TERM="xterm-256color" 4 | 5 | export XDG_CONFIG_HOME="$HOME/.config" 6 | export XDG_DATA_HOME="$HOME/.local/share" 7 | 8 | export DEVBOX_PROFILE="$DEVBOX_PROJECT_ROOT/.devbox/virtenv/.wrappers" 9 | 10 | export PRETTIERD_DEFAULT_CONFIG="$XDG_CONFIG_HOME/prettier.yml" 11 | 12 | SWIFT_BIN_PATH="/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin" 13 | NPM_BIN_PATH="$HOME/.npm-global/bin" 14 | 15 | export PATH="$SWIFT_BIN_PATH:$NPM_BIN_PATH:$PATH" 16 | 17 | export LD_LIBRARY_PATH="$DEVBOX_PACKAGES_DIR/lib:$LD_LIBRARY_PATH" 18 | export DYLD_LIBRARY_PATH="$LD_LIBRARY_PATH:$DYLD_LIBRARY_PATH" 19 | 20 | # if interactive shell 21 | if [[ $- == *i* ]]; then 22 | export EDITOR="nvim" 23 | export VISUAL="$EDITOR" 24 | 25 | export CLICOLOR="1" 26 | export LSCOLORS="gxfxcxdxbxegedabagacad" 27 | 28 | export DISABLE_AUTO_TITLE="true" 29 | fi 30 | -------------------------------------------------------------------------------- /home/.config/shell/zsh/completions/_cargo: -------------------------------------------------------------------------------- 1 | #compdef cargo 2 | if command -v rustc >/dev/null 2>&1; then 3 | source "$(rustc --print sysroot)"/share/zsh/site-functions/_cargo 4 | fi 5 | -------------------------------------------------------------------------------- /home/.config/shell/zsh/completions/_devbox: -------------------------------------------------------------------------------- 1 | #compdef devbox 2 | 3 | # zsh completion for devbox -*- shell-script -*- 4 | 5 | __devbox_debug() 6 | { 7 | local file="$BASH_COMP_DEBUG_FILE" 8 | if [[ -n ${file} ]]; then 9 | echo "$*" >> "${file}" 10 | fi 11 | } 12 | 13 | _devbox() 14 | { 15 | local shellCompDirectiveError=1 16 | local shellCompDirectiveNoSpace=2 17 | local shellCompDirectiveNoFileComp=4 18 | local shellCompDirectiveFilterFileExt=8 19 | local shellCompDirectiveFilterDirs=16 20 | 21 | local lastParam lastChar flagPrefix requestComp out directive comp lastComp noSpace 22 | local -a completions 23 | 24 | __devbox_debug "\n========= starting completion logic ==========" 25 | __devbox_debug "CURRENT: ${CURRENT}, words[*]: ${words[*]}" 26 | 27 | # The user could have moved the cursor backwards on the command-line. 28 | # We need to trigger completion from the $CURRENT location, so we need 29 | # to truncate the command-line ($words) up to the $CURRENT location. 30 | # (We cannot use $CURSOR as its value does not work when a command is an alias.) 31 | words=("${=words[1,CURRENT]}") 32 | __devbox_debug "Truncated words[*]: ${words[*]}," 33 | 34 | lastParam=${words[-1]} 35 | lastChar=${lastParam[-1]} 36 | __devbox_debug "lastParam: ${lastParam}, lastChar: ${lastChar}" 37 | 38 | # For zsh, when completing a flag with an = (e.g., devbox -n=) 39 | # completions must be prefixed with the flag 40 | setopt local_options BASH_REMATCH 41 | if [[ "${lastParam}" =~ '-.*=' ]]; then 42 | # We are dealing with a flag with an = 43 | flagPrefix="-P ${BASH_REMATCH}" 44 | fi 45 | 46 | # Prepare the command to obtain completions 47 | requestComp="${words[1]} __complete ${words[2,-1]}" 48 | if [ "${lastChar}" = "" ]; then 49 | # If the last parameter is complete (there is a space following it) 50 | # We add an extra empty parameter so we can indicate this to the go completion code. 51 | __devbox_debug "Adding extra empty parameter" 52 | requestComp="${requestComp} \"\"" 53 | fi 54 | 55 | __devbox_debug "About to call: eval ${requestComp}" 56 | 57 | # Use eval to handle any environment variables and such 58 | out=$(eval ${requestComp} 2>/dev/null) 59 | __devbox_debug "completion output: ${out}" 60 | 61 | # Extract the directive integer following a : from the last line 62 | local lastLine 63 | while IFS='\n' read -r line; do 64 | lastLine=${line} 65 | done < <(printf "%s\n" "${out[@]}") 66 | __devbox_debug "last line: ${lastLine}" 67 | 68 | if [ "${lastLine[1]}" = : ]; then 69 | directive=${lastLine[2,-1]} 70 | # Remove the directive including the : and the newline 71 | local suffix 72 | (( suffix=${#lastLine}+2)) 73 | out=${out[1,-$suffix]} 74 | else 75 | # There is no directive specified. Leave $out as is. 76 | __devbox_debug "No directive found. Setting do default" 77 | directive=0 78 | fi 79 | 80 | __devbox_debug "directive: ${directive}" 81 | __devbox_debug "completions: ${out}" 82 | __devbox_debug "flagPrefix: ${flagPrefix}" 83 | 84 | if [ $((directive & shellCompDirectiveError)) -ne 0 ]; then 85 | __devbox_debug "Completion received error. Ignoring completions." 86 | return 87 | fi 88 | 89 | local activeHelpMarker="_activeHelp_ " 90 | local endIndex=${#activeHelpMarker} 91 | local startIndex=$((${#activeHelpMarker}+1)) 92 | local hasActiveHelp=0 93 | while IFS='\n' read -r comp; do 94 | # Check if this is an activeHelp statement (i.e., prefixed with $activeHelpMarker) 95 | if [ "${comp[1,$endIndex]}" = "$activeHelpMarker" ];then 96 | __devbox_debug "ActiveHelp found: $comp" 97 | comp="${comp[$startIndex,-1]}" 98 | if [ -n "$comp" ]; then 99 | compadd -x "${comp}" 100 | __devbox_debug "ActiveHelp will need delimiter" 101 | hasActiveHelp=1 102 | fi 103 | 104 | continue 105 | fi 106 | 107 | if [ -n "$comp" ]; then 108 | # If requested, completions are returned with a description. 109 | # The description is preceded by a TAB character. 110 | # For zsh's _describe, we need to use a : instead of a TAB. 111 | # We first need to escape any : as part of the completion itself. 112 | comp=${comp//:/\\:} 113 | 114 | local tab="$(printf '\t')" 115 | comp=${comp//$tab/:} 116 | 117 | __devbox_debug "Adding completion: ${comp}" 118 | completions+=${comp} 119 | lastComp=$comp 120 | fi 121 | done < <(printf "%s\n" "${out[@]}") 122 | 123 | # Add a delimiter after the activeHelp statements, but only if: 124 | # - there are completions following the activeHelp statements, or 125 | # - file completion will be performed (so there will be choices after the activeHelp) 126 | if [ $hasActiveHelp -eq 1 ]; then 127 | if [ ${#completions} -ne 0 ] || [ $((directive & shellCompDirectiveNoFileComp)) -eq 0 ]; then 128 | __devbox_debug "Adding activeHelp delimiter" 129 | compadd -x "--" 130 | hasActiveHelp=0 131 | fi 132 | fi 133 | 134 | if [ $((directive & shellCompDirectiveNoSpace)) -ne 0 ]; then 135 | __devbox_debug "Activating nospace." 136 | noSpace="-S ''" 137 | fi 138 | 139 | if [ $((directive & shellCompDirectiveFilterFileExt)) -ne 0 ]; then 140 | # File extension filtering 141 | local filteringCmd 142 | filteringCmd='_files' 143 | for filter in ${completions[@]}; do 144 | if [ ${filter[1]} != '*' ]; then 145 | # zsh requires a glob pattern to do file filtering 146 | filter="\*.$filter" 147 | fi 148 | filteringCmd+=" -g $filter" 149 | done 150 | filteringCmd+=" ${flagPrefix}" 151 | 152 | __devbox_debug "File filtering command: $filteringCmd" 153 | _arguments '*:filename:'"$filteringCmd" 154 | elif [ $((directive & shellCompDirectiveFilterDirs)) -ne 0 ]; then 155 | # File completion for directories only 156 | local subdir 157 | subdir="${completions[1]}" 158 | if [ -n "$subdir" ]; then 159 | __devbox_debug "Listing directories in $subdir" 160 | pushd "${subdir}" >/dev/null 2>&1 161 | else 162 | __devbox_debug "Listing directories in ." 163 | fi 164 | 165 | local result 166 | _arguments '*:dirname:_files -/'" ${flagPrefix}" 167 | result=$? 168 | if [ -n "$subdir" ]; then 169 | popd >/dev/null 2>&1 170 | fi 171 | return $result 172 | else 173 | __devbox_debug "Calling _describe" 174 | if eval _describe "completions" completions $flagPrefix $noSpace; then 175 | __devbox_debug "_describe found some completions" 176 | 177 | # Return the success of having called _describe 178 | return 0 179 | else 180 | __devbox_debug "_describe did not find completions." 181 | __devbox_debug "Checking if we should do file completion." 182 | if [ $((directive & shellCompDirectiveNoFileComp)) -ne 0 ]; then 183 | __devbox_debug "deactivating file completion" 184 | 185 | # We must return an error code here to let zsh know that there were no 186 | # completions found by _describe; this is what will trigger other 187 | # matching algorithms to attempt to find completions. 188 | # For example zsh can match letters in the middle of words. 189 | return 1 190 | else 191 | # Perform file completion 192 | __devbox_debug "Activating file completion" 193 | 194 | # We must return the result of this command, so it must be the 195 | # last command, or else we must store its result to return it. 196 | _arguments '*:filename:_files'" ${flagPrefix}" 197 | fi 198 | fi 199 | fi 200 | } 201 | 202 | # don't run the completion function when being source-ed or eval-ed 203 | if [ "$funcstack[1]" = "_devbox" ]; then 204 | _devbox 205 | fi 206 | -------------------------------------------------------------------------------- /home/.config/starship.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | symbol = " " 3 | 4 | [rust] 5 | symbol = " " 6 | 7 | [nix_shell] 8 | disabled = true 9 | -------------------------------------------------------------------------------- /home/.config/vimium/vimium-options.json: -------------------------------------------------------------------------------- 1 | { 2 | "keyMappings": "unmap r\nunmap p\nunmap t\n\nmapkey j\nmapkey k\nmapkey h\nmapkey l\n\nunmap \nunmap \nmap scrollPageUp\nmap scrollPageDown\n\nunmap \nunmap \nmap goBack\nmap goForward\n\nunmap f\nunmap F\nunmap a\nunmap A\nmap a LinkHints.activateMode\nmap A LinkHints.activateModeToOpenInNewTab\n\nunmap /\nmap f enterFindMode", 3 | "linkHintCharacters": "uhetonaskmpgcrl", 4 | "scrollStepSize": 65, 5 | "searchEngines": "", 6 | "settingsVersion": "2.1.2", 7 | "userDefinedLinkHintCss": "div > .vimiumHintMarker {\n /* linkhint boxes */\n background: #282828 !important;\n box-shadow: 0 0 18px #467cc0 !important;\n border: 2px solid #282828 !important;\n}\n\ndiv > .vimiumHintMarker span {\n /* linkhint text */\n color: #7fb2c8 !important;\n font-weight: bold !important;\n font-size: 15px !important;\n text-shadow: none !important;\n}\n\ndiv > .vimiumHintMarker > .matchingCharacter {\n color: #9782e2 !important;\n}\n\ndiv.vimiumHUD {\n background: #282828 !important;\n border-radius: 3px !important;\n box-shadow: 0 0 18px #467cc0 !important;\n border: 0 !important;\n}\n\ndiv.vimiumHUD .vimiumHUDSearchArea {\n background-color: #282828 !important;\n border-radius: 3px 3px 0 0 !important;\n}\n\ndiv.vimiumHUD .vimiumHUDSearchAreaInner {\n color: #7fb2c8 !important;\n font-family: BerkeleyMono Nerd Font, Menlo, monospace !important;\n font-size: 12px !important;\n border-radius: 3px !important;\n}\n\ndiv.vimiumHUD .hud-find {\n background: #282828 !important;\n border: 1px solid #282828 !important;\n}\n\ndiv.vimiumHUD span#hud-find-input {\n color: #7fb2c8 !important;\n}\n\ndiv.vimiumHUD span#hud-match-count {\n color: #7fb2c8 !important;\n font-size: 12px !important;\n}", 8 | "exclusionRules": [ 9 | { 10 | "passKeys": "", 11 | "pattern": "https?://configure.zsa.io/*" 12 | } 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /home/.config/yamlfmt/.yamlfmt: -------------------------------------------------------------------------------- 1 | formatter: 2 | indent: 2 3 | retain_line_breaks: true 4 | -------------------------------------------------------------------------------- /home/.config/zed/keymap.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "bindings": { 4 | "cmd-m": "workspace::ToggleZoom", 5 | "cmd-p": "command_palette::Toggle", 6 | "cmd-t": "file_finder::Toggle", 7 | "cmd-shift-e": "workspace::ToggleLeftDock", 8 | "cmd-shift-alt-e": "project_panel::ToggleFocus", 9 | "cmd-shift-a": "workspace::ToggleRightDock", 10 | "cmd-shift-alt-a": "assistant::ToggleFocus", 11 | "cmd-shift-t": "workspace::ToggleBottomDock", 12 | "cmd-shift-alt-t": "terminal_panel::ToggleFocus", 13 | "cmd-escape": "workspace::CloseAllDocks", 14 | "cmd-shift-p": "projects::OpenRecent", 15 | "cmd-shift-f": "pane::DeploySearch", 16 | "cmd-shift-d": "diagnostics::Deploy", 17 | "shift-alt-r": "workspace::Restart", 18 | "shift-alt-c": "workspace::ToggleCenteredLayout", 19 | "shift-alt-f": "zed::ToggleFullScreen", 20 | "cmd-w": "menu::Cancel", 21 | "cmd-shift-w": "menu::Cancel", 22 | "cmd-shift-q": "workspace::CloseWindow" 23 | } 24 | }, 25 | { 26 | "context": "Editor && mode == full", 27 | "bindings": { 28 | "ctrl-up": "editor::AddSelectionAbove", 29 | "ctrl-down": "editor::AddSelectionBelow", 30 | "cmd-d": "editor::DuplicateLineDown", 31 | "cmd-f": ["buffer_search::Deploy", { "focus": true }], 32 | "cmd-h": ["buffer_search::Deploy", { "focus": false }], 33 | "cmd-shift-h": "editor::SelectAllMatches", 34 | "cmd-shift-n": "editor::SelectNext", 35 | "cmd-r": "editor::Rename", 36 | "cmd-u": "editor::FindAllReferences", 37 | "cmd-i": "editor::Hover", 38 | "cmd-o": "outline::Toggle", 39 | "cmd-shift-o": "project_symbols::Toggle", 40 | "cmd-shift-i": "assistant::InlineAssist", 41 | "cmd-shift-l": "language_selector::Toggle", 42 | "ctrl-c": "editor::ShowCompletions", 43 | "ctrl-f": "editor::Format", 44 | "ctrl-a": "editor::ToggleCodeActions", 45 | "ctrl-x": "editor::ExpandMacroRecursively", 46 | "alt-c": "copilot::Suggest", 47 | "alt-shift-c": "copilot::NextSuggestion", 48 | "ctrl-left": "pane::GoBack", 49 | "ctrl-right": "pane::GoForward", 50 | "cmd-up": "vim::ScrollUp", 51 | "cmd-down": "vim::ScrollDown", 52 | "cmd-shift-up": "vim::LineUp", 53 | "cmd-shift-down": "vim::LineDown", 54 | "ctrl-shift-h": "editor::GoToDiagnostic", 55 | "ctrl-shift-t": "editor::GoToPrevDiagnostic", 56 | "alt-shift-h": "editor::GoToHunk", 57 | "alt-shift-t": "editor::GoToPrevHunk", 58 | "cmd-space": "editor::ToggleHunkDiff", 59 | "cmd-shift-space": "editor::ExpandAllHunkDiffs", 60 | "cmd-shift-backspace": "editor::RevertSelectedHunks", 61 | "cmd-shift-w": "pane::CloseAllItems" 62 | } 63 | }, 64 | { 65 | "context": "Editor", 66 | "bindings": { 67 | "alt-n": "vim::NextSubwordStart", 68 | "alt-d": "vim::PreviousSubwordStart", 69 | "ctrl-n": "vim::NextSubwordEnd", 70 | "ctrl-d": "vim::PreviousSubwordEnd" 71 | } 72 | }, 73 | { 74 | "context": "Editor && vim_mode != insert && !VimWaiting && !VimObject", 75 | "bindings": { 76 | "g d": "editor::GoToDefinition", 77 | "g shift-d": "editor::GoToDefinitionSplit", 78 | "g t": "editor::GoToTypeDefinition", 79 | "g shift-t": "editor::GoToTypeDefinitionSplit", 80 | "space left": "pane::SplitLeft", 81 | "space right": "pane::SplitRight", 82 | "space up": "pane::SplitUp", 83 | "space down": "pane::SplitDown", 84 | } 85 | }, 86 | { 87 | "context": "Dock", 88 | "bindings": { 89 | "shift-left": ["workspace::ActivatePaneInDirection", "Left"], 90 | "shift-right": ["workspace::ActivatePaneInDirection", "Right"], 91 | "shift-up": ["workspace::ActivatePaneInDirection", "Up"], 92 | "shift-down": ["workspace::ActivatePaneInDirection", "Down"] 93 | } 94 | }, 95 | { 96 | "context": "Editor", 97 | "bindings": { 98 | "shift-left": ["workspace::ActivatePaneInDirection", "Left"], 99 | "shift-right": ["workspace::ActivatePaneInDirection", "Right"], 100 | "shift-up": ["workspace::ActivatePaneInDirection", "Up"], 101 | "shift-down": ["workspace::ActivatePaneInDirection", "Down"] 102 | } 103 | }, 104 | { 105 | "context": "Editor && vim_mode != insert", 106 | "bindings": { 107 | "shift-alt-left": ["workspace::SwapPaneInDirection", "Left"], 108 | "shift-alt-right": ["workspace::SwapPaneInDirection", "Right"], 109 | "shift-alt-up": ["workspace::SwapPaneInDirection", "Up"], 110 | "shift-alt-down": ["workspace::SwapPaneInDirection", "Down"] 111 | } 112 | }, 113 | { 114 | "context": "Editor && vim_mode == insert && !VimWaiting && !VimObject", 115 | "bindings": { 116 | "shift-delete": "vim::InsertLineAbove", 117 | "shift-enter": "vim::InsertLineBelow" 118 | } 119 | }, 120 | { 121 | "context": "Editor && vim_mode == normal && !VimWaiting && !VimObject", 122 | "bindings": { 123 | "shift-delete": ["workspace::SendKeystrokes", "shift-o escape"], 124 | "shift-enter": ["workspace::SendKeystrokes", "o escape"] 125 | } 126 | }, 127 | { 128 | "context": "Editor && (vim_mode == normal || vim_mode == visual) && !VimWaiting && !VimObject", 129 | "bindings": { 130 | "tab": "editor::Indent", 131 | "shift-tab": "editor::Outdent" 132 | } 133 | }, 134 | { 135 | "context": "Editor && vim_mode == normal && !VimWaiting && !VimObject", 136 | "bindings": { 137 | "enter": ["workspace::SendKeystrokes", "c i w"] 138 | } 139 | }, 140 | { 141 | "context": "Editor && vim_mode == visual && !VimWaiting && !VimObject", 142 | "bindings": { 143 | "enter": ["workspace::SendKeystrokes", "c"] 144 | } 145 | }, 146 | { 147 | "context": "Editor && vim_mode == visual && !VimWaiting && !VimObject", 148 | "bindings": { 149 | // TODO: Surround in visual mode 150 | } 151 | }, 152 | { 153 | "context": "BufferSearchBar", 154 | "bindings": { 155 | "alt-c": "search::ToggleCaseSensitive", 156 | "alt-w": "search::ToggleWholeWord", 157 | "alt-x": "search::ToggleRegex", 158 | "alt-r": "search::ToggleReplace", 159 | "alt-i": "search::ToggleIncludeIgnored" 160 | } 161 | }, 162 | { 163 | "context": "ProjectSearchBar", 164 | "bindings": { 165 | "alt-c": "search::ToggleCaseSensitive", 166 | "alt-w": "search::ToggleWholeWord", 167 | "alt-x": "search::ToggleRegex", 168 | "alt-r": "search::ToggleReplace", 169 | "alt-i": "search::ToggleIncludeIgnored" 170 | } 171 | }, 172 | // TODO: It should be scoped to Diagnostics, but it seems like there is no such context 173 | { 174 | "context": "Workspace", 175 | "bindings": { 176 | "alt-w": "diagnostics::ToggleWarnings" 177 | } 178 | }, 179 | { 180 | "context": "ProjectPanel", 181 | "bindings": { 182 | "left": "project_panel::CollapseSelectedEntry", 183 | "cmd-left": "project_panel::CollapseAllEntries", 184 | "right": "project_panel::ExpandSelectedEntry", 185 | "cmd-n": "project_panel::NewFile", 186 | "alt-n": "project_panel::NewDirectory", 187 | "cmd-x": "project_panel::Cut", 188 | "cmd-c": "project_panel::Copy", 189 | "cmd-v": "project_panel::Paste", 190 | "cmd-d": "project_panel::Duplicate", 191 | "cmd-r": "project_panel::Rename", 192 | "cmd-u": "project_panel::SelectParent", 193 | "cmd-f": "project_panel::NewSearchInDirectory", 194 | "alt-r": "project_panel::RevealInFinder", 195 | "ctrl-c": "project_panel::CopyRelativePath", 196 | "ctrl-shift-c": "project_panel::CopyPath", 197 | "backspace": ["project_panel::Trash", { "skip_prompt": false }], 198 | "delete": ["project_panel::Trash", { "skip_prompt": false }], 199 | "cmd-backspace": ["project_panel::Delete", { "skip_prompt": false }], 200 | "cmd-delete": ["project_panel::Delete", { "skip_prompt": false }], 201 | "shift-down": "menu::SelectNext", 202 | "shift-up": "menu::SelectPrev", 203 | "escape": "menu::Cancel", 204 | "cmd-w": "workspace::ToggleLeftDock", 205 | "cmd-shift-w": "workspace::ToggleLeftDock" 206 | } 207 | }, 208 | { 209 | "context": "AssistantPanel", 210 | "bindings": { 211 | "cmd-h": "assistant::ToggleHistory", 212 | "cmd-w": "workspace::ToggleRightDock", 213 | "cmd-shift-w": "workspace::ToggleRightDock" 214 | } 215 | }, 216 | { 217 | "context": "Terminal", 218 | "bindings": { 219 | "cmd-shift-w": "workspace::ToggleBottomDock" 220 | } 221 | } 222 | ] 223 | -------------------------------------------------------------------------------- /home/.config/zed/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "theme": "35mil Dark Theme", 3 | "ui_font_family": "BerkeleyMono Nerd Font", 4 | "buffer_font_family": "BerkeleyMono Nerd Font", 5 | "buffer_font_size": 16, 6 | "tab_size": 4, 7 | "preferred_line_length": 100, 8 | "show_wrap_guides": true, 9 | "wrap_guides": [80, 120], 10 | "autosave": "on_focus_change", 11 | "auto_update": true, 12 | "ensure_final_newline_on_save": true, 13 | "remove_trailing_whitespace_on_save": true, 14 | "format_on_save": "on", 15 | "current_line_highlight": "all", 16 | "cursor_blink": false, 17 | "vertical_scroll_margin": 0, 18 | "multi_cursor_modifier": "cmd_or_ctrl", 19 | "use_autoclose": true, 20 | "always_treat_brackets_as_autoclosed": false, 21 | "when_closing_with_no_tabs": "keep_window_open", 22 | "hover_popover_enabled": false, 23 | "show_copilot_suggestions": true, 24 | "inlay_hints": { 25 | "enabled": true, 26 | "show_type_hints": true, 27 | "show_parameter_hints": true, 28 | "show_other_hints": true, 29 | "edit_debounce_ms": 700, 30 | "scroll_debounce_ms": 50 31 | }, 32 | "indent_guides": { 33 | "enabled": true, 34 | "line_width": 1, 35 | "coloring": "fixed", 36 | "background_coloring": "disabled" 37 | }, 38 | "tab_bar": { 39 | "show": false 40 | }, 41 | "toolbar": { 42 | "breadcrumbs": true, 43 | "quick_actions": false 44 | }, 45 | "centered_layout": { 46 | "left_padding": 0.27, 47 | "right_padding": 0.27 48 | }, 49 | "preview_tabs": { 50 | "enabled": true, 51 | "enable_preview_from_file_finder": true, 52 | "enable_preview_from_code_navigation": true 53 | }, 54 | "vim_mode": true, 55 | "vim": { 56 | "use_system_clipboard": "on_yank", 57 | "use_multiline_find": true 58 | }, 59 | "git": { 60 | "git_gutter": "tracked_files", 61 | "inline_blame": { 62 | "enabled": false 63 | } 64 | }, 65 | "terminal": { 66 | "alternate_scroll": "off", 67 | "blinking": "off", 68 | "copy_on_select": true, 69 | "option_as_meta": false, 70 | "button": true, 71 | "toolbar": { 72 | "title": true 73 | }, 74 | "working_directory": "current_project_directory" 75 | }, 76 | "lsp": { 77 | "rust-analyzer": { 78 | "initialization_options": { 79 | "check": { 80 | "command": "clippy" 81 | } 82 | } 83 | } 84 | }, 85 | "languages": { 86 | "JSON": { 87 | "format_on_save": "off" 88 | }, 89 | "TOML": { 90 | "format_on_save": "off" 91 | }, 92 | "YAML": { 93 | "format_on_save": "off" 94 | }, 95 | "Clojure": { 96 | "format_on_save": "off" 97 | }, 98 | "Markdown": { 99 | "format_on_save": "off" 100 | } 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /home/.config/zellij/banners/01.banner: -------------------------------------------------------------------------------- 1 | ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣀⣄⣠⣀⡀⣀⣠⣤⣤⣤⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ 2 | ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣄⢠⣠⣼⣿⣿⣿⣟⣿⣿⣿⣿⣿⣿⣿⣿⡿⠋⠀⠀⠀⢠⣤⣦⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠰⢦⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ 3 | ⠀⠀⠀⠀⠀⠀⠀⠀⣼⣿⣟⣾⣿⣽⣿⣿⣅⠈⠉⠻⣿⣿⣿⣿⣿⡿⠇⠀⠀⠀⠀⠀⠉⠀⠀⠀⠀⠀⢀⡶⠒⢉⡀⢠⣤⣶⣶⣿⣷⣆⣀⡀⠀⢲⣖⠒⠀⠀⠀⠀⠀⠀⠀ 4 | ⢀⣤⣾⣶⣦⣤⣤⣶⣿⣿⣿⣿⣿⣿⣽⡿⠻⣷⣀⠀⢻⣿⣿⣿⡿⠟⠀⠀⠀⠀⠀⠀⣤⣶⣶⣤⣀⣀⣬⣷⣦⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣶⣦⣤⣦⣼⣀⠀ 5 | ⠈⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⠛⠓⣿⣿⠟⠁⠘⣿⡟⠁⠀⠘⠛⠁⠀⠀⢠⣾⣿⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⠏⠙⠁ 6 | ⠀⠸⠟⠋⠀⠈⠙⣿⣿⣿⣿⣿⣿⣷⣦⡄⣿⣿⣿⣆⠀⠀⠀⠀⠀⠀⠀⠀⣼⣆⢘⣿⣯⣼⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡉⠉⢱⡿⠀⠀⠀⠀⠀ 7 | ⠀⠀⠀⠀⠀⠀⠀⠘⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣟⡿⠦⠀⠀⠀⠀⠀⠀⠀⠙⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⡗⠀⠈⠀⠀⠀⠀⠀⠀ 8 | ⠀⠀⠀⠀⠀⠀⠀⠀⢻⣿⣿⣿⣿⣿⣿⣿⣿⠋⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⢿⣿⣉⣿⡿⢿⢷⣾⣾⣿⣞⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠋⣠⠟⠀⠀⠀⠀⠀⠀⠀⠀ 9 | ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠹⣿⣿⣿⠿⠿⣿⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⣾⣿⣿⣷⣦⣶⣦⣼⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⠈⠛⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀ 10 | ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⠻⣿⣤⡖⠛⠶⠤⡀⠀⠀⠀⠀⠀⠀⠀⢰⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⠁⠙⣿⣿⠿⢻⣿⣿⡿⠋⢩⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ 11 | ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠙⠧⣤⣦⣤⣄⡀⠀⠀⠀⠀⠀⠘⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡇⠀⠀⠀⠘⣧⠀⠈⣹⡻⠇⢀⣿⡆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ 12 | ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⣿⣿⣿⣿⣿⣤⣀⡀⠀⠀⠀⠀⠀⠀⠈⢽⣿⣿⣿⣿⣿⠋⠀⠀⠀⠀⠀⠀⠀⠀⠹⣷⣴⣿⣷⢲⣦⣤⡀⢀⡀⠀⠀⠀⠀⠀⠀ 13 | ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⢿⣿⣿⣿⣿⣿⣿⠟⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣿⣷⢀⡄⠀⠀⠀⠀⠀⠀⠀⠀⠈⠉⠂⠛⣆⣤⡜⣟⠋⠙⠂⠀⠀⠀⠀⠀ 14 | ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢹⣿⣿⣿⣿⠟⠀⠀⠀⠀⠀⠀⠀⠀⠘⣿⣿⣿⣿⠉⣿⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣤⣾⣿⣿⣿⣿⣆⠀⠰⠄⠀⠉⠀⠀ 15 | ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣸⣿⣿⡿⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢹⣿⡿⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢻⣿⠿⠿⣿⣿⣿⠇⠀⠀⢀⠀⠀⠀ 16 | ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣿⡿⠛⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⢻⡇⠀⠀⢀⣼⠗⠀⠀ 17 | ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⠃⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⠁⠀⠀⠀ 18 | ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⠒⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ 19 | -------------------------------------------------------------------------------- /home/.config/zellij/config.kdl: -------------------------------------------------------------------------------- 1 | // Zellij's keybinding system is pretty limited. 2 | // In order to expand its capabilities, binding each action to a unicode symbol 3 | // and setting keymap in Alacritty config. This way, it's possible to use ⌘, 4 | // as well as combinations of modifiers, such as ⌘ ⇧, etc. 5 | // See Alacritty config for details. 6 | keybinds clear-defaults=true { 7 | shared_except "normal" "locked" "search" "scroll" "renametab" "renamepane" { 8 | bind "Enter" "Esc" { SwitchToMode "Normal"; } 9 | } 10 | 11 | shared_among "search" "scroll" { 12 | bind "Esc" { ScrollToBottom; SwitchToMode "Normal"; } 13 | } 14 | 15 | shared { 16 | bind "" { Detach; } // Cmd T 17 | bind "" { Quit; } // Cmd Q 18 | } 19 | 20 | shared_except "entersearch" "locked" { 21 | bind "" { SwitchToMode "EnterSearch"; SearchInput 0; } // Cmd F 22 | } 23 | 24 | shared_except "locked" "search" { 25 | bind "" { NewPane "Right"; } // Cmd N 26 | bind "" { NewPane "Down"; } // Cmd Shift N 27 | bind "" { SwitchToMode "RenamePane"; PaneNameInput 0; } // Cmd R 28 | bind "" { TogglePaneFrames; SwitchToMode "Normal"; } // Cmd B 29 | bind "" { ToggleFocusFullscreen; SwitchToMode "Normal"; } // Cmd M 30 | bind "" { ToggleFloatingPanes; } // Cmd O 31 | bind "" { CloseFocus; SwitchToMode "Normal"; } // Cmd W 32 | 33 | bind "ﰯ" { MoveFocusOrTab "Left"; } // Shift ← 34 | bind "ﰲ" { MoveFocusOrTab "Right"; } // Shift → 35 | bind "ﰵ" { MoveFocus "Up"; } // Shift ↑ 36 | bind "ﰬ" { MoveFocus "Down"; } // Shift ↓ 37 | 38 | bind "" { Resize "Left"; } // Ctrl Shift ← 39 | bind "" { Resize "Right"; } // Ctrl Shift → 40 | bind "" { Resize "Up"; } // Ctrl Shift ↑ 41 | bind "" { Resize "Down"; } // Ctrl Shift ↓ 42 | 43 | bind "" { MovePane "Left"; } // Opt Shift ← 44 | bind "" { MovePane "Right"; } // Opt Shift → 45 | bind "" { MovePane "Up"; } // Opt Shift ↑ 46 | bind "" { MovePane "Down"; } // Opt Shift ↓ 47 | 48 | bind "" { 49 | NewTab { layout "terminal"; } 50 | SwitchToMode "Normal"; 51 | } // Opt ↑ 52 | bind "" { SwitchToMode "RenameTab"; TabNameInput 0; } // Opt R 53 | bind "" { CloseTab; SwitchToMode "Normal"; } // Opt W 54 | bind "" { GoToPreviousTab; } // Opt ← 55 | bind "" { GoToNextTab; } // Opt → 56 | bind "" { MoveTab "Left"; } // Opt Shift ← 57 | bind "" { MoveTab "Right"; } // Opt Shift → 58 | } 59 | 60 | shared_except "locked" { 61 | bind "" { ScrollUp; } // Cmd ↑ 62 | bind "" { ScrollDown; } // Cmd ↓ 63 | bind "" { HalfPageScrollUp; } // Cmd Shift ↑ 64 | bind "" { HalfPageScrollDown; } // Cmd Shift ↓ 65 | bind "" { PageScrollUp; } // Cmd Shift → 66 | bind "" { PageScrollDown; } // Cmd Shift ← 67 | } 68 | 69 | search { 70 | bind "n" { Search "down"; } 71 | bind "N" { Search "up"; } 72 | bind "c" { SearchToggleOption "CaseSensitivity"; } 73 | bind "w" { SearchToggleOption "Wrap"; } 74 | bind "o" { SearchToggleOption "WholeWord"; } 75 | } 76 | 77 | entersearch { 78 | bind "Ctrl c" "Esc" { SwitchToMode "Normal"; } 79 | bind "Enter" { SwitchToMode "Search"; SearchToggleOption "CaseSensitivity"; } 80 | } 81 | 82 | renametab { 83 | bind "Enter" { SwitchToMode "Normal"; } 84 | bind "Esc" { UndoRenameTab; SwitchToMode "Tab"; } 85 | } 86 | 87 | renamepane { 88 | bind "Enter" { SwitchToMode "Normal"; } 89 | bind "Esc" { UndoRenamePane; SwitchToMode "Pane"; } 90 | } 91 | } 92 | 93 | plugins { 94 | tab-bar { path "tab-bar"; } 95 | status-bar { path "status-bar"; } 96 | strider { path "strider"; } 97 | compact-bar { path "compact-bar"; } 98 | } 99 | 100 | // Choose what to do when zellij receives SIGTERM, SIGINT, SIGQUIT or SIGHUP 101 | // eg. when terminal window with an active zellij session is closed 102 | // Options: 103 | // - detach (Default) 104 | // - quit 105 | on_force_close "detach" 106 | 107 | // Send a request r a simplified ui (without arrow fonts) to plugins 108 | // Options: 109 | // - true 110 | // - false (Default) 111 | simplified_ui false 112 | 113 | // Choose the path to the default shell that zellij will use for opening new panes 114 | // Default: $SHELL 115 | // 116 | // default_shell "fish" 117 | 118 | // Toggle between having pane frames around the panes 119 | // Options: 120 | // - true (default) 121 | // - false 122 | pane_frames true 123 | 124 | // Choose the theme that is specified in the themes section. 125 | // Default: default 126 | theme "default" 127 | 128 | // The name of the default layout to load on startup 129 | // Default: "default" 130 | default_layout "terminal" 131 | 132 | // Choose the mode that zellij uses when starting up. 133 | // Default: normal 134 | default_mode "normal" 135 | 136 | // Toggle enabling the mouse mode. 137 | // On certain configurations, or terminals this could 138 | // potentially interfere with copying text. 139 | // Options: 140 | // - true (default) 141 | // - false 142 | mouse_mode true 143 | 144 | // Configure the scroll back buffer size 145 | // This is the number of lines zellij stores for each pane in the scroll back 146 | // buffer. Excess number of lines are discarded in a FIFO fashion. 147 | // Valid values: positive integers 148 | // Default value: 10000 149 | // 150 | scroll_buffer_size 100000 151 | 152 | // Provide a command to execute when copying text. The text will be piped to 153 | // the stdin of the program to perform the copy. This can be used with 154 | // terminal emulators which do not support the OSC 52 ANSI control sequence 155 | // that will be used by default if this option is not set. 156 | // Examples: 157 | // 158 | // copy_command "xclip -selection clipboard" // x11 159 | // copy_command "wl-copy" // wayland 160 | copy_command "pbcopy" // osx 161 | 162 | // Choose the destination for copied text 163 | // Allows using the primary selection buffer (on x11/wayland) instead of the system clipboard. 164 | // Does not apply when using copy_command. 165 | // Options: 166 | // - system (default) 167 | // - primary 168 | copy_clipboard "system" 169 | 170 | // Enable or disable automatic copy (and clear) of selection when releasing mouse 171 | // Default: true 172 | copy_on_select true 173 | 174 | // Path to the default editor to use to edit pane scrollbuffer 175 | // Default: $EDITOR or $VISUAL 176 | // 177 | // scrollback_editor "/usr/bin/vim" 178 | 179 | // When attaching to an existing session with other users, 180 | // should the session be mirrored (true) 181 | // or should each user have their own cursor (false) 182 | // Default: false 183 | // 184 | // mirror_session true 185 | 186 | // The folder in which Zellij will look for layouts 187 | // 188 | // layout_dir "/path/to/my/layout_dir" 189 | 190 | // The folder in which Zellij will look for themes 191 | // 192 | // theme_dir "/path/to/my/theme_dir" 193 | 194 | session_serialization false 195 | disable_session_metadata true 196 | -------------------------------------------------------------------------------- /home/.config/zellij/layouts/terminal.kdl: -------------------------------------------------------------------------------- 1 | layout { 2 | tab name="terminal" { 3 | pane 4 | pane size="30%" 5 | pane size=1 borderless=true { 6 | plugin location="file:/Users/Alex/.config/zellij/plugins/statusbar.wasm" 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /home/.config/zellij/themes/default.kdl: -------------------------------------------------------------------------------- 1 | themes { 2 | default { 3 | fg "#afb4c3" 4 | bg "#272b30" 5 | black "#272b30" 6 | red "#cc6666" 7 | green "#bdb968" 8 | yellow "#f0c674" 9 | blue "#81a2be" 10 | magenta "#b08cba" 11 | cyan "#7fb2c8" 12 | white "#afb4c3" 13 | orange "#de935f" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /home/.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | end_of_line = lf 6 | indent_style = space 7 | indent_size = 4 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.{md,mdx}] 12 | trim_trailing_whitespace = false 13 | 14 | [*.{yml,yaml}] 15 | indent_size = 2 16 | -------------------------------------------------------------------------------- /home/.local/share/devbox/global/default/devbox.json: -------------------------------------------------------------------------------- 1 | { 2 | "packages": [ 3 | "direnv@latest", 4 | "starship@latest", 5 | "tree@latest", 6 | "fd@latest", 7 | "bat@latest", 8 | "fzf@latest", 9 | "skim@latest", 10 | "htop@latest", 11 | "curl@latest", 12 | "wget@latest", 13 | "pstree", 14 | "mkcert@latest", 15 | "ripgrep@latest", 16 | "fortune@latest", 17 | "watchman@latest", 18 | "lazygit", 19 | "bottom@latest", 20 | "zellij@latest", 21 | "tree-sitter@latest", 22 | "git@latest", 23 | "zsh@latest", 24 | "zsh-autosuggestions@latest", 25 | "zsh-completions@latest", 26 | "libiconv@latest", 27 | "btop@latest", 28 | "goku@latest", 29 | "watchexec@latest", 30 | "prettierd@latest", 31 | "yamlfmt@latest", 32 | "jq@latest", 33 | "libgit2@latest", 34 | "gpgme@latest", 35 | "neovim@latest" 36 | ] 37 | } 38 | -------------------------------------------------------------------------------- /home/.profile: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alex35mil/dotfiles/98c4539994572df10c4b941b04d43a14c6024ccc/home/.profile -------------------------------------------------------------------------------- /home/.zprofile: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alex35mil/dotfiles/98c4539994572df10c4b941b04d43a14c6024ccc/home/.zprofile -------------------------------------------------------------------------------- /home/.zshenv: -------------------------------------------------------------------------------- 1 | source ~/.config/shell/init.sh 2 | source ~/.config/shell/variables.sh 3 | -------------------------------------------------------------------------------- /home/.zshrc: -------------------------------------------------------------------------------- 1 | source ~/.config/shell/zsh/options.sh 2 | source ~/.config/shell/shortcuts.sh 3 | source ~/.config/shell/apps/cargo.sh 4 | source ~/.config/shell/apps/devbox.sh 5 | source ~/.config/shell/apps/direnv.sh 6 | source ~/.config/shell/apps/docker.sh 7 | source ~/.config/shell/apps/git.sh 8 | source ~/.config/shell/apps/neovim.sh 9 | source ~/.config/shell/apps/nix.sh 10 | source ~/.config/shell/apps/node.sh 11 | source ~/.config/shell/apps/starship.sh 12 | source ~/.config/shell/apps/zellij.sh 13 | -------------------------------------------------------------------------------- /script/cargo.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | cargo install --locked \ 4 | cargo-binstall \ 5 | cargo-expand \ 6 | cargo-outdated \ 7 | cargo-sync-readme \ 8 | cargo-update \ 9 | cargo-wasi \ 10 | cargo-watch \ 11 | sea-orm-cli \ 12 | sqlx-cli \ 13 | typos-cli 14 | -------------------------------------------------------------------------------- /script/font/original/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alex35mil/dotfiles/98c4539994572df10c4b941b04d43a14c6024ccc/script/font/original/.gitkeep -------------------------------------------------------------------------------- /script/font/patch.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | docker run --pull always --rm -v ./original/:/in -v ./patched:/out nerdfonts/patcher --complete 4 | -------------------------------------------------------------------------------- /script/font/patched/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alex35mil/dotfiles/98c4539994572df10c4b941b04d43a14c6024ccc/script/font/patched/.gitkeep -------------------------------------------------------------------------------- /script/install.sh: -------------------------------------------------------------------------------- 1 | #!/bin/zsh 2 | 3 | ######################## 4 | # HOW THIS SCRIPT WORKS 5 | ######################## 6 | # To install these dotfiles, I will use the `find` command to collect and symlink 7 | # all the configuration files from the `dotfiles/home` directory. 8 | # However, I will make an exception for the files in the directories listed 9 | # in the $UMBRELLA_DIRECTORIES array down below. Why? Since I add/remove files 10 | # in these directories relatively often, I don't want to run the install script 11 | # every time it happens. Symlinking the whole directory instead of each 12 | # individual file would solve this. 13 | ######################## 14 | 15 | # Let's set script options first. 16 | 17 | # The `errexit` option causes the script to exit immediately if any command 18 | # within this script exits with a non-zero status. 19 | set -o errexit 20 | # The `nounset` option causes the script to exit if any variable is used 21 | # before being set. 22 | set -o nounset 23 | # The `pipefail` option causes a pipeline to produce a failure return code 24 | # if any command in the pipeline fails. 25 | set -o pipefail 26 | 27 | # The TRACE variable is used to turn on debugging mode. 28 | # Can be used like this: `TRACE=1 script/install.sh` 29 | # The `${TRACE-0}` syntax is used to substitute a default value (0) 30 | # if the variable TRACE is not set. 31 | if [[ "${TRACE-0}" == "1" ]]; then 32 | # If TRACE is set to `1`, the `xtrace` option is set, which enables 33 | # debugging by printing each command and its arguments to standard error 34 | # before executing. 35 | set -o xtrace 36 | fi 37 | 38 | # Let's store the required paths in variables. 39 | # 40 | # DOTFILES will contain the root directory of this repo. 41 | # 42 | # Breaking it down: 43 | # - `${(%):-%N}`: This is a zsh-specific parameter expansion. 44 | # %N gives the script name and the surrounding (%) gives the absolute path. 45 | # - `dirname `${(%):-%N}"": This command takes the absolute path to the script 46 | # and returns the path to the script's directory. 47 | # - `cd "$( dirname "${(%):-%N}" )" && cd ..`: This command first changes 48 | # to the script's directory and then moves up one directory. 49 | # - `pwd`: This command prints the current working directory, which is now 50 | # the parent directory of the script's directory). 51 | # - `$( cd "$( dirname "${(%):-%N}" )" && cd .. && pwd )`: 52 | # This entire command substitution returns the absolute path of the parent 53 | # directory of the script's directory. 54 | DOTFILES="$( cd "$( dirname "${(%):-%N}" )" && cd .. && pwd )" 55 | 56 | DOTFILES_BIN="$DOTFILES/bin" 57 | DOTFILES_HOME="$DOTFILES/home" 58 | 59 | HOME_CONFIG="$HOME/.config" 60 | 61 | # I want to symlink these directories instead of each individual file in them. 62 | UMBRELLA_DIRECTORIES=( 63 | ".config/nvim" 64 | ".config/shell" 65 | ".config/zellij" 66 | ".config/raycast/scripts" 67 | ) 68 | 69 | # Let's collect all the paths to configuration files in an associative array 70 | declare -A PATHS 71 | 72 | # `cd` to the $DOTFILES_HOME directory to get relative paths with `find` 73 | cd $DOTFILES_HOME 74 | 75 | # Here, I `find` all the files in the $DOTFILES_HOME directory, 76 | # and if a file is inside one of the $UMBRELLA_DIRECTORIES, 77 | # I add the directory to the $PATHS array. 78 | # Otherwise, I add the file itself to the $PATHS array. 79 | for file in $(find . -type f | sed 's|^\./||'); do 80 | dir="" 81 | 82 | for d in $UMBRELLA_DIRECTORIES; do 83 | if [[ $file == $d/* ]]; then 84 | dir=$d 85 | break 86 | fi 87 | done 88 | 89 | if [[ -n $dir ]]; then 90 | PATHS[$dir]="d" 91 | else 92 | PATHS[$file]="f" 93 | fi 94 | done 95 | 96 | # Before making any changes, let's ensure we don't overwrite anything 97 | for loc in ${(o)${(k)PATHS}}; do 98 | local target="$HOME/$loc" 99 | 100 | if [[ -e "$target" && ! -L "$target" ]]; then 101 | echo "🚫 ERROR: $target already exists and is not a symlink. Exiting." 102 | exit 1 103 | fi 104 | done 105 | 106 | # If we're good, let's ensure `.config` directory exists 107 | echo 108 | echo "🛠 Ensuring config directory: $HOME_CONFIG..." 109 | mkdir -p "$HOME_CONFIG" 110 | echo "🛠 Ensuring config directory: $HOME_CONFIG... done." 111 | 112 | # And create the symlinks 113 | echo 114 | echo "🛠 Creating symlinks..." 115 | for loc in ${(o)${(k)PATHS}}; do 116 | local src="$DOTFILES_HOME/$loc" 117 | local target="$HOME/$loc" 118 | local kind="${PATHS[$loc]}" 119 | 120 | echo "🔖 Creating symlink: $src -> $target..." 121 | 122 | mkdir -p "$(dirname "$target")" 123 | 124 | case "$kind" in 125 | f) 126 | ln -sf "$src" "$target" 127 | ;; 128 | d) 129 | ln -sfn "$src" "$target" 130 | ;; 131 | esac 132 | 133 | echo "🔖 Creating symlink: $src -> $target... done." 134 | done 135 | echo "🛠 Creating symlinks... done." 136 | 137 | # Then, let's build the binaries from the `dotfiles/bin` directory 138 | 139 | # Zellij statusbar plugin 140 | echo 141 | echo "🛠 Building Zellij statusbar..." 142 | 143 | ZELLIJ_STATUSBAR_SRC="$DOTFILES_BIN/zellij/statusbar" 144 | ZELLIJ_STATUSBAR_DEST="$DOTFILES_HOME/.config/zellij/plugins" 145 | ZELLIJ_STATUSBAR_BIN="statusbar.wasm" 146 | 147 | mkdir -p "$ZELLIJ_STATUSBAR_DEST" 148 | rm "$ZELLIJ_STATUSBAR_DEST/$ZELLIJ_STATUSBAR_BIN" || true 149 | cd $ZELLIJ_STATUSBAR_SRC 150 | cargo build --release 151 | cp "target/wasm32-wasi/release/$ZELLIJ_STATUSBAR_BIN" "$ZELLIJ_STATUSBAR_DEST/" 152 | 153 | echo "🛠 Building Zellij statusbar... done." 154 | 155 | # Zellij runner 156 | echo 157 | echo "🛠 Building Zellij runner..." 158 | 159 | ZELLIJ_RUNNER_SRC="$DOTFILES_BIN/zellij/runner" 160 | 161 | cd $ZELLIJ_RUNNER_SRC 162 | cargo install --locked --path . 163 | 164 | cd $DOTFILES 165 | 166 | echo "🛠 Building Zellij runner... done." 167 | 168 | # Finally, ensuring .hushlogin exists to get rid of "Last login..." message 169 | echo 170 | echo "📋 Ensuring .hushlogin: $HOME/.hushlogin..." 171 | touch "$HOME/.hushlogin" 172 | echo "📋 Ensuring .hushlogin: $HOME/.hushlogin... done." 173 | 174 | # Before exiting, let's restart the shell to get all the new goodies. 175 | # Since I can run the install script from either bash/zsh or nu shell, 176 | # I set the $PSHELL variable on the call site to let this script know 177 | # which shell to restart. 178 | PSHELL="${PSHELL:-}" 179 | 180 | echo 181 | if [[ -n $PSHELL ]]; then 182 | case $PSHELL in 183 | *bash) 184 | echo "🚀 All done. Restarting $PSHELL shell." 185 | exec bash -l 186 | ;; 187 | *zsh) 188 | echo "🚀 All done. Restarting $PSHELL shell." 189 | exec zsh -l 190 | ;; 191 | *nu) 192 | echo "🚀 All done. Restarting $PSHELL shell." 193 | exec nu 194 | ;; 195 | *) 196 | echo "❕ All done, but I'm not sure what $PSHELL shell is. Restart this shell manually." 197 | ;; 198 | esac 199 | else 200 | echo "❕ All done, but PSHELL is not set. Restart the shell manually." 201 | fi 202 | --------------------------------------------------------------------------------