├── dotfiles ├── .config │ ├── git │ │ ├── ignore │ │ └── config │ ├── nvim │ │ ├── colors │ │ │ ├── tansai.lua │ │ │ └── shinkai.vim │ │ ├── after │ │ │ ├── ftplugin │ │ │ │ ├── javascript.lua │ │ │ │ ├── caddy.lua │ │ │ │ ├── gosum.lua │ │ │ │ ├── hcl.lua │ │ │ │ ├── gomod.lua │ │ │ │ ├── typescriptreact.lua │ │ │ │ ├── astro.lua │ │ │ │ ├── json.lua │ │ │ │ ├── help.lua │ │ │ │ ├── scss.lua │ │ │ │ ├── sh.lua │ │ │ │ ├── typst.lua │ │ │ │ ├── dockerfile.lua │ │ │ │ ├── query.lua │ │ │ │ ├── terraform.lua │ │ │ │ ├── yaml.lua │ │ │ │ ├── lua.lua │ │ │ │ ├── markdown.lua │ │ │ │ ├── vue.lua │ │ │ │ ├── go.lua │ │ │ │ ├── typescript.lua │ │ │ │ └── python.lua │ │ │ └── queries │ │ │ │ └── markdown │ │ │ │ ├── injections.scm │ │ │ │ └── highlights.scm │ │ ├── skeletons │ │ │ ├── component.tsx │ │ │ ├── taskfile.yml │ │ │ ├── bash.sh │ │ │ ├── sfc.vue │ │ │ ├── main.py │ │ │ ├── dependabot.yml │ │ │ ├── github-workflow.yml │ │ │ ├── editorconfig.txt │ │ │ ├── license.txt │ │ │ └── readme.md │ │ ├── lua │ │ │ ├── plugins │ │ │ │ ├── devicons.lua │ │ │ │ ├── schemastore.lua │ │ │ │ ├── gitsigns.lua │ │ │ │ ├── neoscroll.lua │ │ │ │ ├── luasnip.lua │ │ │ │ ├── nvim-lint.lua │ │ │ │ ├── colorscheme.lua │ │ │ │ ├── notify.lua │ │ │ │ ├── smartcolumn.lua │ │ │ │ ├── lualine.lua │ │ │ │ ├── telescope.lua │ │ │ │ ├── treesitter.lua │ │ │ │ ├── cmp.lua │ │ │ │ ├── mason.lua │ │ │ │ ├── conform.lua │ │ │ │ ├── mini-nvim.lua │ │ │ │ └── lspconfig.lua │ │ │ ├── highlights.lua │ │ │ ├── tansai.lua │ │ │ ├── utils.lua │ │ │ ├── terminal.lua │ │ │ ├── options.lua │ │ │ ├── keymaps.lua │ │ │ ├── autocmds.lua │ │ │ └── statusline.lua │ │ ├── lsp │ │ │ ├── terraformls.lua │ │ │ ├── vale-ls.lua │ │ │ ├── bashls.lua │ │ │ ├── yamlls.lua │ │ │ ├── tinymist.lua │ │ │ ├── jsonls.lua │ │ │ ├── cssls.lua │ │ │ ├── dockerls.lua │ │ │ ├── astro.lua │ │ │ ├── lua_ls.lua │ │ │ ├── pyright.lua │ │ │ └── gopls.lua │ │ ├── luasnippets │ │ │ ├── vue.lua │ │ │ ├── lua.lua │ │ │ ├── python.lua │ │ │ └── go.lua │ │ ├── filetype.lua │ │ ├── lazy-lock.json │ │ └── init.lua │ ├── pip │ │ └── pip.conf │ ├── flameshot │ │ └── flameshot.ini │ ├── bat │ │ └── config │ ├── gh │ │ └── config.yml │ ├── tmux │ │ ├── statusline │ │ │ ├── statusline.conf │ │ │ └── battery-status │ │ └── tmux.conf │ ├── wezterm │ │ └── wezterm.lua │ └── starship │ │ └── starship.toml ├── .vim │ └── vimrc ├── .zsh │ ├── functions │ └── aliases ├── .ssh │ └── config ├── .homebrew │ └── linux.Brewfile ├── .local │ └── bin │ │ ├── music-sort │ │ ├── tag │ │ ├── update │ │ └── mkblog └── .zshrc ├── .stylua.toml ├── selene.toml ├── vim.toml ├── assets ├── neovim.png ├── starship.png └── wezterm.png ├── .github ├── DISCUSSION_TEMPLATE │ └── general.yml ├── ISSUE_TEMPLATE │ ├── feature-enhancement.yml │ ├── config.yml │ └── bug-report.yml ├── dependabot.yml ├── stale.yml ├── workflows │ ├── auto-dependabot.yaml │ └── qa-checks.yml ├── SUPPORT.md ├── SECURITY.md ├── PULL_REQUEST_TEMPLATE.md └── CONTRIBUTING.md ├── .editorconfig ├── .gitattributes ├── LICENSE ├── .pre-commit-config.yaml ├── .gitignore ├── README.md └── bootstrap.sh /dotfiles/.config/git/ignore: -------------------------------------------------------------------------------- 1 | *scratch* 2 | -------------------------------------------------------------------------------- /.stylua.toml: -------------------------------------------------------------------------------- 1 | indent_type = "Spaces" 2 | indent_width = 2 3 | -------------------------------------------------------------------------------- /dotfiles/.config/nvim/colors/tansai.lua: -------------------------------------------------------------------------------- 1 | require("tansai").load() 2 | -------------------------------------------------------------------------------- /selene.toml: -------------------------------------------------------------------------------- 1 | std="vim" 2 | 3 | [lints] 4 | mixed_table = "allow" 5 | -------------------------------------------------------------------------------- /dotfiles/.config/nvim/after/ftplugin/javascript.lua: -------------------------------------------------------------------------------- 1 | vim.treesitter.start() 2 | -------------------------------------------------------------------------------- /vim.toml: -------------------------------------------------------------------------------- 1 | [selene] 2 | base = "lua51" 3 | name = "vim" 4 | 5 | [vim] 6 | any = true 7 | -------------------------------------------------------------------------------- /assets/neovim.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jarmos-san/dotfiles/HEAD/assets/neovim.png -------------------------------------------------------------------------------- /assets/starship.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jarmos-san/dotfiles/HEAD/assets/starship.png -------------------------------------------------------------------------------- /assets/wezterm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jarmos-san/dotfiles/HEAD/assets/wezterm.png -------------------------------------------------------------------------------- /dotfiles/.config/pip/pip.conf: -------------------------------------------------------------------------------- 1 | [global] 2 | require-virtualenv=true 3 | disable-pip-version-check=true 4 | -------------------------------------------------------------------------------- /dotfiles/.config/nvim/after/ftplugin/caddy.lua: -------------------------------------------------------------------------------- 1 | vim.treesitter.start() -- Start the Treesitter parsing process for Caddyfiles 2 | -------------------------------------------------------------------------------- /dotfiles/.config/nvim/after/ftplugin/gosum.lua: -------------------------------------------------------------------------------- 1 | -- Start the Treesitter parser for "go.sum" files 2 | vim.treesitter.start() 3 | -------------------------------------------------------------------------------- /dotfiles/.config/nvim/after/ftplugin/hcl.lua: -------------------------------------------------------------------------------- 1 | -- Start the Treesitter parsing process for HCL files 2 | vim.treesitter.start() 3 | -------------------------------------------------------------------------------- /dotfiles/.config/nvim/after/ftplugin/gomod.lua: -------------------------------------------------------------------------------- 1 | -- Start the Treesitter parsing process for "go.mod" files 2 | vim.treesitter.start() 3 | -------------------------------------------------------------------------------- /dotfiles/.config/nvim/after/queries/markdown/injections.scm: -------------------------------------------------------------------------------- 1 | ; extends 2 | ((inline) @_inline (#match? @_inline "^\(import\|export\)")) @tsx 3 | -------------------------------------------------------------------------------- /dotfiles/.config/nvim/after/queries/markdown/highlights.scm: -------------------------------------------------------------------------------- 1 | ; extends 2 | ((inline) @_inline (#match? @_inline "^\(import\|export\)")) @nospell 3 | -------------------------------------------------------------------------------- /dotfiles/.config/nvim/after/ftplugin/typescriptreact.lua: -------------------------------------------------------------------------------- 1 | vim.opt.iskeyword:append("-") -- Make Neovim recognise dash-seperated words as a single word 2 | -------------------------------------------------------------------------------- /dotfiles/.config/nvim/skeletons/component.tsx: -------------------------------------------------------------------------------- 1 | function SomeComponent() { 2 | return

Hello World!

; 3 | } 4 | 5 | export default SomeComponent; 6 | -------------------------------------------------------------------------------- /dotfiles/.config/nvim/lua/plugins/devicons.lua: -------------------------------------------------------------------------------- 1 | -- Module for adding devicon support to Neovim 2 | 3 | return { 4 | "nvim-tree/nvim-web-devicons", 5 | name = "devicons", 6 | } 7 | -------------------------------------------------------------------------------- /dotfiles/.config/nvim/skeletons/taskfile.yml: -------------------------------------------------------------------------------- 1 | version: "3" 2 | 3 | tasks: 4 | build: 5 | description: Build the project 6 | cmds: 7 | - echo "Running build command..." 8 | -------------------------------------------------------------------------------- /dotfiles/.config/nvim/after/ftplugin/astro.lua: -------------------------------------------------------------------------------- 1 | -- Start the Treesitter parsing process 2 | vim.treesitter.start() 3 | 4 | -- Start the "astro" LSP server 5 | vim.lsp.enable("astro", true) 6 | -------------------------------------------------------------------------------- /dotfiles/.config/nvim/after/ftplugin/json.lua: -------------------------------------------------------------------------------- 1 | -- Start the Treesitter parsing process 2 | vim.treesitter.start() 3 | 4 | -- Start the "jsonls" LSP server 5 | vim.lsp.enable("jsonls", true) 6 | -------------------------------------------------------------------------------- /dotfiles/.config/nvim/skeletons/bash.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -euo pipefail 4 | 5 | # Add the rest of the contents for the script below this line 6 | 7 | echo "Hello World!" 8 | -------------------------------------------------------------------------------- /dotfiles/.config/nvim/lsp/terraformls.lua: -------------------------------------------------------------------------------- 1 | return { 2 | cmd = { "terraform-ls", "serve" }, 3 | filetypes = { "terraform", "terraform-vars" }, 4 | root_markers = { ".terraform", ".git" }, 5 | } 6 | -------------------------------------------------------------------------------- /dotfiles/.config/flameshot/flameshot.ini: -------------------------------------------------------------------------------- 1 | [General] 2 | copyAndCloseAfterUpload=true 3 | disabledTrayIcon=false 4 | drawColor=#ff0000 5 | drawThickness=0 6 | filenamePattern=%F%H%M 7 | startupLaunch=true 8 | -------------------------------------------------------------------------------- /dotfiles/.config/nvim/lua/plugins/schemastore.lua: -------------------------------------------------------------------------------- 1 | -- Module for configuring the schemas for various JSON files 2 | 3 | return { 4 | "b0o/schemastore.nvim", 5 | event = "BufRead", 6 | ft = "json", 7 | } 8 | -------------------------------------------------------------------------------- /dotfiles/.config/nvim/after/ftplugin/help.lua: -------------------------------------------------------------------------------- 1 | -- Settings to apply specifically to "vimdoc" files/buffers 2 | 3 | vim.b.miniindentscope_disable = true -- This is necessary to disable indent lines on help files 4 | -------------------------------------------------------------------------------- /dotfiles/.config/nvim/after/ftplugin/scss.lua: -------------------------------------------------------------------------------- 1 | -- Start the Treesitter parsing process for SASS files 2 | vim.treesitter.start() 3 | 4 | -- Start the LSP server for the SASS files 5 | vim.lsp.enable("cssls", true) 6 | -------------------------------------------------------------------------------- /dotfiles/.config/nvim/after/ftplugin/sh.lua: -------------------------------------------------------------------------------- 1 | -- Start the Treesitter parser for Shell files 2 | vim.treesitter.start() 3 | 4 | -- Start the "bashls" LSP server for Bash scripting 5 | vim.lsp.enable("bashls", true) 6 | -------------------------------------------------------------------------------- /dotfiles/.config/nvim/after/ftplugin/typst.lua: -------------------------------------------------------------------------------- 1 | -- Start the Treesitter parsing process 2 | vim.treesitter.start() 3 | 4 | -- Enable the "tinymist" LSP server for Typst files 5 | vim.lsp.enable("tinymist", true) 6 | -------------------------------------------------------------------------------- /dotfiles/.config/nvim/lua/plugins/gitsigns.lua: -------------------------------------------------------------------------------- 1 | -- Module for configuring the "gitsigns" plugin for Git VCS capabilities 2 | 3 | return { 4 | "lewis6991/gitsigns.nvim", 5 | event = "BufReadPost", 6 | config = true, 7 | } 8 | -------------------------------------------------------------------------------- /dotfiles/.config/nvim/after/ftplugin/dockerfile.lua: -------------------------------------------------------------------------------- 1 | -- Start the Treesitter parsing process for Dockerfile 2 | vim.treesitter.start() 3 | 4 | -- Enable the "dockerls" LSP server for Dockerfile 5 | vim.lsp.enable("dockerls", true) 6 | -------------------------------------------------------------------------------- /dotfiles/.config/nvim/lsp/vale-ls.lua: -------------------------------------------------------------------------------- 1 | -- Configurations for "vale-ls", the LSP for Vale (a linter for prose) 2 | return { 3 | cmd = { "vale-ls" }, 4 | filetypes = { "markdown", "text", "rst" }, 5 | root_markers = { ".vale.ini" }, 6 | } 7 | -------------------------------------------------------------------------------- /dotfiles/.config/nvim/after/ftplugin/query.lua: -------------------------------------------------------------------------------- 1 | -- Filetype plugin configurations for the "query" filetype 2 | 3 | -- Disable the redundant number column on the right side for "query" files 4 | vim.wo.number = false 5 | vim.wo.relativenumber = false 6 | -------------------------------------------------------------------------------- /.github/DISCUSSION_TEMPLATE/general.yml: -------------------------------------------------------------------------------- 1 | title: "[General Discussion] " 2 | labels: ["discussion"] 3 | body: 4 | - type: markdown 5 | attributes: 6 | value: Share your ideas or questions or random banter here! 7 | validations: 8 | required: true 9 | -------------------------------------------------------------------------------- /dotfiles/.config/nvim/skeletons/sfc.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 8 | 9 | 14 | -------------------------------------------------------------------------------- /dotfiles/.config/nvim/lsp/bashls.lua: -------------------------------------------------------------------------------- 1 | return { 2 | cmd = { "bash-language-server", "start" }, 3 | filetypes = { "bash", "sh" }, 4 | root_markers = { ".git" }, 5 | settings = { 6 | bashIde = { 7 | globPattern = "*@(.sh|.inc|.bash|.command)", 8 | }, 9 | }, 10 | } 11 | -------------------------------------------------------------------------------- /dotfiles/.config/nvim/skeletons/main.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | """The entrypoint file of the Python script.""" 4 | 5 | 6 | def main() -> None: 7 | """Invoke this function as the entrypoint of the script.""" 8 | pass 9 | 10 | 11 | if __name__ == "__main__": 12 | main() 13 | -------------------------------------------------------------------------------- /dotfiles/.config/nvim/after/ftplugin/terraform.lua: -------------------------------------------------------------------------------- 1 | -- Set the correct comment string format for Terraform files 2 | vim.opt.commentstring = "// %s" 3 | 4 | -- Start the Treesitter parsing process 5 | vim.treesitter.start() 6 | 7 | -- Start the "terraform-ls" LSP server 8 | vim.lsp.enable("terraformls", true) 9 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature-enhancement.yml: -------------------------------------------------------------------------------- 1 | name: Feature Enhancement 2 | description: Request or improve an existing feature 3 | labels: ["enhancement"] 4 | assignees: 5 | - Jarmos-san 6 | body: 7 | - type: textarea 8 | attributes: 9 | label: "Provide details of the feature enhancement" 10 | -------------------------------------------------------------------------------- /dotfiles/.config/nvim/lsp/yamlls.lua: -------------------------------------------------------------------------------- 1 | return { 2 | cmd = { "yaml-language-server", "--stdio" }, 3 | filetypes = { "yaml" }, 4 | root_markers = { ".git" }, 5 | settings = { 6 | redhat = { 7 | telemetry = false, 8 | }, 9 | schemas = require("schemastore").yaml.schemas(), 10 | validate = true, 11 | }, 12 | } 13 | -------------------------------------------------------------------------------- /dotfiles/.config/nvim/skeletons/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | 3 | updates: 4 | - package-ecosystem: "github-actions" 5 | directory: "/" 6 | schedule: 7 | interval: "daily" 8 | time: "06:00" 9 | timezone: "Asia/Kolkata" 10 | commit-message: 11 | prefix: "🔀" 12 | labels: 13 | - "dependencies" 14 | -------------------------------------------------------------------------------- /dotfiles/.config/nvim/lsp/tinymist.lua: -------------------------------------------------------------------------------- 1 | -- LSP configurations for the "tinymist" LSP server to be used by Typst files 2 | -- TODO: Add the user commands to invoke some of the inbuilt tinymist commands 3 | return { 4 | cmd = { "tinymist" }, 5 | filetypes = { "typst" }, 6 | root_markers = { ".git" }, 7 | settings = { 8 | formatterMode = "typstyle", 9 | }, 10 | } 11 | -------------------------------------------------------------------------------- /dotfiles/.config/nvim/skeletons/github-workflow.yml: -------------------------------------------------------------------------------- 1 | name: GitHub Workflow Template 2 | 3 | on: [push] 4 | 5 | jobs: 6 | workflow-job: 7 | name: Sample GitHub Workflow 8 | runs-on: ubuntu-latest 9 | steps: 10 | - name: Checkout Repository 11 | uses: actions/checkout@v3 12 | 13 | - name: Run "Hello World!" 14 | run: echo "Hello World!" 15 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = space 5 | indent_size = 4 6 | end_of_line = lf 7 | charset = utf-8 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true 10 | 11 | [*.lua] 12 | indent_size = 2 13 | 14 | [*.py] 15 | indent_size = 4 16 | 17 | [*.{json,md,toml,yml,yaml}] 18 | indent_size = 2 19 | 20 | [*.{sh,bash_profile}] 21 | indent_size = 2 22 | -------------------------------------------------------------------------------- /dotfiles/.config/nvim/lua/plugins/neoscroll.lua: -------------------------------------------------------------------------------- 1 | -- Module for configuring the plugin for smooth scrolling 2 | 3 | return { 4 | "karb94/neoscroll.nvim", 5 | event = { "BufRead", "BufNewFile" }, 6 | opts = { 7 | respect_scrolloff = true, 8 | cursor_scrolls_alone = false, 9 | }, 10 | config = function(_, opts) 11 | require("neoscroll").setup(opts) 12 | end, 13 | } 14 | -------------------------------------------------------------------------------- /dotfiles/.config/nvim/after/ftplugin/yaml.lua: -------------------------------------------------------------------------------- 1 | -- Start the Treesitter parsing logic 2 | vim.treesitter.start() 3 | 4 | -- INFO: Only open "massive" buffers with folds enabled 5 | if vim.api.nvim_buf_line_count(0) >= 100 then 6 | vim.opt.foldmethod = "indent" 7 | vim.opt.foldlevel = 1 8 | vim.opt.foldenable = true 9 | end 10 | 11 | -- Start the "yamlls" LSP server 12 | vim.lsp.enable("yamlls", true) 13 | -------------------------------------------------------------------------------- /dotfiles/.config/bat/config: -------------------------------------------------------------------------------- 1 | # Specify desired highlighting theme (e.g. "TwoDark"). Run `bat --list-themes` 2 | # for a list of all available themes 3 | --theme="gruvbox-dark" 4 | 5 | # Uncomment the following line if you are using less version >= 551 and want to 6 | # enable mouse scrolling support in `bat` when running inside tmux. This might 7 | # disable text selection, unless you press shift. 8 | --pager="less -R" 9 | -------------------------------------------------------------------------------- /dotfiles/.config/nvim/lsp/jsonls.lua: -------------------------------------------------------------------------------- 1 | local schemastore = require("schemastore") 2 | 3 | return { 4 | cmd = { "vscode-json-language-server", "--stdio" }, 5 | filetypes = { "json", "jsonc" }, 6 | init_options = { 7 | provideFormatter = true, 8 | }, 9 | root_markers = { ".git" }, 10 | settings = { 11 | json = { 12 | schemas = schemastore.json.schemas(), 13 | validate = { enable = true }, 14 | }, 15 | }, 16 | } 17 | -------------------------------------------------------------------------------- /dotfiles/.config/nvim/lsp/cssls.lua: -------------------------------------------------------------------------------- 1 | return { 2 | cmd = { "vscode-css-language-server", "--stdio" }, 3 | filetypes = { "css", "scss", "less" }, 4 | init_options = { 5 | provideFormatter = true, 6 | }, 7 | root_markers = { "package.json", ".git" }, 8 | settings = { 9 | css = { 10 | validate = true, 11 | }, 12 | less = { 13 | validate = true, 14 | }, 15 | scss = { 16 | validate = true, 17 | }, 18 | }, 19 | } 20 | -------------------------------------------------------------------------------- /dotfiles/.config/nvim/lua/plugins/luasnip.lua: -------------------------------------------------------------------------------- 1 | -- Module for configuring the Luasnip snippets engine 2 | 3 | return { 4 | "L3MON4D3/LuaSnip", 5 | event = "InsertEnter", 6 | build = "make install_jsregexp", 7 | opts = { 8 | region_check_events = "InsertEnter", 9 | delete_check_events = "InsertEnter", 10 | }, 11 | config = function(_, opts) 12 | require("luasnip").setup(opts) 13 | require("luasnip.loaders.from_lua").load() 14 | end, 15 | } 16 | -------------------------------------------------------------------------------- /dotfiles/.config/nvim/after/ftplugin/lua.lua: -------------------------------------------------------------------------------- 1 | -- Module for configuring Lua specific buffer contents 2 | 3 | local autocmd = require("utils").autocmd 4 | local augroup = require("utils").augroup 5 | 6 | autocmd("BufWritePost", { 7 | desc = "Lint Lua files using Stylua", 8 | group = augroup("lint_lua_files"), 9 | callback = function() 10 | require("lint").try_lint() 11 | end, 12 | }) 13 | 14 | -- Start the Treesitter parser process 15 | vim.treesitter.start() 16 | -------------------------------------------------------------------------------- /dotfiles/.config/nvim/after/ftplugin/markdown.lua: -------------------------------------------------------------------------------- 1 | -- Filetype plugin which applies settings only for Markdown files 2 | 3 | vim.opt.wrap = true -- Wrap lines instead of continuing on beyond the limits of the monitor 4 | vim.opt.linebreak = true -- Wrap the lines at the end of a word instead of the last character of a line 5 | 6 | -- Enable the "vale-ls" LSP server for Markdown files 7 | vim.lsp.enable("vale-ls", true) 8 | 9 | -- Start the Treesitter parsing process 10 | vim.treesitter.start() 11 | -------------------------------------------------------------------------------- /dotfiles/.config/nvim/lua/plugins/nvim-lint.lua: -------------------------------------------------------------------------------- 1 | -- Module to configure the plugin which handles the various linters used with the editor 2 | 3 | return { 4 | "mfussenegger/nvim-lint", 5 | event = { "BufReadPre", "InsertLeave", "BufNewFile", "LspAttach" }, 6 | config = function() 7 | require("lint").linters_by_ft = { 8 | lua = { "selene" }, 9 | sh = { "shellcheck" }, 10 | python = { "ruff", "mypy" }, 11 | ["yaml.ansible"] = { "ansible-lint", "yamllint" }, 12 | yaml = { "yamllint" }, 13 | } 14 | end, 15 | } 16 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | 3 | updates: 4 | - package-ecosystem: "github-actions" 5 | directory: "/" 6 | schedule: 7 | interval: "daily" 8 | time: "06:00" 9 | timezone: "Asia/Kolkata" 10 | commit-message: 11 | prefix: "🔀" 12 | labels: 13 | - "dependencies" 14 | 15 | - package-ecosystem: "pip" 16 | directory: "/" 17 | schedule: 18 | interval: "daily" 19 | time: "06:00" 20 | timezone: "Asia/Kolkata" 21 | commit-message: 22 | prefix: "🔀" 23 | labels: 24 | - "dependencies" 25 | -------------------------------------------------------------------------------- /dotfiles/.vim/vimrc: -------------------------------------------------------------------------------- 1 | set background=dark 2 | set nocp 3 | set clipboard=unnamed 4 | set wildmenu 5 | set backspace=indent,eol,start 6 | set gdefault 7 | set encoding=utf-8 nobomb 8 | set number relativenumber 9 | set tabstop=2 10 | set hlsearch incsearch 11 | set ignorecase 12 | set noerrorbells 13 | set nostartofline 14 | set ruler 15 | set shortmess=atI 16 | set showcmd 17 | set scrolloff=6 18 | 19 | inoremap jk 20 | nnoremap :write! 21 | nnoremap :ggVG 22 | nnoremap 23 | nnoremap 24 | 25 | syntax on 26 | 27 | colorscheme slate 28 | -------------------------------------------------------------------------------- /dotfiles/.config/nvim/lua/highlights.lua: -------------------------------------------------------------------------------- 1 | -- Custom highlights to override the highlights set by whatever colorscheme is used 2 | -- at any given moment 3 | 4 | local M = {} 5 | 6 | M.setup = function() 7 | -- Apply a black border around the completion menu 8 | vim.api.nvim_set_hl(0, "BlinkCmpMenuBorder", { fg = "#000000" }) 9 | 10 | -- Apply whitish foreground to the selected item in the completion menu and a darker 11 | -- background to the background for better visibility 12 | vim.api.nvim_set_hl(0, "BlinkCmpMenuSelection", { fg = "#dce0dc", bg = "#434543", bold = true }) 13 | end 14 | 15 | return M 16 | -------------------------------------------------------------------------------- /dotfiles/.zsh/functions: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env zsh 2 | 3 | # This script contains a bunch of utility functions to make life on the terminal easier 4 | 5 | # Create a directory and then "cd" into 6 | mkc() { 7 | if [[ -n "$1" ]]; then 8 | mkdir --parents "$1" && cd "$1" 9 | else 10 | echo "usage: mkc " 11 | fi 12 | } 13 | 14 | # Stop and remove a running Docker Container 15 | dcs() { 16 | if [[ -n "$1" ]]; then 17 | docker container stop $1 18 | docker container remove $1 --volumes 19 | else 20 | echo "usage: dcs " 21 | fi 22 | } 23 | -------------------------------------------------------------------------------- /dotfiles/.config/nvim/lua/plugins/colorscheme.lua: -------------------------------------------------------------------------------- 1 | return { 2 | "comfysage/evergarden", 3 | priority = 1000, 4 | opts = { 5 | theme = { 6 | variant = "fall", 7 | accent = "green", 8 | }, 9 | editor = { 10 | transparent_background = false, 11 | sign = { color = "none" }, 12 | float = { 13 | color = "mantle", 14 | invert_border = true, 15 | }, 16 | completion = { 17 | color = "surface0", 18 | }, 19 | }, 20 | integrations = { 21 | blink_cmp = true, 22 | gitsigns = true, 23 | telescope = true, 24 | }, 25 | }, 26 | } 27 | -------------------------------------------------------------------------------- /dotfiles/.ssh/config: -------------------------------------------------------------------------------- 1 | # Configurations for all other remote servers 2 | Host * 3 | AddKeysToAgent yes 4 | IdentitiesOnly yes 5 | PreferredAuthentications publickey 6 | Compression yes 7 | HashKnownHosts yes 8 | StrictHostKeyChecking ask 9 | ServerAliveInterval 20 10 | ServerAliveCountMax 3 11 | TCPKeepAlive yes 12 | PasswordAuthentication no 13 | 14 | # Configurations for SSH functionality on GitHub 15 | Host github.com 16 | HostName github.com 17 | User Jarmos-san 18 | IdentityFile ~/.ssh/id_ed25519 19 | 20 | Host plane 21 | HostName 130.61.29.84 22 | User ubuntu 23 | IdentityFile ~/.ssh/id_ed25519 24 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false 2 | 3 | contact_links: 4 | - name: Community Support 5 | url: https://github.com/Jarmos-san/dotfiles/discussions 6 | about: Please ask and answer questions here. 7 | 8 | - name: Report Issues and/or Bugs 9 | url: https://github.com/Jarmos-san/dotfiles/issues 10 | about: Please report bugs & other issues here. 11 | 12 | - name: Security Policy 13 | url: https://github.com/Jarmos-san/dotfiles/security/policy 14 | about: 15 | Refer to the Security Policy to report security vulnerabilities or if you 16 | would like to know about how your personal information is used. 17 | -------------------------------------------------------------------------------- /dotfiles/.config/gh/config.yml: -------------------------------------------------------------------------------- 1 | version: 1 2 | 3 | # What protocol to use when performing git operations. Supported values: ssh, https 4 | git_protocol: ssh 5 | 6 | # What editor gh should run when creating issues, pull requests, etc. If blank, will 7 | # refer to environment. 8 | editor: nvim 9 | 10 | # When to interactively prompt. This is a global config that cannot be overridden by 11 | # hostname. Supported values: enabled, disabled 12 | prompt: enabled 13 | 14 | # A pager program to send command output to, e.g. "less". Set the value to "cat" to 15 | # disable the pager. 16 | pager: bat 17 | 18 | # Aliases allow you to create nicknames for gh commands 19 | aliases: 20 | co: pr checkout 21 | -------------------------------------------------------------------------------- /dotfiles/.homebrew/linux.Brewfile: -------------------------------------------------------------------------------- 1 | tap "eth-p/software" 2 | tap "go-task/tap" 3 | tap "homebrew/bundle" 4 | tap "xo/xo" 5 | tap "hashicorp/tap" 6 | 7 | brew "gcc" 8 | brew "btop" 9 | brew "cmatrix" 10 | brew "eza" 11 | brew "gcc@11" 12 | brew "gh" 13 | brew "httpie" 14 | brew "jq" 15 | brew "node" 16 | brew "neovim" 17 | brew "poetry" 18 | brew "pre-commit" 19 | brew "ripgrep" 20 | brew "selene" 21 | brew "starship" 22 | brew "vim" 23 | brew "zsh" 24 | brew "eth-p/software/bat-extras-batdiff" 25 | brew "go-task/tap/go-task" 26 | brew "xo/xo/usql" 27 | brew "hashicorp/tap/terraform" 28 | brew "hashicorp/tap/packer" 29 | brew "pnpm" 30 | brew "webp" 31 | brew "azure-cli" 32 | brew "tmux" 33 | brew "ansible" 34 | brew "typst" 35 | brew "uv" 36 | -------------------------------------------------------------------------------- /dotfiles/.config/nvim/lua/plugins/notify.lua: -------------------------------------------------------------------------------- 1 | -- Module for configuring the notifications plugin 2 | 3 | return { 4 | -- UI plugin for showing notifications appropriately instead of taking up the message space 5 | "rcarriga/nvim-notify", 6 | event = "VeryLazy", 7 | init = function() 8 | -- Set Neovim to use 24-bit colours 9 | vim.opt.termguicolors = true 10 | end, 11 | config = function() 12 | local notify = require("notify") 13 | 14 | notify.setup({ 15 | -- Configure the plugin to fade in/out w/o distractions 16 | stages = "fade", 17 | 18 | -- Add a "transparent" background to stop the plugin from complaining too much 19 | background_colour = "#000000", 20 | }) 21 | 22 | vim.notify = notify 23 | end, 24 | } 25 | -------------------------------------------------------------------------------- /dotfiles/.config/nvim/luasnippets/vue.lua: -------------------------------------------------------------------------------- 1 | local luasnip = require("luasnip") 2 | local snippet = luasnip.snippet 3 | local insert_node = luasnip.insert_node 4 | local fmt = require("luasnip.extras.fmt").fmt 5 | 6 | return { 7 | -- Snippet to create the script template 8 | snippet( 9 | { trig = "script", desc = "Create a script block" }, 10 | fmt( 11 | [[ 12 | 15 | ]], 16 | { insert_node(1, "") } 17 | ) 18 | ), 19 | 20 | -- Snippet for creating the style template 21 | snippet( 22 | { trig = "style", desc = "Create a style template block" }, 23 | fmt( 24 | [[ 25 | 28 | ]], 29 | { insert_node(1, "") } 30 | ) 31 | ), 32 | } 33 | -------------------------------------------------------------------------------- /dotfiles/.config/nvim/lsp/dockerls.lua: -------------------------------------------------------------------------------- 1 | return { 2 | cmd = { "docker-langserver", "--stdio" }, 3 | filetypes = { "dockerfile" }, 4 | root_markers = { "Dockerfile" }, 5 | settings = { 6 | docker = { 7 | languageServer = { 8 | formatter = { 9 | ignoreMultilineInstructions = false, 10 | }, 11 | diagnostics = { 12 | deprecatedMaintainer = "warning", 13 | directiveCasing = "warning", 14 | emptyContinuationLine = "error", 15 | instructionCasing = "error", 16 | instructionCmdMultiple = "error", 17 | instructionEntrypointMultiple = "error", 18 | instructionHealthcheckMultiple = "error", 19 | instructionJSONInSingleQuotes = "error", 20 | }, 21 | }, 22 | }, 23 | }, 24 | } 25 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Common settings that generally should always be used with your language specific settings 2 | 3 | # Auto detect text files and perform LF normalization 4 | * text=auto 5 | 6 | # 7 | # The above will handle all files NOT found below 8 | # 9 | 10 | # Documents 11 | *.bibtex text diff=bibtex 12 | *.doc diff=astextplain 13 | *.DOC diff=astextplain 14 | *.docx diff=astextplain 15 | *.DOCX diff=astextplain 16 | *.dot diff=astextplain 17 | *.DOT diff=astextplain 18 | *.pdf diff=astextplain 19 | *.PDF diff=astextplain 20 | *.rtf diff=astextplain 21 | # Basic .gitattributes for a Vim repo. 22 | # Vim on Linux works with LF only, Vim on Windows works with both LF and CRLF 23 | 24 | # Source files 25 | # ============ 26 | *.vim text eol=lf 27 | .vimrc text eol=lf 28 | .gvimrc text eol=lf 29 | -------------------------------------------------------------------------------- /dotfiles/.config/nvim/skeletons/editorconfig.txt: -------------------------------------------------------------------------------- 1 | # EditorConfig is awesome: https://EditorConfig.org 2 | 3 | # top-most EditorConfig file 4 | root = true 5 | 6 | # Unix-style newlines with a newline ending every file 7 | [*] 8 | end_of_line = lf 9 | insert_final_newline = true 10 | 11 | # Matches multiple files with brace expansion notation 12 | # Set default charset 13 | [*.{js,py}] 14 | charset = utf-8 15 | 16 | # 4 space indentation 17 | [*.py] 18 | indent_style = space 19 | indent_size = 4 20 | 21 | # Tab indentation (no size specified) 22 | [Makefile] 23 | indent_style = tab 24 | 25 | # Indentation override for all JS under lib directory 26 | [lib/**.js] 27 | indent_style = space 28 | indent_size = 2 29 | 30 | # Matches the exact files either package.json or .travis.yml 31 | [{package.json,.travis.yml}] 32 | indent_style = space 33 | indent_size = 2 34 | -------------------------------------------------------------------------------- /.github/stale.yml: -------------------------------------------------------------------------------- 1 | # Number of days of inactivity before an issue becomes stale 2 | daysUntilStale: 20 3 | 4 | # Number of days of inactivity before a stale issue is closed 5 | daysUntilClose: 7 6 | 7 | # Issues with these labels will never be considered stale 8 | exemptLabels: 9 | - pinned 10 | 11 | # Label to use when marking an issue as stale 12 | staleLabel: stale 13 | 14 | # Comment to post when marking an issue as stale. Set to `false` to disable 15 | markComment: > 16 | This issue has been automatically marked as stale because it has not had 17 | recent activity. It will be closed within a week if no further activity 18 | occurs. Thank you for your contributions. 19 | 20 | # Comment to post when closing a stale issue. Set to `false` to disable 21 | closeComment: > 22 | This thread will now be closed since it hasn't seen any activity for a week. 23 | -------------------------------------------------------------------------------- /.github/workflows/auto-dependabot.yaml: -------------------------------------------------------------------------------- 1 | name: Dependabot Auto-Merge 2 | 3 | on: pull_request 4 | 5 | permissions: 6 | contents: write 7 | pull-requests: write 8 | 9 | jobs: 10 | dependabot: 11 | name: Dependabot 12 | runs-on: ubuntu-latest 13 | if: github.event.pull_request.user.login == 'dependabot[bot]' 14 | steps: 15 | - name: Fetch Dependabot Metadata 16 | id: metadata 17 | uses: dependabot/fetch-metadata@v2.4.0 18 | with: 19 | github-token: "${{ secrets.GITHUB_TOKEN }}" 20 | 21 | - name: Enable Auto-Merge 22 | if: 23 | contains(steps.metadata.outputs.dependency-names, 'dependencies') && 24 | steps.metadata.outputs.update-type == 'version-update:semver-patch' 25 | env: 26 | PR_URL: ${{github.event.pull_request.html_url}} 27 | GH_TOKEN: ${{secrets.GITHUB_TOKEN}} 28 | run: gh pr merge --auto --merge "$PR_URL" 29 | -------------------------------------------------------------------------------- /dotfiles/.config/nvim/after/ftplugin/vue.lua: -------------------------------------------------------------------------------- 1 | -- Folding configurations for Neovim 2 | if vim.api.nvim_buf_line_count(0) >= 100 then 3 | vim.o.foldmethod = "expr" -- Allow folding using the "nvim-treesitter" plugin 4 | vim.o.foldexpr = "nvim_treesitter#foldexpr()" -- Configure the folding algorithm to be from the plugin 5 | vim.o.foldlevel = 0 -- Configure the maximum indenting for the folding 6 | end 7 | 8 | vim.treesitter.start() 9 | 10 | -- TODO: Move this autocommand to its own module/package 11 | vim.api.nvim_create_autocmd("CursorHold", { 12 | buffer = vim.api.nvim_get_current_buf(), 13 | callback = function() 14 | local hover_window_configs = { 15 | focusable = false, 16 | close_events = { "BufLeave", "CursorMoved", "InsertEnter", "FocusLost" }, 17 | border = "rounded", 18 | source = "always", 19 | prefix = " ", 20 | scope = "cursor", 21 | } 22 | 23 | vim.diagnostic.open_float(nil, hover_window_configs) 24 | end, 25 | }) 26 | -------------------------------------------------------------------------------- /dotfiles/.config/nvim/lsp/astro.lua: -------------------------------------------------------------------------------- 1 | local get_typescript_server_path = function(root_dir) 2 | local project_roots = vim.fs.find("node_modules", { path = root_dir, upward = true, limit = math.huge }) 3 | for _, project_root in ipairs(project_roots) do 4 | local typescript_path = project_root .. "/typescript" 5 | local stat = vim.loop.fs_stat(typescript_path) 6 | if stat and stat.type == "directory" then 7 | return typescript_path .. "/lib" 8 | end 9 | end 10 | return "" 11 | end 12 | 13 | return { 14 | before_init = function(_, config) 15 | if config.init_options and config.init_options.typescript and not config.init_options.typescript.tsdk then 16 | config.init_options.typescript.tsdk = get_typescript_server_path(config.root_dir) 17 | end 18 | end, 19 | cmd = { "astro-ls", "--stdio" }, 20 | filetypes = { "astro" }, 21 | init_options = { 22 | typescript = {}, 23 | }, 24 | root_markers = { "package.json", "tsconfig.json", "jsconfig.json", ".git" }, 25 | } 26 | -------------------------------------------------------------------------------- /dotfiles/.config/nvim/after/ftplugin/go.lua: -------------------------------------------------------------------------------- 1 | -- Module for configuring Golang filetypes 2 | 3 | local autocmd = require("utils").autocmd 4 | local augroup = require("utils").augroup 5 | local map = require("utils").map 6 | 7 | autocmd("BufWritePost", { 8 | desc = "Format the buffer contents after save", 9 | group = augroup("format_go_files"), 10 | callback = function() 11 | require("lint").try_lint() 12 | end, 13 | }) 14 | 15 | map("n", "", "terminal go run %") 16 | 17 | -- Configure the indent-based folds for Go buffers 18 | if vim.api.nvim_buf_line_count(0) >= 100 then 19 | vim.opt.foldmethod = "expr" 20 | vim.opt.foldexpr = "nvim_treesitter#foldexpr()" 21 | vim.opt.foldlevel = 0 -- Start with folds closed 22 | vim.opt.foldcolumn = "auto" -- Show fold indicators on the left margin 23 | vim.opt.foldnestmax = 99 -- Maximum depth of folds 24 | end 25 | 26 | -- Start the Treesitter parsing process 27 | vim.treesitter.start() 28 | 29 | -- Start the "gopls" LSP server 30 | vim.lsp.enable("gopls", true) 31 | -------------------------------------------------------------------------------- /dotfiles/.config/nvim/luasnippets/lua.lua: -------------------------------------------------------------------------------- 1 | local luasnip = require("luasnip") 2 | local snippet = luasnip.snippet 3 | local insert_node = luasnip.insert_node 4 | local fmt = require("luasnip.extras.fmt").fmt 5 | 6 | return { 7 | snippet( 8 | { trig = "func", desc = "Create a Lua function" }, 9 | fmt( 10 | [[ 11 | local {1} = function({2}) 12 | {3} 13 | end 14 | ]], 15 | { 16 | insert_node(1, "function_name"), 17 | insert_node(2, "args"), 18 | insert_node(3, ""), 19 | } 20 | ) 21 | ), 22 | 23 | snippet( 24 | { trig = "req", desc = "Create a require statement" }, 25 | fmt( 26 | [[ 27 | local {1} = require('{2}') 28 | ]], 29 | { insert_node(1, ""), insert_node(2, "module_name") } 30 | ) 31 | ), 32 | 33 | snippet( 34 | { trig = "if", desc = "Create an if statement" }, 35 | fmt( 36 | [[ 37 | if {1} then 38 | {2} 39 | end 40 | ]], 41 | { insert_node(1, "condition"), insert_node(2, "body") } 42 | ) 43 | ), 44 | } 45 | -------------------------------------------------------------------------------- /.github/SUPPORT.md: -------------------------------------------------------------------------------- 1 | # Dotfiles 2 | 3 | This repository hosts a couple of shell scripts for automating setting up a 4 | fresh new development environment on a system. Refer to the 5 | [README](../README.md) for more information on what all will be downloaded & 6 | installed on to your machine _automatically_. 7 | 8 | ## Contributing 9 | 10 | Please read [CONTRIBUTING](./CONTRIBUTING.md) guidelines for details on our code 11 | of conduct, and the process for submitting pull requests to us. 12 | 13 | ## Versioning 14 | 15 | The project is always under development & ever-changing according to my needs & 16 | requirements. Hence, I decided to not include versioning for the project, as 17 | such it's always tagged as `latest`. 18 | 19 | ## Authors 20 | 21 | - **Somraj Saha** - [Jarmos-san](https://github.com/jarmos-san) 22 | 23 | See also the list of 24 | [contributors](https://github.com/jarmos-san/dotfiles/contributors) who 25 | participated in this project. 26 | 27 | ## License 28 | 29 | This project is licensed under the GNU GPLv3.0 License - see the 30 | [LICENSE.md](./../LICENSE) file for details 31 | -------------------------------------------------------------------------------- /dotfiles/.config/nvim/after/ftplugin/typescript.lua: -------------------------------------------------------------------------------- 1 | -- Start the Treesitter parsing process for TypeScript files 2 | vim.treesitter.start() 3 | 4 | -- Folding configurations for Neovim 5 | if vim.api.nvim_buf_line_count(0) >= 100 then 6 | vim.o.foldmethod = "expr" -- Allow folding using the "nvim-treesitter" plugin 7 | vim.o.foldexpr = "nvim_treesitter#foldexpr()" -- Configure the folding algorithm to be from the plugin 8 | vim.o.foldlevel = 1 -- Configure the maximum indenting for the folding 9 | end 10 | 11 | vim.diagnostic.config({ virtual_text = true }) 12 | 13 | -- TODO: Move this autocommand to its own module/package 14 | vim.api.nvim_create_autocmd("CursorHold", { 15 | buffer = vim.api.nvim_get_current_buf(), 16 | callback = function() 17 | local hover_window_configs = { 18 | focusable = false, 19 | close_events = { "BufLeave", "CursorMoved", "InsertEnter", "FocusLost" }, 20 | border = "rounded", 21 | source = "always", 22 | prefix = " ", 23 | scope = "cursor", 24 | } 25 | 26 | vim.diagnostic.open_float(nil, hover_window_configs) 27 | end, 28 | }) 29 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018-Present Somraj Saha and contributors 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /dotfiles/.config/nvim/lua/tansai.lua: -------------------------------------------------------------------------------- 1 | local M = {} 2 | 3 | -- Alias to the API for setting the syntax highlights 4 | local hl = vim.api.nvim_set_hl 5 | 6 | -- Table of colours 7 | local colours = { 8 | none = "none", 9 | grey = "#45413d", 10 | light_grey = "#6e6c69", 11 | white = "#ffffff", 12 | black = "#000000", 13 | blue = "blue", 14 | } 15 | 16 | M.load = function() 17 | -- Clear any syntax highlighting (if any) that exists 18 | if vim.g.colors_name then 19 | vim.cmd.hi("clear") 20 | end 21 | 22 | -- Set some basic configuration options for Neovim 23 | vim.g.colors_name = "tansai" 24 | vim.o.termguicolors = true 25 | vim.o.background = "dark" 26 | 27 | -- Basic highlighting unrelated to code (or syntax) highlights 28 | hl(0, "Normal", { bg = colours.none, fg = colours.none }) 29 | hl(0, "NonText", { bg = colours.none, fg = colours.none }) 30 | hl(0, "CursorLine", { bg = colours.grey, fg = colours.none }) 31 | hl(0, "CursorLineNr", { bg = colours.grey, fg = colours.white }) 32 | hl(0, "LineNr", { bg = colours.none, fg = colours.grey }) 33 | hl(0, "Comment", { bg = colours.none, fg = colours.light_grey }) 34 | end 35 | 36 | return M 37 | -------------------------------------------------------------------------------- /dotfiles/.config/nvim/skeletons/license.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Somraj Saha 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /.github/SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | **For any security concerns please refer to this.** 4 | 5 | This repository hosts the Shell scripts I use to handle creation/manipulation of 6 | the dotfiles on my personal development machines. When executed they download 7 | certain applications from the Internet & perform certain file manipulations. 8 | Hence use the scripts from this repository with discretion. The owner of this 9 | repository will not be held responsible for any damage and/or unintended actions 10 | to your personal development machine. 11 | 12 | But, if you're willing to use the scripts from this repository & find a bug or 13 | two, please report it to the owner immediately. You can drop an email or leave 14 | him a tweet at--[@Jarmosan](https:twitter.com/jarmosan). 15 | 16 | You can also open a PR if you think there's an urgent security concern. Please 17 | refer to the [Contributing Guidelines](./CONTRIBUTING.md) on how to contribute 18 | to the project. 19 | 20 | **_WARNING_**: Use the contents of this repository with care. They can change 21 | and/or manipulate stuff in your filesystem. **So know what you're doing before 22 | cloning this repository & using the scripts in it!** 23 | -------------------------------------------------------------------------------- /dotfiles/.config/nvim/lua/plugins/smartcolumn.lua: -------------------------------------------------------------------------------- 1 | -- Module for configuring the colour column smartly 2 | 3 | return { 4 | "m4xshen/smartcolumn.nvim", 5 | event = "BufRead", 6 | opts = { 7 | disabled_filetypes = { 8 | "caddy", 9 | "checkhealth", 10 | "conf", 11 | "dosini", 12 | "dotenv", 13 | "gitattributes", 14 | "gitcommit", 15 | "gitconfig", 16 | "gitignore", 17 | "gitrebase", 18 | "gosum", 19 | "help", 20 | "json", 21 | "markdown", 22 | "mason", 23 | "mdx", 24 | "netrw", 25 | "lazy", 26 | "log", 27 | "lspinfo", 28 | "scss", 29 | "sh", 30 | "ministarter", 31 | "mermaid", 32 | "terraform", 33 | "text", 34 | "Trouble", 35 | "tmux", 36 | "toml", 37 | "typst", 38 | "zsh", 39 | }, 40 | custom_colorcolumn = { 41 | lua = "120", 42 | dockerfile = "120", 43 | python = "88", 44 | yaml = "90", 45 | markdown = "80", 46 | typescriptreact = "81", 47 | rust = "100", 48 | go = "88", 49 | hcl = "120", 50 | jsonc = "90", 51 | vue = "89", 52 | }, 53 | }, 54 | } 55 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug-report.yml: -------------------------------------------------------------------------------- 1 | name: Bug Report 2 | description: File a bug report 3 | title: "[Bug]: " 4 | labels: ["bug"] 5 | assignees: 6 | - Jarmos-san 7 | body: 8 | - type: markdown 9 | attributes: 10 | value: | 11 | Thanks for taking the time to fill out this bug report! 12 | - type: textarea 13 | id: what-happened 14 | attributes: 15 | label: Explain the Bug 16 | description: 17 | Explain in details the bug you encountered and the expected behaviour. 18 | placeholder: Explain the bug and the intended behaviour in detail. 19 | value: "A bug happened!" 20 | validations: 21 | required: true 22 | - type: textarea 23 | id: logs 24 | attributes: 25 | label: Relevant log output 26 | description: 27 | Please copy and paste any relevant log output. This will be 28 | automatically formatted into code, so no need for backticks. 29 | render: Shell 30 | - type: textarea 31 | id: screenshots 32 | attributes: 33 | label: Share relevant screenshots, if possible 34 | description: 35 | Please share a screenshot or two, if possible for us to better 36 | understand the issue. 37 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | # Pull Request Template 2 | 3 | ## Description 4 | 5 | Please include a comprehensive summary of the change & how does the changes 6 | help. Also include relevant motivation and context. List any dependencies that 7 | are required for this change. 8 | 9 | ## Type of change 10 | 11 | Please delete options that are not relevant. 12 | 13 | - [ ] Bug fix (non-breaking change which fixes an issue) 14 | - [ ] New feature (non-breaking change which adds functionality) 15 | - [ ] Breaking change (fix or feature that would cause existing functionality to 16 | not work as expected) 17 | - [ ] This change requires a documentation update 18 | 19 | ## Is it Tested 20 | 21 | Have you tested it before making a PR? 22 | 23 | Does it work flawlessly on a Ubuntu Machine? 24 | 25 | - [ ] Yes 26 | - [ ] No 27 | 28 | **Test Configuration(s)**: 29 | 30 | - Ubuntu version: 31 | - Bash version: 32 | - Windows version: 33 | 34 | ## Checklist 35 | 36 | - [ ] My code follows the style guidelines of this project 37 | - [ ] I have performed a self-review of my own code 38 | - [ ] I have commented my code, particularly in hard-to-understand areas 39 | - [ ] My changes generate no new warnings 40 | - [ ] I have checked my code and corrected any misspellings 41 | -------------------------------------------------------------------------------- /dotfiles/.config/nvim/lua/plugins/lualine.lua: -------------------------------------------------------------------------------- 1 | -- Module for configuring the statusline plugin - "lualine" 2 | 3 | return { 4 | "nvim-lualine/lualine.nvim", 5 | -- This needs to be loaded after the "VeryLazy" event otherwise an ugly 6 | -- unstyled statusline is created after Neovim startup 7 | event = "VeryLazy", 8 | opts = { 9 | -- Leaving an empty table renders the square-edged components, else the default angled ones are loaded 10 | section_separators = {}, 11 | component_separator = "|", 12 | theme = "gruvbox", 13 | disabled_filetypes = { 14 | statusline = { 15 | "dashboard", 16 | "filesytem", 17 | "mason", 18 | "neo-tree", 19 | "neo-tree-popup", 20 | "null-ls-info", 21 | "lazy", 22 | "lspinfo", 23 | "ministarter", 24 | "TelescopePrompt", 25 | }, 26 | }, 27 | }, 28 | config = function(_, opts) 29 | local sections = { 30 | -- Statusline components to showcase on the right-most end 31 | lualine_x = { "filetype" }, 32 | lualine_y = { "progress" }, 33 | lualine_z = { "location" }, 34 | lualine_c = { -- INFO: This section shows the entire filepath relative to the project root 35 | { "filename", path = 1 }, 36 | }, 37 | } 38 | 39 | require("lualine").setup({ options = opts, sections = sections }) 40 | end, 41 | disable = true, 42 | } 43 | -------------------------------------------------------------------------------- /dotfiles/.config/nvim/lsp/lua_ls.lua: -------------------------------------------------------------------------------- 1 | -- Configurations for the "lua_ls" LSP server for Lua files 2 | return { 3 | cmd = { "lua-language-server" }, 4 | filetypes = { "lua" }, 5 | root_markers = { 6 | ".luarc.json", 7 | ".luarc.jsonc", 8 | ".luacheckrc", 9 | ".stylua.toml", 10 | "stylua.toml", 11 | "selene.toml", 12 | "selene.yml", 13 | ".git", 14 | }, 15 | on_init = function(client) 16 | if client.workspace_folders then 17 | local path = client.workspace_folders[1].name 18 | 19 | if 20 | path ~= vim.fn.stdpath("config") 21 | and (vim.uv.fs_stat(path .. "/.luarc.json") or vim.uv.fs_stat(path .. "/.luarc.jsonc")) 22 | then 23 | return 24 | end 25 | end 26 | 27 | client.config.settings.Lua = vim.tbl_deep_extend("force", client.config.settings.Lua, { 28 | runtime = { 29 | version = "LuaJIT", 30 | path = vim.split(package.path, ";"), 31 | }, 32 | path = { "lua/?.lua", "lua/?/init.lua" }, 33 | workspace = { 34 | checkThirdParty = false, 35 | library = { 36 | vim.env.VIMRUNTIME, 37 | }, 38 | }, 39 | diagnostics = { 40 | globals = { "vim" }, 41 | enable = true, 42 | }, 43 | format = { enable = false }, 44 | telemetry = { 45 | enable = false, 46 | }, 47 | }) 48 | end, 49 | settings = { 50 | Lua = {}, 51 | }, 52 | } 53 | -------------------------------------------------------------------------------- /dotfiles/.config/nvim/filetype.lua: -------------------------------------------------------------------------------- 1 | -- Module for defining new filetypes. I picked up these configurations based on inspirations from this dotfiles repo: 2 | -- https://github.com/davidosomething/dotfiles/blob/be22db1fc97d49516f52cef5c2306528e0bf6028/nvim/lua/dko/filetypes.lua 3 | 4 | vim.filetype.add({ 5 | -- Detect and assign filetype based on the extension of the filename 6 | extension = { 7 | astro = "astro", 8 | mdx = "markdown", 9 | log = "log", 10 | conf = "conf", 11 | env = "dotenv", 12 | }, 13 | -- Detect and apply filetypes based on the entire filename 14 | filename = { 15 | [".env"] = "dotenv", 16 | ["env"] = "dotenv", 17 | ["tsconfig.json"] = "jsonc", 18 | ["cloudbeaver.conf"] = "jsonc", 19 | ["playbook.yml"] = "yaml.ansible", 20 | ["site.yml"] = "yaml.ansible", 21 | }, 22 | -- Detect and apply filetypes based on certain patterns of the filenames 23 | pattern = { 24 | -- INFO: Match filenames like - ".env.example", ".env.local" and so on 25 | ["%.env%.[%w_.-]+"] = "dotenv", 26 | [".*/ansible/.*%.ya?ml"] = "yaml.ansible", -- Match all YAML files under the "ansible" directory 27 | [".*/roles/.*%.ya?ml"] = "yaml.ansible", 28 | [".*/ansible/.*%.ya?ml%.j2"] = "yaml", -- Ansible template should be considered YAML files 29 | [".*/*.conf*"] = "conf", -- Config files (like "postgresql.conf" and so on) 30 | [".*/Caddyfile%.?.*"] = "caddy", -- Match files like "Caddyfile", "Caddyfile.j2", "Caddyfile.tmpl" 31 | }, 32 | }) 33 | -------------------------------------------------------------------------------- /dotfiles/.config/nvim/lsp/pyright.lua: -------------------------------------------------------------------------------- 1 | return { 2 | cmd = { "pyright-langserver", "--stdio" }, 3 | filetypes = { "pyright-langserver", "--stdio" }, 4 | root_markes = { 5 | "pyproject.toml", 6 | "setup.py", 7 | "setup.cfg", 8 | "requirements.txt", 9 | "Pipfile", 10 | "pyrightconfig.json", 11 | ".git", 12 | }, 13 | settings = { 14 | python = { 15 | analysis = { 16 | autoSearchPaths = true, 17 | diagnosticMode = "openFilesOnly", 18 | useLibraryCodeForTypes = true, 19 | }, 20 | }, 21 | }, 22 | on_attach = function(client, bufnr) 23 | vim.api.nvim_buf_create_user_command(bufnr, "LspPyrightOrganizeImports", function() 24 | client:exec_cmd({ 25 | command = "pyright.oganizeimports", 26 | arguments = vim.url_from_bufnr(bufnr), 27 | }) 28 | end, { 29 | desc = "Organize Python Imports", 30 | }) 31 | 32 | vim.api.nvim_buf_create_user_command(bufnr, "LspPyrightSetPythonPath", function(path) 33 | if client.settings then 34 | client.settings.python = vim.tbl_deep_extend("force", client.settings.python, { pythonPath = path }) 35 | else 36 | client.config.settings = 37 | vim.tbl_deep_extend("force", client.config.settings, { python = { pythonPath = path } }) 38 | end 39 | vim.notify("workspace/didChangeConfiguration", { settings = nil }) 40 | end, { desc = "Reconfigure Pyright with provided Python path", nargs = 1, complete = "file" }) 41 | end, 42 | } 43 | -------------------------------------------------------------------------------- /dotfiles/.config/tmux/statusline/statusline.conf: -------------------------------------------------------------------------------- 1 | ### General Statusline Settings ### 2 | # Enable the status bar 3 | set -g status on 4 | 5 | # Set the statusline to be rendered at the top of the screen and justified centred 6 | set -g status-position top 7 | set -g status-justify centre 8 | 9 | # Refresh the statusline every 5 seconds 10 | set -g status-interval 5 11 | 12 | # Set the background of the statusline to be of a darker shade of black 13 | set -g status-bg "#000000" 14 | 15 | # Set fixed width for the left and right-most sections 16 | set -g status-left-length 100 17 | set -g status-right-length 100 18 | 19 | # Configure left sections 20 | set -g status-left "\ 21 | #[bg=#27215d,fg=#e7e6e9]  #H #[fg=#868190](#(uptime --pretty)) \ 22 | #{?#{==:#S,dotfiles},#[bg=#223a7d#,fg=#e7e6ed]  #S,} \ 23 | #[bg=#3c5397,fg=#e7e6e9]  #I:#P \ 24 | " 25 | 26 | # Active window 27 | set -g window-status-current-format "\ 28 | #[bg=#a6cfd5,fg=#111515] #I: 󰐨 #W \ 29 | #[default] \ 30 | " 31 | 32 | # Configure the right section 33 | set -g status-right "\ 34 | #[bg=#3c5397,fg=#e7e6e9] #(~/.config/tmux/statusline/battery-status) \ 35 | #[bg=#223a7d#,fg=#e7e6ed]  #(TZ="Asia/Kolkata" date "+%%H:%%M") IST |\ 36 | #[bg=#223a7d#,fg=#e7e6ed]  #(TZ="Europe/Sofia" date "+%%H:%%M") EET |\ 37 | #[bg=#223a7d#,fg=#e7e6ed]  #(TZ="Etc/Utc" date "+%%H:%%M") UTC \ 38 | #[bg=#27215d,fg=#e7e6e9]  %d-%b-%Y \ 39 | " 40 | 41 | # Inactive windows 42 | set -g window-status-format "\ 43 | #[fg=#868190]#I: #W \ 44 | " 45 | 46 | # vim: ft=tmux 47 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | default_install_hook_types: 2 | - pre-commit 3 | - commit-msg 4 | 5 | repos: 6 | - repo: https://github.com/pre-commit/pre-commit-hooks 7 | rev: v6.0.0 8 | hooks: 9 | - id: trailing-whitespace 10 | - id: end-of-file-fixer 11 | exclude: ^dotfiles/.config/nvim/lazy-lock.json 12 | - id: check-yaml 13 | - id: check-added-large-files 14 | - id: detect-private-key 15 | 16 | - repo: https://github.com/jumanjihouse/pre-commit-hooks 17 | rev: 3.0.0 18 | hooks: 19 | - id: shfmt 20 | name: format shell scripts 21 | args: 22 | - "--indent=2" 23 | - "--case-indent" 24 | - "--binary-next-line" 25 | - "--space-redirects" 26 | - "--keep-padding" 27 | 28 | - repo: https://github.com/JohnnyMorganz/StyLua 29 | rev: v2.3.1 30 | hooks: 31 | - id: stylua 32 | name: format lua files 33 | 34 | - repo: https://github.com/astral-sh/ruff-pre-commit 35 | rev: v0.14.9 36 | hooks: 37 | - id: ruff 38 | name: format/lint python files 39 | args: [--fix, --exit-non-zero-on-fix] 40 | 41 | - repo: https://github.com/pre-commit/mirrors-mypy 42 | rev: v1.19.0 43 | hooks: 44 | - id: mypy 45 | name: type check python files 46 | 47 | # TODO: Add a pre-commit hook for Selene 48 | 49 | - repo: https://github.com/Weburz/crisp 50 | rev: v1.0.0 51 | hooks: 52 | - id: crisp 53 | name: lint commit messages 54 | -------------------------------------------------------------------------------- /dotfiles/.config/nvim/lua/plugins/telescope.lua: -------------------------------------------------------------------------------- 1 | -- Module for configuring the Telescope plugin 2 | 3 | return { 4 | "nvim-telescope/telescope.nvim", 5 | event = "BufRead", 6 | cmd = "Telescope", 7 | opts = { 8 | defaults = { 9 | file_ignore_patterns = { 10 | "%.git", 11 | "node_modules", 12 | "%.venv", 13 | "^%.?env$", 14 | "%.terraform", 15 | "%.mypy_cache", 16 | "%.ruff_cache", 17 | "%.nuxt", 18 | "%.task", 19 | "dist", 20 | "%.pyc", 21 | "%.pytest_cache", 22 | "%.vitest", 23 | "%.tsbuildinfo", 24 | "coverage", 25 | "%.data", 26 | "pip", 27 | }, 28 | }, 29 | pickers = { 30 | find_files = { 31 | find_command = { "rg", "--files", "--hidden", "--glob", "!**/.git/*", "--no-ignore" }, 32 | -- TODO: Figure a way out to make vertical splits through Telescope 33 | -- mappings = { 34 | -- i = { 35 | -- [""] = function(bufnr) 36 | -- if vim.bo[0].filetype ~= "ministarter" then 37 | -- require("telescope.actions").select_vertical(bufnr) 38 | -- end 39 | -- end, 40 | -- }, 41 | -- }, 42 | }, 43 | }, 44 | }, 45 | config = function(_, opts) 46 | require("telescope").setup(opts) 47 | end, 48 | dependencies = { 49 | "devicons", 50 | "nvim-lua/plenary.nvim", 51 | "neovim/nvim-lspconfig", 52 | "nvim-treesitter/nvim-treesitter", 53 | }, 54 | } 55 | -------------------------------------------------------------------------------- /dotfiles/.local/bin/music-sort: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | """ 4 | Script to sort local music collection. 5 | 6 | Author: Somraj Saha 7 | License: MIT License (see https://github.com/Jarmos-san/dotfiles/blob/main/LICENSE for 8 | more information) 9 | 10 | INFO: This is a WIP script, it is not ready for usage yet! 11 | """ 12 | 13 | from pathlib import Path 14 | 15 | # INFO: Labels for logging when printing to STDOUT 16 | ERROR = "\033[1;31mINFO\033[0m" 17 | SUCCESS = "\033[1;32mINFO\033[0m" 18 | WARN = "\033[1;33mINFO\033[0m" 19 | INFO = "\033[1;34mINFO\033[0m" 20 | 21 | 22 | def dir_exist(dirs: tuple[Path, Path]) -> bool: 23 | """Check whether a download location exists or not.""" 24 | # INFO: Check if any of the aforementioned downloads folder exists, if not then 25 | # short-circuit the logic and return the function 26 | for dir in dirs: 27 | if dir.exists(): 28 | return True 29 | 30 | return False 31 | 32 | 33 | def main() -> None: 34 | """Entrypoint of the script.""" 35 | # Location of the home directory where the downloads directory is supposed to be in 36 | home_dir = Path.home() 37 | 38 | # Possible sets of download locations 39 | download_dirs = (home_dir / "Downloads", home_dir / "downloads") 40 | 41 | if not dir_exist(download_dirs): 42 | print(f"[{ERROR}] No download directory found...aborting!") 43 | else: 44 | print(f"[{SUCCESS}] Download directory found...sorting music right now!") 45 | 46 | 47 | if __name__ == "__main__": 48 | try: 49 | main() 50 | except Exception as err: 51 | print(f"[{ERROR}] Sorting music collection failed!\n{err}") 52 | -------------------------------------------------------------------------------- /dotfiles/.config/nvim/lua/plugins/treesitter.lua: -------------------------------------------------------------------------------- 1 | -- Module for configuring the Treesitter plugin 2 | 3 | return { 4 | { 5 | "nvim-treesitter/nvim-treesitter", 6 | lazy = false, 7 | branch = "main", 8 | build = function() 9 | require("nvim-treesitter").update():wait(300000) 10 | end, 11 | config = function() 12 | local parsers = { 13 | -- "astro", 14 | -- "bash", 15 | -- "caddy", 16 | -- "comment", 17 | -- "css", 18 | -- "diff", 19 | -- "dockerfile", 20 | -- "editorconfig", 21 | -- "git_rebase", 22 | -- "gitattributes", 23 | -- "gitcommit", 24 | -- "gitignore", 25 | -- "go", 26 | -- "gomod", 27 | -- "gosum", 28 | -- "hcl", 29 | -- "html", 30 | -- "ini", 31 | -- "javascript", 32 | -- "jinja", 33 | -- "jinja_inline", 34 | -- "jsdoc", 35 | "json", 36 | -- "lua", 37 | -- "luadoc", 38 | -- "lua_patterns", 39 | -- "make", 40 | -- "markdown", 41 | -- "markdown_inline", 42 | -- "mermaid", 43 | "python", 44 | -- "regex", 45 | -- "robots", 46 | -- "rst", 47 | "scss", 48 | -- "terraform", 49 | -- "tsx", 50 | -- "toml", 51 | -- "typescript", 52 | -- "typst", 53 | -- "yaml", 54 | -- "vim", 55 | -- "vimdoc", 56 | "vue", 57 | } 58 | require("nvim-treesitter").setup() 59 | require("nvim-treesitter").install(parsers):wait(300000) 60 | end, 61 | -- TODO: Fix OOM issues which is crashing WSL entirely 62 | -- enabled = false, 63 | }, 64 | } 65 | -------------------------------------------------------------------------------- /dotfiles/.config/nvim/lua/plugins/cmp.lua: -------------------------------------------------------------------------------- 1 | -- Module for configuring the completion capabilities of Neovim 2 | 3 | return { 4 | "saghen/blink.cmp", 5 | version = "*", 6 | ---@module 'blink.cmp' 7 | ---@type blink.cmp.Config 8 | opts = { 9 | signature = { 10 | enabled = true, 11 | window = { 12 | border = "rounded", 13 | }, 14 | }, 15 | keymap = { 16 | preset = "enter", 17 | }, 18 | appearance = { 19 | use_nvim_cmp_as_default = false, 20 | nerd_font_variant = "mono", 21 | }, 22 | snippets = { preset = "luasnip" }, 23 | sources = { 24 | default = { "lsp", "path", "snippets" }, 25 | }, 26 | completion = { 27 | accept = { 28 | auto_brackets = { enabled = true }, 29 | }, 30 | documentation = { 31 | auto_show = true, 32 | auto_show_delay_ms = 250, 33 | treesitter_highlighting = true, 34 | window = { 35 | border = "rounded", 36 | winblend = 0, 37 | }, 38 | }, 39 | list = { 40 | selection = { 41 | preselect = function(ctx) 42 | return ctx.mode ~= "cmdline" 43 | end, 44 | auto_insert = function(ctx) 45 | return ctx.mode ~= "cmdline" 46 | end, 47 | }, 48 | }, 49 | ghost_text = { 50 | enabled = true, 51 | }, 52 | menu = { 53 | border = "rounded", 54 | winblend = 0, 55 | draw = { 56 | treesitter = { "lsp" }, 57 | columns = { 58 | { "kind_icon" }, 59 | { "label" }, 60 | { "source_name" }, 61 | }, 62 | }, 63 | }, 64 | }, 65 | }, 66 | dependencies = "L3MON4D3/LuaSnip", 67 | } 68 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by https://www.toptal.com/developers/gitignore/api/powershell,visualstudiocode,vim,git 2 | # Edit at https://www.toptal.com/developers/gitignore?templates=powershell,visualstudiocode,vim,git 3 | 4 | ### Git ### 5 | # Created by git for backups. To disable backups in Git: 6 | # $ git config --global mergetool.keepBackup false 7 | *.orig 8 | 9 | # Created by git when using merge tools for conflicts 10 | *.BACKUP.* 11 | *.BASE.* 12 | *.LOCAL.* 13 | *.REMOTE.* 14 | *_BACKUP_*.txt 15 | *_BASE_*.txt 16 | *_LOCAL_*.txt 17 | *_REMOTE_*.txt 18 | 19 | ### PowerShell ### 20 | # Exclude packaged modules 21 | *.zip 22 | 23 | # Exclude .NET assemblies from source 24 | *.dll 25 | 26 | ### Vim ### 27 | # Swap 28 | [._]*.s[a-v][a-z] 29 | !*.svg # comment out if you don't need vector files 30 | [._]*.sw[a-p] 31 | [._]s[a-rt-v][a-z] 32 | [._]ss[a-gi-z] 33 | [._]sw[a-p] 34 | 35 | # Session 36 | Session.vim 37 | Sessionx.vim 38 | 39 | # Temporary 40 | .netrwhist 41 | *~ 42 | # Auto-generated tag files 43 | tags 44 | # Persistent undo 45 | [._]*.un~ 46 | 47 | ### VisualStudioCode ### 48 | .vscode/* 49 | !.vscode/settings.json 50 | !.vscode/tasks.json 51 | !.vscode/launch.json 52 | !.vscode/extensions.json 53 | *.code-workspace 54 | 55 | # Local History for Visual Studio Code 56 | .history/ 57 | 58 | ### VisualStudioCode Patch ### 59 | # Ignore all local history of files 60 | .history 61 | .ionide 62 | 63 | .luarc.json 64 | **/gh/hosts.yml 65 | scratch 66 | .venv 67 | .mypy_cache 68 | .ruff_cache 69 | **/adb 70 | 71 | **/.config/git/credentials 72 | **/cobra-cli 73 | 74 | **/.zsh/plugins 75 | 76 | **/.local/bin 77 | !**/.local/bin/update 78 | !**/.local/bin/git-clean 79 | 80 | **/tmux/plugins/**/* 81 | # End of https://www.toptal.com/developers/gitignore/api/powershell,visualstudiocode,vim,git 82 | -------------------------------------------------------------------------------- /dotfiles/.config/nvim/lua/plugins/mason.lua: -------------------------------------------------------------------------------- 1 | -- Module for configuring the "mason" plugin for managing LSP servers 2 | 3 | return { 4 | { 5 | "mason-org/mason.nvim", 6 | cmd = { "LspInstall", "LspUninstall", "Mason" }, 7 | opts = { 8 | -- Configure the plugin to have rounded borders 9 | ui = { border = "rounded" }, 10 | 11 | -- Configure the log levels for the plugin 12 | log_level = vim.log.levels.WARN, 13 | }, 14 | config = function(_, opts) 15 | require("mason").setup(opts) 16 | end, 17 | dependencies = { "neovim/nvim-lspconfig" }, 18 | }, 19 | 20 | { 21 | "WhoIsSethDaniel/mason-tool-installer.nvim", 22 | cmd = { "MasonToolsInstall", "MasonToolsUpdate", "MasonToolsClean" }, 23 | opts = { 24 | ensure_installed = { 25 | "astro-language-server", 26 | "ansible-language-server", 27 | "ansible-lint", 28 | "bash-language-server", 29 | "black", 30 | "css-lsp", 31 | "debugpy", 32 | "dockerfile-language-server", 33 | "eslint-lsp", 34 | "goimports-reviser", 35 | "golines", 36 | "gopls", 37 | "hadolint", 38 | "hclfmt", 39 | "json-lsp", 40 | "lua-language-server", 41 | "mypy", 42 | "prettier", 43 | "pyright", 44 | "ruff", 45 | "selene", -- FIXME: Broken on Ubuntu 20.04 46 | "shellcheck", 47 | "shfmt", 48 | "stylua", 49 | "stylelint", 50 | "sqlls", 51 | "terraform-ls", 52 | "typescript-language-server", 53 | "tinymist", 54 | "vale-ls", 55 | "vtsls", 56 | "vue-language-server", 57 | "yaml-language-server", 58 | "yamllint", 59 | }, 60 | }, 61 | config = function(_, opts) 62 | require("mason-tool-installer").setup(opts) 63 | end, 64 | }, 65 | } 66 | -------------------------------------------------------------------------------- /dotfiles/.config/nvim/lua/utils.lua: -------------------------------------------------------------------------------- 1 | local M = {} 2 | 3 | -- Utlity function to make autocommands easily 4 | M.autocmd = vim.api.nvim_create_autocmd 5 | 6 | -- Utlity function to make augroups more easily 7 | M.augroup = function(name) 8 | return vim.api.nvim_create_augroup("augroup" .. name, { clear = true }) 9 | end 10 | 11 | -- Utlity function to make keybind mappings easier & DRY 12 | M.map = function(mode, lhs, rhs, opts) 13 | local keys = require("lazy.core.handler").handlers.keys 14 | 15 | if not keys.active[keys.parse({ lhs, mode = mode }).id] then 16 | opts = opts or {} 17 | opts.silent = opts.silent ~= false 18 | vim.keymap.set(mode, lhs, rhs, opts) 19 | end 20 | end 21 | 22 | -- M.format = function(command) 23 | -- -- INFO: Get the current location of the cursor on the current window 24 | -- local cursor = vim.api.nvim_win_get_cursor(0) 25 | -- 26 | -- -- INFO: The formatting command to invoke after the contents are saved 27 | -- vim.cmd(command) 28 | -- 29 | -- -- INFO: In case the formatting got rid of the line we came from 30 | -- cursor[1] = math.min(cursor[1], vim.api.nvim_buf_line_count(0)) 31 | -- 32 | -- -- INFO: Update the current cursor location according to the caluclated values 33 | -- vim.api.nvim_win_set_cursor(0, cursor) 34 | -- end 35 | 36 | -- Setup highlight groups for Neovim easily 37 | M.highlight = vim.api.nvim_set_hl 38 | 39 | -- Check if the current directory is version-controlled using Git 40 | M.is_git_repo = function() 41 | local handle = io.popen("git rev-parse --is-inside-work-tree 2>/dev/null") 42 | local output = handle:read("*a") 43 | handle:close() 44 | 45 | if output:match("true") then 46 | return true 47 | else 48 | return false 49 | end 50 | end 51 | 52 | -- Check if the ".git" directory exists in the current directory 53 | M.has_git_dir = function() 54 | local handle = io.popen("ls -a 2>/dev/null") 55 | local output = handle:read("*a") 56 | handle:close() 57 | 58 | if output:match("%.git") then 59 | return true 60 | else 61 | return false 62 | end 63 | end 64 | 65 | return M 66 | -------------------------------------------------------------------------------- /dotfiles/.config/wezterm/wezterm.lua: -------------------------------------------------------------------------------- 1 | local wezterm = require("wezterm") 2 | local mux = wezterm.mux 3 | 4 | -- Ensure the terminal is opened is in fullscreen mode right after startup 5 | wezterm.on("gui-startup", function(cmd) 6 | local _, _, window = mux.spawn_window(cmd or {}) 7 | window:gui_window():toggle_fullscreen() 8 | end) 9 | 10 | -- This Lua module returns a table of configuration values which Wezterm reads to 11 | -- customise the aesthetics of the terminal. 12 | return { 13 | -- Reduce unnecessary padding on the window 14 | window_padding = { left = 1, right = 0, top = 8, bottom = 0 }, 15 | 16 | -- Some bare basic key bindings for managing the terminal 17 | keys = { 18 | { 19 | -- Key binding to toggle fullscreen mode 20 | key = "F11", 21 | mods = "NONE", 22 | action = wezterm.action.ToggleFullScreen, 23 | }, 24 | }, 25 | 26 | -- INFO: Enable "light mode" on the desktop 27 | color_scheme = "Google Dark (base16)", 28 | 29 | -- Set a monospaced font for easier time when writing code 30 | font = wezterm.font("CaskaydiaCove Nerd Font Mono", { 31 | weight = "DemiBold", 32 | stretch = "Normal", 33 | style = "Normal", 34 | }), 35 | 36 | -- The default shell to invoke when launching the terminal 37 | default_prog = { "/home/linuxbrew/.linuxbrew/bin/zsh", "-l" }, 38 | 39 | -- Make the font size of the terminal contents legible 40 | font_size = 11.0, 41 | 42 | -- Hide the tab bar if there's only one tab open 43 | hide_tab_bar_if_only_one_tab = true, 44 | 45 | -- Make the window background transparent 46 | window_background_opacity = 0.96, 47 | 48 | -- Make the cursor to blink on the terminal 49 | default_cursor_style = "BlinkingBlock", 50 | 51 | -- Set the rate at which the cursor will blink 52 | cursor_blink_rate = 600, 53 | 54 | -- Disable checking for updates every day (which is annoying af!) 55 | check_for_updates = false, 56 | 57 | -- Disable the annoying audio bell 58 | audible_bell = "Disabled", 59 | 60 | -- Disable warning about missing glyphs 61 | warn_about_missing_glyphs = false, 62 | } 63 | -------------------------------------------------------------------------------- /dotfiles/.zshrc: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env zsh 2 | 3 | # The following lines were added by compinstall 4 | zstyle ":completion:*" completer _expand _complete _ignored _correct _approximate 5 | zstyle ":completion:*" matcher-list "" "" "m:{[:lower:]}={[:upper:]}" "m:{[:lower:][:upper:]}={[:upper:][:lower:]}" 6 | zstyle :compinstall filename "$HOME/.zshrc" 7 | 8 | autoload -Uz compinit 9 | compinit 10 | # End of lines added by compinstall 11 | # Lines configured by zsh-newuser-install 12 | setopt autocd beep extendedglob nomatch notify 13 | # End of lines configured by zsh-newuser-install 14 | 15 | # Update the default PATH 16 | export PATH="$HOME/.local/bin:$PATH" 17 | 18 | # Enable Starship 19 | eval "$(starship init zsh)" 20 | 21 | # Check if ~/.zsh directory exists 22 | if [[ -d "$HOME/.zsh" ]]; then 23 | # Source all files within the ~/.zsh directory 24 | for file in "$HOME/.zsh"/*; do 25 | source "$file" 26 | done 27 | fi 28 | 29 | # Various ZSH plugins to make the Shell usage experience better 30 | plugins=( 31 | "zsh-syntax-highlighting/zsh-syntax-highlighting.plugin.zsh" 32 | "zsh-autosuggestions/zsh-autosuggestions.plugin.zsh" 33 | "zsh-colored-man-pages/colored-man-pages.plugin.zsh" 34 | "zsh-completions/zsh-completions.plugin.zsh" 35 | ) 36 | 37 | # Loop through the list of plugins mentioned above & source them for usage 38 | for plugin in "${plugins[@]}"; do 39 | source "$HOME/.zsh/plugins/${plugin}" 40 | done 41 | 42 | # Ensure the "plugins" array to removed from memory for safety reasons 43 | unset plugins 44 | 45 | # Configure some ZSH keybinds only if using the Kitty terminal 46 | if [[ $TERM == "kitty-xterm" ]]; then 47 | bindkey "^[[4~" end-of-line 48 | bindkey "^[[1~" beginning-of-line 49 | else 50 | bindkey "^[[H" beginning-of-line 51 | bindkey "^[[F" end-of-line 52 | bindkey "^[[3~" delete-char 53 | fi 54 | 55 | # INFO: See the thread here - "https://vi.stackexchange.com/a/7654" for more information 56 | if [[ -n $VIRTUAL_ENV && -e "${VIRTUAL_ENV}/bin/activate" ]]; then 57 | source "${VIRTUAL_ENV}/bin/activate" 58 | fi 59 | 60 | # TODO: Customise the prompt without using 'Starship' 61 | # https://www.makeuseof.com/customize-zsh-prompt-macos-terminal 62 | 63 | export UV_PYTHON_DOWNLOADS=never 64 | -------------------------------------------------------------------------------- /.github/workflows/qa-checks.yml: -------------------------------------------------------------------------------- 1 | name: QA Checks 2 | 3 | on: 4 | push: 5 | 6 | jobs: 7 | runStyLua: 8 | name: Format Lua Files 9 | runs-on: ubuntu-latest 10 | steps: 11 | - name: Checkout Repository 12 | uses: actions/checkout@v6 13 | 14 | - name: Download and Setup Stylua 15 | env: 16 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 17 | run: | 18 | gh release download --repo JohnnyMorganz/StyLua \ 19 | --pattern "stylua-linux-x86_64.zip" 20 | unzip "stylua-linux-x86_64.zip" 21 | cp stylua /usr/local/bin/ 22 | echo "Downloaded Stylua v$(stylua --version | grep --only-matching --perl-regexp '\d+\.\d+\.\d+')" 23 | 24 | - name: Run the Stylua formatter for Lua code 25 | run: stylua . --check 26 | 27 | runSeleneLinter: 28 | name: Lint Lua Files 29 | runs-on: ubuntu-latest 30 | steps: 31 | - name: Checkout Repository 32 | uses: actions/checkout@v6 33 | 34 | - name: Download and Setup Selene 35 | env: 36 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 37 | run: | 38 | gh release download --repo Kampfkarren/selene --pattern "selene-*-linux.zip" 39 | unzip "selene-light-*-linux.zip" 40 | cp selene /usr/local/bin/ && chmod u+x /usr/local/bin/selene 41 | echo "Downloaded Selene v$(selene --version | grep --only-matching --perl-regexp '\d+\.\d+\.\d+')" 42 | 43 | - name: Run Selene to Lint Lua Code 44 | run: selene . 45 | 46 | runRuff: 47 | name: Lint Python Files 48 | runs-on: ubuntu-latest 49 | steps: 50 | - name: Checkout Repository 51 | uses: actions/checkout@v6 52 | 53 | - name: Download and Setup Ruff 54 | env: 55 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 56 | run: pipx install ruff 57 | 58 | - name: Run the Ruff Linter for Python Code 59 | run: ruff check "$PWD" 60 | 61 | runBlackFormatter: 62 | name: Format Python Files 63 | runs-on: ubuntu-latest 64 | steps: 65 | - name: Checkout Repository 66 | uses: actions/checkout@v6 67 | 68 | - name: Run the Black Formatter on Python Files 69 | run: | 70 | pip install black 71 | black . --check 72 | -------------------------------------------------------------------------------- /dotfiles/.config/nvim/lua/plugins/conform.lua: -------------------------------------------------------------------------------- 1 | -- Module for configuring the "conform" plugin for formatting using LSP 2 | 3 | return { 4 | "stevearc/conform.nvim", 5 | event = { "LspAttach", "BufReadPost", "BufNewFile" }, 6 | opts = { 7 | formatters_by_ft = { 8 | html = { "prettier" }, 9 | javascript = { "prettier" }, 10 | go = { "goimports-reviser", "golines", "gofmt" }, 11 | hcl = { "hclfmt" }, 12 | markdown = { "prettier" }, 13 | lua = { "stylua" }, 14 | scss = { "prettier" }, 15 | sh = { "shfmt" }, 16 | python = { "ruff_organize_imports", "ruff_format" }, 17 | typescript = { "prettier" }, 18 | vue = { "prettier" }, 19 | yaml = { "prettier" }, 20 | }, 21 | format_on_save = function(bufnr) 22 | local bufname = vim.api.nvim_buf_get_name(bufnr) 23 | 24 | -- Disable file formatting on any temporary buffer contents 25 | if bufname:match("/tmp/") then 26 | return 27 | else 28 | return { 29 | timeout_ms = 10000, 30 | lsp_fallback = true, 31 | } 32 | end 33 | end, 34 | }, 35 | config = function(_, opts) 36 | local conform = require("conform") 37 | 38 | -- Setup "conform.nvim" to work 39 | conform.setup(opts) 40 | 41 | -- Customise the default "prettier" command to format Markdown files as well 42 | conform.formatters.prettier = { 43 | prepend_args = { "--prose-wrap", "always" }, 44 | } 45 | 46 | -- Add proper indents to the formatted Shell files 47 | conform.formatters.shfmt = { 48 | prepend_args = { 49 | "--indent=2", 50 | "--binary-next-line", 51 | "--case-indent", 52 | "--space-redirects", 53 | "--keep-padding", 54 | }, 55 | } 56 | 57 | -- Format long lines in Go source code 58 | conform.formatters.golines = { 59 | prepend_args = { 60 | "--max-len=88", 61 | "--reformat-tags", 62 | "--shorten-comments", 63 | }, 64 | } 65 | 66 | -- Format the import statements in Go source code 67 | conform.formatters["goimports-reviser"] = { 68 | prepend_args = { 69 | -- FIXME: It removes "used" statements too!!!! 70 | -- "-rm-unused", -- Remove unused imports 71 | "-set-alias", -- Create aliases for versioned imports 72 | }, 73 | } 74 | end, 75 | dependencies = { "neovim/nvim-lspconfig" }, 76 | } 77 | -------------------------------------------------------------------------------- /dotfiles/.config/nvim/after/ftplugin/python.lua: -------------------------------------------------------------------------------- 1 | -- Filetype plugin module for configuring Python development in Neovim 2 | -- Refer to the resource shared below for further inspiration 3 | -- https://github.com/aikow/dotfiles/blob/main/config/nvim/after/ftplugin/python.lua 4 | 5 | local autocmd = require("utils").autocmd 6 | local augroup = require("utils").augroup 7 | local map = require("utils").map 8 | 9 | -- INFO: Local keymap (specific to Python files) to execute the current Python script 10 | if os.getenv("VIRTUAL_ENV") ~= nil then 11 | map("n", "", "terminal pytest %") 12 | map("n", "", "terminal python %") 13 | else 14 | map("n", "", "terminal python3 %") 15 | end 16 | 17 | autocmd({ "BufWritePost" }, { 18 | desc = "Lint buffer contents after writing them", 19 | group = augroup("lint_python_files"), 20 | callback = function() 21 | require("lint").try_lint() 22 | end, 23 | }) 24 | 25 | -- Wrap words at the EOL "cleanly" (i.e) ensure the words are wrapped and not just characters 26 | vim.opt.wrap = true 27 | vim.opt.linebreak = true 28 | 29 | -- Start the Treesitter parse process for highligting Python files 30 | vim.treesitter.start() 31 | 32 | -- Configure the indent-based folds for Python buffers 33 | if vim.api.nvim_buf_line_count(0) >= 100 then 34 | vim.opt.foldmethod = "expr" 35 | vim.opt.foldexpr = "nvim_treesitter#foldexpr()" 36 | vim.opt.foldlevel = 0 37 | vim.opt.foldcolumn = "auto" 38 | end 39 | 40 | -- Configure and enable the LSP server for Python 41 | vim.diagnostic.config({ 42 | float = true, -- Show the diagnostic messages in a floating window 43 | underline = true, -- Show squiggly lines under the statement with an error/warning 44 | update_in_insert = true, -- Update the message even when in Insert mode 45 | severity_sort = true, -- Configure Neovim to sort the error messages according to their severity 46 | virtual_text = true, -- Show virtual lines besides the statement with an error/warning 47 | }) 48 | 49 | -- Enable the LSP server for Python 50 | vim.lsp.enable("pyright", true) 51 | 52 | -- TODO: Move this autocommand to its own module/package 53 | vim.api.nvim_create_autocmd("CursorHold", { 54 | buffer = vim.api.nvim_get_current_buf(), 55 | callback = function() 56 | local hover_window_configs = { 57 | focusable = false, 58 | close_events = { "BufLeave", "CursorMoved", "InsertEnter", "FocusLost" }, 59 | border = "rounded", 60 | source = "always", 61 | prefix = " ", 62 | scope = "cursor", 63 | } 64 | 65 | vim.diagnostic.open_float(nil, hover_window_configs) 66 | end, 67 | }) 68 | -------------------------------------------------------------------------------- /dotfiles/.config/nvim/skeletons/readme.md: -------------------------------------------------------------------------------- 1 | # 🍱 Name of the Project 2 | 3 | 4 | 5 | ![GitHub code size in bytes](https://img.shields.io/github/languages/code-size/Jarmos-san/neovim-docker?color=%23181717&label=Size&logo=github) 6 | ![GitHub](https://img.shields.io/github/license/Jarmos-san/neovim-docker?label=License&logo=github) 7 | ![Twitter URL](https://img.shields.io/twitter/url?style=social&url=https%3A%2F%2Fgithub.com%2FJarmos-san%2Fneovim-docker) 8 | 9 | About the project in not more than 5-10 sentences to keep the user engaged & 10 | give them a brief idea of the project as well. 11 | 12 | ## 🦮 How to Use the Project 13 | 14 | Share some usage guidelines here like: 15 | 16 | 1. How to download the project. 17 | 2. Once downloaded how to invoke the command & run it on the user's local 18 | machine. 19 | 3. How & where to find help once the user starts using the project. 20 | 21 | ## 🫂 Contributing & Supporting the Project 22 | 23 | Share detailed guidelines on how the interested user can start contributing to 24 | the project. 25 | 26 | ### How to Contribute to the Project 27 | 28 | There are numerous ways to contribute to the project & here are a few ways I can 29 | think of on the top of my head. 30 | 31 | - Found bugs? Report it by opening an [issue thread][4]. 32 | - Have a better plugin or an enhancement suggestions? Let the author know about 33 | it. 34 | - Are you interested in writing Lua code or perhaps use this project as your 35 | own? Then feel free to share a PR or two. 36 | - Found the project useful to get started with working on Neovim ASAP? Then 37 | consider sponsoring the author as it keeps him motivated & pays the bills. 38 | 39 | To learn more about contributing to the project, refer to the "[Developer 40 | Guidelines][13]" section of the wiki. Also don't forget to check out the more 41 | detailed instructions as laid down in the "[Contributing Guidelines][14]" for 42 | the project. 43 | 44 | That said, if you've any questions related to the development of this project, 45 | please feel to reach out to author & maintainer of the project! 46 | 47 | ## 📄 Usage Terms & Conditions 48 | 49 | The project is licensed under the terms & conditions (T&Cs) for the MIT license. 50 | So, you free to use, distribute, copy, modify & such with the contents of this 51 | repository in whatever manner you want to. The caveat is, your usage should 52 | adhere to the T&Cs of the MIT license. 53 | 54 | For more information on the licensing T&Cs, feel free to refer to the 55 | [LICENSE](./LICENSE) document. 56 | 57 | 58 | 59 | [1]: https://www.example.com 60 | -------------------------------------------------------------------------------- /dotfiles/.zsh/aliases: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env zsh 2 | 3 | # A bunch of custom aliases for easier terminal usage. 4 | alias ct="cookiecutter" 5 | alias pcs="pre-commit sample-config >> .pre-commit-config.yaml && pre-commit autoupdate &>/dev/null" 6 | 7 | # Docker commands 8 | alias compose="docker compose" 9 | alias dps="docker ps --format 'table {{ .ID }}\t{{ .Names }}\t{{ .Ports }}'" 10 | alias dimc="docker image prune --force" 11 | alias drmi="docker image rm" 12 | alias dcdown="docker compose down --remove-orphans --volumes" 13 | alias dcup="docker compose up --detach" 14 | alias dclogs="docker compose logs" 15 | alias dims="docker images" 16 | 17 | # Easy and utilitarian aliases for quick terminal usage 18 | alias reload="source $HOME/.zshrc" 19 | alias top="btop --utf-force" 20 | alias cm="cmatrix -abs" 21 | alias rands="openssl rand -base64 32" 22 | alias ll="eza --long --all --classify --icons --git --ignore-glob='.git'" 23 | alias loc="wc -l" 24 | alias tree="eza --tree --all --icons --ignore-glob='.git' --git-ignore" 25 | alias dateiso="date +%Y-%m-%dT%H:%M:%S%z" 26 | 27 | # Spin dev/experimental databases 28 | alias pgdb="docker run --detach --name postgresql --rm -p 5432:5432 \ 29 | -e POSTGRESQL_USERNAME=psqladmin \ 30 | -e POSTGRESQL_PASSWORD=admin \ 31 | -e POSTGRESQL_DATABASE=postgres \ 32 | bitnami/postgresql:16" 33 | alias rsdb="docker run --name redis --rm -p 6379:6379 \ 34 | -e ALLOW_EMPTY_PASSWORD=yes \ 35 | bitnami/redis:7.2" 36 | 37 | # Terraform related aliases 38 | alias tfinit="terraform init" 39 | alias tfval="terraform validate" 40 | alias tfplan="terraform plan" 41 | 42 | # NPM aliases 43 | alias npm="pnpm" 44 | alias npx="pnpm dlx" 45 | 46 | # Google's webp CLI alias 47 | alias webp="cwebp" 48 | 49 | # A bunch of Tmux aliases for easier multiplex usage 50 | alias tls="tmux list-session" 51 | alias tnew="tmux new-session" 52 | alias dots="tmux new-session -s dotfiles -n dotfiles -c ~/.dotfiles" 53 | alias tks="tmux kill-server" 54 | alias homelab="tmux new-session -s homelab -n homelab -c ~/projects/homelab" 55 | 56 | # Some complex Git aliases 57 | alias git-sync="git switch main && git fetch --prune && git branch -vv | awk '/: gone/ {print $1}' | xargs -r git branch --delete" 58 | 59 | # Some aliases for working with Python 60 | alias mkvenv="uv venv" 61 | # FIXME: Why does it get evaluated when creating an interactive shell environment? 62 | # alias penv="eval $(poetry env activate)" 63 | alias py="python3" 64 | alias python="python3" 65 | 66 | # Some aliases for working with Go 67 | alias goimports="goimports-reviser -use-cache -rm-unused -set-alias" 68 | 69 | # Alias to cd into the "blogs" directory 70 | alias blogs="cd ~/projects/blogposts" 71 | -------------------------------------------------------------------------------- /dotfiles/.local/bin/tag: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | """ 4 | Simple script to make Git tagging easier. 5 | 6 | The script intelligently identifies the project configuration file (like "package.json" 7 | or "pyproject.toml"), updates the project version and applies a Git Tag as well! 8 | 9 | Author: Somraj Saha 10 | License: MIT License 11 | """ 12 | 13 | # INFO: This is a WIP script, nothing is set in stone yet! 14 | 15 | import subprocess 16 | from argparse import ArgumentParser, Namespace 17 | from pathlib import Path 18 | 19 | 20 | def is_git_repository() -> bool | None: 21 | """Check if the current working directory is a Git repository or not.""" 22 | try: 23 | command = subprocess.run(["git", "rev-parse", "--is-inside-work-tree"]) 24 | 25 | if command.returncode == 0 and command.stdout.strip() == b"true": 26 | return True 27 | else: 28 | return False 29 | except FileNotFoundError as error: 30 | raise error 31 | 32 | 33 | def argument_parser() -> Namespace: 34 | """Parse the list of argument passed to the script and return them.""" 35 | parser = ArgumentParser(description="Make Git tagging easy and quick.") 36 | 37 | parser.add_argument("name", help="The name of the tag") 38 | parser.add_argument("message", help="The message to annotate the tag with") 39 | 40 | return parser.parse_args() 41 | 42 | 43 | def run_git_tag() -> None: 44 | """Invoke the git-tag function to annotate a commit.""" 45 | args = argument_parser() 46 | 47 | subprocess.run( 48 | ["git", "tag", "--annotate", "--sign", args.name, f"--message={args.message}"] 49 | ) 50 | 51 | 52 | def main() -> None: 53 | """Entrypoint of the script.""" 54 | # A list of the project configuration files to update with the latest version tag 55 | filename = ("package.json", "pyproject.toml", "Cargo.toml") 56 | 57 | if is_git_repository(): 58 | run_git_tag() 59 | 60 | for file in filename: 61 | filepath = Path.cwd() / file 62 | if filepath.exists(): 63 | match filepath.name: 64 | case "package.json": 65 | print('Update the "package.json" file!') 66 | case "pyproject.toml": 67 | print('Update the "pyproject.toml" file!') 68 | case "Cargo.toml": 69 | print('Update the "Cargo.toml" file!') 70 | case _: 71 | print("Failed to identify project configuration file!") 72 | else: 73 | print("Not a Git directory...not tagging anything!") 74 | 75 | 76 | if __name__ == "__main__": 77 | main() 78 | -------------------------------------------------------------------------------- /dotfiles/.config/nvim/lazy-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "LuaSnip": { "branch": "master", "commit": "3732756842a2f7e0e76a7b0487e9692072857277" }, 3 | "blink.cmp": { "branch": "main", "commit": "b19413d214068f316c78978b08264ed1c41830ec" }, 4 | "conform.nvim": { "branch": "master", "commit": "41715945edf518ca73a9bd63ab6cdc23dd5c7b33" }, 5 | "devicons": { "branch": "master", "commit": "8dcb311b0c92d460fac00eac706abd43d94d68af" }, 6 | "evergarden": { "branch": "main", "commit": "ed86852e01f03853326c68961ff10bcaf8ff5f9c" }, 7 | "gitsigns.nvim": { "branch": "main", "commit": "5813e4878748805f1518cee7abb50fd7205a3a48" }, 8 | "lazy.nvim": { "branch": "main", "commit": "306a05526ada86a7b30af95c5cc81ffba93fef97" }, 9 | "lualine.nvim": { "branch": "master", "commit": "47f91c416daef12db467145e16bed5bbfe00add8" }, 10 | "mason-tool-installer.nvim": { "branch": "main", "commit": "517ef5994ef9d6b738322664d5fdd948f0fdeb46" }, 11 | "mason.nvim": { "branch": "main", "commit": "57e5a8addb8c71fb063ee4acda466c7cf6ad2800" }, 12 | "mini.bufremove": { "branch": "main", "commit": "10857aa39160c127694151828914df3131ba83b6" }, 13 | "mini.comment": { "branch": "main", "commit": "a0c721115faff8d05505c0a12dab410084d9e536" }, 14 | "mini.indentscope": { "branch": "main", "commit": "0308f949f31769e509696af5d5f91cebb2159c69" }, 15 | "mini.move": { "branch": "main", "commit": "4d214202d71e0a4066b6288176bbe88f268f9777" }, 16 | "mini.pairs": { "branch": "main", "commit": "d5a29b6254dad07757832db505ea5aeab9aad43a" }, 17 | "mini.splitjoin": { "branch": "main", "commit": "9fcd8856efb95a505090c3225726466494076127" }, 18 | "mini.starter": { "branch": "main", "commit": "8ee6ce6a4c9be47682516908557cc062c4d595a2" }, 19 | "mini.surround": { "branch": "main", "commit": "88c52297ed3e69ecf9f8652837888ecc727a28ee" }, 20 | "neoscroll.nvim": { "branch": "master", "commit": "f957373912e88579e26fdaea4735450ff2ef5c9c" }, 21 | "nvim-lint": { "branch": "master", "commit": "7a64f4067065c16a355d40d0d599b8ca6b25de6d" }, 22 | "nvim-lspconfig": { "branch": "master", "commit": "c4f67bf85b01a57e3c130352c0a0e453ab8cd5b9" }, 23 | "nvim-notify": { "branch": "master", "commit": "8701bece920b38ea289b457f902e2ad184131a5d" }, 24 | "nvim-treesitter": { "branch": "main", "commit": "4fc09bee78e91bf4ba471cdab4bf9dfa37fde51c" }, 25 | "nvim-ts-context-commentstring": { "branch": "main", "commit": "1b212c2eee76d787bbea6aa5e92a2b534e7b4f8f" }, 26 | "plenary.nvim": { "branch": "master", "commit": "b9fd5226c2f76c951fc8ed5923d85e4de065e509" }, 27 | "schemastore.nvim": { "branch": "main", "commit": "806187c790d93625564708c286e16142d87a5cc9" }, 28 | "smartcolumn.nvim": { "branch": "main", "commit": "b9cdbdf42f7ac5a659204cd5926017c7ff724a19" }, 29 | "telescope.nvim": { "branch": "master", "commit": "3d757e586ff0bfc85bdb7b46c9d3d932147a0cde" } 30 | } 31 | -------------------------------------------------------------------------------- /dotfiles/.config/nvim/lua/terminal.lua: -------------------------------------------------------------------------------- 1 | -- This module contains the Lua code to configure the inbuilt terminal 2 | 3 | local M = {} 4 | 5 | local buf, win 6 | 7 | local create_term = function() 8 | vim.fn.termopen(vim.o.shell, { 9 | on_exit = function() 10 | buf, win = nil, nil 11 | end, 12 | }) 13 | end 14 | 15 | M.setup = { 16 | float = function() 17 | buf = vim.api.nvim_create_buf(false, true) -- Create a new buffer 18 | 19 | -- Various settings of the window 20 | local width = math.floor(vim.o.columns * 0.8) -- 80% of the screen size 21 | local height = math.floor(vim.o.lines * 0.5) -- 50% of the screen size 22 | local row = math.floor((vim.o.lines - height) / 2) 23 | local col = math.floor((vim.o.columns - width) / 2) 24 | local title = string.format("Terminal (%s)", vim.o.shell) 25 | 26 | -- Configure the settings of the window 27 | local opts = { 28 | relative = "editor", 29 | row = row, 30 | col = col, 31 | width = width, 32 | height = height, 33 | border = "rounded", 34 | title = title, 35 | title_pos = "center", 36 | } 37 | 38 | -- Create a floating window to render the terminal into 39 | win = vim.api.nvim_open_win(buf, true, opts) 40 | 41 | -- Open a terminal session in the floating window 42 | create_term() 43 | end, 44 | 45 | vertical = function() 46 | buf = vim.api.nvim_create_buf(false, true) 47 | 48 | -- Open a vertical split and switch to it 49 | vim.api.nvim_open_win(buf, true, { split = "right" }) 50 | 51 | -- Open a terminal session in the floating window 52 | create_term() 53 | end, 54 | 55 | toggle = function() 56 | if win and vim.api.nvim_win_is_valid(win) then 57 | vim.api.nvim_win_close(win, true) 58 | buf, win = nil, nil 59 | return 60 | end 61 | 62 | buf = vim.api.nvim_create_buf(false, true) -- Create a new buffer 63 | 64 | -- Various settings of the window 65 | local width = math.floor(vim.o.columns * 0.8) -- 80% of the screen size 66 | local height = math.floor(vim.o.lines * 0.5) -- 50% of the screen size 67 | local row = math.floor((vim.o.lines - height) / 2) 68 | local col = math.floor((vim.o.columns - width) / 2) 69 | local title = string.format("Terminal (%s)", vim.o.shell) 70 | 71 | -- Configure the settings of the window 72 | local opts = { 73 | relative = "editor", 74 | row = row, 75 | col = col, 76 | width = width, 77 | height = height, 78 | border = "rounded", 79 | title = title, 80 | title_pos = "center", 81 | } 82 | 83 | -- Create a floating window to render the terminal into 84 | win = vim.api.nvim_open_win(buf, true, opts) 85 | 86 | -- Open a terminal session in the floating window 87 | create_term() 88 | end, 89 | } 90 | 91 | return M 92 | -------------------------------------------------------------------------------- /dotfiles/.config/nvim/lua/plugins/mini-nvim.lua: -------------------------------------------------------------------------------- 1 | -- Module for configuring and managing the "mini.nvim" plugins 2 | 3 | return { 4 | { 5 | "nvim-mini/mini.comment", 6 | event = { "BufNewFile", "BufReadPost" }, 7 | opts = { 8 | -- FIXME: Blank lines are also commented (need a fix someday) 9 | ignore_blank_lines = true, 10 | custom_commentstring = function() 11 | return require("ts_context_commentstring.internal").calculate_commentstring() or vim.bo.commentstring 12 | end, 13 | }, 14 | config = function(_, opts) 15 | require("mini.comment").setup(opts) 16 | end, 17 | dependencies = { "JoosepAlviste/nvim-ts-context-commentstring" }, 18 | }, 19 | 20 | { 21 | "nvim-mini/mini.pairs", 22 | event = { "CmdwinEnter", "InsertEnter" }, 23 | opts = { 24 | modes = { 25 | insert = true, -- "Insert" mode 26 | command = true, -- "Command" mode 27 | terminal = true, -- "Terminal" mode 28 | }, 29 | }, 30 | config = function(_, opts) 31 | require("mini.pairs").setup(opts) 32 | end, 33 | }, 34 | 35 | { 36 | "nvim-mini/mini.surround", 37 | event = "BufReadPost", 38 | config = function() 39 | require("mini.surround").setup() 40 | end, 41 | }, 42 | 43 | { 44 | "nvim-mini/mini.indentscope", 45 | event = "BufReadPost", 46 | config = function() 47 | require("mini.indentscope").setup() 48 | end, 49 | }, 50 | 51 | { 52 | "nvim-mini/mini.bufremove", 53 | event = { "BufReadPost", "BufNewFile" }, 54 | config = function() 55 | require("mini.bufremove").setup() 56 | end, 57 | }, 58 | 59 | { 60 | -- Plugin to show a nice, minimal and easy-to-use startup screen 61 | "nvim-mini/mini.starter", 62 | event = "VimEnter", 63 | opts = function() 64 | local header = "Hello World!" 65 | return { 66 | items = { 67 | { name = "Open Old Files", action = "Telescope oldfiles", section = "File Explorer" }, 68 | { name = "Open File Explorer", action = "Neotree toggle", section = "File Explorer" }, 69 | { action = require("mini.starter").sections.recent_files(8, true, true), section = "Recent Files" }, 70 | { name = "Fuzzy Search for Files/Folders", action = "Telescope find_files", section = "File Explorer" }, 71 | }, 72 | header = header, 73 | footer = 'Press "alt + j/k" to navigate up/down.', 74 | } 75 | end, 76 | config = function(_, opts) 77 | require("mini.starter").setup(opts) 78 | end, 79 | }, 80 | 81 | { 82 | "nvim-mini/mini.splitjoin", 83 | event = "BufReadPost", 84 | config = function() 85 | require("mini.splitjoin").setup() 86 | end, 87 | }, 88 | 89 | { 90 | "nvim-mini/mini.move", 91 | event = "BufReadPost", 92 | config = function() 93 | require("mini.move").setup() 94 | end, 95 | }, 96 | } 97 | -------------------------------------------------------------------------------- /dotfiles/.config/nvim/init.lua: -------------------------------------------------------------------------------- 1 | -- Path to install "lazy.nvim" at 2 | local lazypath = vim.fn.stdpath("data") .. "/lazy/lazy.nvim" 3 | 4 | if not (vim.uv or vim.loop).fs_stat(lazypath) then 5 | local lazyrepo = "https://github.com/folke/lazy.nvim.git" 6 | local out = vim.fn.system({ "git", "clone", "--filter=blob:none", "--branch=stable", lazyrepo, lazypath }) 7 | if vim.v.shell_error ~= 0 then 8 | vim.api.nvim_echo({ 9 | { "Failed to clone lazy.nvim:\n", "ErrorMsg" }, 10 | { out, "WarningMsg" }, 11 | { "\nPress any key to exit..." }, 12 | }, true, {}) 13 | vim.fn.getchar() 14 | os.exit(1) 15 | end 16 | end 17 | 18 | -- Update the Neovim runtimepath for "lazy.nvim" to source the plugins. 19 | vim.opt.rtp:prepend(lazypath) 20 | 21 | -- Map the key to . 22 | vim.g.mapleader = " " 23 | 24 | -- Disable some in-built features which are unnecessary (and probably affects performance?) 25 | vim.g.loaded_python3_provider = 0 26 | vim.g.loaded_ruby_provider = 0 27 | vim.g.loaded_perl_provider = 0 28 | vim.g.loaded_node_provider = 0 29 | 30 | -- Install the necessary plugins through "lazy.nvim" 31 | require("lazy").setup("plugins", { 32 | defaults = { lazy = true }, -- Make all plugins to be lazy-loaded. 33 | ui = { 34 | border = "rounded", -- Enable rounded borders for the "lazy.nvim" UI. 35 | }, 36 | performance = { 37 | rtp = { 38 | disabled_plugins = { -- Disable certain in-built plugins which are useful af. 39 | "gzip", 40 | "matchit", 41 | "matchparen", 42 | "tarPlugin", 43 | "tohtml", 44 | "tutor", 45 | "zipPlugin", 46 | "rplugin", 47 | "man", 48 | "spellfile", 49 | }, 50 | }, 51 | }, 52 | rocks = { 53 | enabled = false, 54 | }, 55 | }) 56 | 57 | -- Safely load the necessary user-defined Lua modules meant to customise Neovim. 58 | for _, module in ipairs({ "options", "autocmds", "keymaps" }) do 59 | local ok, error = pcall(require, module) 60 | 61 | if not ok then 62 | print("Error loading module: " .. error) 63 | end 64 | end 65 | 66 | -- My WIP personalised colour scheme 67 | -- vim.cmd.colorscheme("tansai") 68 | 69 | vim.cmd.colorscheme("evergarden") 70 | 71 | -- INFO: Enable an experimental fast module loader. See the PR for more information: 72 | -- https://github.com/neovim/neovim/pull/22668 73 | vim.loader.enable() 74 | 75 | -- Additional features to look into later on: 76 | -- https://github.com/rafcamlet/nvim-luapad 77 | 78 | -- INFO: Good book to learn Vim from; 79 | -- https://learnvim.irian.to/ 80 | 81 | -- FIXME: Figure a way out to handle semantic highlights better with the following article as a source of reference: 82 | -- https://gist.github.com/swarn/fb37d9eefe1bc616c2a7e476c0bc0316 83 | 84 | -- TODO: Figure a way out to manage the plugin using lazy.nvim 85 | require("statusline").setup() 86 | 87 | -- Enable the required LSP servers 88 | vim.lsp.enable({ "lua_ls" }) 89 | -------------------------------------------------------------------------------- /dotfiles/.config/nvim/colors/shinkai.vim: -------------------------------------------------------------------------------- 1 | hi clear 2 | syntax reset 3 | let g:colors_name = "shinkai" 4 | set background=light 5 | set t_Co=256 6 | hi Normal guifg=#000000 ctermbg=NONE guibg=#ffffff gui=NONE 7 | 8 | hi DiffText guifg=#06448b guibg=NONE 9 | hi ErrorMsg guifg=#06448b guibg=NONE 10 | hi WarningMsg guifg=#06448b guibg=NONE 11 | hi PreProc guifg=#06448b guibg=NONE 12 | hi Exception guifg=#06448b guibg=NONE 13 | hi Error guifg=#06448b guibg=NONE 14 | hi DiffDelete guifg=#06448b guibg=NONE 15 | hi GitGutterDelete guifg=#06448b guibg=NONE 16 | hi GitGutterChangeDelete guifg=#06448b guibg=NONE 17 | hi cssIdentifier guifg=#06448b guibg=NONE 18 | hi cssImportant guifg=#06448b guibg=NONE 19 | hi Type guifg=#06448b guibg=NONE 20 | hi Identifier guifg=#06448b guibg=NONE 21 | hi PMenuSel guifg=#045835 guibg=NONE 22 | hi Constant guifg=#045835 guibg=NONE 23 | hi Repeat guifg=#045835 guibg=NONE 24 | hi DiffAdd guifg=#045835 guibg=NONE 25 | hi GitGutterAdd guifg=#045835 guibg=NONE 26 | hi cssIncludeKeyword guifg=#045835 guibg=NONE 27 | hi Keyword guifg=#045835 guibg=NONE 28 | hi IncSearch guifg=#60720b guibg=NONE 29 | hi Title guifg=#60720b guibg=NONE 30 | hi PreCondit guifg=#60720b guibg=NONE 31 | hi Debug guifg=#60720b guibg=NONE 32 | hi SpecialChar guifg=#60720b guibg=NONE 33 | hi Conditional guifg=#60720b guibg=NONE 34 | hi Todo guifg=#60720b guibg=NONE 35 | hi Special guifg=#60720b guibg=NONE 36 | hi Label guifg=#60720b guibg=NONE 37 | hi Delimiter guifg=#60720b guibg=NONE 38 | hi Number guifg=#60720b guibg=NONE 39 | hi CursorLineNR guifg=#60720b guibg=NONE 40 | hi Define guifg=#60720b guibg=NONE 41 | hi MoreMsg guifg=#60720b guibg=NONE 42 | hi Tag guifg=#60720b guibg=NONE 43 | hi String guifg=#60720b guibg=NONE 44 | hi MatchParen guifg=#60720b guibg=NONE 45 | hi Macro guifg=#60720b guibg=NONE 46 | hi DiffChange guifg=#60720b guibg=NONE 47 | hi GitGutterChange guifg=#60720b guibg=NONE 48 | hi cssColor guifg=#60720b guibg=NONE 49 | hi Function guifg=#1368f3 guibg=NONE 50 | hi Directory guifg=#620eb1 guibg=NONE 51 | hi markdownLinkText guifg=#620eb1 guibg=NONE 52 | hi javaScriptBoolean guifg=#620eb1 guibg=NONE 53 | hi Include guifg=#620eb1 guibg=NONE 54 | hi Storage guifg=#620eb1 guibg=NONE 55 | hi cssClassName guifg=#620eb1 guibg=NONE 56 | hi cssClassNameDot guifg=#620eb1 guibg=NONE 57 | hi Statement guifg=#0ecaf1 guibg=NONE 58 | hi Operator guifg=#0ecaf1 guibg=NONE 59 | hi cssAttr guifg=#0ecaf1 guibg=NONE 60 | 61 | 62 | hi Pmenu guifg=#000000 guibg=#454545 63 | hi SignColumn guibg=#ffffff 64 | hi Title guifg=#000000 65 | hi LineNr guifg=#666666 guibg=#ffffff 66 | hi NonText guifg=#c481ff guibg=#ffffff 67 | hi Comment guifg=#c481ff gui=italic 68 | hi SpecialComment guifg=#c481ff gui=italic guibg=NONE 69 | hi CursorLine guibg=#454545 70 | hi TabLineFill gui=NONE guibg=#454545 71 | hi TabLine guifg=#666666 guibg=#454545 gui=NONE 72 | hi StatusLine gui=bold guibg=#454545 guifg=#000000 73 | hi StatusLineNC gui=NONE guibg=#ffffff guifg=#000000 74 | hi Search guibg=#c481ff guifg=#ffffff 75 | hi VertSplit gui=NONE guifg=#454545 guibg=NONE 76 | hi Visual gui=NONE guibg=#454545 77 | -------------------------------------------------------------------------------- /dotfiles/.config/nvim/lsp/gopls.lua: -------------------------------------------------------------------------------- 1 | ---@brief 2 | --- 3 | --- https://github.com/golang/tools/tree/master/gopls 4 | --- 5 | --- Google's lsp server for golang. 6 | 7 | --- @class go_dir_custom_args 8 | --- 9 | --- @field envvar_id string 10 | --- 11 | --- @field custom_subdir string? 12 | 13 | local mod_cache = nil 14 | local std_lib = nil 15 | 16 | ---@param custom_args go_dir_custom_args 17 | ---@param on_complete fun(dir: string | nil) 18 | local function identify_go_dir(custom_args, on_complete) 19 | local cmd = { "go", "env", custom_args.envvar_id } 20 | vim.system(cmd, { text = true }, function(output) 21 | local res = vim.trim(output.stdout or "") 22 | if output.code == 0 and res ~= "" then 23 | if custom_args.custom_subdir and custom_args.custom_subdir ~= "" then 24 | res = res .. custom_args.custom_subdir 25 | end 26 | on_complete(res) 27 | else 28 | vim.schedule(function() 29 | vim.notify( 30 | ("[gopls] identify " .. custom_args.envvar_id .. " dir cmd failed with code %d: %s\n%s"):format( 31 | output.code, 32 | vim.inspect(cmd), 33 | output.stderr 34 | ) 35 | ) 36 | end) 37 | on_complete(nil) 38 | end 39 | end) 40 | end 41 | 42 | ---@return string? 43 | local function get_std_lib_dir() 44 | if std_lib and std_lib ~= "" then 45 | return std_lib 46 | end 47 | 48 | identify_go_dir({ envvar_id = "GOROOT", custom_subdir = "/src" }, function(dir) 49 | if dir then 50 | std_lib = dir 51 | end 52 | end) 53 | return std_lib 54 | end 55 | 56 | ---@return string? 57 | local function get_mod_cache_dir() 58 | if mod_cache and mod_cache ~= "" then 59 | return mod_cache 60 | end 61 | 62 | identify_go_dir({ envvar_id = "GOMODCACHE" }, function(dir) 63 | if dir then 64 | mod_cache = dir 65 | end 66 | end) 67 | return mod_cache 68 | end 69 | 70 | ---@param fname string 71 | ---@return string? 72 | local function get_root_dir(fname) 73 | if mod_cache and fname:sub(1, #mod_cache) == mod_cache then 74 | local clients = vim.lsp.get_clients({ name = "gopls" }) 75 | if #clients > 0 then 76 | return clients[#clients].config.root_dir 77 | end 78 | end 79 | if std_lib and fname:sub(1, #std_lib) == std_lib then 80 | local clients = vim.lsp.get_clients({ name = "gopls" }) 81 | if #clients > 0 then 82 | return clients[#clients].config.root_dir 83 | end 84 | end 85 | return vim.fs.root(fname, "go.work") or vim.fs.root(fname, "go.mod") or vim.fs.root(fname, ".git") 86 | end 87 | 88 | return { 89 | cmd = { "gopls" }, 90 | filetypes = { "go", "gomod", "gowork", "gotmpl" }, 91 | root_dir = function(bufnr, on_dir) 92 | local fname = vim.api.nvim_buf_get_name(bufnr) 93 | get_mod_cache_dir() 94 | get_std_lib_dir() 95 | -- see: https://github.com/neovim/nvim-lspconfig/issues/804 96 | on_dir(get_root_dir(fname)) 97 | end, 98 | settings = { 99 | templateExtension = { "tmpl" }, 100 | gofumpt = true, 101 | }, 102 | } 103 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Jarmos's Dotfiles 2 | 3 | [![QA Checks](https://github.com/Jarmos-san/dotfiles/actions/workflows/qa-checks.yml/badge.svg)](https://github.com/Jarmos-san/dotfiles/actions/workflows/qa-checks.yml) 4 | ![GitHub repo size](https://img.shields.io/github/repo-size/Jarmos-san/dotfiles?label=Repo%20Size&logo=GitHub&style=flat-square) 5 | ![GitHub](https://img.shields.io/github/license/Jarmos-san/dotfiles?label=License&logo=GitHub&style=flat-square) 6 | ![Twitter Follow](https://img.shields.io/twitter/follow/Jarmosan?style=social) 7 | 8 | This repository contains various "_dotfiles_" for my personal development needs. 9 | The said dotfiles are mostly configurations for the tools I use to write code on 10 | a daily basis. 11 | 12 | ## How to Use This Project 13 | 14 | The contents of this repository are **VERY** personalised & might not suit 15 | **YOUR** particular needs as-is. Hence, I strongly recommend to use the contents 16 | of this repository as a source of reference only. 17 | 18 | **DISCLAIMER**: Do not fork this repository & run the [scripts](./setup) 19 | provided here to setup your system. I'll not be held responsible for any 20 | potential data loss or system corruption in case something goes south when using 21 | the contents of this repository. Running the automation script below to setup 22 | everything: 23 | 24 | ```console 25 | curl -fsSL "https://tinyurl.com/setup-dotfile" | bash -c 26 | ``` 27 | 28 |
29 | See screenshots of what the tools look like! 30 | Neovim: 31 | Neovim screenshot 32 | Wezterm: 33 | Wezterm screenshot 34 | Starship: 35 | Starship prompt screenshot 36 | 37 |
38 | 39 | ## Acknowledgements 40 | 41 | The configurations I used are heavily inspired from other giants of the 42 | community. Following are some of the repositories I keep an eye out for 43 | inspiration. 44 | 45 | - Salomon Popp's [disrupted/dotfiles](https://github.com/disrupted/dotfiles) 46 | - Mathias Bynen's 47 | [mathiasbynens/dotfiles](https://github.com/mathiasbynens/dotfiles) 48 | - [codeinthehouse's gist](https://gist.githubusercontent.com/codeinthehole/26b37efa67041e1307db/raw/67c06401c3cdb7f7f96aa9054e95cbe0e473b7f0/osx_bootstrap.sh) 49 | - Dries Vints's [driesvints/dotfiles](https://github.com/driesvints/dotfiles) 50 | - Tom Payne's [twpayne/dotfiles](https://github.com/twpayne/dotfiles) 51 | - Maria José Solano's 52 | [MariaSolOs/dotfiles](https://github.com/MariaSolOs/dotfiles) 53 | - TJ Devrie's [kickstart.nvim](https://github.com/nvim-lua/kickstart.nvim) 54 | 55 | More will be added as & when I come across any. 56 | 57 | ## Terms & Conditions of Usage 58 | 59 | Everything in this repository is licensed under the T&Cs of a FOSS license. More 60 | specifically, the project is licensed under the T&Cs of the MIT License, so for 61 | more info on it, refer to the [LICENSE](./LICENSE). So feel free to copy & 62 | distribute any of the configurations I shared in this repository. 63 | -------------------------------------------------------------------------------- /dotfiles/.config/git/config: -------------------------------------------------------------------------------- 1 | [init] 2 | defaultBranch = main 3 | 4 | [include] 5 | path = ~/.config/git/credentials 6 | 7 | [merge] 8 | tool = nvim 9 | 10 | [mergetool] 11 | keepBackup = false 12 | prompt = false 13 | keepTemporaries = false 14 | 15 | [mergetool "nvim"] 16 | ; INFO: More information about the following suggestions can be found at: 17 | ; https://smittie.de/posts/git-mergetool 18 | ; cmd = nvim -d $LOCAL $REMOTE $MERGED -c '$wincmd w' -c '$wincmd J' 19 | ; cmd = "nvim -d -c \"wincmd l\" -c \"normal ]c\" \"$LOCAL\" \"$MERGED\" \"$REMOTE\"" 20 | 21 | ; NOTE: This is still experimental!!! 22 | ; cmd = "nvim -d '$LOCAL' '$MERGED' '$REMOTE' -c 'wincmd l' -c 'wincmd J'" 23 | ; Use the following repository to run some experiments 24 | ; https://github.com/redguardtoo/test-git-mergetool 25 | 26 | [push] 27 | default = current 28 | 29 | [core] 30 | editor = nvim 31 | pager = bat 32 | whitespace = fix 33 | excludesfile = '~/.config/git/ignore' 34 | 35 | [color "branch"] 36 | current = white magenta bold 37 | local = green bold 38 | remote = blue bold 39 | upstream = magenta bold 40 | plain = white bold 41 | 42 | [color "diff"] 43 | meta = yellow bold 44 | frag = magenta bold 45 | old = red bold 46 | new = green bold 47 | whitespace = red reverse 48 | 49 | [color "status"] 50 | added = green bold 51 | updated = yellow bold 52 | changed = red bold 53 | untracked = cyan black bold 54 | localBranch = cyan bold 55 | remoteBranch = red bold 56 | 57 | [commit] 58 | ; gpgSign = true 59 | ; TODO: Uncomment the following line after reconfigurng Git 60 | gpgSign = false 61 | 62 | [status] 63 | showStash = true 64 | relativepaths = false 65 | 66 | [tag] 67 | forceSignAnnotated = true 68 | gpgSign = false 69 | 70 | [url "git@github.com:"] 71 | insteadof = "gh:" 72 | 73 | [url "git@gist.github.com/"] 74 | insteadof = "gist:" 75 | 76 | [url "git@github.com:Jarmos-san/"] 77 | insteadof = "jarmos:" 78 | 79 | [url "git@github.com:"] 80 | insteadof = "https://github.com" 81 | 82 | [help] 83 | autocorrect = 1 84 | 85 | [color "status"] 86 | added = green bold 87 | updated = yellow bold 88 | changed = red bold 89 | untracked = cyan black bold 90 | localBranch = cyan bold 91 | remoteBranch = red bold 92 | 93 | [color "diff"] 94 | meta = yellow bold 95 | frag = magenta bold 96 | old = red bold 97 | new = green bold 98 | whitespace = red reverse 99 | 100 | [color "branch"] 101 | current = black magenta bold 102 | local = green bold 103 | remote = blue bold 104 | upstream = magenta bold 105 | plain = white bold 106 | 107 | [submodule] 108 | recurse = true 109 | 110 | [alias] 111 | st = status --short --branch --untracked-files=all 112 | ci = commit -m 113 | ca = commit -am 114 | cb = checkout -b 115 | pl = pull --rebase 116 | pu = push 117 | cl = clone 118 | vb = branch -vv 119 | rv = remote -v 120 | ra = remote add origin 121 | tar = archive --format=tar 122 | zip = archive --format=zip 123 | logs = log --pretty=oneline --max-count=20 124 | -------------------------------------------------------------------------------- /dotfiles/.config/tmux/tmux.conf: -------------------------------------------------------------------------------- 1 | # Source the configuration file for the statusline 2 | source-file ~/.config/tmux/statusline/statusline.conf 3 | 4 | ### General Options ### 5 | # Use Vi style keybindings in copy mode (hjkl for navigation, v/y for selection) 6 | set-option -gw mode-keys vi 7 | 8 | # Default terminal type advertised to programs running inside Tmux 9 | set-option -g default-terminal "tmux-256color" 10 | 11 | # Start the window and pane numbering at 0 (instead of the default 0) 12 | set-option -g base-index 1 13 | set-option -g pane-base-index 1 14 | 15 | # Enable true colour (RGB) support for xterm-compatible terminals 16 | set-option -a terminal-features 'xterm-256color:RGB' 17 | 18 | # Allow applications inside Tmux to receive focus events (helps Neovim 19 | # auto-refresh LSP, adjust cursor shape and so on) 20 | set-option -g focus-events on 21 | 22 | ### Window / Pane Navigation ### 23 | # Move between windows with Ctrl+p / Ctrl + n (previous / next) 24 | bind-key C-p previous-window 25 | bind-key C-n next-window 26 | 27 | # Vim style pane navigation (prefix + hjkl) 28 | bind-key h select-pane -L # Left 29 | bind-key j select-pane -D # Down 30 | bind-key k select-pane -U # Up 31 | bind-key l select-pane -R # Right 32 | 33 | ### Copy Mode ### 34 | # Visual selection in copy mode (like Vim's v/V) 35 | bind-key -T copy-mode-vi v send -X begin-selection 36 | bind-key -T copy-mode-vi V send -X select-line 37 | 38 | if-shell "uname -r | grep -qEi 'microsoft|wsl'" { 39 | bind -T copy-mode-vi y send -X copy-pipe-and-cancel "clip.exe" 40 | } { 41 | if-shell "command -v wl-copy" { 42 | bind -T copy-mode-vi y send -X copy-pipe-and-cancel "wl-copy" 43 | } { 44 | bind -T copy-mode-vi y send -X copy-selection-and-cancel 45 | } 46 | } 47 | 48 | ### General QoL Improvements ### 49 | # Unbind the default prefix key and set Space as the custom prefix key instead 50 | unbind C-b 51 | set-option -g prefix C-Space 52 | 53 | # Reload the Tmux config file with prefix + R 54 | bind-key R source-file "~/.config/tmux/tmux.conf"\; display-message 'Reloaded Tmux configurations' 55 | 56 | # Kill the pane without confirmation 57 | bind-key X kill-pane 58 | 59 | # Kill the current session safely after transmitting an user prompt 60 | bind-key K confirm-before -p "Kill Session #S? (y/N)" kill-session 61 | 62 | # Set the status bar position to the top of the client 63 | set-option -g status-position top 64 | 65 | # Create panes in the same working directory 66 | bind-key '"' split-window -c "#{pane_current_path}" # Horizontal split 67 | bind-key % split-window -hc "#{pane_current_path}" # Vertical split 68 | 69 | # Create a new window (and immediately rename it) with the current directory 70 | bind-key c new-window -c "#{pane_current_path}" \; command-prompt "rename-window '%%'" 71 | 72 | # Set the value of EDITOR to 'nvim' (Neovim) 73 | set-environment -g EDITOR nvim 74 | 75 | # Set the colours for the Tmux command prompt 76 | set-option -g message-style "bg=#030007,fg=#cae2e6" 77 | 78 | # Set the colour of the clock on Tmux 79 | set-option -g clock-mode-colour "#c2e7d9" 80 | 81 | ### Configurations for the panes ### 82 | # Configure the display panes to be displayed on screen for 1.5s before disappearing 83 | set-option -g display-panes-time 1500 84 | 85 | # Add a high-contrast orange colour to the displayed pane 86 | set-option -g display-panes-color "orange" 87 | 88 | # Add a high contrast red colour to the currently active pane 89 | set-option -g display-panes-active-colour "green" 90 | 91 | # Set a thick border for the panes 92 | set-option -g pane-border-lines "heavy" 93 | 94 | # vim:ft=tmux 95 | -------------------------------------------------------------------------------- /dotfiles/.config/starship/starship.toml: -------------------------------------------------------------------------------- 1 | "$schema" = 'https://starship.rs/config-schema.json' 2 | 3 | # Global/prompt-wide configurations 4 | command_timeout = 20000 # Increase the default timeout duration for long-running applications 5 | 6 | # palette = "catppuccin_macchiato" 7 | 8 | # Replace the "❯" symbol in the prompt with "➜" 9 | [character] # The name of the module we are configuring is "character" 10 | success_symbol = "[->](bold green)" # The "success_symbol" segment is being set to "➜" with the color "bold green" 11 | error_symbol = "[->](bold red)" # Similar to the "sucess_symbol" but in bright red 12 | vicmd_symbol = "[❮](green)" 13 | 14 | # Prompt customizations for Docker projects 15 | [docker_context] 16 | symbol = " " # Replaces the default emoji "🐳 " 17 | 18 | # Prompt customizations for projects which are packages 19 | # For more info on this module refer to the documentations at: 20 | # https://starship.rs/config/#package-version 21 | [package] 22 | symbol = " " # Replaces the default emoji "📦 " 23 | 24 | # Prompt customizations for Python projects 25 | [python] 26 | symbol = " " # Replaces the defailt emoji "🐍 " 27 | 28 | # Prompt customization for Version Control info with Git 29 | [git_branch] 30 | symbol = " " # Replaces the default emoji " " 31 | 32 | [directory] 33 | truncation_length = 4 34 | # Catppuccin 'lavender' 35 | style = "bold lavender" 36 | 37 | # palette tables should be last in the config ⚓️ 38 | [palettes.catppuccin_macchiato] 39 | rosewater = "#f4dbd6" 40 | flamingo = "#f0c6c6" 41 | pink = "#f5bde6" 42 | mauve = "#c6a0f6" 43 | red = "#ed8796" 44 | maroon = "#ee99a0" 45 | peach = "#f5a97f" 46 | yellow = "#eed49f" 47 | green = "#a6da95" 48 | teal = "#8bd5ca" 49 | sky = "#91d7e3" 50 | sapphire = "#7dc4e4" 51 | blue = "#8aadf4" 52 | lavender = "#b7bdf8" 53 | text = "#cad3f5" 54 | subtext1 = "#b8c0e0" 55 | subtext0 = "#a5adcb" 56 | overlay2 = "#939ab7" 57 | overlay1 = "#8087a2" 58 | overlay0 = "#6e738d" 59 | surface2 = "#5b6078" 60 | surface1 = "#494d64" 61 | surface0 = "#363a4f" 62 | base = "#24273a" 63 | mantle = "#1e2030" 64 | crust = "#181926" 65 | 66 | [palettes.catppuccin_frappe] 67 | rosewater = "#f2d5cf" 68 | flamingo = "#eebebe" 69 | pink = "#f4b8e4" 70 | mauve = "#ca9ee6" 71 | red = "#e78284" 72 | maroon = "#ea999c" 73 | peach = "#ef9f76" 74 | yellow = "#e5c890" 75 | green = "#a6d189" 76 | teal = "#81c8be" 77 | sky = "#99d1db" 78 | sapphire = "#85c1dc" 79 | blue = "#8caaee" 80 | lavender = "#babbf1" 81 | text = "#c6d0f5" 82 | subtext1 = "#b5bfe2" 83 | subtext0 = "#a5adce" 84 | overlay2 = "#949cbb" 85 | overlay1 = "#838ba7" 86 | overlay0 = "#737994" 87 | surface2 = "#626880" 88 | surface1 = "#51576d" 89 | surface0 = "#414559" 90 | base = "#303446" 91 | mantle = "#292c3c" 92 | crust = "#232634" 93 | 94 | [palettes.catppuccin_latte] 95 | rosewater = "#dc8a78" 96 | flamingo = "#dd7878" 97 | pink = "#ea76cb" 98 | mauve = "#8839ef" 99 | red = "#d20f39" 100 | maroon = "#e64553" 101 | peach = "#fe640b" 102 | yellow = "#df8e1d" 103 | green = "#40a02b" 104 | teal = "#179299" 105 | sky = "#04a5e5" 106 | sapphire = "#209fb5" 107 | blue = "#1e66f5" 108 | lavender = "#7287fd" 109 | text = "#4c4f69" 110 | subtext1 = "#5c5f77" 111 | subtext0 = "#6c6f85" 112 | overlay2 = "#7c7f93" 113 | overlay1 = "#8c8fa1" 114 | overlay0 = "#9ca0b0" 115 | surface2 = "#acb0be" 116 | surface1 = "#bcc0cc" 117 | surface0 = "#ccd0da" 118 | base = "#eff1f5" 119 | mantle = "#e6e9ef" 120 | crust = "#dce0e8" 121 | 122 | [palettes.catppuccin_mocha] 123 | rosewater = "#f5e0dc" 124 | flamingo = "#f2cdcd" 125 | pink = "#f5c2e7" 126 | mauve = "#cba6f7" 127 | red = "#f38ba8" 128 | maroon = "#eba0ac" 129 | peach = "#fab387" 130 | yellow = "#f9e2af" 131 | green = "#a6e3a1" 132 | teal = "#94e2d5" 133 | sky = "#89dceb" 134 | sapphire = "#74c7ec" 135 | blue = "#89b4fa" 136 | lavender = "#b4befe" 137 | text = "#cdd6f4" 138 | subtext1 = "#bac2de" 139 | subtext0 = "#a6adc8" 140 | overlay2 = "#9399b2" 141 | overlay1 = "#7f849c" 142 | overlay0 = "#6c7086" 143 | surface2 = "#585b70" 144 | surface1 = "#45475a" 145 | surface0 = "#313244" 146 | base = "#1e1e2e" 147 | mantle = "#181825" 148 | crust = "#11111b" 149 | -------------------------------------------------------------------------------- /dotfiles/.config/nvim/lua/options.lua: -------------------------------------------------------------------------------- 1 | local opt = vim.opt 2 | 3 | -- Sync the system clipboard with Neovim 4 | opt.clipboard = "unnamedplus" 5 | 6 | -- Enable the global status line 7 | opt.laststatus = 2 8 | 9 | -- Make the autocompletion window more accessible 10 | opt.completeopt = "menu,menuone,noselect" 11 | 12 | -- Hide the * markups for bold & italics 13 | opt.conceallevel = 3 14 | 15 | -- Case-insensitive searching UNLESS \C or one or more capital letters in the search term 16 | opt.ignorecase = true 17 | opt.smartcase = true 18 | 19 | -- Preview substitutions as its typed 20 | opt.inccommand = "split" 21 | 22 | -- The language to use when spelling checking 23 | opt.spelllang = { "en" } 24 | 25 | -- Configure how new splits should be opened 26 | opt.splitbelow = true 27 | opt.splitright = true 28 | 29 | -- Decrease mapped sequence wait time to display which-key popup sooner 30 | opt.timeoutlen = 300 31 | 32 | -- Save undo history 33 | opt.undofile = true 34 | opt.undolevels = 10000 35 | 36 | -- Save swap file & trigger CursorHold 37 | opt.updatetime = 200 38 | 39 | -- Command-line completion mode 40 | opt.wildmode = "longest:full,full" 41 | 42 | -- Maximum window width 43 | opt.winminwidth = 5 44 | 45 | --Disable swapfile creation since it gets annoying after a while 46 | opt.swapfile = false 47 | 48 | -- Configure Neovim to highlight the current location of the cursor 49 | opt.cursorline = true 50 | 51 | -- True color support for various plugins 52 | opt.termguicolors = true 53 | 54 | -- Make the completion popup window a bit transparent 55 | opt.pumblend = 10 56 | 57 | -- Display only 10 rows for the completion menu 58 | opt.pumheight = 10 59 | 60 | -- Disable showing the current mode since its already visible on the statusline 61 | opt.showmode = false 62 | 63 | -- Disable prompting the invoked command back to the user 64 | opt.showcmd = false 65 | 66 | -- Disable showing the current location of the cursor since the Lualine plugin takes care of it 67 | opt.ruler = false 68 | 69 | -- Configure Neovim to not wrap the contents of the buffer 70 | opt.wrap = false 71 | 72 | -- Add a slight padding to wrapped lines to distinguish them from the rest of the lines 73 | opt.showbreak = "...." 74 | 75 | -- Save the contents of the buffer after exiting Insert mode 76 | opt.autowrite = true 77 | 78 | -- Prompt to save the contents of the buffer before exiting 79 | opt.confirm = true 80 | 81 | -- Enable horinzontal scrolling when word wrap is disabled 82 | opt.sidescroll = 8 83 | 84 | -- FIXME: The following option might only be useful in certain filetypes like JSX, Markdown and such 85 | -- Make Neovim recognise dash-seperated words as a single word 86 | opt.iskeyword:append("-") 87 | 88 | -- Maintain a buffer of rows between the current row & the either ends of the window 89 | opt.scrolloff = 6 90 | 91 | -- Enable the current line number to be shown 92 | opt.number = true 93 | opt.relativenumber = true 94 | 95 | -- Allow the sign column to show else it'll keep shifting later on 96 | opt.signcolumn = "yes" 97 | 98 | -- Explicitly tell Neovim to use ZSH for terminal commands instead of relying on $SHELL 99 | opt.shell = "zsh" 100 | 101 | -- Enable break indent 102 | vim.opt.breakindent = true 103 | 104 | -- Sets how neovim will display certain whitespace characters in the editor. 105 | vim.opt.list = true 106 | vim.opt.listchars = { tab = "» ", trail = "·", nbsp = "␣" } 107 | 108 | -- These conditional lines of code are necessary when using Neovim from within WSL2. See ":h clipboard-wsl" for info 109 | if vim.fn.has("wsl") == 1 then 110 | vim.g.clipboard = { 111 | name = "WslClipboard", 112 | copy = { 113 | ["+"] = "clip.exe", 114 | ["*"] = "clip.exe", 115 | }, 116 | paste = { 117 | ["+"] = [[powershell.exe -c [Console]::Out.Write($(Get-Clipboard -Raw).tostring().replace("`r", ""))]], 118 | ["*"] = [[powershell.exe -c [Console]::Out.Write($(Get-Clipboard -Raw).tostring().replace("`r", ""))]], 119 | }, 120 | cache_enabled = 0, 121 | } 122 | end 123 | 124 | -- Disable the "~" lines on the left side column shown only the end of buffer is reached 125 | vim.opt.fillchars = "eob: " 126 | 127 | -- Remove the command line section completely! 128 | vim.opt.cmdheight = 1 129 | 130 | -- Add borders for all floating windows 131 | vim.opt.winborder = "rounded" 132 | -------------------------------------------------------------------------------- /dotfiles/.config/nvim/lua/keymaps.lua: -------------------------------------------------------------------------------- 1 | -- Module of keymaps & bindings which makes using Neovim a pleasure 2 | 3 | local telescope = require("telescope.builtin") 4 | local utils = require("utils") 5 | local map = require("utils").map 6 | local terminal = require("terminal").setup 7 | 8 | -- Open the starter dashboard if the buffer list is empty 9 | local open_starter_if_empty_buffer = function() 10 | local buf_id = vim.api.nvim_get_current_buf() 11 | local is_empty = vim.api.nvim_buf_get_name(buf_id) == "" and vim.bo[buf_id].filetype == "" 12 | if not is_empty then 13 | return 14 | end 15 | 16 | require("mini.starter").open() 17 | vim.cmd(buf_id .. "bwipeout") 18 | end 19 | 20 | -- Delete all buffers and open the starter dashboard 21 | local bdelete = function() 22 | require("mini.bufremove").delete() 23 | open_starter_if_empty_buffer() 24 | end 25 | 26 | -- Use the ":Telescope git_files" command if the current directory is version controlled with Git 27 | local git_files = function() 28 | if utils.is_git_repo() or utils.has_git_dir() then 29 | telescope.git_files() 30 | end 31 | end 32 | 33 | -- Change to Normal mode by pressing "jk" in quick succession 34 | map("i", "jk", "", { desc = "Change to Normal mode" }) 35 | 36 | -- Easier navigation to the beginning or the start of the line 37 | map("n", "H", "", { desc = "Move to the beginning of the line" }) 38 | map("n", "L", "", { desc = "Move to the end of the line" }) 39 | 40 | -- Resize windows using 41 | map("n", "", "resize +2", { desc = "Increase window height" }) 42 | map("n", "", "resize -2", { desc = "Decrease window height" }) 43 | map("n", "", "vertical resize +2", { desc = "Increase window width" }) 44 | map("n", "", "vertical resize -2", { desc = "Increase window width" }) 45 | 46 | -- Better & easier indenting 47 | map("v", "<", "", ">gv") 49 | 50 | -- Disable the redundant (and sometimes annoying "Ex mode") 51 | -- INFO: See the docs at ":h gQ" for more info on what its supposed to do 52 | map("n", "gQ", "") 53 | 54 | -- Easier navigation in Insert mode without the arrow keys! 55 | map("i", "", "", { desc = "Move left in Insert mode" }) 56 | map("i", "", "", { desc = "Move down in Insert mode" }) 57 | map("i", "", "", { desc = "Move up in Insert mode" }) 58 | map("i", "", "", { desc = "Move right in Insert mode" }) 59 | 60 | -- List all available files (and directories) using Telescope 61 | map("n", "ff", telescope.find_files, { desc = "List all available files/directories" }) 62 | map("n", "gf", git_files, { desc = "List all files and folders tracked inside the Git repository" }) 63 | map("n", "of", telescope.oldfiles, { desc = "Open recently opened files" }) 64 | 65 | -- Delete the buffer contents from the Neovim session 66 | map("n", "bd", bdelete, { desc = "Delete the buffer contents from the Neovim session" }) 67 | 68 | -- List all currently loaded buffers 69 | map("n", "b", telescope.buffers, { desc = "List all currently in-memory loaded buffers" }) 70 | 71 | -- Navigate easier around buffers while using the "leader" key 72 | map("n", "bn", "bnext", { desc = "Change to the next buffer" }) 73 | map("n", "bp", "bprevious", { desc = "Change to the previous buffer" }) 74 | 75 | -- Visually list in Telescope all the currently registered marks on the current buffer 76 | map("n", "m", telescope.marks, { desc = "List all Vim marks registered on the current buffer" }) 77 | 78 | -- List all the registers available on the buffer 79 | map("n", "r", telescope.registers, { desc = "Show the contents of the registers" }) 80 | 81 | -- Open Telescope to fuzzy search through the help docs 82 | map("n", "h", telescope.help_tags, { desc = "Open the help tags menu" }) 83 | 84 | -- Grep through the contents of the current directory for a particular string pattern 85 | map("n", "lg", telescope.live_grep, { desc = "Perform a grep on the file contents of the current directory" }) 86 | 87 | -- Open a Terminal inside Neovim itself 88 | map("n", "t", terminal.float, { desc = "Open the terminal prompt in a horizontal split" }) 89 | map("n", "tv", terminal.vertical, { desc = "Open the terminal prompt in vertical split" }) 90 | map({ "n", "i" }, "", terminal.toggle, { desc = "Toggle a floating terminal open/close" }) 91 | 92 | -- Exit terminal mode in builtin terminal with an easier to use shortcut 93 | map("t", "jk", "", { desc = "Exit terminal mode" }) 94 | 95 | -- Open a list of keymaps which can be fuzzy-searched using the Telescope UI 96 | map("n", "k", telescope.keymaps, { desc = "Open a list of available keymaps" }) 97 | -------------------------------------------------------------------------------- /dotfiles/.config/tmux/statusline/battery-status: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | ############################################################################### 4 | # 5 | # Battery Status Check 6 | # 7 | # This script prints the battery charge percentage of the system Tmux is 8 | # running on and it is designed to: 9 | # - Detect whether Tmux is running inside a WSL2 distribution. 10 | # - Fetch the battery percentage using the relevant API available on the 11 | # system for e.g. using PowerShell in WSL2. 12 | # - Print the battery percentage with an appropriate glyph (Nerd Font 13 | # required). 14 | # 15 | # **NOTE**: The script is intended to be run when initialising a Tmux 16 | # environment. Executing the script in a standalone manner may yield unexpected 17 | # results. 18 | # 19 | # Author: Somraj Saha (contact@jarmos.dev) 20 | # 21 | # License: MIT License (https://github.com/Jarmos-san/dotfiles?tab=MIT-1-ov-file#readme) 22 | # 23 | ############################################################################### 24 | 25 | import os 26 | import platform 27 | import subprocess 28 | 29 | 30 | def battery_wsl2() -> str: 31 | """Retrieve the remaining battery percentage from the WSL2 environment. 32 | 33 | This function invokes a PowerShell command to query the `Win32_Battery` CIM 34 | instance and extract the `EstimatedChargeRemaining` property which 35 | represents the current battery charge. 36 | 37 | Returns: 38 | str: The remaining battery percentage as a string (without the "%"). 39 | 40 | Raises: 41 | subprocess.ChildProcessError: If the PowerShell command fails. 42 | Exception: Any unexpected errors during command execution. 43 | """ 44 | try: 45 | output = subprocess.check_output( 46 | [ 47 | "powershell.exe", 48 | "-Command", 49 | "Get-CimInstance -ClassName Win32_Battery | ", 50 | "Select-Object -ExpandProperty EstimatedChargeRemaining", 51 | ], 52 | ) 53 | return output.decode("utf-8").strip().replace("\r", "") 54 | except Exception: 55 | raise 56 | 57 | 58 | def is_charging() -> bool: 59 | """Retrieve the raw battery status code from Windows using PowerShell. 60 | 61 | This function executes a PowerShell command via `powershell.exe` to query the 62 | `Win32_Battery` WMI class. It returns the `BatteryStatus` value as a string. 63 | 64 | Returns: 65 | str: The battery status code returned by Windows: 66 | - "1" = Discharging 67 | - "2" = Charging (on AC power) 68 | - "3" = Fully Charged 69 | - Other codes may indicate low battery, unknown, etc. 70 | 71 | Raises: 72 | subprocess.CalledProcessError: If the PowerShell command fails. 73 | """ 74 | try: 75 | command = subprocess.check_output( 76 | [ 77 | "powershell.exe", 78 | "-Command", 79 | "Get-CimInstance -ClassName Win32_Battery | ", 80 | "Select-Object -ExpandProperty BatteryStatus", 81 | ] 82 | ) 83 | except Exception: 84 | raise 85 | 86 | output = command.decode().strip().replace("\r", "") 87 | 88 | return output == "2" 89 | 90 | 91 | def battery_percent_printer(battery_percent: int) -> None: 92 | """Print a symbolic representation of a battery percentage. 93 | 94 | Args: 95 | battery_percent (int): The current battery charge (0-100 inclusive). 96 | 97 | Behavior: 98 | - Maps the percentage to one of ten predefined symbols, each covering 99 | a 10% range of the battery level. 100 | - Prints the symbol followed by the percentage value. 101 | - If `battery_percent` is outside the valid range, prints an error symbol. 102 | """ 103 | if is_charging(): 104 | symbols = ["󰢜", "󰂆", "󰂇", "󰂈", "󰢝", "󰂉", "󰢞", "󰂊", "󰂋", "󰂅"] 105 | else: 106 | symbols = ["󰁺", "󰁻", "󰁼", "󰁽", "󰁾", "󰁿", "󰂀", "󰂁", "󰂂", "󰁹"] 107 | 108 | if 0 <= battery_percent <= 100: 109 | index = min(battery_percent // 10, 9) 110 | print(f"{symbols[index]} {battery_percent}%") 111 | else: 112 | print("󰂑") 113 | 114 | 115 | def main() -> None: 116 | """Entrypoint of the script. 117 | 118 | Detects the current platform and determines whether the environment is 119 | WLS2. If so, fetches and prints the battery percentage otherwise prints a 120 | placeholder string. 121 | """ 122 | system = platform.system() 123 | 124 | battery_percent = None 125 | if system == "Linux": 126 | try: 127 | with open("/proc/version") as file: 128 | if "microsoft" in file.read() and os.getenv("WSL_INTEROP"): 129 | battery_percent = int(battery_wsl2()) 130 | except FileNotFoundError as err: 131 | raise err 132 | 133 | if battery_percent: 134 | battery_percent_printer(battery_percent) 135 | 136 | 137 | if __name__ == "__main__": 138 | main() 139 | -------------------------------------------------------------------------------- /dotfiles/.config/nvim/luasnippets/python.lua: -------------------------------------------------------------------------------- 1 | local luasnip = require("luasnip") 2 | local snippet = luasnip.snippet 3 | local insert_node = luasnip.insert_node 4 | local fmt = require("luasnip.extras.fmt").fmt 5 | 6 | return { 7 | -- Define the snippet for Python function definitions 8 | snippet( 9 | { trig = "def", desc = "Create a Python function definition" }, 10 | fmt( -- The format of the snippet 11 | [[ 12 | def {1}({2}: {3}) -> {4}: 13 | """{5}. 14 | 15 | Args: 16 | {2}: {6}. 17 | 18 | Returns: 19 | {4}: {7} 20 | 21 | Raises: 22 | {8} 23 | """ 24 | {9} 25 | ]], 26 | { -- The node of the snippet to replace content with 27 | insert_node(1, "function_name"), 28 | insert_node(2, "arg"), 29 | insert_node(3, "ArgumentType"), 30 | insert_node(4, "ReturnType"), 31 | insert_node(5, "Describe the function briefly."), 32 | insert_node(6, "Explain the argument briefly."), 33 | insert_node(7, "Explain the return type briefly."), 34 | insert_node(8, "Exception"), 35 | insert_node(9, ""), 36 | }, 37 | { 38 | repeat_duplicates = true, -- Ensure duplicates content are copied as-is 39 | } 40 | ) 41 | ), 42 | 43 | -- Define the snippet for Python classes 44 | snippet( 45 | { trig = "class", desc = "Create a Python class implementation" }, 46 | fmt( 47 | [[ 48 | class {1}({2}): 49 | """{3}""" 50 | 51 | {4} 52 | ]], 53 | { 54 | insert_node(1, "ClassName"), 55 | insert_node(2, "ParentClassName"), 56 | insert_node(3, "Briefly describe the class and its characteristics."), 57 | insert_node(4, ""), 58 | } 59 | ) 60 | ), 61 | 62 | -- Snippet for the "if __name__ == '__main__:' logic" 63 | snippet( 64 | { trig = "__main__", desc = "Create logic to invoke the Python script with apt shebang" }, 65 | fmt( 66 | [[ 67 | if __name__ == '__main__': 68 | main() 69 | ]], 70 | {} 71 | ) 72 | ), 73 | 74 | -- Snippet for the "__repr__" function 75 | snippet( 76 | { trig = "__repr__", desc = "Implement a class's __repr__ method" }, 77 | fmt( 78 | [[ 79 | def __repr__(self) -> str: 80 | """{1}""" 81 | return f"{{{2}}}" 82 | ]], 83 | { 84 | insert_node(1, "Return a string representation of the class instance for debugging."), 85 | insert_node(2, ""), 86 | } 87 | ) 88 | ), 89 | 90 | -- Snippet for if-else statements 91 | snippet( 92 | { trig = "if-else", desc = 'Create an "if-else" logic block' }, 93 | fmt( 94 | [[ 95 | if {1}: 96 | {2} 97 | else: 98 | {3} 99 | ]], 100 | { 101 | insert_node(1, ""), 102 | insert_node(2, ""), 103 | insert_node(3, ""), 104 | } 105 | ) 106 | ), 107 | 108 | -- Snippets for match-case statements 109 | snippet( 110 | { trig = "match", desc = "Create a match statement" }, 111 | fmt( 112 | [[ 113 | match {1}: 114 | case {2}: 115 | {3} 116 | case _: 117 | {4} 118 | ]], 119 | { 120 | insert_node(1, ""), 121 | insert_node(2, ""), 122 | insert_node(3, ""), 123 | insert_node(4, ""), 124 | } 125 | ) 126 | ), 127 | 128 | -- Snippets for creating Pyright directives 129 | snippet( 130 | { trig = "pyright", desc = "Create a Pyright directive" }, 131 | fmt( 132 | [[ 133 | # pyright: ignore[{1}] 134 | ]], 135 | { insert_node(1, "directive") } 136 | ) 137 | ), 138 | 139 | -- Snippets for creating "noqa" directives (possibly used by tools like Ruff) 140 | snippet( 141 | { trig = "noqa", desc = "Create a directive for tools like Ruff" }, 142 | fmt( 143 | [[ 144 | # noqa: {1} 145 | ]], 146 | { insert_node(1, "directive") } 147 | ) 148 | ), 149 | 150 | -- Snippet to generate a testcase function 151 | snippet( 152 | { trig = "testfunc", desc = "Create a testcase function" }, 153 | fmt( 154 | [[ 155 | def test_{1}() -> None: 156 | """{2}""" 157 | {3} 158 | assert False 159 | ]], 160 | { insert_node(1, ""), insert_node(2, "A brief test case function description."), insert_node(3, "") } 161 | ) 162 | ), 163 | 164 | -- Snippet to generate a testcase class 165 | snippet( 166 | { trig = "testclass", desc = "Create a test class" }, 167 | fmt( 168 | [[ 169 | class Test{1}(): 170 | """{2}""" 171 | 172 | def {3}(self) -> {4}: 173 | """{5}""" 174 | return {4} 175 | 176 | def test_{6}(self) -> None: 177 | """{7}""" 178 | {8} 179 | assert False 180 | ]], 181 | { 182 | insert_node(1, ""), 183 | insert_node(2, "Describe the test class"), 184 | insert_node(3, "fixture"), 185 | insert_node(4, "ReturnType"), 186 | insert_node(5, "Describe the fixture"), 187 | insert_node(6, ""), 188 | insert_node(7, "Describe the test function"), 189 | insert_node(8, ""), 190 | } 191 | ) 192 | ), 193 | } 194 | -------------------------------------------------------------------------------- /dotfiles/.config/nvim/lua/plugins/lspconfig.lua: -------------------------------------------------------------------------------- 1 | -- Module for configuring the plugin responsible for handling LSP configurations 2 | 3 | return { 4 | -- Official plugin for more ease in configuring the in-built LSP client. 5 | "neovim/nvim-lspconfig", 6 | event = "LspAttach", 7 | init = function() 8 | vim.opt.updatetime = 250 -- Make Neovim to display the diagnostic hover window as fast as possible. 9 | -- Setup the LSP plugin to log only error messages else the log file grows too large eventually! 10 | vim.lsp.set_log_level(vim.log.levels.ERROR) 11 | vim.diagnostic.config({ 12 | underline = true, -- Show diagnostic errors with a squigly underline 13 | update_in_insert = true, -- Update the diagnostic message even when in Insert mode 14 | severity_sort = true, -- Configure Neovim to sort the error messages according to the severity. 15 | }) 16 | end, 17 | config = function() 18 | local map = require("utils").map 19 | local telescope = require("telescope.builtin") 20 | 21 | -- Add rounded borders to the LSP flaoting windows 22 | require("lspconfig.ui.windows").default_options.border = "rounded" 23 | 24 | local on_attach = function() 25 | map("n", "gd", telescope.lsp_definitions, { desc = "Jump to the object definition" }) 26 | map("n", "gD", vim.lsp.buf.declaration, { desc = "Jump to the object declaration" }) 27 | map("n", "gT", telescope.lsp_type_definitions, { desc = "Get the type documentations" }) 28 | map("n", "gi", vim.lsp.buf.implementation, { desc = "Jump to the implementation" }) 29 | map("n", "K", vim.lsp.buf.hover, { desc = "Open the documentations of the object" }) 30 | map("n", "", vim.lsp.buf.signature_help, { desc = "Get the help documentations" }) 31 | map("n", "gr", vim.lsp.buf.rename, { desc = "Rename the object under the cursor" }) 32 | map("n", "gR", telescope.lsp_references, { desc = "Jump to the reference of the object" }) 33 | map("n", "gra", vim.lsp.buf.code_action, { desc = "Open available code actions" }) 34 | map("n", "wa", vim.lsp.buf.add_workspace_folder, { desc = "Add workspace folder" }) 35 | map("n", "wr", vim.lsp.buf.remove_workspace_folder, { desc = "Remove workspace folder" }) 36 | map("n", "wl", vim.lsp.buf.list_workspace_folders, { desc = "List workspace folders" }) 37 | end 38 | 39 | local capabilities = require("blink.cmp").get_lsp_capabilities() 40 | 41 | -- INFO: Necessary configuration for the JSON LSP server. See the following URL for more information: 42 | -- https://github.com/neovim/nvim-lspconfig/blob/master/doc/server_configurations.md#jsonls 43 | capabilities.textDocument.completion.completionItem.snippetSupport = true 44 | 45 | --[[ 46 | -- Configurations required for the Vue LSP server to work as expected 47 | --]] 48 | -- Path to the LSP server executable 49 | local vue_language_server_path = vim.fn.stdpath("data") 50 | .. "/mason/packages/vue-language-server/node_modules/@vue/language-server" 51 | 52 | -- Configuration to initialise the 'vtsls' LSP server with 53 | -- NOTE: The VUe LSP server does not work as expected with the official `tsserver` 54 | local vtsls_config = { 55 | filetypes = { "typescript", "javascript", "javascriptreact", "typescriptreact", "vue" }, 56 | settings = { 57 | vtsls = { 58 | tsserver = { 59 | globalPlugins = { 60 | { 61 | name = "@vue/typescript-plugin", 62 | location = vue_language_server_path, 63 | languages = { "vue" }, 64 | configNamespace = "typescript", 65 | }, 66 | }, 67 | }, 68 | }, 69 | }, 70 | } 71 | 72 | -- Configurations the Vue LSP is supposed to be initialised with 73 | local vue_ls_config = { 74 | on_init = function(client) 75 | client.handlers["tsserver/request"] = function(_, result, context) 76 | local clients = vim.lsp.get_clients({ bufnr = context.bufnr, name = "vtsls" }) 77 | if #clients == 0 then 78 | vim.notify("Could not find `vtsls` LSP client, `vue_ls` would not work without it.", vim.log.levels.ERROR) 79 | return 80 | end 81 | 82 | local ts_client = clients[1] 83 | 84 | local param = unpack(result) 85 | local id, command, payload = unpack(param) 86 | ts_client:exec_cmd({ 87 | title = "vue_request_forward", 88 | command = "typescript.tsserverRequest", 89 | arguments = { 90 | command, 91 | payload, 92 | }, 93 | }, { 94 | bufnr = context.bufnr, 95 | }, function(_, r) 96 | local response_data = { { 97 | id, 98 | r.body, 99 | } } 100 | client:notify("tsserver/response", response_data) 101 | end) 102 | end 103 | end, 104 | } 105 | 106 | vim.lsp.config("vtsls", vtsls_config) 107 | vim.lsp.config("vue_ls", vue_ls_config) 108 | vim.lsp.enable({ "vtsls", "vue_ls" }) 109 | 110 | -- Enable the LSP for Ansible work 111 | vim.lsp.config("ansiblels", { 112 | on_attach = on_attach, 113 | capabilities = capabilities, 114 | }) 115 | end, 116 | dependencies = { 117 | -- This plugin needs to be loaded as well otherwise Neovim can't find the LSP binary on $PATH. 118 | "williamboman/mason.nvim", 119 | }, 120 | } 121 | -------------------------------------------------------------------------------- /dotfiles/.config/nvim/lua/autocmds.lua: -------------------------------------------------------------------------------- 1 | -- Module for configuring some global autocommand which will always be loaded at startup 2 | 3 | local autocmd = require("utils").autocmd 4 | local augroup = require("utils").augroup 5 | 6 | autocmd("TextYankPost", { 7 | desc = "Highlight the yanked text for a specified time.", 8 | group = augroup("yank_highlight"), 9 | callback = function() 10 | vim.highlight.on_yank({ timeout = 250 }) -- Keep the highlight for 250ms after yanking. 11 | end, 12 | }) 13 | 14 | autocmd("TermOpen", { 15 | desc = "Get into Insert mode when the terminal is opened", 16 | group = augroup("terminal_insert"), 17 | callback = function() 18 | vim.opt.number = false 19 | vim.opt.relativenumber = false 20 | vim.cmd("startinsert | 1") 21 | end, 22 | }) 23 | 24 | autocmd("FocusLost", { 25 | desc = "Save/write all unsaved buffers when focus is lost", 26 | group = augroup("save_buffers"), 27 | pattern = "*", 28 | command = "silent! wall", 29 | }) 30 | 31 | autocmd("BufReadPost", { 32 | desc = "Jump to the last known position of a file before closing it", 33 | group = augroup("buffer_checkpoint"), 34 | callback = function() 35 | local mark = vim.api.nvim_buf_get_mark(0, '"') 36 | local line_count = vim.api.nvim_buf_line_count(0) 37 | 38 | if mark[1] > 0 and mark[1] <= line_count then 39 | pcall(vim.api.nvim_win_set_cursor, 0, mark) 40 | end 41 | end, 42 | }) 43 | 44 | autocmd("VimResized", { 45 | desc = "Resize the splits if the window is resized", 46 | group = augroup("resize_splits"), 47 | callback = function() 48 | vim.cmd("tabdo wincmd =") 49 | end, 50 | }) 51 | 52 | autocmd("FileType", { 53 | desc = "Close some filtypes simply by pressing 'q'", 54 | group = augroup("close_with_q"), 55 | pattern = { "checkhealth", "help", "lspinfo", "man", "notify", "qf", "query" }, 56 | callback = function(event) 57 | vim.bo[event.buf].buflisted = false 58 | vim.keymap.set("n", "q", "close", { buffer = event.buf, silent = true }) 59 | end, 60 | }) 61 | 62 | autocmd({ "CursorMoved", "CursorMovedI" }, { 63 | desc = "Redraw the cursorline when navigating around the buffer", 64 | group = augroup("cursorline_number"), 65 | callback = function() 66 | if vim.wo.cursorline then 67 | vim.cmd("redraw") 68 | end 69 | end, 70 | }) 71 | 72 | autocmd("BufNewFile", { 73 | desc = "Create an EditorConfig file", 74 | group = augroup("editorconfig_template"), 75 | pattern = "**/.editorconfig", 76 | command = "0r ~/.config/nvim/skeletons/editorconfig.txt", 77 | }) 78 | 79 | autocmd("BufNewFile", { 80 | desc = "Create a simple README.md file", 81 | group = augroup("readme_template"), 82 | pattern = "**/README.md", 83 | command = "0r ~/.config/nvim/skeletons/readme.md", 84 | }) 85 | 86 | autocmd("BufNewFile", { 87 | desc = "Create a Dependabot configuration file", 88 | group = augroup("dependabot_template"), 89 | pattern = "**/.github/dependabot.yml", 90 | command = "0r ~/.config/nvim/skeletons/dependabot.yml", 91 | }) 92 | 93 | autocmd("BufNewFile", { 94 | desc = "Create a GitHub Workflow file", 95 | group = augroup("github_workflow_template"), 96 | pattern = "**/.github/workflows/*.yml", 97 | command = "0r ~/.config/nvim/skeletons/github-workflow.yml", 98 | }) 99 | 100 | autocmd("BufNewFile", { 101 | desc = "Create a template Taskfile.yml", 102 | group = augroup("taskfile_template"), 103 | pattern = "**/Taskfile.yml", 104 | command = "0r ~/.config/nvim/skeletons/taskfile.yml", 105 | }) 106 | 107 | autocmd("BufNewFile", { 108 | desc = "Create an entrypoint file for Python projects", 109 | group = augroup("python_entrypoint_file"), 110 | pattern = "**/main.py", 111 | command = "0r ~/.config/nvim/skeletons/main.py", 112 | }) 113 | 114 | autocmd("BufNewFile", { 115 | desc = "Create a LICENSE Plain-Text file for projects on GitHub", 116 | group = augroup("license_template"), 117 | pattern = "**/LICENSE", 118 | command = "0r ~/.config/nvim/skeletons/license.txt", 119 | }) 120 | 121 | autocmd("BufNewFile", { 122 | desc = "Create a Vue SFC", 123 | group = augroup("vue_sfc_template"), 124 | pattern = "*.vue", 125 | command = "0r ~/.config/nvim/skeletons/sfc.vue", 126 | }) 127 | 128 | autocmd("TermClose", { 129 | desc = "Delete the terminal buffer when the process exits", 130 | group = augroup("terminal_close"), 131 | callback = function() 132 | vim.cmd("bdelete") 133 | end, 134 | }) 135 | 136 | autocmd("BufWritePre", { 137 | desc = "Trim training whitespace after writing the contents of a buffer", 138 | group = augroup("trim_trailing_whitespace"), 139 | pattern = "*", 140 | command = "%s/\\s\\+$//e", 141 | }) 142 | 143 | -- Autocommand to apply the highlights while performing a search and replace action 144 | autocmd("CmdlineEnter", { 145 | desc = "Apply highlights during search and replace", 146 | group = augroup("apply_highlights"), 147 | pattern = { "/", "?" }, 148 | callback = function() 149 | vim.o.hlsearch = true 150 | end, 151 | }) 152 | 153 | -- Autocommand to clear the highlights after performing a search and replace action 154 | autocmd("CmdlineLeave", { 155 | desc = "Clear highlights after search and replace", 156 | group = augroup("clear_highlights"), 157 | pattern = { "/", "?" }, 158 | callback = function() 159 | vim.o.hlsearch = false 160 | end, 161 | }) 162 | 163 | -- Autocommand to apply custom highlights after the colorscheme is applied 164 | autocmd("ColorScheme", { 165 | desc = "Apply custom highlights after colorscheme", 166 | group = augroup("apply_custom_highlights"), 167 | callback = function() 168 | require("highlights").setup() 169 | end, 170 | }) 171 | -------------------------------------------------------------------------------- /dotfiles/.config/nvim/lua/statusline.lua: -------------------------------------------------------------------------------- 1 | -- This is a WORK-IN-PROGRESS custom implementation of a statusline. 2 | -- Once complete, it'll replace the lualine plugin 3 | -- Inspirational resources are as follows: 4 | -- https://nuxsh.is-a.dev/blog/custom-nvim-statusline.html 5 | -- https://elianiva.my.id/posts/neovim-lua-statusline/ 6 | 7 | ---@class Statusline 8 | ---@field render fun(): string 9 | ---@field setup fun(): nil 10 | local M = {} 11 | 12 | ---@return nil 13 | local define_highlight_groups = function() 14 | vim.api.nvim_set_hl(0, "StatuslineModeNormal", { fg = "#282c34", bg = "#98c379", bold = true }) 15 | vim.api.nvim_set_hl(0, "StatuslineModeInsert", { fg = "#282c34", bg = "#61afef", bold = true }) 16 | vim.api.nvim_set_hl(0, "StatuslineModeVisual", { fg = "#282c34", bg = "#c678dd", bold = true }) 17 | vim.api.nvim_set_hl(0, "StatuslineModeCommand", { fg = "#282c34", bg = "#e5c07b", bold = true }) 18 | vim.api.nvim_set_hl(0, "StatuslineModeReplace", { fg = "#282c34", bg = "#e06c75", bold = true }) 19 | vim.api.nvim_set_hl(0, "StatuslineModeTerminal", { fg = "#282c34", bg = "#56b6c2", bold = true }) 20 | end 21 | 22 | ---@type {[string]: {label: string, hl: string}} 23 | ---The various Vim modes and their respective codes as returned by the mode() function. 24 | ---See vim.api.nvim_get_mode for more information. 25 | local modes = { 26 | ["n"] = { label = "NORMAL", hl = "StatuslineModeNormal" }, 27 | ["no"] = { label = "NORMAL", hl = "StatuslineModeNormal" }, 28 | ["v"] = { label = "VISUAL", hl = "StatuslineModeVisual" }, 29 | ["V"] = { label = "VISUAL LINE", hl = "StatuslineModeVisual" }, 30 | [""] = { label = "VISUAL BLOCK", hl = "StatuslineModeVisual" }, 31 | ["s"] = { label = "SELECT", hl = "StatuslineModeVisual" }, 32 | ["S"] = { label = "SELECT LINE", hl = "StatuslineModeVisual" }, 33 | [""] = { label = "SELECT BLOCK", hl = "StatuslineModeVisual" }, 34 | ["i"] = { label = "INSERT", hl = "StatuslineModeInsert" }, 35 | ["ic"] = { label = "INSERT", hl = "StatuslineModeInsert" }, 36 | ["R"] = { label = "REPLACE", hl = "StatuslineModeReplace" }, 37 | ["Rv"] = { label = "REPLACE (VISUAL)", hl = "StatuslineModeReplace" }, 38 | ["c"] = { label = "COMMAND", hl = "StatuslineModeCommand" }, 39 | ["cv"] = { label = "COMMAND (VIM EX)", hl = "StatuslineModeCommand" }, 40 | ["ce"] = { label = "COMMAND (EX)", hl = "StatuslineModeCommand" }, 41 | ["r"] = { label = "PROMPT", hl = "StatuslineModeCommand" }, 42 | ["rm"] = { label = "MOAR", hl = "StatuslineModeCommand" }, 43 | ["r?"] = { label = "CONFIRM", hl = "StatuslineModeCommand" }, 44 | ["!"] = { label = "SHELL", hl = "StatuslineModeCommand" }, 45 | ["t"] = { label = "TERMINAL", hl = "StatuslineModeTerminal" }, 46 | ["nt"] = { label = "TERMINAL", hl = "StatuslineModeTerminal" }, 47 | } 48 | 49 | ---@return string 50 | ---Return the current "mode" and return a uppercase formatted string representation. 51 | ---@see vim.api.nvim_get_mode 52 | local get_mode = function() 53 | local current_mode = vim.api.nvim_get_mode().mode 54 | local mode_info = modes[current_mode] or { label = "UNKNOWN", hl = "StatuslineModeNormal" } 55 | 56 | return string.format("%%#%s# %s ", mode_info.hl, mode_info.label) 57 | end 58 | 59 | ---@return string 60 | ---Get the total number of diagnostic entries in the current buffer and return a nicely 61 | ---formatted string with set icons to go with them. 62 | ---@see vim.diagnostic 63 | local get_diagnostics = function() 64 | ---@type {['errors']: integer, ['warnings']: number, ['info']: number, ['hints']: number} 65 | local count = { 66 | errors = 0, 67 | warnings = 0, 68 | info = 0, 69 | hints = 0, 70 | } 71 | 72 | ---@type { [string]: integer } 73 | local levels = { 74 | errors = vim.diagnostic.severity.ERROR, 75 | warnings = vim.diagnostic.severity.WARN, 76 | info = vim.diagnostic.severity.INFO, 77 | hints = vim.diagnostic.severity.HINT, 78 | } 79 | 80 | for key, level in pairs(levels) do 81 | count[key] = vim.tbl_count(vim.diagnostic.get(0, { severity = level })) 82 | end 83 | 84 | local errors = "" 85 | local warnings = "" 86 | local hints = "" 87 | local info = "" 88 | 89 | if count["errors"] ~= 0 then 90 | errors = " %#LspDiagnosticsSignError#? " .. count["errors"] 91 | end 92 | 93 | if count["warnings"] ~= 0 then 94 | warnings = " %#LspDiagnosticsSignWarning# " .. count["warnings"] 95 | end 96 | 97 | if count["hints"] ~= 0 then 98 | hints = " %#LspDiagnosticsSignHint#? " .. count["hints"] 99 | end 100 | 101 | if count["info"] ~= 0 then 102 | info = " %#LspDiagnosticsSignInformation#? " .. count["info"] 103 | end 104 | 105 | return errors .. warnings .. hints .. info .. "%#Normal#" 106 | end 107 | 108 | ---@return string 109 | ---Return the full filename path 110 | local get_filepath = function() 111 | ---@type string 112 | local fpath = vim.fn.fnamemodify(vim.fn.expand("%"), ":~:.") 113 | 114 | if fpath == "" or fpath == "." then 115 | return " " 116 | end 117 | 118 | return string.format(" %s", fpath) 119 | end 120 | 121 | ---@return string 122 | ---Return the current location of the cursor 123 | local get_cursor_location = function() 124 | ---@type integer 125 | local line = vim.fn.line(".") 126 | ---@type integer 127 | local column = vim.fn.col(".") 128 | 129 | return string.format("%s:%s", line, column) 130 | end 131 | 132 | ---@return string 133 | ---Return the filetype of the current buffer 134 | local get_filetype = function() 135 | ---@type string 136 | local ftype = vim.bo.filetype 137 | 138 | return string.format(" [%s]", ftype) 139 | end 140 | 141 | ---@return string 142 | ---Render the statusline programatically 143 | function M.render() 144 | return table.concat({ 145 | get_mode(), 146 | get_diagnostics(), 147 | get_filepath(), 148 | "%=", 149 | get_cursor_location(), 150 | get_filetype(), 151 | }) 152 | end 153 | 154 | ---@return nil 155 | function M.setup() 156 | define_highlight_groups() 157 | vim.o.statusline = "%!v:lua.require('statusline').render()" 158 | end 159 | 160 | return M 161 | -------------------------------------------------------------------------------- /dotfiles/.config/nvim/luasnippets/go.lua: -------------------------------------------------------------------------------- 1 | local luasnip = require("luasnip") 2 | local snippet = luasnip.snippet 3 | local insert_node = luasnip.insert_node 4 | local fmt = require("luasnip.extras.fmt").fmt 5 | 6 | return { 7 | -- Snippet for defining a function 8 | snippet( 9 | { trig = "func", desc = "Create a function definition" }, 10 | fmt( 11 | [[ 12 | /** 13 | * {1} - {6} 14 | * 15 | * Parameters: 16 | * {8} 17 | * 18 | * Returns: 19 | * {7} 20 | */ 21 | func {1}({2} {3}) ({4}) {{ 22 | return {5} 23 | }} 24 | ]], 25 | { 26 | insert_node(1, "FunctionName"), 27 | insert_node(2, "Argument"), 28 | insert_node(3, "ArgumentType"), 29 | insert_node(4, "ReturnType"), 30 | insert_node(5, ""), 31 | insert_node(6, "Describe the function briefly."), 32 | insert_node(7, "Describe the return type briefly."), 33 | insert_node(8, "Describe the function arguments."), 34 | } 35 | ) 36 | ), 37 | 38 | -- Snippet to create a Go struct 39 | snippet( 40 | { trig = "struct", desc = "Create a Go struct" }, 41 | fmt( 42 | [[ 43 | type {1} struct {{ 44 | {2} 45 | }} 46 | ]], 47 | { insert_node(1, "StructName"), insert_node(2, "") } 48 | ) 49 | ), 50 | 51 | -- Snippet to create struct method 52 | snippet( 53 | { trig = "method", desc = "Create a struct method" }, 54 | fmt( 55 | [[ 56 | func ({1}) {2}({3}) {4} {{ 57 | return {5} 58 | }} 59 | ]], 60 | { 61 | insert_node(1, "Struct"), 62 | insert_node(2, "Method"), 63 | insert_node(3, "Args"), 64 | insert_node(4, "ReturnType"), 65 | insert_node(5, ""), 66 | } 67 | ) 68 | ), 69 | 70 | -- Snippet to create an interface 71 | snippet( 72 | { trig = "interface", desc = "Create an interface" }, 73 | fmt( 74 | [[ 75 | type {1} interface {{ 76 | {2}({3} {4}) {5} 77 | }} 78 | ]], 79 | { 80 | insert_node(1, "InterfaceName"), 81 | insert_node(2, "MethodName"), 82 | insert_node(3, "Argument"), 83 | insert_node(4, "ArgumentType"), 84 | insert_node(5, "ReturnType"), 85 | } 86 | ) 87 | ), 88 | 89 | -- Snippet for error handling 90 | snippet( 91 | { trig = "err", desc = "Create an error handling block" }, 92 | fmt( 93 | [[ 94 | if err != nil {{ 95 | return {1} 96 | }} 97 | ]], 98 | { insert_node(1, "err") } 99 | ) 100 | ), 101 | 102 | -- Snippet for a basic for-loop 103 | snippet( 104 | { trig = "for", desc = "Create a basic for-loop snippet" }, 105 | fmt( 106 | [[ 107 | for {1} {{ 108 | {2} 109 | }} 110 | ]], 111 | { insert_node(1, "i := 0; i < n; i++"), insert_node(2, "Statement") } 112 | ) 113 | ), 114 | 115 | -- Snippet to generate a testcase function 116 | snippet( 117 | { trig = "test", desc = "Create a snippet to generate a test function" }, 118 | fmt( 119 | [[ 120 | func Test{1}(t *testing.T) {{ 121 | {2} 122 | }} 123 | ]], 124 | { 125 | insert_node(1, "Name"), 126 | insert_node(2, ""), 127 | } 128 | ) 129 | ), 130 | 131 | -- Snippet to create a map 132 | snippet( 133 | { trig = "map", desc = "Create a map object" }, 134 | fmt( 135 | [[ 136 | map[{1}]{2} {{ 137 | {3} 138 | }} 139 | ]], 140 | { insert_node(1, "KeyType"), insert_node(2, "ValueType"), insert_node(3, "") } 141 | ) 142 | ), 143 | 144 | -- Snippet to create a channel 145 | snippet( 146 | { trig = "chan", desc = "Create a snippet for channels" }, 147 | fmt( 148 | [[ 149 | make(chan {1}) 150 | ]], 151 | insert_node(1, "Type") 152 | ) 153 | ), 154 | 155 | -- Snippet for generating function documentations 156 | snippet( 157 | { trig = "fndoc", desc = "Create a snippet for function documentations" }, 158 | fmt( 159 | [[ 160 | /** 161 | * {1} - {2} 162 | * 163 | * Parameters: 164 | * {3} 165 | * 166 | * Returns: 167 | * {4} 168 | */ 169 | ]], 170 | { 171 | insert_node(1, "FunctionName"), 172 | insert_node(2, "Description"), 173 | insert_node(3, "param1 Type, param2 Type"), 174 | insert_node(4, "Return description"), 175 | } 176 | ) 177 | ), 178 | 179 | -- Snippet for creating documentations for structs 180 | snippet( 181 | { trig = "structdoc", desc = "Create a snippet for generating struct documentations" }, 182 | fmt( 183 | [[ 184 | /** 185 | * {1} - {2} 186 | * 187 | * Fields: 188 | * {3} 189 | */ 190 | ]], 191 | { 192 | insert_node(1, "StructName"), 193 | insert_node(2, "Description"), 194 | insert_node(3, "Field1: Type // Field description"), 195 | } 196 | ) 197 | ), 198 | 199 | -- Snippet for creating documentation for packages 200 | snippet( 201 | { trig = "pkgdoc", desc = "Create a snippet for generating package documentations" }, 202 | fmt( 203 | [[ 204 | /** 205 | * Package {1} - {2} 206 | */ 207 | ]], 208 | { insert_node(1, "packageName"), insert_node(2, "Description of th package") } 209 | ) 210 | ), 211 | 212 | -- Snippet for creating documentation for methods 213 | snippet( 214 | { trig = "methoddoc", desc = "Create a snippet for generating documentations for struct methods" }, 215 | fmt( 216 | [[ 217 | /** 218 | * {1} - {2} method of {3} 219 | * 220 | * Parameters: 221 | * {4} 222 | * 223 | * Returns: 224 | * {5} 225 | */ 226 | ]], 227 | { 228 | insert_node(1, "MethodName"), 229 | insert_node(2, "Description"), 230 | insert_node(3, "StructName"), 231 | insert_node(4, "arg Type // Description"), 232 | insert_node(5, "ReturnType // Description"), 233 | } 234 | ) 235 | ), 236 | 237 | -- Snippet for creating documentations for struct fields 238 | snippet( 239 | { trig = "fields", desc = "Create a snippet for generating documentations for struct fields" }, 240 | fmt( 241 | [[ 242 | // {1}: {2} - {3} 243 | ]], 244 | { insert_node(1, "FieldName"), insert_node(2, "Type"), insert_node(3, "Field Description") } 245 | ) 246 | ), 247 | 248 | -- Snippet for generating the documentations for errors 249 | snippet( 250 | { trig = "errdoc", desc = "Creating a snippet for generating documentations for errors" }, 251 | fmt([[ // {1}: {2} - {3}]], { insert_node(1, "ErrorName"), insert_node(2, "Type"), insert_node(3, "Description") }) 252 | ), 253 | 254 | -- Snippet for generating the documentations for a function 255 | snippet( 256 | { trig = "funcdoc", desc = "Create a snippet for generating documentations for functions" }, 257 | fmt( 258 | [[ 259 | /** 260 | * {1}: {2} 261 | * 262 | * Parameters: 263 | * {3} 264 | * 265 | * Returns: 266 | * {4} 267 | */ 268 | ]], 269 | { 270 | insert_node(1, "FunctionName"), 271 | insert_node(2, "Description"), 272 | insert_node(3, "Parameters"), 273 | insert_node(4, "Returns"), 274 | } 275 | ) 276 | ), 277 | } 278 | -------------------------------------------------------------------------------- /dotfiles/.local/bin/update: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | """System maintenance and update utility. 4 | 5 | This script provides an unified interface for maintaining and updating the software 6 | across multiple environments. Depending on the Operating Systems, installed package 7 | managers and active shell, the script can perform; 8 | 9 | - Linux distribution updates using the appropriate package manager. 10 | - Homebrew package updates on MacOS or Linux systems where Homebrew is installed. 11 | - Zsh plugin updates for users running the Zsh shell with plugin repositories stored 12 | under `~/.zsh/plugins`. 13 | 14 | The script determines which update routines to run based on environment inspection 15 | rather than user input, making it suitable for automated maintenance tasks or periodic 16 | system cleanup. 17 | 18 | Errors from subprocess commands (such as package manager failures) may propagate unless 19 | caught internally, ensuring misconfigurations or unexpected system states are not 20 | silently ignored. 21 | 22 | Author: Somraj Saha 23 | License: MIT 24 | """ 25 | 26 | import datetime 27 | import os 28 | import platform 29 | import subprocess 30 | import sys 31 | from argparse import ArgumentParser, Namespace 32 | from pathlib import Path 33 | 34 | # Message labels with their respective colour codes 35 | _RESET = "\x1b[0m" 36 | _BLUE = "\x1b[94m" 37 | _GREEN = "\x1b[92m" 38 | # _YELLOW = "\x1b[93m" 39 | # _WARN = f"[{_YELLOW}WARN{_RESET}]" 40 | _RED = "\x1b[31m" 41 | _INFO = f"[{_BLUE}INFO{_RESET}]" 42 | _SUCCESS = f"[{_GREEN}SUCCESS{_RESET}]" 43 | _ERROR = f"[{_RED}ERROR{_RESET}]" 44 | 45 | 46 | def parse_args() -> Namespace: 47 | """Parse and return the CLI arguments. 48 | 49 | Returns: 50 | An argparse.Namespace object containing the parsed arguments. 51 | """ 52 | current_year = datetime.datetime.now(datetime.timezone.utc).year 53 | description = "intelligently update the system packages" 54 | epilog = f"© Somraj Saha 2018-{current_year} " 55 | 56 | parser = ArgumentParser(description=description, epilog=epilog) 57 | 58 | return parser.parse_args() 59 | 60 | 61 | def run_linux_updates() -> None: 62 | """Detect the Linux distribution and run system updates accordingly. 63 | 64 | Supported distributions: 65 | - Ubuntu (apt-get) 66 | - Debian (apt-get) 67 | - Fedora (dnf) 68 | 69 | This function executes the appropriate package manager commands for 70 | updating system packages and removing unused dependencies. It uses 71 | `subprocess.run(..., check=True)` to ensure errors are surfaced. 72 | 73 | If the distribution is not recognized, the function logs an error 74 | and terminates the program with a non-zero exit code. 75 | """ 76 | distro = platform.freedesktop_os_release().get("NAME", "") 77 | 78 | match distro: 79 | case "Ubuntu" | "Debian": 80 | print(f"{_INFO} Updating {distro} system...") 81 | subprocess.run(["sudo", "apt-get", "update"], check=True) 82 | subprocess.run(["sudo", "apt-get", "upgrade", "--yes"], check=True) 83 | subprocess.run( 84 | ["sudo", "apt-get", "autoremove", "--purge", "--yes"], check=True 85 | ) 86 | print(f"{_SUCCESS} {distro} APT packages upgrade complete!") 87 | case "Fedora": 88 | print(f"{_INFO} Updating {distro} system...") 89 | subprocess.run(["sudo", "dnf", "upgrade", "--assumeyes"], check=True) 90 | subprocess.run(["sudo", "dnf", "autoremove", "--assumeyes"], check=True) 91 | print(f"{_SUCCESS} {distro} APT packages upgrade complete!") 92 | case _: 93 | print(f"{_ERROR} Failed to identify system information...exiting!") 94 | sys.exit(1) 95 | 96 | 97 | def homebrew_installed() -> bool: 98 | """Determine whether Homebrew is installed and accessible. 99 | 100 | This function checks for the presence of the `brew` executable by attempting to run 101 | `brew --version`. No output is displayed during the check. 102 | 103 | Returns: 104 | `True`: Homebrew is installed and the `brew` command can be executed. 105 | `False`: Homebrew is not installed, not available on the system `PATH` or 106 | returned an unexpected error during its execution. 107 | """ 108 | try: 109 | subprocess.run(["brew", "--version"], check=True, stdout=subprocess.DEVNULL) 110 | return True 111 | except (FileNotFoundError, subprocess.CalledProcessError): 112 | return False 113 | 114 | 115 | def run_homebrew_updates() -> None: 116 | """Run system package updates using Homebrew. 117 | 118 | This function executes the standard Homebrew maintenance sequence: 119 | - `brew update` to refresh the available package definitions. 120 | - `brew upgrade` to upgrade installed formulae and casks. 121 | - `brew autoremove` to removed unused dependency packages. 122 | - `brew cleanup` to remove outdated files and cached data. 123 | 124 | All the commands are executed with the `check=True` parameter to raise a 125 | `subprocess.CalledProcessError` to be raised if any step fails. 126 | 127 | Raises: 128 | subprocess.CalledProcessError: If any Homebrew command exits with a non-zero 129 | status. 130 | """ 131 | print(f"{_INFO} Running Homebrew updates") 132 | 133 | subprocess.run(["brew", "update"], check=True) 134 | subprocess.run(["brew", "upgrade"], check=True) 135 | subprocess.run(["brew", "autoremove"], check=True) 136 | subprocess.run(["brew", "cleanup"], check=True) 137 | 138 | print(f"{_SUCCESS} Homebrew package upgrades complete!") 139 | 140 | 141 | def run_zsh_updates() -> None: 142 | """Update the local Zsh plugins by pulling the latest changes. 143 | 144 | This function assumes the Zsh plugins are cloned under: 145 | `~/.zsh/plugins/` 146 | 147 | For each plugin repository listed in the `plugins` tuple, the function: 148 | 1. Constructs the local plugin directory path. 149 | 2. Changes the working directory to that location. 150 | 3. Executes `git pull --rebase` to fetch and apply the upstream updates. 151 | 152 | All Git operations are executed with `check=True`, causing 153 | `subprocess.CalledProcessError` to be raised if any update fails. 154 | 155 | Raises: 156 | `FileNotFoundError`: If a plugin directory does not exist. 157 | `subprocess.CalledProcessError`: If a Git update operation exits with a non-zero 158 | status. 159 | """ 160 | plugins = ( 161 | "zsh-users/zsh-autosuggestions", 162 | "ael-code/zsh-colored-man-pages", 163 | "zsh-users/zsh-completions", 164 | "zsh-users/zsh-syntax-highlighting", 165 | ) 166 | 167 | print(f"{_INFO} Running ZSH plugin updates") 168 | for plugin in plugins: 169 | print(f"{_INFO} Fetching https://github.com/{plugin}") 170 | plugin_dir = Path.home() / ".zsh" / "plugins" / plugin.split("/")[-1] 171 | os.chdir(plugin_dir) 172 | subprocess.run( 173 | ["git", "pull", "--rebase"], check=True, stdout=subprocess.DEVNULL 174 | ) 175 | print(f"{_SUCCESS} ZSH update plugins complete!") 176 | 177 | 178 | def main() -> None: 179 | """Executes the full system update routine for the current environment. 180 | 181 | This function orchestrates all available update mechanisms based on the system 182 | configuration and installed tooling: 183 | 184 | 1. Parses the CLI arguments for the script. 185 | 2. Detects the active shell via the `SHELL` environment variable. 186 | 3. If running on Linux system, executes OS-level package updates. 187 | 4. If Homebrew is installed, runs Homebrew package maintenance. 188 | 5. If the active shell is Zsh, updates the Zsh plugins. 189 | 190 | The function prints progress messages and ends with a success message once all 191 | relevant update routines have completed. Errors from underlying update handlers 192 | (such as failed subprocess calls) may propagate upwards unless explicitly handled 193 | within those functions. 194 | 195 | Raises: 196 | subprocess.CalledProcessError: If any invoked update command (Linux, Homebrew 197 | or Zsh plugin updates) fails and is executed with `check=True`. 198 | """ 199 | # Parse the CLI arguments of the script 200 | parse_args() 201 | 202 | # Chech which shell is enabled for the interactive environment 203 | shell = os.getenv("SHELL") 204 | 205 | # Run the package updates for a Linux distribution 206 | if platform.uname().system == "Linux": 207 | run_linux_updates() 208 | 209 | # Run the Homebrew package updates 210 | if homebrew_installed(): 211 | run_homebrew_updates() 212 | 213 | # Update the zsh plugins 214 | if shell and shell.split("/")[-1] == "zsh": 215 | run_zsh_updates() 216 | 217 | print(f"{_SUCCESS} System update complete...exiting now") 218 | 219 | 220 | if __name__ == "__main__": 221 | main() 222 | -------------------------------------------------------------------------------- /dotfiles/.local/bin/mkblog: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | """ 4 | Script to generate and automate the process of creating a blogpost. 5 | 6 | The script takes user input, either through STDIN or CLI flags to generate a Markdown 7 | file for my blog. The intention of using the script for the purpose is to reproducibly 8 | generate and manage each Markdown file along with some necessary metadata which can be 9 | quite cumbersome to remember every time. 10 | 11 | Author: Somraj Saha 12 | License: MIT (see the LICENSE document for more details) 13 | 14 | TODO: Provide a usage guide. 15 | """ 16 | 17 | import argparse 18 | import datetime 19 | import logging 20 | import os 21 | import pathlib 22 | import re 23 | import shlex 24 | import subprocess 25 | from dataclasses import dataclass 26 | 27 | # The current timestamp during the template generation process 28 | _BLOG_DIR = pathlib.Path.home() / "projects" / "blogposts" / "blogs" 29 | 30 | 31 | def configure_logging(level: int, name: str = __name__) -> logging.Logger: 32 | """Configure and return a logger with a console handler and custom formatting. 33 | 34 | The function initialises or retrieves a logger with the given name, sets its logging 35 | level, attaches a stream handler which outputs to STDOUT and applies a simple, 36 | structured log message format. 37 | 38 | **NOTE**: The function unconditionally adds a new `StreamHandler` each time it is 39 | called. Hence, callers should ensure it is not invoked repeatedly for the same 40 | logger name unless multiple handlers are desired. 41 | 42 | Args: 43 | level: The logging level to apply (e.g., logging.INFO, logging.DEBUG). 44 | name: The name of the logger to configure. Defaults to the caller's module name. 45 | 46 | Returns: 47 | A configured `logging.Logger` instance. 48 | """ 49 | # Set the name of the root logger 50 | logger = logging.getLogger(name) 51 | logger.setLevel(level) 52 | logger.propagate = False 53 | 54 | # Configure the formatting style of the log messages 55 | formatter = logging.Formatter("[{levelname}] - {message}", style="{") 56 | 57 | # Set the logger to send the messages to the console output 58 | if not logger.handlers: 59 | console_handler = logging.StreamHandler() 60 | console_handler.setLevel(level) 61 | console_handler.setFormatter(formatter) 62 | logger.addHandler(console_handler) 63 | 64 | return logger 65 | 66 | 67 | def parse_args() -> argparse.Namespace: 68 | """Parse and return the CLI arguments. 69 | 70 | Returns: 71 | An argparse.Namespace object containing the parsed arguments. 72 | """ 73 | current_year = datetime.datetime.now(datetime.timezone.utc).year 74 | 75 | # Some usage guidelines and message for using the program. 76 | description = "generate blogpost Markdown files in a reproducible manner" 77 | epilog = f"© 2018-{current_year} Somraj Saha " 78 | blogs = _BLOG_DIR 79 | 80 | # Create the parser to fetch the CLI flags passed to the script. 81 | parser = argparse.ArgumentParser(description=description, epilog=epilog) 82 | 83 | # Add argument to set the title of the blogpost 84 | parser.add_argument("title", type=str, help="the title of the blog post") 85 | 86 | # Add argument to set the description of the blogpost 87 | parser.add_argument( 88 | "description", type=str, help="the description of the blog post" 89 | ) 90 | 91 | # Add the option to store whether the blog is a draft 92 | parser.add_argument( 93 | "-D", 94 | "--draft", 95 | action="store_true", 96 | default=True, 97 | help='create a draft blogpost, defaults to "True"', 98 | ) 99 | 100 | # Add the option to set the default path to store the blogpost to 101 | parser.add_argument( 102 | "-o", 103 | "--output", 104 | type=pathlib.Path, 105 | default=_BLOG_DIR, 106 | help=f'directory to save the generated Markdown file to, defaults to "{blogs}"', 107 | ) 108 | 109 | # Add a flag to edit the blog post 110 | parser.add_argument( 111 | "-e", 112 | "--edit", 113 | action="store_true", 114 | help='edit the generated Markdown file using $EDITOR, defaults to "False"', 115 | ) 116 | 117 | # Add the option to optionally force creation of the Markdown file (even if it 118 | # already exists) 119 | parser.add_argument( 120 | "-f", "--force", action="store_true", help="overwrite if file already exists" 121 | ) 122 | 123 | # Add the option to provide verbose output when generating the file contents 124 | parser.add_argument( 125 | "-d", "--debug", action="store_true", help="enable verbose output" 126 | ) 127 | 128 | # Parse the arguments and options 129 | return parser.parse_args() 130 | 131 | 132 | @dataclass 133 | class Blog: 134 | """Represents a blog post and provides utilities for generating and writing a 135 | Markdown file with YAML frontmatter. 136 | 137 | This class is intended to be used as a lightweight content scaffold for 138 | filesystem-based blogging workflows. 139 | """ 140 | 141 | title: str 142 | draft: bool 143 | description: str 144 | 145 | def _slugify(self) -> str: 146 | """Generate a filesystem-safe slug from the blog title. 147 | 148 | The title is lowercased, spaces are replaced with hyphens and any characters 149 | other than lowercase alphanumerics and hyphens are removed. 150 | 151 | Returns: 152 | A lowercase, hyphen-separated string suitable for use as a filename. 153 | 154 | Raises: 155 | ValueError if the title cannot be slugified for some reason. 156 | """ 157 | slug = re.sub(r"[^a-z0-9]+", "-", self.title.lower()) 158 | 159 | if not slug: 160 | raise ValueError("Title cannot be converted into a valid filename") 161 | 162 | return slug.strip("-") 163 | 164 | def _create_template(self) -> str: 165 | """Create a Markdown template with populated YAML frontmatter. 166 | 167 | The frontmatter includes the blog title, description, publication 168 | timestamp (UTC), and publication status derived from the `draft` 169 | flag. 170 | 171 | Returns: 172 | A Markdown-formatted string containing YAML frontmatter 173 | followed by placeholder content. 174 | """ 175 | timestamp = datetime.datetime.now(datetime.timezone.utc) 176 | 177 | return ( 178 | "---\n" 179 | + f"title: {self.title}\n" 180 | + f"description: {self.description}\n" 181 | + f"publishedOn: {timestamp}\n" 182 | + f"status: {'draft' if self.draft else 'published'}\n" 183 | + "---\n\n" 184 | + "Add blog content here..." 185 | ) 186 | 187 | def write_file( 188 | self, base_dir: pathlib.Path, force: bool, logger: logging.Logger 189 | ) -> pathlib.Path | None: 190 | """Write the blog post to a Markdown file on disk. 191 | 192 | The file is created under the user's home directory at 193 | `~/projects/blogposts/blogs`, using a slugified version of the 194 | title as the filename. 195 | 196 | If a file with the same name already exists and `force` is 197 | False, the method prints a warning and does not overwrite the 198 | file. 199 | 200 | Args: 201 | base_dir (pathlib.Path): The base directory path where the Markdown file 202 | will be generated at. 203 | force (bool): Whether to overwrite an existing file to replace it with a new 204 | file. 205 | logger (logging.Logger): An instance of `logging.Logger` to print log 206 | messages to the log handler. 207 | 208 | Returns: 209 | The path to the written Markdown file, or None if the file 210 | already exists and overwriting was not allowed. 211 | """ 212 | # Check if the output directory exists, else create it before generating the 213 | # Markdown file into 214 | if not base_dir.is_dir(): 215 | base_dir.mkdir(parents=True, exist_ok=True) 216 | 217 | # Sanitize and create the filepath of the Markdown file 218 | filepath = base_dir / f"{self._slugify()}.md" 219 | 220 | # Print a warning message to the user if the specified file already exists 221 | if filepath.exists() and not force: 222 | logger.warning(f"{filepath} already exists") 223 | logger.info('Use the "--force" flag to overwrite the existing file') 224 | 225 | return None 226 | 227 | # Generate the Markdown file along with its specified template content 228 | content = self._create_template() 229 | filepath.write_text(content, encoding="utf-8") 230 | 231 | return filepath 232 | 233 | 234 | def main() -> None: 235 | """Entrypoint of the script.""" 236 | # Parse the CLI arguments 237 | args = parse_args() 238 | 239 | # Create an instance of "Logger" to print log messages 240 | logger = configure_logging(logging.DEBUG if args.debug else logging.INFO) 241 | 242 | # Set the editor command 243 | editor = os.getenv("EDITOR") 244 | 245 | # Create an instance of "Blog" to generate a blogpost from 246 | blog = Blog(title=args.title, draft=args.draft, description=args.description) 247 | 248 | # Write the blogpost to disk and get its filepath 249 | filepath = blog.write_file(base_dir=args.output, force=args.force, logger=logger) 250 | 251 | # Set the editor command which can be invoked directly from the script 252 | cmd = None 253 | if editor: 254 | cmd = shlex.split(editor) + [str(filepath)] 255 | 256 | # Print useful guidelines to edit the template if it was successfully generated 257 | if filepath and editor: 258 | logger.info(f"Blog template is generated at {str(filepath)}") 259 | logger.info( 260 | "Start editing it by running these commands:\n\n\t\x1b[92mcd " 261 | + f"{filepath.parent}\n\t{editor} {filepath}\x1b[0m" 262 | ) 263 | 264 | # Open the file using the editor if the script is allowed to do so 265 | if args.edit and cmd: 266 | result = subprocess.run(cmd) 267 | if result.returncode != 0: 268 | logger.error(f'"{cmd}" command exited with a non-zero status') 269 | 270 | 271 | if __name__ == "__main__": 272 | main() 273 | -------------------------------------------------------------------------------- /.github/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to (My) Dotfiles 2 | 3 | :+1::tada: First off, thanks for taking the time to contribute! :tada::+1: 4 | 5 | The following is a set of guidelines for contributing to my collection of 6 | [dotfiles](https://dotfiles.github.io/). They're meant to automate the process 7 | of setting up my personal development machines (**_both Unix & 8 | Windows-based_**). 9 | 10 | The scripts are hosted in this current repository on GitHub for backup purpose & 11 | a robust environment for packaging & distribution. 12 | 13 | The content in the current file you're reading from are mostly guidelines, not 14 | rules. Use your best judgment to use and/or propose changes to this document in 15 | a [Pull Request](./PULL_REQUEST_TEMPLATE.md). 16 | 17 | ## Table Of Contents 18 | 19 | - [Contributing to (My) Dotfiles](#contributing-to-my-dotfiles) 20 | - [Table Of Contents](#table-of-contents) 21 | - [Code of Conduct](#code-of-conduct) 22 | - [I Don't Want To Read This Whole Thing I Just Have a Question](#i-dont-want-to-read-this-whole-thing-i-just-have-a-question) 23 | - [What should I know before I get started](#what-should-i-know-before-i-get-started) 24 | - [dotfiles](#dotfiles) 25 | - [Design Decisions](#design-decisions) 26 | - [How Can I Contribute](#how-can-i-contribute) 27 | - [Suggesting Enhancements](#suggesting-enhancements) 28 | - [Pull Requests](#pull-requests) 29 | - [Styleguides](#styleguides) 30 | - [Git Commit Messages](#git-commit-messages) 31 | - [Shell Styleguide](#shell-styleguide) 32 | - [Documentation Styleguide](#documentation-styleguide) 33 | - [Additional Notes](#additional-notes) 34 | - [Pull Request Labels](#pull-request-labels) 35 | - [PR Labels](#pr-labels) 36 | 37 | ## Code of Conduct 38 | 39 | This project and everyone participating in it are governed by the 40 | [CODE OF CONDUCT](https://github.com/Jarmos-san/.github/blob/master/CODE_OF_CONDUCT.md). 41 | By participating, you are expected to uphold this code. Please report 42 | unacceptable behaviour to [somraj.mle@gmail.com](mailto:somraj.mle@gmail.com). 43 | 44 | ### I Don't Want To Read This Whole Thing I Just Have a Question 45 | 46 | > **Note:** Please don't file an issue to ask a question. You'll get faster 47 | > results by using the resources below. 48 | 49 | The scripts hosted here in the repository works perfectly fine for me & as 50 | expected. If you've some suggestions about writing certain parts of the script 51 | in a better way, I welcome PRs for it. 52 | 53 | Besides, if you've questions regarding my dev environment, feel free to tweet to 54 | me at--[@Jarmosan](https://twitter.com/Jarmosan). Or if you want a detailed 55 | explanation, feel free to have a 56 | [discussion](https://github.com/Jarmos-san/dotfiles/discussions) over it. 57 | 58 | Or, perhaps you want to something more personal, then head over to 59 | [here](https://github.com/Jarmos-san/Jarmos-san/discussions/categories/q-a) for 60 | a public Q&A session. 61 | 62 | With that said, you might've noticed the "_Issues_" tab is disabled. I did so on 63 | purpose since the scripts work perfectly for my use case. 64 | 65 | ## What should I know before I get started 66 | 67 | ### dotfiles 68 | 69 | "_dotfiles_" refers to this repository which hosts some shell scripts for 70 | setting up automated development environments on my Unix-based & Windows-based 71 | machines. 72 | 73 | The scripts downloads & installs the following applications on my system: 74 | 75 | 1. Python 76 | 77 | 2. Docker 78 | 79 | 3. Poetry(Python package management system) 80 | 81 | 4. zsh 82 | 83 | and a few more stuff (check the 84 | [wiki](https://github.com/Jarmos-san/dotfiles/wiki) for a more detailed 85 | explanation)... 86 | 87 | It's not an application for you to download right way to use. Doing so can have 88 | unintended actions on your system. So if you do use some of the scripts or 89 | borrow a snippet or two, **know what you're doing**. 90 | 91 | I strongly recommend reading through the scripts to learn what each line are 92 | doing. When in doubt, feel free to reach out to me. 93 | 94 | ### Design Decisions 95 | 96 | The idea behind hosting all these scripts under one roof is for easier packaging 97 | & distribution besides backup availability. The fact that one can set up a 98 | full-blown dev environment on their Ubuntu machine with a call of just a `wget` 99 | invocation or even a `git` clone makes hosting dotfiles in a remote repository 100 | very favourable. 101 | 102 | ## How Can I Contribute 103 | 104 | ### Suggesting Enhancements 105 | 106 | This section guides you through submitting an enhancement suggestion for the 107 | dotfiles, including completely new features and minor improvements to existing 108 | functionality. Following these guidelines helps maintainers and the community 109 | understand your suggestion :pencil: and find related suggestions :mag_right:. 110 | 111 | Before creating enhancement suggestions, please know that I've designed the 112 | scripts as per my use case, hence there's not much changes required to it. 113 | Exceptions are when I change my development environment or plan on automating 114 | something else too. Hence, as you might've already figured, severe changes 115 | aren't really required. But if there's a good enhancement you think will benefit 116 | the greater good of all, please open a PR. Also, refer to the 117 | [Pull Requests](#pull-requests) section for instruction on opening a PR. You can 118 | fill up the [PR template](./PULL_REQUEST_TEMPLATE.md) & wait for a review. 119 | 120 | #### Pull Requests 121 | 122 | The process described here has several goals: 123 | 124 | - Maintain a quality standard for easier maintainability of the Shell scripts. 125 | - Fix problems that are important to users of the scripts. 126 | - Engage the community in working toward the best possible way to automate 127 | setting up their own dev environment. 128 | - Enable a sustainable system for the maintainer to review contributions. 129 | 130 | Please follow these steps to have your contribution considered by the 131 | maintainers: 132 | 133 | 1. Follow all instructions in [the template](./PULL_REQUEST_TEMPLATE.md) 134 | 2. Follow the [styleguides](#styleguides) 135 | 3. After you submit your pull request, verify that all 136 | [status checks](https://help.github.com/articles/about-status-checks/) are 137 | passing
What if the status checks are failing?If 138 | a status check is failing, and you believe that the failure is unrelated to 139 | your change, please leave a comment on the pull request explaining why you 140 | believe the failure is unrelated. A maintainer will re-run the status check 141 | for you. If we conclude that the failure was a false positive, then we will 142 | open an issue to track that problem with our status check suite.
143 | 144 | ## Styleguides 145 | 146 | ### Git Commit Messages 147 | 148 | - Use the present tense ("Add feature" not "Added feature") 149 | - Use the imperative mood ("Move the cursor to..." not "Moves the cursor to...") 150 | - Limit the first line to 80 characters or less 151 | - Reference issues and pull requests liberally after the first line 152 | - Consider starting the commit message with an applicable emoji: 153 | 154 | - :art: `:art:` when improving the format/structure of the code 155 | - :racehorse: `:racehorse:` when improving performance 156 | - :non-potable_water: `:non-potable_water:` when plugging memory leaks 157 | - :memo: `:memo:` when writing docs 158 | - :penguin: `:penguin:` when fixing something on Linux 159 | - :apple: `:apple:` when fixing something on macOS 160 | - :checkered_flag: `:checkered_flag:` when fixing something on Windows 161 | - :bug: `:bug:` when fixing a bug 162 | - :fire: `:fire:` when removing code or files 163 | - :green_heart: `:green_heart:` when fixing the CI build 164 | - :white_check_mark: `:white_check_mark:` when adding tests 165 | - :lock: `:lock:` when dealing with security 166 | - :arrow_up: `:arrow_up:` when upgrading dependencies 167 | - :arrow_down: `:arrow_down:` when downgrading dependencies 168 | - :shirt: `:shirt:` when removing linter warnings 169 | 170 | ...There are more available at [gitmoji](https://gitmoji.carloscuesta.me/). 171 | 172 | ### Shell Styleguide 173 | 174 | All Shell scripts must adhere to Google's 175 | [Shell Style Guide](https://google.github.io/styleguide/shellguide.html). 176 | 177 | 178 | 179 | ### Documentation Styleguide 180 | 181 | **This section needs to be updated properly, feel free to make a PR if you know 182 | how to document dotfiles.** 183 | 184 | As of now, the documentation exists on the [README.md](../README.md) but I think 185 | it would be more efficient to include external documentation as the project 186 | grows. Ideas are welcome but for now, please make sure to include enough 187 | instructions & docs on the README itself if you make some changes. 188 | 189 | ## Additional Notes 190 | 191 | ### Pull Request Labels 192 | 193 | This section lists the labels we use to help track & manage and pull requests. 194 | 195 | [GitHub search](https://help.github.com/articles/searching-issues/) makes it 196 | easy to use labels for finding groups of pull requests you're interested in. For 197 | example, you might be interested in 198 | [open pull requests in `jarmos/dotfiles` which haven't been reviewed yet](https://github.com/search?utf8=%E2%9C%93&q=is%3Aopen+is%3Apr+repo%3Ajarmos%2Fdotfiles+comments%3A0). 199 | To help you find pull requests, each label is listed with search links for 200 | finding open items with that label in `jarmos/dotfiles` only. it is recommended 201 | to read about 202 | [other search filters](https://help.github.com/articles/searching-issues/) which 203 | will help you write more focused queries. 204 | 205 | The labels are loosely grouped by their purpose, but it's not required that 206 | every PR have a label from every group or that a PR can't have more than one 207 | label from the same group. 208 | 209 | 210 | 211 | ### PR Labels 212 | 213 | | Labels | Description of the Labels | 214 | | :----------------: | ---------------------------------------------------------------------- | 215 | | `bug` | Issues reporting a bug | 216 | | `documentation` | Issues related to documentations | 217 | | `duplicate` | Issue or PR threads which already has a previous entry | 218 | | `enhancement` | Issue or PR which suggests some improvements | 219 | | `good first issue` | Issue which are easy to contribute to for beginners | 220 | | `help wanted` | Issues and/or PRs which could benefit from a helping hand | 221 | | `invalid` | Issue and/or PR threads which are invalid or useless | 222 | | `pinned` | Issue and/or PR threads which are important & needs attention | 223 | | `question` | Issue threads which should be converted to a Discussion thread instead | 224 | | `stale` | Issue and/or PRs which hasn't received any feedback & will be closed | 225 | | `wontfix` | Issue threads which won't be fixed like ever | 226 | -------------------------------------------------------------------------------- /bootstrap.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################### 4 | # Script to automatically setup a fresh new Linux/MacOS system (or VM). 5 | # 6 | # This script should ONLY be used after installing a fresh new OS on a new 7 | # machine or inside a VM to setup a development environment automatically. The 8 | # script will install necessary tools like code editors, package managers and 9 | # more before setting up their configuration files automatically. 10 | # 11 | # USAGE: To use the script, run the following command (its not ready for usage yet); 12 | # 13 | # curl -fsSL https://raw.githubusercontent.com///path/to/script \ 14 | # | bash -s 15 | # 16 | # NOTE: The script is designed to be subjective, hence it is RECOMMENDED to NOT 17 | # invoke it without understanding the context of the contents! Please read 18 | # through the script or reach out to the author for clarification on what 19 | # certain parts of the script does. 20 | # 21 | # DISCLAIMER: The script IS NOT TESTED and there is no guranteed it works 22 | # properly! 23 | # 24 | # Author: Somraj Saha 25 | # License: MIT (see the LICENSE document for more info on this regards) 26 | ############################################################################### 27 | 28 | # Enable some options for Bash to stop executing the script if there's an error 29 | set -o errexit 30 | set -o nounset 31 | set -o pipefail 32 | 33 | # Enable debugging capabilities to the script 34 | if [[ "${TRACE-0}" == "1" ]]; then 35 | set -o xtrace 36 | fi 37 | 38 | # Logic to print out a simple help message to STDOUT 39 | if [[ "${1-}" =~ ^-*h(elp)?$ ]]; then 40 | echo 'Usage: ./script.sh arg-one arg-two 41 | 42 | This is an awesome bash script to make your life better. 43 | 44 | ' 45 | exit 46 | fi 47 | 48 | # Execute the script in context to the current directory where the script is run 49 | cd "$(dirname "$0")" 50 | 51 | ############################################################################### 52 | # Print a nicely formatted informative message to STDOUT 53 | ############################################################################### 54 | info() { 55 | echo -e "\033[0;34m[INFO]\033[0m $1" 56 | } 57 | 58 | ############################################################################### 59 | # Print a nicely formatted warning message to STDOUT 60 | ############################################################################### 61 | warn() { 62 | echo -e "\033[0;33m[WARN]\033[0m $1" 63 | } 64 | 65 | ############################################################################### 66 | # Print a nicely formatted success message to STDOUT 67 | ############################################################################### 68 | success() { 69 | echo -e "\033[0;32m[SUCCESS]\033[0m $1" 70 | } 71 | 72 | ############################################################################### 73 | # Print a nicely formatted error message to STDOUT 74 | ############################################################################### 75 | error() { 76 | echo -e "\033[0;31m[ERROR]\033[0m $1" 77 | } 78 | 79 | # Check if the script is running as root 80 | if [[ "$EUID" -ne 0 ]]; then 81 | warn "Please run with root (or \"sudo\") privileges!" 82 | fi 83 | 84 | ############################################################################### 85 | # Configure the system to not require a password prompt for sudo privileges 86 | ############################################################################### 87 | sudo_nopasswd() { 88 | local user 89 | local sudoers_file 90 | 91 | user="jarmos" 92 | sudoers_file="/etc/sudoers.d/{$user}_nopasswd" 93 | 94 | echo "$user ALL=(ALL) NOPASSWD: ALL" > "$sudoers_file" 95 | 96 | chmod 0440 "$sudoers_file" 97 | 98 | success "Passwordless \"sudo\" has been enabled for user \"$user\"." 99 | } 100 | 101 | ############################################################################### 102 | # Warn user and prompt for confirmation before executing the script 103 | ############################################################################### 104 | warn_user() { 105 | warn "The script will perform an automated setup of the system and can cause\ 106 | potential harm to the system!" 107 | 108 | read -rp "Do you still want to proceed? (yes/no) " yn 109 | 110 | case $yn in 111 | yes) info "This system will now be automatically setup..." ;; 112 | no) 113 | info "Aborting automated system updated..." 114 | exit 0 115 | ;; 116 | *) 117 | error "Invalid response" 118 | exit 1 119 | ;; 120 | esac 121 | } 122 | 123 | # Warn and prompt the user for confirmation to prevent accidental execution 124 | warn_user 125 | 126 | info "Please manually enter the prompts below before the automation starts" 127 | 128 | read -rp "GitHub Access Token: " github_pat 129 | read -rp "SSH key name for GitHub: " github_ssh_key_name 130 | read -rp "Enter email address for Git: " git_email 131 | read -rp "Enter username for Git: " git_name 132 | 133 | GHTOKEN="$github_pat" 134 | SSH_KEY_NAME="$github_ssh_key_name" 135 | # GPG_SIGN_NAME=$(read -rp "GPG signature name: ") 136 | # GPG_SIGN_EMAIL=$(read -rp "GPG signature email address: ") 137 | # GPG_SIGN_KEY=$(read -rp "GPG signature key: ") 138 | OS_NAME=$(grep -Po "(?<=^ID=).+" /etc/os-release | sed 's/"//g') 139 | 140 | info "Automatic setup is starting...please feel free to grab a cup of coffee!" 141 | 142 | ################################################################################ 143 | # On Debian systems, update the sources to point to the "unstable" repository 144 | ################################################################################ 145 | add_unstable_sources() { 146 | unstable_repo_url="deb https://deb.debian.org/debian unstable main" 147 | sources_list="/etc/apt/sources.list" 148 | echo "$unstable_repo_url" | tee "$sources_list" &> /dev/null 149 | } 150 | 151 | ############################################################################### 152 | # Update the system before starting the automated setup 153 | ############################################################################### 154 | update_system() { 155 | info "Updating the system before starting the automated setup..." 156 | 157 | case "$OS_NAME" in 158 | debian) 159 | add_unstable_sources 160 | sudo apt-get update 161 | sudo apt-get upgrade --yes 162 | ;; 163 | ubuntu) 164 | sudo apt-get update 165 | sudo apt-get upgrade --yes 166 | ;; 167 | fedora) 168 | sudo dnf upgrade --refresh --assumeyes 169 | ;; 170 | *) 171 | error "Failed to identify the OS" 172 | exit 1 173 | ;; 174 | esac 175 | } 176 | 177 | ############################################################################### 178 | # Install some necessary prerequisite tools before the setup script runs 179 | ############################################################################### 180 | install_prerequisite_tools() { 181 | # List of prerequisite tools to check for existence 182 | declare -a prerequisite_tools 183 | 184 | # List of prerequisite tools which aren't installed and will be eventually! 185 | declare -a missing_tools 186 | 187 | case "$OS_NAME" in 188 | debian | ubuntu) 189 | prerequisite_tools=( 190 | "git" "curl" "build-essential" "gnupg" "ca-certificates" 191 | ) 192 | ;; 193 | *) 194 | error "Failed to identify the OS!" 195 | exit 1 196 | ;; 197 | esac 198 | 199 | # Check for missing prerequisite tools and store them for future reference 200 | for tool in "${prerequisite_tools[@]}"; do 201 | if ! command -v "${tool}" &> /dev/null; then 202 | missing_tools+=("$tool") 203 | else 204 | missing_tools=() 205 | fi 206 | done 207 | 208 | if [[ ${#missing_tools[@]} -ne 0 ]]; then 209 | warn "These tools were not found & hence will be installed!" 210 | 211 | for tool in "${missing_tools[@]}"; do 212 | echo " $tool" 213 | done 214 | 215 | sudo apt-get install --yes --no-install-recommends "${missing_tools[@]}" 216 | 217 | info "Prerequisite tools installed...proceeding with automated setup" 218 | fi 219 | } 220 | 221 | ############################################################################### 222 | # Setup necessary directories relative to the home directory on the system 223 | ############################################################################### 224 | create_necessary_dirs() { 225 | declare -a dirs 226 | 227 | dirs=(".config" ".gnupg" ".ssh" "projects" "work") 228 | 229 | info "Setting up necessary directories for proper system functioning" 230 | 231 | for dir in "${dirs[@]}"; do 232 | if [[ ! -d "$HOME/$dir" ]]; then 233 | info "$HOME/$dir not found...created" 234 | mkdir --parents "$HOME/$dir" 235 | fi 236 | done 237 | } 238 | 239 | ############################################################################### 240 | # Setup SSH for authenticating to GitHub using Git 241 | # 242 | # FIXME: Identify better ways to automate SSH setup for GitHub because it fails 243 | # and breaks right now 244 | ############################################################################### 245 | setup_github_ssh() { 246 | # Check for the "~/.ssh" directory's existence to createh the SSH keys safely 247 | if [[ ! -d "$HOME/.ssh" ]]; then 248 | error "The $HOME/.ssh directory does not exist...please create it!" 249 | exit 1 250 | fi 251 | 252 | info "Generating the SSH secret/public key pair now..." 253 | 254 | ssh-keygen -q -b 4096 -t ed25519 -N "" -f "$HOME/.ssh/id_ed25519" 255 | 256 | pubkey=$(cat "$HOME/.ssh/id_ed25519.pub") 257 | 258 | curl --silent --location \ 259 | --request POST \ 260 | --header "Accept: application/vnd.github+json" \ 261 | --header "Authorization: Bearer $GHTOKEN" \ 262 | --header "X-GitHub-Api-Version: 2022-11-28" \ 263 | https://api.github.com/user/keys \ 264 | --data-binary "{\"title\":\"$SSH_KEY_NAME\",\"key\":\"$pubkey\"}" 265 | 266 | info "SSH public key pushed to remote service..." 267 | 268 | chmod 600 "$HOME/.ssh/*" 269 | chmod 700 "$HOME/.ssh" 270 | chmod 644 "$HOME/.ssh/*.pub" 271 | 272 | eval "$(ssh-agent -s)" &> /dev/null 273 | 274 | ssh-add "$HOME/.ssh/id_ed25519.pub" 275 | 276 | info "Testing SSH connection to GitHub..." 277 | ssh -T git@github.com 278 | } 279 | 280 | ############################################################################### 281 | # Setup and install fonts 282 | ############################################################################### 283 | setup_fonts() { 284 | # URL for Cascadia Code assets to download from 285 | font_url="https://github.com/ryanoasis/nerd-fonts/releases/download/v3.1.1/CascadiaCode.zip" 286 | 287 | # Only download and setup the Cascadia Code fonts for systems other than WSL2 288 | if [[ ! -e "/proc/sys/fs/binfmt_misc/WSLInterop" ]]; then 289 | info "Downloading fonts from the remote source..." 290 | 291 | curl --silent --fail --show-error --remote-name "$font_url" 292 | 293 | unzip CascadiaCode.zip &> /dev/null 294 | 295 | rm CascadiaCode.zip 296 | 297 | mv ./CascadiaCode/CaskaydiaCoveNerdFontMono-Bold.ttf "$HOME/.fonts" 298 | fi 299 | } 300 | 301 | ############################################################################### 302 | # Setup and install the "lazy.nvim" package manager for Neovim on the system 303 | ############################################################################### 304 | install_lazy_nvim() { 305 | lazy_nvim_repo="https://github.com/folke/lazy.nvim" 306 | lazy_path="$HOME/.local/share/nvim/lazy/lazy.nvim" 307 | 308 | info "Preparing to setup up the LazyNvim package manager for Neovim..." 309 | 310 | # If the LazyNvim installation directory doesn't exist, create it 311 | if [[ ! -d "$lazy_path" ]]; then 312 | mkdir --parents "$lazy_path" 313 | fi 314 | 315 | # Exit script execution safely if Git isn't installed and/or accessible 316 | if ! command -v git &> /dev/null; then 317 | error "Failed to installed LazyNvim...please ensure Git is installed!" 318 | exit 1 319 | fi 320 | 321 | # Clone the LazyNvim source repository to the local machine for usage 322 | git clone --filter=blob:none $lazy_nvim_repo --branch=stable "$lazy_path" \ 323 | &> /dev/null 324 | 325 | success "LazyNvim installation complete!" 326 | } 327 | 328 | ############################################################################### 329 | # Install some ZSH plugns 330 | ############################################################################### 331 | install_zsh_plugins() { 332 | declare -a plugins 333 | 334 | # Location where the ZSH plugins will be downloaded to 335 | plugins_parent_directory="$HOME/.zsh/plugins" 336 | 337 | # List of all the ZSH plugins 338 | plugins=( 339 | "https://github.com/zsh-users/zsh-autosuggestions.git" 340 | "https://github.com/zsh-users/zsh-syntax-highlighting.git" 341 | "https://github.com/zsh-users/zsh-completions.git" 342 | "https://github.com/ael-code/zsh-colored-man-pages.git" 343 | ) 344 | 345 | info "Preparing to install the ZSH plugins..." 346 | 347 | # Create the parent ZSH plugins directory if it doesn't already exist 348 | if [[ ! -d $plugins_parent_directory ]]; then 349 | mkdir --parents "$plugins_parent_directory" 350 | fi 351 | 352 | # Ensure Git is installed & executable, else exit the script execution safely 353 | if [[ $(command -v git &> /dev/null) ]]; then 354 | error "Git not found...please ensure its installed and executable!" 355 | exit 1 356 | fi 357 | 358 | # Loop through the list of plugins to install 359 | for plugin_url in "${plugins[@]}"; do 360 | plugin_name=$(basename "$plugin_url" .git) 361 | 362 | target_dir="$plugins_parent_directory/$plugin_name" 363 | 364 | # If the plugins wasn't already installed, download it locally 365 | if [[ ! -d "$target_dir" ]]; then 366 | git clone "$plugin_url" "$target_dir" 367 | fi 368 | done 369 | 370 | success "ZSH plugins installation complete!" 371 | 372 | info "The plugins will be usable after a system restart..." 373 | } 374 | 375 | ############################################################################### 376 | # Setup the dotfiles and related configuration files 377 | ############################################################################### 378 | setup_dotfiles() { 379 | info "Preparing to download and setup the dotfiles..." 380 | 381 | # Check if git is installed & executable else exit safely 382 | if ! command -v git &> /dev/null; then 383 | error "Git not found...please ensure its installed and executable!" 384 | exit 1 385 | fi 386 | 387 | git clone https://github.com/Jarmos-san/dotfiles "$HOME"/.dotfiles 388 | 389 | # Create symlinks of the dotfiles 390 | for file in "$HOME"/.dotfiles/dotfiles/*; do 391 | if [[ -f "$file" || -d "$file" ]]; then 392 | ln --symbolic "$file" "$HOME" 393 | info "Created symlink for $file" 394 | fi 395 | done 396 | 397 | success "Dotfiles setup complete!" 398 | } 399 | 400 | ############################################################################### 401 | # Install Homebrew only on Linux and MacOS systems 402 | ############################################################################### 403 | install_homebrew() { 404 | installation_script=https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh 405 | 406 | if [[ $(uname -s) == "Darwin" ]] || [[ $(uname) == "Linux" ]]; then 407 | NONINTERACTIVE=1 /bin/bash -c \ 408 | "$(curl --fail --silent --show-error --location ${installation_script})" 409 | fi 410 | } 411 | 412 | ############################################################################### 413 | # Install Homebrew packages on either Linux or MacOS systems 414 | ############################################################################### 415 | install_homebrew_packages() { 416 | linux_brewfile=$HOME/.dotfiles/dotfiles/linux.Brewfile 417 | macos_brewfile=$HOME/.dotfiles/dotfiles/macos.Brewfile 418 | 419 | if [[ ! $(command -v brew &> /dev/null) ]]; then 420 | error "Homebrew not found...aborting package installation!" 421 | exit 1 422 | fi 423 | 424 | if [[ $(uname -s) == "Linux" ]] && [[ -e $linux_brewfile ]] && [[ -f $linux_brewfile ]]; then 425 | brew bundle --file "$linux_brewfile" 426 | fi 427 | 428 | if [[ $(uname -s) == "Darwin" ]] && [[ -e $macos_brewfile ]] && [[ -f $macos_brewfile ]]; then 429 | brew bundle --file "$macos_brewfile" 430 | fi 431 | } 432 | 433 | ############################################################################### 434 | # Setup ZSH as the default shell 435 | ############################################################################### 436 | setup_zsh() { 437 | command -v zsh | sudo tee -a /etc/shells 438 | sudo chsh -s "$(command -v zsh)" "${USER}" 439 | } 440 | 441 | ############################################################################### 442 | # Setup Git credentials (and potentially other things like SSH access and more!) 443 | ############################################################################### 444 | setup_git() { 445 | git_config_dir="$HOME/.config/git" 446 | 447 | if [[ ! -d $git_config_dir ]]; then 448 | mkdir --parents "$git_config_dir" 449 | else 450 | echo "Failed to create the ${git_config_dir} directory!" 451 | exit 1 452 | fi 453 | 454 | cat << EOF > "${git_config_dir}"/credentials 455 | [user] 456 | email = $git_email 457 | name = $git_name 458 | EOF 459 | } 460 | 461 | ############################################################################### 462 | # The entrypoint of the script which will run the script as per the prescribed 463 | # logic 464 | ############################################################################### 465 | main() { 466 | # Perform a preliminary system update before starting the automated setup 467 | update_system 468 | 469 | # Configure the system for passwordless sudo privileges 470 | sudo_nopasswd 471 | 472 | # Ensure certain folders are present and/or created for a smooth operation 473 | create_necessary_dirs 474 | 475 | # FIXME: Identify ways to automate SSH setup 476 | # Setup SSH for Git/GitHub for cloning/managing the dotfiles itself 477 | # setup_github_ssh 478 | 479 | echo "Setting up system automatically!" 480 | 481 | # Install the fonts for systems with a Linux DE (excluding WSL2 environments) 482 | setup_fonts 483 | 484 | # Install prerequisite tools before the automated setup 485 | install_prerequisite_tools 486 | 487 | # Install and setup the "lazy.nvim" package manager for Neovim 488 | install_lazy_nvim 489 | 490 | # Install all necessary ZSH plugins 491 | install_zsh_plugins 492 | 493 | # Setup the dotfiles (like setting up the symlinks and so on) 494 | setup_dotfiles 495 | 496 | # Install the Homebrew package manager 497 | install_homebrew 498 | 499 | # Install necessary tools using the Homebrew package manager 500 | install_homebrew_packages 501 | 502 | # Make ZSH the default interactive shell environment 503 | setup_zsh 504 | 505 | # Setup Git to work well with GitHub 506 | setup_git 507 | 508 | info "System setup complete! Please restart the system before usage." 509 | } 510 | 511 | # Defer running the script till the last moment for safety reasons 512 | main "$@" 513 | --------------------------------------------------------------------------------