diff --git a/.config/nvim/lua/goodhumored/plugins/barbecue.lua b/.config/nvim/lua/goodhumored/appearance/code/barbecue.lua
similarity index 100%
rename from .config/nvim/lua/goodhumored/plugins/barbecue.lua
rename to .config/nvim/lua/goodhumored/appearance/code/barbecue.lua
diff --git a/.config/nvim/lua/goodhumored/plugins/fzf.lua b/.config/nvim/lua/goodhumored/appearance/code/fzf.lua
similarity index 100%
rename from .config/nvim/lua/goodhumored/plugins/fzf.lua
rename to .config/nvim/lua/goodhumored/appearance/code/fzf.lua
diff --git a/.config/nvim/lua/goodhumored/plugins/git-conflict.lua b/.config/nvim/lua/goodhumored/appearance/code/git-conflict.lua
similarity index 100%
rename from .config/nvim/lua/goodhumored/plugins/git-conflict.lua
rename to .config/nvim/lua/goodhumored/appearance/code/git-conflict.lua
diff --git a/.config/nvim/lua/goodhumored/plugins/highlight-comments.lua b/.config/nvim/lua/goodhumored/appearance/code/highlight-comments.lua
similarity index 100%
rename from .config/nvim/lua/goodhumored/plugins/highlight-comments.lua
rename to .config/nvim/lua/goodhumored/appearance/code/highlight-comments.lua
diff --git a/.config/nvim/lua/goodhumored/plugins/image.lua b/.config/nvim/lua/goodhumored/appearance/code/image.lua
similarity index 100%
rename from .config/nvim/lua/goodhumored/plugins/image.lua
rename to .config/nvim/lua/goodhumored/appearance/code/image.lua
diff --git a/.config/nvim/lua/goodhumored/plugins/inlay-hints.lua b/.config/nvim/lua/goodhumored/appearance/code/inlay-hints.lua
similarity index 100%
rename from .config/nvim/lua/goodhumored/plugins/inlay-hints.lua
rename to .config/nvim/lua/goodhumored/appearance/code/inlay-hints.lua
diff --git a/.config/nvim/lua/goodhumored/plugins/methods_lsp_signature.lua b/.config/nvim/lua/goodhumored/appearance/code/methods-lsp-signature.lua
similarity index 100%
rename from .config/nvim/lua/goodhumored/plugins/methods_lsp_signature.lua
rename to .config/nvim/lua/goodhumored/appearance/code/methods-lsp-signature.lua
diff --git a/.config/nvim/lua/goodhumored/plugins/theme/colorscheme.lua.disable b/.config/nvim/lua/goodhumored/appearance/theme/colorscheme.lua.disable
similarity index 100%
rename from .config/nvim/lua/goodhumored/plugins/theme/colorscheme.lua.disable
rename to .config/nvim/lua/goodhumored/appearance/theme/colorscheme.lua.disable
diff --git a/.config/nvim/lua/goodhumored/plugins/theme/gruvbox.lua b/.config/nvim/lua/goodhumored/appearance/theme/gruvbox.lua
similarity index 100%
rename from .config/nvim/lua/goodhumored/plugins/theme/gruvbox.lua
rename to .config/nvim/lua/goodhumored/appearance/theme/gruvbox.lua
diff --git a/.config/nvim/lua/goodhumored/appearance/theme/init.lua b/.config/nvim/lua/goodhumored/appearance/theme/init.lua
new file mode 100644
index 0000000..720b7ed
--- /dev/null
+++ b/.config/nvim/lua/goodhumored/appearance/theme/init.lua
@@ -0,0 +1 @@
+return require("goodhumored.appearance.theme.gruvbox")
diff --git a/.config/nvim/lua/goodhumored/plugins/theme/kanagawa-color-scheme.lua.disable b/.config/nvim/lua/goodhumored/appearance/theme/kanagawa-color-scheme.lua.disable
similarity index 100%
rename from .config/nvim/lua/goodhumored/plugins/theme/kanagawa-color-scheme.lua.disable
rename to .config/nvim/lua/goodhumored/appearance/theme/kanagawa-color-scheme.lua.disable
diff --git a/.config/nvim/lua/goodhumored/plugins/vimade-window-fade.lua b/.config/nvim/lua/goodhumored/appearance/tint-unfocused.lua
similarity index 100%
rename from .config/nvim/lua/goodhumored/plugins/vimade-window-fade.lua
rename to .config/nvim/lua/goodhumored/appearance/tint-unfocused.lua
diff --git a/.config/nvim/lua/goodhumored/plugins/barbar.lua b/.config/nvim/lua/goodhumored/appearance/ui/barbar.lua
similarity index 100%
rename from .config/nvim/lua/goodhumored/plugins/barbar.lua
rename to .config/nvim/lua/goodhumored/appearance/ui/barbar.lua
diff --git a/.config/nvim/lua/goodhumored/plugins/dap/dapui.lua b/.config/nvim/lua/goodhumored/appearance/ui/dapui.lua
similarity index 100%
rename from .config/nvim/lua/goodhumored/plugins/dap/dapui.lua
rename to .config/nvim/lua/goodhumored/appearance/ui/dapui.lua
diff --git a/.config/nvim/lua/goodhumored/plugins/dressing.lua b/.config/nvim/lua/goodhumored/appearance/ui/dressing.lua
similarity index 100%
rename from .config/nvim/lua/goodhumored/plugins/dressing.lua
rename to .config/nvim/lua/goodhumored/appearance/ui/dressing.lua
diff --git a/.config/nvim/lua/goodhumored/plugins/gitsigns.lua b/.config/nvim/lua/goodhumored/appearance/ui/gitsigns.lua
similarity index 100%
rename from .config/nvim/lua/goodhumored/plugins/gitsigns.lua
rename to .config/nvim/lua/goodhumored/appearance/ui/gitsigns.lua
diff --git a/.config/nvim/lua/goodhumored/plugins/lualine.lua b/.config/nvim/lua/goodhumored/appearance/ui/lualine.lua
similarity index 100%
rename from .config/nvim/lua/goodhumored/plugins/lualine.lua
rename to .config/nvim/lua/goodhumored/appearance/ui/lualine.lua
diff --git a/.config/nvim/lua/goodhumored/plugins/noice.nvim.lua b/.config/nvim/lua/goodhumored/appearance/ui/noice.nvim.lua
similarity index 100%
rename from .config/nvim/lua/goodhumored/plugins/noice.nvim.lua
rename to .config/nvim/lua/goodhumored/appearance/ui/noice.nvim.lua
diff --git a/.config/nvim/lua/goodhumored/plugins/tree.lua b/.config/nvim/lua/goodhumored/appearance/ui/nvim-tree.lua
similarity index 100%
rename from .config/nvim/lua/goodhumored/plugins/tree.lua
rename to .config/nvim/lua/goodhumored/appearance/ui/nvim-tree.lua
diff --git a/.config/nvim/lua/goodhumored/plugins/neozoom.lua b/.config/nvim/lua/goodhumored/comfort-features/neozoom.lua
similarity index 100%
rename from .config/nvim/lua/goodhumored/plugins/neozoom.lua
rename to .config/nvim/lua/goodhumored/comfort-features/neozoom.lua
diff --git a/.config/nvim/lua/goodhumored/plugins/toggleterm.lua b/.config/nvim/lua/goodhumored/comfort-features/toggleterm.lua
similarity index 100%
rename from .config/nvim/lua/goodhumored/plugins/toggleterm.lua
rename to .config/nvim/lua/goodhumored/comfort-features/toggleterm.lua
diff --git a/.config/nvim/lua/goodhumored/plugins/which-key.lua b/.config/nvim/lua/goodhumored/comfort-features/which-key.lua
similarity index 100%
rename from .config/nvim/lua/goodhumored/plugins/which-key.lua
rename to .config/nvim/lua/goodhumored/comfort-features/which-key.lua
diff --git a/.config/nvim/lua/goodhumored/plugins/zen-mode.lua b/.config/nvim/lua/goodhumored/comfort-features/zen-mode.lua
similarity index 100%
rename from .config/nvim/lua/goodhumored/plugins/zen-mode.lua
rename to .config/nvim/lua/goodhumored/comfort-features/zen-mode.lua
diff --git a/.config/nvim/lua/goodhumored/plugins/dap/dap-go.lua b/.config/nvim/lua/goodhumored/core/dap/dap-go.lua
similarity index 100%
rename from .config/nvim/lua/goodhumored/plugins/dap/dap-go.lua
rename to .config/nvim/lua/goodhumored/core/dap/dap-go.lua
diff --git a/.config/nvim/lua/goodhumored/plugins/dap/dap.lua b/.config/nvim/lua/goodhumored/core/dap/dap.lua
similarity index 100%
rename from .config/nvim/lua/goodhumored/plugins/dap/dap.lua
rename to .config/nvim/lua/goodhumored/core/dap/dap.lua
diff --git a/.config/nvim/lua/goodhumored/plugins/dap/vscode-js.lua b/.config/nvim/lua/goodhumored/core/dap/vscode-js.lua
similarity index 100%
rename from .config/nvim/lua/goodhumored/plugins/dap/vscode-js.lua
rename to .config/nvim/lua/goodhumored/core/dap/vscode-js.lua
diff --git a/.config/nvim/lua/goodhumored/plugins/lsp.lua b/.config/nvim/lua/goodhumored/core/lsp.lua
similarity index 98%
rename from .config/nvim/lua/goodhumored/plugins/lsp.lua
rename to .config/nvim/lua/goodhumored/core/lsp.lua
index 942f32b..0b23d90 100644
--- a/.config/nvim/lua/goodhumored/plugins/lsp.lua
+++ b/.config/nvim/lua/goodhumored/core/lsp.lua
@@ -68,7 +68,7 @@ return { -- LSP Configuration & Plugins
 
 				-- Execute a code action, usually your cursor needs to be on top of an error
 				-- or a suggestion from your LSP for this to activate.
-				map("<leader>ca", vim.lsp.buf.code_action, "[C]ode [A]ction")
+				map("<space><space>", vim.lsp.buf.code_action, "Code Action")
 
 				-- WARN: This is not Goto Definition, this is Goto Declaration.
 				--  For example, in C this would take you to the header.
@@ -205,6 +205,16 @@ return { -- LSP Configuration & Plugins
 				autoFixOnSave = true,
 				autoFix = true,
 			},
+
+			rust_analyzer = {
+				settings = {
+					["rust-analyzer"] = {
+						cargo = {
+							allFeatures = true,
+						},
+					},
+				},
+			},
 		}
 
 		-- Ensure the servers and tools above are installed
