├── .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 |
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 |
35 | Session selector
36 |
37 |
38 |
39 |
40 |
41 |
42 | Session panes
43 |
44 |
45 |
46 |
47 | Editor
48 |
49 |
50 |
51 | Single buffer
52 |
53 |
54 |
55 |
56 |
57 |
58 | Buffer selector
59 |
60 |
61 |
62 |
63 |
64 |
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 |
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 | //!
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 |
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 | ["