diff --git a/.config/nvim/lua/goodhumored/plugins/neotest.lua b/.config/nvim/lua/goodhumored/core/neotest.lua
similarity index 100%
rename from .config/nvim/lua/goodhumored/plugins/neotest.lua
rename to .config/nvim/lua/goodhumored/core/neotest.lua
diff --git a/.config/nvim/lua/goodhumored/plugins/treesitter-context.lua b/.config/nvim/lua/goodhumored/core/treesitter-context.lua
similarity index 100%
rename from .config/nvim/lua/goodhumored/plugins/treesitter-context.lua
rename to .config/nvim/lua/goodhumored/core/treesitter-context.lua
diff --git a/.config/nvim/lua/goodhumored/plugins/treesitter.lua b/.config/nvim/lua/goodhumored/core/treesitter.lua
similarity index 100%
rename from .config/nvim/lua/goodhumored/plugins/treesitter.lua
rename to .config/nvim/lua/goodhumored/core/treesitter.lua
diff --git a/.config/nvim/lua/goodhumored/plugins/auto-pairs.lua b/.config/nvim/lua/goodhumored/editing/auto-pairs.lua
similarity index 100%
rename from .config/nvim/lua/goodhumored/plugins/auto-pairs.lua
rename to .config/nvim/lua/goodhumored/editing/auto-pairs.lua
diff --git a/.config/nvim/lua/goodhumored/plugins/auto-tags.lua b/.config/nvim/lua/goodhumored/editing/auto-tags.lua
similarity index 100%
rename from .config/nvim/lua/goodhumored/plugins/auto-tags.lua
rename to .config/nvim/lua/goodhumored/editing/auto-tags.lua
diff --git a/.config/nvim/lua/goodhumored/plugins/autocomplete.lua b/.config/nvim/lua/goodhumored/editing/autocomplete.lua
similarity index 100%
rename from .config/nvim/lua/goodhumored/plugins/autocomplete.lua
rename to .config/nvim/lua/goodhumored/editing/autocomplete.lua
diff --git a/.config/nvim/lua/goodhumored/plugins/autoformat.lua b/.config/nvim/lua/goodhumored/editing/autoformat.lua
similarity index 100%
rename from .config/nvim/lua/goodhumored/plugins/autoformat.lua
rename to .config/nvim/lua/goodhumored/editing/autoformat.lua
diff --git a/.config/nvim/lua/goodhumored/plugins/clipboard-image.lua b/.config/nvim/lua/goodhumored/editing/clipboard-image.lua
similarity index 100%
rename from .config/nvim/lua/goodhumored/plugins/clipboard-image.lua
rename to .config/nvim/lua/goodhumored/editing/clipboard-image.lua
diff --git a/.config/nvim/lua/goodhumored/plugins/color-picker.lua b/.config/nvim/lua/goodhumored/editing/color-picker.lua
similarity index 100%
rename from .config/nvim/lua/goodhumored/plugins/color-picker.lua
rename to .config/nvim/lua/goodhumored/editing/color-picker.lua
diff --git a/.config/nvim/lua/goodhumored/plugins/comment-blocks.lua b/.config/nvim/lua/goodhumored/editing/comment-blocks.lua
similarity index 100%
rename from .config/nvim/lua/goodhumored/plugins/comment-blocks.lua
rename to .config/nvim/lua/goodhumored/editing/comment-blocks.lua
diff --git a/.config/nvim/lua/goodhumored/plugins/conflict-marker.lua b/.config/nvim/lua/goodhumored/editing/conflict-marker.lua
similarity index 100%
rename from .config/nvim/lua/goodhumored/plugins/conflict-marker.lua
rename to .config/nvim/lua/goodhumored/editing/conflict-marker.lua
diff --git a/.config/nvim/lua/goodhumored/plugins/easytables.lua b/.config/nvim/lua/goodhumored/editing/easytables.lua
similarity index 100%
rename from .config/nvim/lua/goodhumored/plugins/easytables.lua
rename to .config/nvim/lua/goodhumored/editing/easytables.lua
diff --git a/.config/nvim/lua/goodhumored/plugins/mini-nvim.lua b/.config/nvim/lua/goodhumored/editing/mini-nvim.lua
similarity index 100%
rename from .config/nvim/lua/goodhumored/plugins/mini-nvim.lua
rename to .config/nvim/lua/goodhumored/editing/mini-nvim.lua
diff --git a/.config/nvim/lua/goodhumored/plugins/nvim-surround.lua b/.config/nvim/lua/goodhumored/editing/nvim-surround.lua
similarity index 100%
rename from .config/nvim/lua/goodhumored/plugins/nvim-surround.lua
rename to .config/nvim/lua/goodhumored/editing/nvim-surround.lua
diff --git a/.config/nvim/lua/goodhumored/plugins/snippets/code-snippets b/.config/nvim/lua/goodhumored/editing/snippets/code-snippets
similarity index 100%
rename from .config/nvim/lua/goodhumored/plugins/snippets/code-snippets
rename to .config/nvim/lua/goodhumored/editing/snippets/code-snippets
diff --git a/.config/nvim/lua/goodhumored/plugins/snippets/friendly-snippets.lua b/.config/nvim/lua/goodhumored/editing/snippets/friendly-snippets.lua
similarity index 100%
rename from .config/nvim/lua/goodhumored/plugins/snippets/friendly-snippets.lua
rename to .config/nvim/lua/goodhumored/editing/snippets/friendly-snippets.lua
diff --git a/.config/nvim/lua/goodhumored/editing/snippets/luasnip.lua b/.config/nvim/lua/goodhumored/editing/snippets/luasnip.lua
new file mode 100644
index 0000000..c2aeecf
--- /dev/null
+++ b/.config/nvim/lua/goodhumored/editing/snippets/luasnip.lua
@@ -0,0 +1,12 @@
+return {
+	"L3MON4D3/LuaSnip",
+	version = "v2.*",
+	build = "make install_jsregexp",
+	config = function()
+		require("luasnip.loaders.from_vscode").load({
+			paths = {
+				"~/.config/nvim/luasnippets",
+			},
+		})
+	end,
+}
diff --git a/.config/nvim/lua/goodhumored/plugins/spider.lua b/.config/nvim/lua/goodhumored/editing/spider.lua
similarity index 100%
rename from .config/nvim/lua/goodhumored/plugins/spider.lua
rename to .config/nvim/lua/goodhumored/editing/spider.lua
diff --git a/.config/nvim/lua/goodhumored/plugins/common.lua b/.config/nvim/lua/goodhumored/editing/vim-sleuth.lua
similarity index 100%
rename from .config/nvim/lua/goodhumored/plugins/common.lua
rename to .config/nvim/lua/goodhumored/editing/vim-sleuth.lua
diff --git a/.config/nvim/lua/goodhumored/plugins/visual-multi.lua b/.config/nvim/lua/goodhumored/editing/visual-multi.lua
similarity index 100%
rename from .config/nvim/lua/goodhumored/plugins/visual-multi.lua
rename to .config/nvim/lua/goodhumored/editing/visual-multi.lua
diff --git a/.config/nvim/lua/goodhumored/plugins/firevim.lua b/.config/nvim/lua/goodhumored/integrations/firevim.lua
similarity index 100%
rename from .config/nvim/lua/goodhumored/plugins/firevim.lua
rename to .config/nvim/lua/goodhumored/integrations/firevim.lua
diff --git a/.config/nvim/lua/goodhumored/plugins/leetcode.lua b/.config/nvim/lua/goodhumored/integrations/leetcode.lua
similarity index 100%
rename from .config/nvim/lua/goodhumored/plugins/leetcode.lua
rename to .config/nvim/lua/goodhumored/integrations/leetcode.lua
diff --git a/.config/nvim/lua/goodhumored/plugins/tmux.lua b/.config/nvim/lua/goodhumored/integrations/tmux.lua
similarity index 100%
rename from .config/nvim/lua/goodhumored/plugins/tmux.lua
rename to .config/nvim/lua/goodhumored/integrations/tmux.lua
diff --git a/.config/nvim/lua/goodhumored/languages/init.lua b/.config/nvim/lua/goodhumored/languages/init.lua
new file mode 100644
index 0000000..fd8e178
--- /dev/null
+++ b/.config/nvim/lua/goodhumored/languages/init.lua
@@ -0,0 +1,12 @@
+return {
+	plugins = {
+		require("goodhumored.languages.latex.ltex"),
+		require("goodhumored.languages.neorg.neorg"),
+		-- require("goodhumored.languages.rust.rust.vim"),
+		require("goodhumored.languages.rust.rust-tools"),
+		require("goodhumored.languages.markdown.otter"),
+		require("goodhumored.languages.markdown.markview"),
+		require("goodhumored.languages.markdown.markdown-preview"),
+		require("goodhumored.languages.plantuml.plantuml"),
+	},
+}
diff --git a/.config/nvim/lua/goodhumored/plugins/ltex.lua b/.config/nvim/lua/goodhumored/languages/latex/ltex.lua
similarity index 100%
rename from .config/nvim/lua/goodhumored/plugins/ltex.lua
rename to .config/nvim/lua/goodhumored/languages/latex/ltex.lua
diff --git a/.config/nvim/lua/goodhumored/plugins/markdown-preview.lua b/.config/nvim/lua/goodhumored/languages/markdown/markdown-preview.lua
similarity index 100%
rename from .config/nvim/lua/goodhumored/plugins/markdown-preview.lua
rename to .config/nvim/lua/goodhumored/languages/markdown/markdown-preview.lua
diff --git a/.config/nvim/lua/goodhumored/plugins/markview.lua b/.config/nvim/lua/goodhumored/languages/markdown/markview.lua
similarity index 100%
rename from .config/nvim/lua/goodhumored/plugins/markview.lua
rename to .config/nvim/lua/goodhumored/languages/markdown/markview.lua
diff --git a/.config/nvim/lua/goodhumored/plugins/otter.lua b/.config/nvim/lua/goodhumored/languages/markdown/otter.lua
similarity index 100%
rename from .config/nvim/lua/goodhumored/plugins/otter.lua
rename to .config/nvim/lua/goodhumored/languages/markdown/otter.lua
diff --git a/.config/nvim/lua/goodhumored/plugins/neorg.lua b/.config/nvim/lua/goodhumored/languages/neorg/neorg.lua
similarity index 94%
rename from .config/nvim/lua/goodhumored/plugins/neorg.lua
rename to .config/nvim/lua/goodhumored/languages/neorg/neorg.lua
index 7200b1a..c3d5449 100644
--- a/.config/nvim/lua/goodhumored/plugins/neorg.lua
+++ b/.config/nvim/lua/goodhumored/languages/neorg/neorg.lua
@@ -2,6 +2,10 @@ return {
 	"nvim-neorg/neorg",
 	lazy = false,
 	version = "*",
+	dependencies = {
+		"nvim-neorg/lua-utils.nvim",
+		"pysan3/pathlib.nvim",
+	},
 	config = function()
 		local neorg = require("neorg")
 		neorg.setup({
diff --git a/.config/nvim/lua/goodhumored/plugins/diagram.lua.disable b/.config/nvim/lua/goodhumored/languages/plantuml/diagram.lua.disable
similarity index 100%
rename from .config/nvim/lua/goodhumored/plugins/diagram.lua.disable
rename to .config/nvim/lua/goodhumored/languages/plantuml/diagram.lua.disable
diff --git a/.config/nvim/lua/goodhumored/plugins/plantuml.lua b/.config/nvim/lua/goodhumored/languages/plantuml/plantuml.lua
similarity index 100%
rename from .config/nvim/lua/goodhumored/plugins/plantuml.lua
rename to .config/nvim/lua/goodhumored/languages/plantuml/plantuml.lua
diff --git a/.config/nvim/lua/goodhumored/languages/rust/rust-tools.lua b/.config/nvim/lua/goodhumored/languages/rust/rust-tools.lua
new file mode 100644
index 0000000..a7fe9e2
--- /dev/null
+++ b/.config/nvim/lua/goodhumored/languages/rust/rust-tools.lua
@@ -0,0 +1,11 @@
+return {
+	"simrat39/rust-tools.nvim",
+	ft = "rust",
+	dependencies = "neovim/nvim-lspconfig",
+	opts = function()
+		return {}
+	end,
+	config = function(_, opts)
+		require("rust-tools").setup(opts)
+	end,
+}
diff --git a/.config/nvim/lua/goodhumored/languages/rust/rust.vim.lua b/.config/nvim/lua/goodhumored/languages/rust/rust.vim.lua
new file mode 100644
index 0000000..fe1a547
--- /dev/null
+++ b/.config/nvim/lua/goodhumored/languages/rust/rust.vim.lua
@@ -0,0 +1,7 @@
+return {
+	"rust-lang/rust.vim",
+	ft = "rust",
+	init = function()
+		vim.g.rustfmt_autosave = 1
+	end,
+}
diff --git a/.config/nvim/lua/goodhumored/lazy.lua b/.config/nvim/lua/goodhumored/lazy.lua
index c257756..95fb260 100644
--- a/.config/nvim/lua/goodhumored/lazy.lua
+++ b/.config/nvim/lua/goodhumored/lazy.lua
@@ -9,13 +9,23 @@ if not vim.uv.fs_stat(lazypath) then
 	end
 end ---@diagnostic disable-next-line: undefined-field
 vim.opt.rtp:prepend(lazypath)
+local languagesPlugins = require("goodhumored.languages")
 
 -- [[ Configure and install plugins ]]
 -- NOTE: Here is where you install your plugins.
 require("lazy").setup({
-	{ import = "goodhumored.plugins" },
-	{ import = "goodhumored.plugins.dap" },
-	{ import = "goodhumored.plugins.snippets" },
+	{ import = "goodhumored.appearance.code" },
+	{ import = "goodhumored.appearance.theme" },
+	{ import = "goodhumored.appearance.ui" },
+	{ import = "goodhumored.appearance.tint-unfocused" },
+	{ import = "goodhumored.comfort-features" },
+	{ import = "goodhumored.core" },
+	{ import = "goodhumored.core.dap" },
+	{ import = "goodhumored.editing" },
+	{ import = "goodhumored.editing.snippets" },
+	{ import = "goodhumored.integrations" },
+	{ import = "goodhumored.sessions" },
+	languagesPlugins.plugins,
 }, {
 	ui = {
 		-- If you are using a Nerd Font: set icons to an empty table which will use the
diff --git a/.config/nvim/lua/goodhumored/plugins/gruvbox.lua b/.config/nvim/lua/goodhumored/plugins/gruvbox.lua
deleted file mode 100644
index 0503b75..0000000
--- a/.config/nvim/lua/goodhumored/plugins/gruvbox.lua
+++ /dev/null
@@ -1,32 +0,0 @@
-return {
-	"ellisonleao/gruvbox.nvim",
-	priority = 1000,
-	init = function()
-		require("gruvbox").setup({
-			terminal_colors = true, -- add neovim terminal colors
-			undercurl = true,
-			underline = true,
-			bold = true,
-			italic = {
-				strings = true,
-				emphasis = true,
-				comments = true,
-				operators = false,
-				folds = true,
-			},
-			strikethrough = true,
-			invert_selection = false,
-			invert_signs = false,
-			invert_tabline = false,
-			invert_intend_guides = false,
-			inverse = true, -- invert background for search, diffs, statuslines and errors
-			contrast = "soft", -- can be "hard", "soft" or empty string
-			palette_overrides = {},
-			overrides = {},
-			dim_inactive = false,
-			transparent_mode = false,
-		})
-		vim.o.background = "dark"
-		vim.cmd("colorscheme gruvbox")
-	end,
-}
diff --git a/.config/nvim/lua/goodhumored/plugins/pastify.lua.disable b/.config/nvim/lua/goodhumored/plugins/pastify.lua.disable
deleted file mode 100644
index 902457d..0000000
--- a/.config/nvim/lua/goodhumored/plugins/pastify.lua.disable
+++ /dev/null
@@ -1,15 +0,0 @@
---          ╭─────────────────────────────────────────────────────────╮
---          │                         pastify                         │
---          │          enables pasting image from clipboard           │
---          ╰─────────────────────────────────────────────────────────╯
-return {
-	"TobinPalmer/pastify.nvim",
-	cmd = { "Pastify", "PastifyAfter" },
-	config = function()
-		require("pastify").setup({
-			-- opts = {
-			--   apikey = "YOUR API KEY (https://api.imgbb.com/)", -- Needed if you want to save online.
-			-- },
-		})
-	end,
-}
diff --git a/.config/nvim/lua/goodhumored/plugins/snippets/luasnip.lua b/.config/nvim/lua/goodhumored/plugins/snippets/luasnip.lua
deleted file mode 100644
index c1c4b4d..0000000
--- a/.config/nvim/lua/goodhumored/plugins/snippets/luasnip.lua
+++ /dev/null
@@ -1,360 +0,0 @@
-return {
-	"L3MON4D3/LuaSnip",
-	-- follow latest release.
-	version = "v2.*", -- Replace <CurrentMajor> by the latest released major (first number of latest release)
-	-- install jsregexp (optional!).
-	build = "make install_jsregexp",
-	config = function()
-		-- load snippets from path/of/your/nvim/config/my-cool-snippets
-		require("luasnip.loaders.from_vscode").lazy_load({
-			paths = {
-				-- "~/.config/Code/User/snippets/typescript.code-snippets",
-				-- "~/.config/nvim/lua/goodhumored/plugins/snippets/code-snippets",
-				"./code-snippets",
-			},
-		})
-		require("luasnip.loaders.from_snipmate").lazy_load()
-		local ls = require("luasnip")
-		local s = ls.snippet
-		local sn = ls.snippet_node
-		local t = ls.text_node
-		local i = ls.insert_node
-		local f = ls.function_node
-		local c = ls.choice_node
-		local d = ls.dynamic_node
-		local r = ls.restore_node
-		local l = require("luasnip.extras").lambda
-		local rep = require("luasnip.extras").rep
-		local p = require("luasnip.extras").partial
-		local m = require("luasnip.extras").match
-		local n = require("luasnip.extras").nonempty
-		local dl = require("luasnip.extras").dynamic_lambda
-		local fmt = require("luasnip.extras.fmt").fmt
-		local fmta = require("luasnip.extras.fmt").fmta
-		local types = require("luasnip.util.types")
-		local conds = require("luasnip.extras.conditions")
-		local conds_expand = require("luasnip.extras.conditions.expand")
-
-		local function copy(args)
-			return args[1]
-		end
-
-		-- Make sure to not pass an invalid command, as io.popen() may write over nvim-text.
-		local function bash(_, _, command)
-			local file = io.popen(command, "r")
-			local res = {}
-			for line in file:lines() do
-				table.insert(res, line)
-			end
-			return res
-		end
-
-		-- Returns a snippet_node wrapped around an insertNode whose initial
-		-- text value is set to the current date in the desired format.
-		local date_input = function(args, snip, old_state, fmt)
-			local fmt = fmt or "%Y-%m-%d"
-			return sn(nil, i(1, os.date(fmt)))
-		end
-
-		local ts_snippets = {
-			s("prr", {
-				t("private readonly _"),
-				i(1, "field"),
-				t(";"),
-			}),
-			s("prr", {
-				t("private readonly _"),
-				i(1, "field"),
-				t(";"),
-			}),
-		}
-
-		local react_snippets = {
-			s("comp", {
-				t({
-					'import React from "react";',
-					"",
-					"export default function ",
-				}),
-				i(1),
-				t({ "({className}: {className?: string}) {", "\treturn (", "\t\t<" }),
-				i(2, "div"),
-				t({ " className={`${className}`}>", "\t\t\t" }),
-				i(3),
-				t({ "", "\t\t</" }),
-				f(copy, 2),
-				t({ ">", "\t)", "}" }),
-			}),
-		}
-
-		ls.add_snippets("typescript", ts_snippets)
-		ls.add_snippets("typescriptreact", react_snippets)
-		ls.add_snippets("all", {
-			-- trigger is `fn`, second argument to snippet-constructor are the nodes to insert into the buffer on expansion.
-			s("fn", {
-				-- Simple static text.
-				t("//Parameters: "),
-				-- function, first parameter is the function, second the Placeholders
-				-- whose text it gets as input.
-				f(copy, 2),
-				t({ "", "function " }),
-				-- Placeholder/Insert.
-				i(1),
-				t("("),
-				-- Placeholder with initial text.
-				i(2, "int foo"),
-				-- Linebreak
-				t({ ") {", "\t" }),
-				-- Last Placeholder, exit Point of the snippet.
-				i(0),
-				t({ "", "}" }),
-			}),
-			s("class", {
-				-- Choice: Switch between two different Nodes, first parameter is its position, second a list of nodes.
-				c(1, {
-					t("public "),
-					t("private "),
-				}),
-				t("class "),
-				i(2),
-				t(" "),
-				c(3, {
-					t("{"),
-					-- sn: Nested Snippet. Instead of a trigger, it has a position, just like insertNodes. !!! These don't expect a 0-node!!!!
-					-- Inside Choices, Nodes don't need a position as the choice node is the one being jumped to.
-					sn(nil, {
-						t("extends "),
-						-- restoreNode: stores and restores nodes.
-						-- pass position, store-key and nodes.
-						r(1, "other_class", i(1)),
-						t(" {"),
-					}),
-					sn(nil, {
-						t("implements "),
-						-- no need to define the nodes for a given key a second time.
-						r(1, "other_class"),
-						t(" {"),
-					}),
-				}),
-				t({ "", "\t" }),
-				i(0),
-				t({ "", "}" }),
-			}),
-			-- Alternative printf-like notation for defining snippets. It uses format
-			-- string with placeholders similar to the ones used with Python's .format().
-			s(
-				"fmt1",
-				fmt("To {title} {} {}.", {
-					i(2, "Name"),
-					i(3, "Surname"),
-					title = c(1, { t("Mr."), t("Ms.") }),
-				})
-			),
-			-- To escape delimiters use double them, e.g. `{}` -> `{{}}`.
-			-- Multi-line format strings by default have empty first/last line removed.
-			-- Indent common to all lines is also removed. Use the third `opts` argument
-			-- to control this behaviour.
-			s(
-				"fmt2",
-				fmt(
-					[[
-		foo({1}, {3}) {{
-			return {2} * {4}
-		}}
-		]],
-					{
-						i(1, "x"),
-						rep(1),
-						i(2, "y"),
-						rep(2),
-					}
-				)
-			),
-			-- Empty placeholders are numbered automatically starting from 1 or the last
-			-- value of a numbered placeholder. Named placeholders do not affect numbering.
-			s(
-				"fmt3",
-				fmt("{} {a} {} {1} {}", {
-					t("1"),
-					t("2"),
-					a = t("A"),
-				})
-			),
-			-- The delimiters can be changed from the default `{}` to something else.
-			s("fmt4", fmt("foo() { return []; }", i(1, "x"), { delimiters = "[]" })),
-			-- `fmta` is a convenient wrapper that uses `<>` instead of `{}`.
-			s("fmt5", fmta("foo() { return <>; }", i(1, "x"))),
-			-- By default all args must be used. Use strict=false to disable the check
-			s("fmt6", fmt("use {} only", { t("this"), t("not this") }, { strict = false })),
-			-- Use a dynamicNode to interpolate the output of a
-			-- function (see date_input above) into the initial
-			-- value of an insertNode.
-			s("novel", {
-				t("It was a dark and stormy night on "),
-				d(1, date_input, {}, { user_args = { "%A, %B %d of %Y" } }),
-				t(" and the clocks were striking thirteen."),
-			}),
-			-- Parsing snippets: First parameter: Snippet-Trigger, Second: Snippet body.
-			-- Placeholders are parsed into choices with 1. the placeholder text(as a snippet) and 2. an empty string.
-			-- This means they are not SELECTed like in other editors/Snippet engines.
-			ls.parser.parse_snippet("lspsyn", "Wow! This ${1:Stuff} really ${2:works. ${3:Well, a bit.}}"),
-
-			-- When wordTrig is set to false, snippets may also expand inside other words.
-			ls.parser.parse_snippet({ trig = "te", wordTrig = false }, "${1:cond} ? ${2:true} : ${3:false}"),
-
-			-- When regTrig is set, trig is treated like a pattern, this snippet will expand after any number.
-			ls.parser.parse_snippet({ trig = "%d", regTrig = true }, "A Number!!"),
-			-- Using the condition, it's possible to allow expansion only in specific cases.
-			s("cond", {
-				t("will only expand in c-style comments"),
-			}, {
-				condition = function(line_to_cursor, matched_trigger, captures)
-					-- optional whitespace followed by //
-					return line_to_cursor:match("%s*//")
-				end,
-			}),
-			-- there's some built-in conditions in "luasnip.extras.conditions.expand" and "luasnip.extras.conditions.show".
-			s("cond2", {
-				t("will only expand at the beginning of the line"),
-			}, {
-				condition = conds_expand.line_begin,
-			}),
-			s("cond3", {
-				t("will only expand at the end of the line"),
-			}, {
-				condition = conds_expand.line_end,
-			}),
-			-- on conditions some logic operators are defined
-			s("cond4", {
-				t("will only expand at the end and the start of the line"),
-			}, {
-				-- last function is just an example how to make own function objects and apply operators on them
-				condition = conds_expand.line_end + conds_expand.line_begin * conds.make_condition(function()
-					return true
-				end),
-			}),
-			-- The last entry of args passed to the user-function is the surrounding snippet.
-			s(
-				{ trig = "a%d", regTrig = true },
-				f(function(_, snip)
-					return "Triggered with " .. snip.trigger .. "."
-				end, {})
-			),
-			-- It's possible to use capture-groups inside regex-triggers.
-			s(
-				{ trig = "b(%d)", regTrig = true },
-				f(function(_, snip)
-					return "Captured Text: " .. snip.captures[1] .. "."
-				end, {})
-			),
-			s({ trig = "c(%d+)", regTrig = true }, {
-				t("will only expand for even numbers"),
-			}, {
-				condition = function(line_to_cursor, matched_trigger, captures)
-					return tonumber(captures[1]) % 2 == 0
-				end,
-			}),
-			-- Use a function to execute any shell command and print its text.
-			s("bash", f(bash, {}, { user_args = { "ls" } })),
-			-- Short version for applying String transformations using function nodes.
-			s("transform", {
-				i(1, "initial text"),
-				t({ "", "" }),
-				-- lambda nodes accept an l._1,2,3,4,5, which in turn accept any string transformations.
-				-- This list will be applied in order to the first node given in the second argument.
-				l(l._1:match("[^i]*$"):gsub("i", "o"):gsub(" ", "_"):upper(), 1),
-			}),
-
-			s("transform2", {
-				i(1, "initial text"),
-				t("::"),
-				i(2, "replacement for e"),
-				t({ "", "" }),
-				-- Lambdas can also apply transforms USING the text of other nodes:
-				l(l._1:gsub("e", l._2), { 1, 2 }),
-			}),
-			s({ trig = "trafo(%d+)", regTrig = true }, {
-				-- env-variables and captures can also be used:
-				l(l.CAPTURE1:gsub("1", l.TM_FILENAME), {}),
-			}),
-			-- Set store_selection_keys = "<Tab>" (for example) in your
-			-- luasnip.config.setup() call to populate
-			-- TM_SELECTED_TEXT/SELECT_RAW/SELECT_DEDENT.
-			-- In this case: select a URL, hit Tab, then expand this snippet.
-			s("link_url", {
-				t('<a href="'),
-				f(function(_, snip)
-					-- TM_SELECTED_TEXT is a table to account for multiline-selections.
-					-- In this case only the first line is inserted.
-					return snip.env.TM_SELECTED_TEXT[1] or {}
-				end, {}),
-				t('">'),
-				i(1),
-				t("</a>"),
-				i(0),
-			}),
-			-- Shorthand for repeating the text in a given node.
-			s("repeat", { i(1, "text"), t({ "", "" }), rep(1) }),
-			-- Directly insert the ouput from a function evaluated at runtime.
-			s("part", p(os.date, "%Y")),
-			-- use matchNodes (`m(argnode, condition, then, else)`) to insert text
-			-- based on a pattern/function/lambda-evaluation.
-			-- It's basically a shortcut for simple functionNodes:
-			s("mat", {
-				i(1, { "sample_text" }),
-				t(": "),
-				m(1, "%d", "contains a number", "no number :("),
-			}),
-			-- The `then`-text defaults to the first capture group/the entire
-			-- match if there are none.
-			s("mat2", {
-				i(1, { "sample_text" }),
-				t(": "),
-				m(1, "[abc][abc][abc]"),
-			}),
-			-- It is even possible to apply gsubs' or other transformations
-			-- before matching.
-			s("mat3", {
-				i(1, { "sample_text" }),
-				t(": "),
-				m(1, l._1:gsub("[123]", ""):match("%d"), "contains a number that isn't 1, 2 or 3!"),
-			}),
-			-- `match` also accepts a function in place of the condition, which in
-			-- turn accepts the usual functionNode-args.
-			-- The condition is considered true if the function returns any
-			-- non-nil/false-value.
-			-- If that value is a string, it is used as the `if`-text if no if is explicitly given.
-			s("mat4", {
-				i(1, { "sample_text" }),
-				t(": "),
-				m(1, function(args)
-					-- args is a table of multiline-strings (as usual).
-					return (#args[1][1] % 2 == 0 and args[1]) or nil
-				end),
-			}),
-			-- The nonempty-node inserts text depending on whether the arg-node is
-			-- empty.
-			s("nempty", {
-				i(1, "sample_text"),
-				n(1, "i(1) is not empty!"),
-			}),
-			-- dynamic lambdas work exactly like regular lambdas, except that they
-			-- don't return a textNode, but a dynamicNode containing one insertNode.
-			-- This makes it easier to dynamically set preset-text for insertNodes.
-			s("dl1", {
-				i(1, "sample_text"),
-				t({ ":", "" }),
-				dl(2, l._1, 1),
-			}),
-			-- Obviously, it's also possible to apply transformations, just like lambdas.
-			s("dl2", {
-				i(1, "sample_text"),
-				i(2, "sample_text_2"),
-				t({ "", "" }),
-				dl(3, l._1:gsub("\n", " linebreak ") .. l._2, { 1, 2 }),
-			}),
-		}, {
-			key = "all",
-		})
-	end,
-}
diff --git a/.config/nvim/lua/goodhumored/plugins/auto-session.lua b/.config/nvim/lua/goodhumored/sessions/auto-session.lua
similarity index 100%
rename from .config/nvim/lua/goodhumored/plugins/auto-session.lua
rename to .config/nvim/lua/goodhumored/sessions/auto-session.lua
diff --git a/.config/nvim/lua/goodhumored/plugins/obsession.lua b/.config/nvim/lua/goodhumored/sessions/obsession.lua
similarity index 100%
rename from .config/nvim/lua/goodhumored/plugins/obsession.lua
rename to .config/nvim/lua/goodhumored/sessions/obsession.lua
diff --git a/.config/nvim/lua/goodhumored/plugins/project-nvim.lua b/.config/nvim/lua/goodhumored/sessions/project-nvim.lua
similarity index 100%
rename from .config/nvim/lua/goodhumored/plugins/project-nvim.lua
rename to .config/nvim/lua/goodhumored/sessions/project-nvim.lua
diff --git a/.config/nvim/luasnippets/package.json b/.config/nvim/luasnippets/package.json
new file mode 100644
index 0000000..377041e
--- /dev/null
+++ b/.config/nvim/luasnippets/package.json
@@ -0,0 +1,14 @@
+{
+  "name": "example-snippets",
+  "contributes": {
+    "snippets": [
+      {
+        "language": [
+          "typescript",
+          "typescriptreact"
+        ],
+        "path": "./ts.jsonc"
+      }
+    ]
+  }
+}
diff --git a/.config/nvim/luasnippets/ts.jsonc b/.config/nvim/luasnippets/ts.jsonc
new file mode 100644
index 0000000..7533f7b
--- /dev/null
+++ b/.config/nvim/luasnippets/ts.jsonc
@@ -0,0 +1,486 @@
+{
+	// Place your global snippets here. Each snippet is defined under a snippet name and has a scope, prefix, body and 
+	// description. Add comma separated ids of the languages where the snippet is applicable in the scope field. If scope 
+	// is left empty or omitted, the snippet gets applied to all languages. The prefix is what is 
+	// used to trigger the snippet and the body will be expanded and inserted. Possible variables are: 
+	// $1, $2 for tab stops, $0 for the final cursor position, and ${1:label}, ${2:another} for placeholders. 
+	// Placeholders with the same ids are connected.
+	// Example:
+	// "Print to console": {
+	// 	"scope": "javascript,typescript",
+	// 	"prefix": "log",
+	// 	"body": [
+	// 		"console.log('$1');",
+	// 		"$2"
+	// 	],
+	// 	"description": "Log output to console"
+	// }
+	"private readonly ...": {
+		"scope": "typescript",
+		"prefix": "prr",
+		"body": [
+			"private readonly _${1:name}: ${2:Type}"
+		]
+	},
+	"props": {
+		"scope": "typescriptreact",
+		"prefix": "props",
+		"body": [
+			"{ className }: { className?: string }"
+		]
+	},
+	"prop": {
+		"scope": "typescript",
+		"prefix": "prop",
+		"body": [
+			"private _${1:name}: ${3:Type}",
+			"get${2:Name}(): ${3:Type} {",
+			"  return this._${1:name}",
+			"}",
+			"set${2:Name}(${1:name}: ${3:Type}) {",
+			"  this._${1:name} = ${1:name}",
+			"}"
+		]
+	},
+	"roprop": {
+		"scope": "typescript",
+		"prefix": "ro",
+		"body": [
+			"private readonly _${1:name}: ${3:Type};",
+			"get${2:Name}(): ${3:Type} {",
+			"  return this._${1:name}",
+			"}"
+		]
+	},
+	"vs": {
+		"scope": "typescript",
+		"prefix": "vs",
+		"body": [
+			"vi.spyOn(${1:class}, \"${2:method}\")${3:.mock$4};"
+		]
+	},
+	"faker lorem word": {
+		"scope": "typescript",
+		"prefix": "flw",
+		"body": [
+			"faker.lorem.word();"
+		]
+	},
+	"react prop": {
+		"scope": "typescript",
+		"prefix": "comp",
+		"body": [
+			"import React from \"react\";",
+			"",
+			"export default function ${1:name}({className}: {className?: string}) {",
+			" return (",
+			"   <${2:div} className={`${className}`}>",
+			"     $0",
+			"     </${2:div}>",
+			" )",
+			"}"
+		]
+	},
+	//          ╭─────────────────────────────────────────────────────────╮
+	//          │            Jest (vitest) snippets down below            │
+	//          ╰─────────────────────────────────────────────────────────╯
+	"afterAll": {
+		"body": "afterAll(() => {\n\t$0\n});",
+		"description": "afterAll function is called once after all specs",
+		"prefix": "aa",
+		"scope": "typescript"
+	},
+	"afterEach": {
+		"body": "afterEach(() => {\n\t$0\n});",
+		"description": "afterEach function is called once after each spec",
+		"prefix": "ae",
+		"scope": "typescript"
+	},
+	"beforeAll": {
+		"body": "beforeAll(() => {\n\t$0\n});",
+		"description": "beforeAll function is called once before all specs",
+		"prefix": "ba",
+		"scope": "typescript"
+	},
+	"beforeAll:async": {
+		"body": "beforeAll(async () => {\n\t$0\n});",
+		"description": "beforeAll with async function is called once before all specs",
+		"prefix": "baa",
+		"scope": "typescript"
+	},
+	"beforeEach": {
+		"body": "beforeEach(() => {\n\t$0\n});",
+		"description": "beforeEach function is called once before each spec",
+		"prefix": "be",
+		"scope": "typescript"
+	},
+	"beforeEach:async": {
+		"body": "beforeEach(async () => {\n\t$0\n});",
+		"description": "beforeEach with async callback function is called once before each spec",
+		"prefix": "bea",
+		"scope": "typescript"
+	},
+	"describe": {
+		"body": "describe('${1:Name of the group}', () => {\n\t$0\n});",
+		"description": "creates a describe block",
+		"prefix": "desc",
+		"scope": "typescript"
+	},
+	"describe.each": {
+		"body": [
+			"describe.each([${1:[1, 2], [2, 4]}])(",
+			"\t'${2:double(%d)}',",
+			"\t(${3:input, expected}) => {",
+			"\t\ttest(`returns \\${expected}`, () => {",
+			"\t\t\t${4:expect(double(input)).toBe(expected);}",
+			"\t\t});",
+			"\t}",
+			");"
+		],
+		"description": "creates a describe block with different test data sets",
+		"prefix": "desce",
+		"scope": "typescript"
+	},
+	"describe.only": {
+		"body": "describe.only('${1:Name of the group}', () => {\n\t$0\n});",
+		"description": "creates a describe block that runs only",
+		"prefix": "desco",
+		"scope": "typescript"
+	},
+	"describe.skip": {
+		"body": "describe.skip('${1:Name of the group}', () => {\n\t$0\n});",
+		"description": "creates a describe block that will be skipped",
+		"prefix": "descs",
+		"scope": "typescript"
+	},
+	"expect": {
+		"body": "expect($0)",
+		"description": "expect actual value",
+		"prefix": "exp",
+		"scope": "typescript"
+	},
+	"expect.assertions": {
+		"body": "expect.assertions($0);",
+		"description": "expects the test to make the indicated number of assertions (useful for async)",
+		"prefix": "expas",
+		"scope": "typescript"
+	},
+	"expect.hasAssertions": {
+		"body": "expect.hasAssertions();$0",
+		"description": "expects the test to make at least one assertion (useful for async)",
+		"prefix": "expha",
+		"scope": "typescript"
+	},
+	"expect.rejects": {
+		"body": "expect($1).rejects$0",
+		"description": "expect promise rejects to",
+		"prefix": "exprj",
+		"scope": "typescript"
+	},
+	"expect.resolves": {
+		"body": "expect($1).resolves$0",
+		"description": "expect promise resolves to",
+		"prefix": "expr",
+		"scope": "typescript"
+	},
+	"it": {
+		"body": "it('${1:should }', () => {\n\t$0\n});",
+		"description": "creates an it block",
+		"prefix": "it",
+		"scope": "typescript"
+	},
+	"it.each": {
+		"body": [
+			"it.each([${1:[1, 2], [2, 4]}])(",
+			"\t'${2:double(%d)}',",
+			"\t(${3:input, expected}) => {",
+			"\t\t${0:expect(double(input)).toBe(expected);}",
+			"\t}",
+			");"
+		],
+		"description": "creates an it block with different test data sets",
+		"prefix": "ite",
+		"scope": "typescript"
+	},
+	"it.only": {
+		"body": "it.only('${1:should }', () => {\n\t$0\n});",
+		"description": "creates an it block that runs only",
+		"prefix": "ito",
+		"scope": "typescript"
+	},
+	"it.skip": {
+		"body": "it.skip('${1:should }', () => {\n\t$0\n});",
+		"description": "creates an it block that will be skipped",
+		"prefix": "its",
+		"scope": "typescript"
+	},
+	"it.todo": {
+		"body": "it.todo('${1:should }');",
+		"description": "creates a test placeholder",
+		"prefix": "itt",
+		"scope": "typescript"
+	},
+	"it:async": {
+		"body": "it('${1:should }', async () => {\n\t$0\n});",
+		"description": "creates an it block with async callback function",
+		"prefix": "ita",
+		"scope": "typescript"
+	},
+	"jest.fn": {
+		"body": "jest.fn($0)",
+		"description": "creates jest.fn()",
+		"prefix": "jfn",
+		"scope": "typescript"
+	},
+	"template:cut": {
+		"body": [
+			"describe('${1:Name of the group}', () => {\n",
+			"\tlet ${2:cut};\n",
+			"\tbeforeEach(() => {\n\t\t$2 = $3;\n\t});\n",
+			"\ttest('${1:should }', () => {",
+			"\t\texpect($2).toBe($0);",
+			"\t});\n",
+			"});"
+		],
+		"description": "creates a template to test a class under test",
+		"prefix": "cut",
+		"scope": "typescript"
+	},
+	"test": {
+		"body": "test('${1:should }', () => {\n\t$0\n});",
+		"description": "creates a test block",
+		"prefix": "test",
+		"scope": "typescript"
+	},
+	"test.each": {
+		"body": [
+			"test.each([${1:[1, 2], [2, 4]}])(",
+			"\t'${2:double(%d)}',",
+			"\t(${3:input, expected}) => {",
+			"\t\t${0:expect(double(input)).toBe(expected);}",
+			"\t}",
+			");"
+		],
+		"description": "creates an test block with different test data sets",
+		"prefix": "teste",
+		"scope": "typescript"
+	},
+	"test.each (table)": {
+		"body": [
+			"test.each`",
+			"\t${1:input}\t| ${2:expected}",
+			"\t\\${1}\t| \\${2}",
+			"\t\\${2}\t| \\${4}",
+			"`('${3:double($${1:input})}', ({ ${1:input}, ${2:expected} }) => {",
+			"\t${0:expect(double(${1:input})).toBe(${2:expected});}",
+			"});"
+		],
+		"description": "creates a test block using a permutation table",
+		"prefix": "testet",
+		"scope": "typescript"
+	},
+	"test.only": {
+		"body": "test.only('${1:should }', () => {\n\t$0\n});",
+		"description": "creates a test block  that runs only",
+		"prefix": "testo",
+		"scope": "typescript"
+	},
+	"test.skip": {
+		"body": "test.skip('${1:should }', () => {\n\t$0\n});",
+		"description": "creates a test block that will be skipped",
+		"prefix": "tests",
+		"scope": "typescript"
+	},
+	"test.todo": {
+		"body": "test.todo('${1:should }');",
+		"description": "creates a test placeholder",
+		"prefix": "testt",
+		"scope": "typescript"
+	},
+	"test:async": {
+		"body": "test('${1:should }', async () => {\n\t$0\n});",
+		"description": "creates an test block with async callback function",
+		"prefix": "testa",
+		"scope": "typescript"
+	},
+	"toBe": {
+		"body": "expect($1).toBe($2);$0",
+		"description": "expects the first argument to be equal with the second one",
+		"prefix": "tb",
+		"scope": "typescript"
+	},
+	"toBeCloseTo": {
+		"body": "expect($1).toBeCloseTo(${2:number}, ${3:delta});$0",
+		"description": "expects the first argument to be close to the second one base on the delta",
+		"prefix": "tbct",
+		"scope": "typescript"
+	},
+	"toBeDefined": {
+		"body": "expect($1).toBeDefined();$0",
+		"description": "expects the argument is defined",
+		"prefix": "tbd",
+		"scope": "typescript"
+	},
+	"toBeFalsy": {
+		"body": "expect($1).toBeFalsy();$0",
+		"description": "expects the argument is falsy",
+		"prefix": "tbf",
+		"scope": "typescript"
+	},
+	"toBeGreaterThan": {
+		"body": "expect($1).toBeGreaterThan($2);$0",
+		"description": "expects the argument is greater than or equal",
+		"prefix": "tbgt",
+		"scope": "typescript"
+	},
+	"toBeGreaterThanOrEqual": {
+		"body": "expect($1).toBeGreaterThanOrEqual($2);$0",
+		"description": "expects the argument is greater than",
+		"prefix": "tbgte",
+		"scope": "typescript"
+	},
+	"toBeInstanceOf": {
+		"body": "expect($1).toBeInstanceOf($2);$0",
+		"description": "expects the argument is less than",
+		"prefix": "tbi",
+		"scope": "typescript"
+	},
+	"toBeLessThan": {
+		"body": "expect($1).toBeLessThan($2);$0",
+		"description": "expects the argument is less than",
+		"prefix": "tblt",
+		"scope": "typescript"
+	},
+	"toBeLessThanOrEqual": {
+		"body": "expect($1).toBeLessThanOrEqual($2);$0",
+		"description": "expects the argument is less than or equal",
+		"prefix": "tblte",
+		"scope": "typescript"
+	},
+	"toBeNull": {
+		"body": "expect($1).toBeNull();$0",
+		"description": "expects the argument is null",
+		"prefix": "tbn",
+		"scope": "typescript"
+	},
+	"toBeTruthy": {
+		"body": "expect($1).toBeTruthy();$0",
+		"description": "expects the argument is truthy",
+		"prefix": "tbt",
+		"scope": "typescript"
+	},
+	"toBeUndefined": {
+		"body": "expect($1).toBeUndefined();$0",
+		"description": "expects the argument is undefined",
+		"prefix": "tbu",
+		"scope": "typescript"
+	},
+	"toContain": {
+		"body": "expect(${1:list}).toContain($2);$0",
+		"description": "expects the list contains the item (===)",
+		"prefix": "tc",
+		"scope": "typescript"
+	},
+	"toContainEqual": {
+		"body": "expect(${1:list}).toContainEqual($2);$0",
+		"description": "expects the list contains the item (equals)",
+		"prefix": "tce",
+		"scope": "typescript"
+	},
+	"toEqual": {
+		"body": "expect($1).toEqual($2);$0",
+		"description": "expects the first argument to be equal with the second one",
+		"prefix": "te",
+		"scope": "typescript"
+	},
+	"toHaveBeenCalled": {
+		"body": "expect($1).toHaveBeenCalled();$0",
+		"description": "returns true if the spy was called",
+		"prefix": "thbc",
+		"scope": "typescript"
+	},
+	"toHaveBeenCalledTimes": {
+		"body": "expect($1).toHaveBeenCalledTimes($2);$0",
+		"description": "returns true if the spy has been called given times",
+		"prefix": "thbct",
+		"scope": "typescript"
+	},
+	"toHaveBeenCalledWith": {
+		"body": "expect($1).toHaveBeenCalledWith($2);$0",
+		"description": "returns true if the spy has been called with",
+		"prefix": "thbcw",
+		"scope": "typescript"
+	},
+	"toHaveBeenLastCalledWith": {
+		"body": "expect($1).toHaveBeenLastCalledWith($2);$0",
+		"description": "returns true if the spy has been last called with",
+		"prefix": "thblcw",
+		"scope": "typescript"
+	},
+	"toHaveLength": {
+		"body": "expect($1).toHaveLength($2);$0",
+		"description": "expects the object to have length",
+		"prefix": "thl",
+		"scope": "typescript"
+	},
+	"toHaveProperty": {
+		"body": "expect($1).toHaveProperty(${2:keyPath}, ${3:value});$0",
+		"description": "returns true if the argument matches the second object",
+		"prefix": "thp",
+		"scope": "typescript"
+	},
+	"toMatch": {
+		"body": "expect($1).toMatch($2);$0",
+		"description": "returns true if the argument matches the second value",
+		"prefix": "tm",
+		"scope": "typescript"
+	},
+	"toMatchInlineSnapshot": {
+		"body": "expect($1).toMatchInlineSnapshot($2);$0",
+		"description": "returns true if the argument matches the most recent inline snapshot",
+		"prefix": "tmis",
+		"scope": "typescript"
+	},
+	"toMatchObject": {
+		"body": "expect($1).toMatchObject($2);$0",
+		"description": "returns true if the argument matches the second object",
+		"prefix": "tmo",
+		"scope": "typescript"
+	},
+	"toMatchSnapshot": {
+		"body": "expect($1).toMatchSnapshot($2);$0",
+		"description": "returns true if the argument matches the most recent snapshot",
+		"prefix": "tms",
+		"scope": "typescript"
+	},
+	"toStrictEqual": {
+		"body": "expect($1).toStrictEqual($2);$0",
+		"description": "expects the first argument to be strictly equal with the second one",
+		"prefix": "tse",
+		"scope": "typescript"
+	},
+	"toThrow": {
+		"body": "expect(() => {\n\t$0\n}).toThrow($1);",
+		"description": "expects that the method will throw an error",
+		"prefix": "tt",
+		"scope": "typescript"
+	},
+	"toThrowError": {
+		"body": "expect(() => {\n\t$0\n}).toThrowError($1);",
+		"description": "expects that the method will throw an error",
+		"prefix": "tte",
+		"scope": "typescript"
+	},
+	"toThrowErrorMatchingInlineSnapshot": {
+		"body": "expect(() => {\n\t$0\n}).toThrowErrorMatchingInlineSnapshot();",
+		"description": "expects that the method will throw an error matching the inline snapshot",
+		"prefix": "ttemis",
+		"scope": "typescript"
+	},
+	"toThrowErrorMatchingSnapshot": {
+		"body": "expect(() => {\n\t$0\n}).toThrowErrorMatchingSnapshot();",
+		"description": "expects that the method will throw an error mathing the snapshpot",
+		"prefix": "ttems",
+		"scope": "typescript"
+	}
+}