diff --git a/dprint.json b/dprint.json new file mode 100644 index 00000000000..4d7b2024c41 --- /dev/null +++ b/dprint.json @@ -0,0 +1,18 @@ +{ + "typescript": {}, + "json": {}, + "markdown": {}, + "toml": {}, + "malva": {}, + "markup": {}, + "yaml": {}, + "plugins": [ + "https://plugins.dprint.dev/typescript-0.96.1.wasm", + "https://plugins.dprint.dev/json-0.23.0.wasm", + "https://plugins.dprint.dev/markdown-0.22.1.wasm", + "https://plugins.dprint.dev/toml-0.7.0.wasm", + "https://plugins.dprint.dev/g-plane/malva-v0.16.0.wasm", + "https://plugins.dprint.dev/g-plane/markup_fmt-v0.27.3.wasm", + "https://plugins.dprint.dev/g-plane/pretty_yaml-v0.6.0.wasm" + ] +} diff --git a/init.lua b/init.lua index aff5250e921..0dd7bdce485 100644 --- a/init.lua +++ b/init.lua @@ -99,7 +99,7 @@ do vim.g.maplocalleader = ' ' -- Set to true if you have a Nerd Font installed and selected in the terminal - vim.g.have_nerd_font = false + vim.g.have_nerd_font = true -- [[ Setting options ]] -- See `:help vim.o` @@ -122,7 +122,9 @@ do -- Schedule the setting after `UiEnter` because it can increase startup-time. -- Remove this option if you want your OS clipboard to remain independent. -- See `:help 'clipboard'` - vim.schedule(function() vim.o.clipboard = 'unnamedplus' end) + vim.schedule(function() + -- vim.opt.clipboard = 'unnamedplus' + end) -- Enable break indent vim.o.breakindent = true @@ -217,7 +219,7 @@ do -- -- NOTE: This won't work in all terminal emulators/tmux/etc. Try your own mapping -- or just use to exit terminal mode - vim.keymap.set('t', '', '', { desc = 'Exit terminal mode' }) + -- vim.keymap.set('t', '', '', { desc = 'Exit terminal mode' }) -- TIP: Disable arrow keys in normal mode -- vim.keymap.set('n', '', 'echo "Use h to move!!"') @@ -430,7 +432,17 @@ do -- - saiw) - [S]urround [A]dd [I]nner [W]ord [)]Paren -- - sd' - [S]urround [D]elete [']quotes -- - sr)' - [S]urround [R]eplace [)] ['] - require('mini.surround').setup() + require('mini.surround').setup { + mappings = { + add = 'ra', + delete = 'rd', + find = 'rf', + find_left = 'rF', + highlight = 'rh', + replace = 'rr', + update_n_lines = 'rn', + }, + } -- Simple and easy statusline. -- You could remove this setup call if you don't like it, @@ -494,12 +506,16 @@ do -- You can put your default mappings / updates / etc. in here -- All the info you're looking for is in `:help telescope.setup()` -- - -- defaults = { - -- mappings = { - -- i = { [''] = 'to_fuzzy_refine' }, - -- }, - -- }, - -- pickers = {} + defaults = { + file_ignore_patterns = { + 'node_modules', + 'package-lock.json', + 'yarn.lock', + 'pnpm-lock.yaml', + 'lazy-lock.json', + }, + mappings = {}, + }, extensions = { ['ui-select'] = { require('telescope.themes').get_dropdown() }, }, @@ -692,7 +708,9 @@ do -- See `:help lsp-config` for information about keys and how to configure ---@type table local servers = { - -- clangd = {}, + clangd = { + cmd = { 'clangd', '--background-index' }, + }, -- gopls = {}, -- pyright = {}, -- rust_analyzer = {}, @@ -701,7 +719,7 @@ do -- https://github.com/pmizio/typescript-tools.nvim -- -- But for many setups, the LSP (`ts_ls`) will work just fine - -- ts_ls = {}, + vtsls = {}, stylua = {}, -- Used to format Lua code @@ -760,6 +778,20 @@ do local ensure_installed = vim.tbl_keys(servers or {}) vim.list_extend(ensure_installed, { -- You can add other tools here that you want Mason to install + 'stylua', + 'tailwindcss', + 'html', + 'intelephense', + 'pretty-php', + 'svelte', + 'vtsls', + 'gofumpt', + 'gopls', + 'shfmt', + 'rust-analyzer', + 'ruff', + 'biome', + 'clang-format', }) require('mason-tool-installer').setup { ensure_installed = ensure_installed } @@ -784,6 +816,22 @@ do local enabled_filetypes = { -- lua = true, -- python = true, + javascript = true, + typescript = true, + javascriptreact = true, + typescriptreact = true, + scss = true, + pandoc = true, + markdown = true, + json = true, + css = true, + yml = true, + html = true, + php = true, + cpp = true, + sh = true, + go = true, + python = true, } if enabled_filetypes[vim.bo[bufnr].filetype] then return { timeout_ms = 500 } @@ -794,6 +842,11 @@ do default_format_opts = { lsp_format = 'fallback', -- Use external formatters if configured below, otherwise use LSP formatting. Set to `false` to disable LSP formatting entirely. }, + formatters = { + ['pretty-php'] = { + prepend_args = { '-s2' }, + }, + }, -- You can also specify external formatters in here. formatters_by_ft = { -- rust = { 'rustfmt' }, @@ -801,7 +854,29 @@ do -- python = { "isort", "black" }, -- -- You can use 'stop_after_first' to run the first available formatter from the list - -- javascript = { "prettierd", "prettier", stop_after_first = true }, + javascript = { 'biome' }, + typescript = { 'biome' }, + javascriptreact = { 'biome' }, + typescriptreact = { 'biome' }, + scss = { 'biome' }, + pandoc = { 'biome' }, + markdown = { 'biome' }, + json = { 'biome' }, + css = { 'biome' }, + yml = { 'biome' }, + html = { 'biome' }, + php = { 'pretty-php' }, + cpp = { 'clang_format' }, + sh = { 'shfmt' }, + go = { 'gofumpt' }, + python = { + -- To fix auto-fixable lint errors + 'ruff_fix', + -- To run the Ruff formatter + 'ruff_format', + -- To organize the imports + 'ruff_organize_imports', + }, }, } @@ -820,12 +895,20 @@ do vim.pack.add { { src = gh 'L3MON4D3/LuaSnip', version = vim.version.range '2.*' } } require('luasnip').setup {} + local ls = require 'luasnip' + ls.config.set_config { + store_selection_keys = '', + } + ls.filetype_extend('svelte', { 'typescript', 'html' }) + -- `friendly-snippets` contains a variety of premade snippets. -- See the README about individual language/framework/plugin snippets: -- https://github.com/rafamadriz/friendly-snippets -- -- vim.pack.add { gh 'rafamadriz/friendly-snippets' } - -- require('luasnip.loaders.from_vscode').lazy_load() + require('luasnip.loaders.from_vscode').load { + paths = { '~/git/friendly-snippets' }, + } -- [[ Autocomplete Engine ]] vim.pack.add { { src = gh 'saghen/blink.cmp', version = vim.version.range '1.*' } } @@ -852,7 +935,13 @@ do -- : Toggle signature help -- -- See `:help blink-cmp-config-keymap` for defining your own keymap - preset = 'default', + preset = 'enter', + [''] = { + function(cmp) cmp.show() end, + 'show', + 'show_documentation', + 'hide_documentation', + }, -- For more advanced Luasnip keymaps (e.g. selecting choice nodes, expansion) see: -- https://github.com/L3MON4D3/LuaSnip?tab=readme-ov-file#keymaps @@ -888,6 +977,15 @@ do -- Shows a signature help window while you type arguments for a function signature = { enabled = true }, } + + -- Luasnip choice node navigation + vim.keymap.set({ 'i', 's' }, '', function() + if require('luasnip').choice_active() then require('luasnip').change_choice(1) end + end, { desc = 'LuaSnip: next choice' }) + + vim.keymap.set({ 'i', 's' }, '', function() + if require('luasnip').choice_active() then require('luasnip').change_choice(-1) end + end, { desc = 'LuaSnip: previous choice' }) end -- ============================================================ @@ -903,6 +1001,8 @@ do -- NOTE: You can also specify a branch or a specific commit vim.pack.add { { src = gh 'nvim-treesitter/nvim-treesitter', version = 'main' } } + require('nvim-treesitter.install').compilers = { 'clang', 'gcc', 'zig' } + -- Ensure basic parsers are installed local parsers = { 'bash', 'c', 'diff', 'html', 'lua', 'luadoc', 'markdown', 'markdown_inline', 'query', 'vim', 'vimdoc' } require('nvim-treesitter').install(parsers) @@ -966,17 +1066,17 @@ do -- Here are some example plugins that I've included in the Kickstart repository. -- Uncomment any of the lines below to enable them (you will need to restart nvim). -- - -- require 'kickstart.plugins.debug' - -- require 'kickstart.plugins.indent_line' - -- require 'kickstart.plugins.lint' - -- require 'kickstart.plugins.autopairs' - -- require 'kickstart.plugins.neo-tree' + require 'kickstart.plugins.debug' + require 'kickstart.plugins.indent_line' + require 'kickstart.plugins.lint' + require 'kickstart.plugins.autopairs' + require 'kickstart.plugins.neo-tree' -- require 'kickstart.plugins.gitsigns' -- adds gitsigns recommended keymaps -- NOTE: You can add your own plugins, configuration, etc from `lua/custom/plugins/*.lua` -- -- Uncomment the following line and add your plugins to `lua/custom/plugins/*.lua` to get going. - -- require 'custom.plugins' + require 'custom.plugins' end -- The line beneath this is called `modeline`. See `:help modeline` diff --git a/lua/custom/plugins/00-plugins.lua b/lua/custom/plugins/00-plugins.lua new file mode 100644 index 00000000000..178f1afb961 --- /dev/null +++ b/lua/custom/plugins/00-plugins.lua @@ -0,0 +1,162 @@ +-- ============================================================================= +-- PLUGIN REGISTRATIONS +-- ============================================================================= +vim.pack.add({ + { src = 'https://github.com/folke/flash.nvim' }, + { src = 'https://github.com/yokowasis/emmet-vim' }, + { + src = 'https://github.com/jake-stewart/multicursor.nvim', + version = '1.0', + }, + { src = 'https://github.com/MagicDuck/grug-far.nvim' }, + { src = 'https://github.com/tpope/vim-dadbod' }, + { src = 'https://github.com/kristijanhusak/vim-dadbod-ui' }, + { src = 'https://github.com/kristijanhusak/vim-dadbod-completion' }, + { src = 'https://github.com/thesimonho/kanagawa-paper.nvim' }, + { src = 'https://github.com/NeogitOrg/neogit' }, + { src = 'https://github.com/sindrets/diffview.nvim' }, + { src = 'https://github.com/rcarriga/nvim-notify' }, + { src = 'https://github.com/folke/noice.nvim' }, + { src = 'https://github.com/theHamsta/nvim-dap-virtual-text' }, +}) + +-- ============================================================================= +-- FLASH NAVIGATION +-- ============================================================================= +require("flash").setup({}) + +vim.keymap.set({ "n", "x", "o" }, "s", function() + require("flash").jump() +end, { desc = "Flash" }) + +vim.keymap.set({ "n", "x", "o" }, "S", function() + require("flash").treesitter() +end, { desc = "Flash Treesitter" }) + +vim.keymap.set("o", "r", function() + require("flash").remote() +end, { desc = "Remote Flash" }) + +vim.keymap.set({ "o", "x" }, "R", function() + require("flash").treesitter_search() +end, { desc = "Treesitter Search" }) + +vim.keymap.set("c", "", function() + require("flash").toggle() +end, { desc = "Toggle Flash Search" }) + +-- ============================================================================= +-- EMMET +-- ============================================================================= +vim.g.user_emmet_settings = { + typescriptreact = { + attribute_name = { + ["class"] = "class", + }, + }, +} + +-- ============================================================================= +-- MULTICURSOR +-- ============================================================================= +local mc = require("multicursor-nvim") +mc.setup() + +local set = vim.keymap.set + +set({ "n", "x" }, "", function() + mc.matchAddCursor(1) +end) + +set("n", "", mc.handleMouse) +set("n", "", mc.handleMouseDrag) +set("n", "", mc.handleMouseRelease) + +set({ "n", "x" }, "", mc.toggleCursor) + +mc.addKeymapLayer(function(layerSet) + layerSet({ "n", "x" }, "x", mc.deleteCursor) + + layerSet("n", "", function() + if not mc.cursorsEnabled() then + mc.enableCursors() + else + mc.clearCursors() + end + end) +end) + +local hl = vim.api.nvim_set_hl +hl(0, "MultiCursorCursor", { reverse = true }) +hl(0, "MultiCursorVisual", { link = "Visual" }) +hl(0, "MultiCursorSign", { link = "SignColumn" }) +hl(0, "MultiCursorMatchPreview", { link = "Search" }) +hl(0, "MultiCursorDisabledCursor", { reverse = true }) +hl(0, "MultiCursorDisabledVisual", { link = "Visual" }) +hl(0, "MultiCursorDisabledSign", { link = "SignColumn" }) + +-- ============================================================================= +-- GRUG-FAR (SEARCH & REPLACE) +-- ============================================================================= +require("grug-far").setup({ + headerMaxWidth = 80, +}) + +vim.api.nvim_create_user_command("GrugFar", function() + require("grug-far").open() +end, {}) + +local set = vim.keymap.set + +set("n", "S", "GrugFar", { desc = "Search and Replace (grug-far)" }) + +-- set("n", "sw", function() +-- require("grug-far").grug_far({ prefills = { search = vim.fn.expand("") } }) +-- end, { desc = "Search current word" }) + +-- set("n", "sf", function() +-- require("grug-far").grug_far({ prefills = { paths = vim.fn.expand("%") } }) +-- end, { desc = "Search in current file" }) + +-- ============================================================================= +-- DADBOD (DATABASE TOOLS) +-- ============================================================================= +vim.g.db_ui_use_nerd_fonts = 1 + +vim.api.nvim_create_autocmd("FileType", { + pattern = { "sql", "mysql", "plsql" }, + callback = function() + vim.fn["compe#register"]({ source = "vim-dadbod-completion" }) + end, +}) + +-- ============================================================================= +-- KANAGAWA-PAPER COLORSCHEME +-- ============================================================================= +require("kanagawa-paper").setup({}) + +vim.cmd("colorscheme kanagawa-paper-ink") + +-- ============================================================================= +-- NOICE (UI OVERLAY FOR MESSAGES, CMDLINE, AND POPUPMENU) +-- ============================================================================= +require("notify").setup({ + background_colour = "#000000", +}) + +require("noice").setup({ + lsp = { + override = { + ["vim.lsp.util.convert_input_to_markdown_lines"] = true, + ["vim.lsp.util.stylize_markdown"] = true, + ["cmp.entry.get_documentation"] = true, + }, + }, + presets = { + bottom_search = true, + command_palette = true, + long_message_to_split = true, + inc_rename = false, + lsp_doc_border = true, + }, +}) diff --git a/lua/custom/plugins/01-functions.lua b/lua/custom/plugins/01-functions.lua new file mode 100644 index 00000000000..491d4a1324f --- /dev/null +++ b/lua/custom/plugins/01-functions.lua @@ -0,0 +1,375 @@ +-- Notification function for job output +function notif(jobid, data, event, timeout, notifid) + if type(data) == 'number' then + return + end + + local output = table.concat(data, '\n') + if output ~= '' then + vim.notify(output, vim.log.levels.WARN, { + title = 'Notification', + timeout = timeout or 5000, + }) + end +end + +function CompileAndRun() + local filetype = GetFileType() + + -- Get full folder path of the current buffer + local folder_path = vim.fn.expand '%:p:h' + + -- get full path up to "labs" folder + local labs_fullfolder = folder_path:match '(.+labs)' + + -- Get the filename (with extension) of the current buffer + local filename_with_extension = vim.fn.expand '%:t' + + -- Get the filename without the extension + local filename_without_extension = vim.fn.expand '%:t:r' + + -- Get the file extension of the current buffer + local file_extension = vim.fn.fnamemodify(filename_with_extension, ':e') + + if file_extension == 'cjs' or file_extension == 'mjs' then + filetype = 'javascript' + elseif file_extension == 'md' then + filetype = 'markdown' + end + + local iste = true + + if filetype == 'cpp' then + vim.cmd( + ':tabnew | te g++ --std=c++17 ' + .. folder_path + .. '/' + .. filename_with_extension + .. ' -o ' + .. folder_path + .. '/' + .. filename_without_extension + .. '.out' + .. ' && ' + .. folder_path + .. '/' + .. filename_without_extension + .. '.out' + ) + elseif filetype == 'javascript' then + vim.cmd(':tabnew | te node ' .. folder_path .. '/' .. filename_with_extension) + elseif file_extension == 'py' then + vim.cmd(':tabnew | te python ' .. folder_path .. '/' .. filename_with_extension) + elseif filetype == 'typescript' then + vim.cmd(':tabnew | te ts-node ' .. folder_path .. '/' .. filename_with_extension) + elseif filetype == 'shell' then + vim.cmd(':tabnew | te bash ' .. folder_path .. '/' .. filename_with_extension) + else + vim.notify('Filetype ' .. filetype .. ' not supported for compile and run') + return + end + + if iste then + vim.api.nvim_feedkeys('i', 'n', true) + end +end + +-- livegrep search +function customSearchGrep() + local extension = vim.fn.input 'Enter File Extension (*): ' + local dirs = vim.fn.input 'Enter Search Directories (.): ' + + -- if escape is pressed, return + if extension == '' and dirs == '' then + return + end + + if extension == '' then + extension = '*' + end + if dirs == '' then + dirs = '.' + end + + vim.cmd('Telescope live_grep glob_pattern=*.{' .. extension .. '} search_dirs=' .. dirs) +end + +function SearchAndReplace(search, replace) + -- make sure search is not empty + if search == '' then + return + end + + local command = ':%s/' .. search .. '/' .. replace .. '/g' + local termcodes = vim.api.nvim_replace_termcodes(command, true, true, true) + vim.api.nvim_feedkeys(termcodes, 'n', true) +end + +function NextJSNewPage(pagename) + local page_path = 'src/app/pages/' .. pagename .. '/page.tsx' + local page_content = {} + page_content[#page_content + 1] = [["use client"]] + page_content[#page_content + 1] = [[import type { NextPage } from "next";]] + page_content[#page_content + 1] = [[]] + page_content[#page_content + 1] = [[const Test: NextPage<{ someProps: string }> = (props) => {]] + page_content[#page_content + 1] = [[ return <>Hello Test;]] + page_content[#page_content + 1] = [[};]] + page_content[#page_content + 1] = [[]] + page_content[#page_content + 1] = [[export default Test;]] + vim.fn.mkdir('src/app/pages/' .. pagename, 'p') + vim.fn.writefile(page_content, page_path) + vim.cmd('e ' .. page_path) +end + +function NextJSNewApiGet(pagename) + local page_path = 'src/app/api/' .. pagename .. '/route.ts' + local page_content = {} + page_content[#page_content + 1] = [[import { NextRequest, NextResponse } from "next/server";]] + page_content[#page_content + 1] = [[// export const runtime = "edge";]] + page_content[#page_content + 1] = [[]] + page_content[#page_content + 1] = [[export const OPTIONS = async () => {]] + page_content[#page_content + 1] = [[ return NextResponse.json({]] + page_content[#page_content + 1] = [[ status: "ok",]] + page_content[#page_content + 1] = [[ });]] + page_content[#page_content + 1] = [[};]] + page_content[#page_content + 1] = [[]] + page_content[#page_content + 1] = [[export const GET = async (]] + page_content[#page_content + 1] = [[ req: NextRequest,]] + page_content[#page_content + 1] = [[ { params }: { params: { [s: string]: string } }]] + page_content[#page_content + 1] = [[) => {]] + page_content[#page_content + 1] = [[ try {]] + page_content[#page_content + 1] = [[ const url = new URL(req.url);]] + page_content[#page_content + 1] = [[ const {} = params ? params : {};]] + page_content[#page_content + 1] = [[ const searchParams = new URLSearchParams(url.search);]] + page_content[#page_content + 1] = [[ const test = searchParams.get("test");]] + page_content[#page_content + 1] = [[]] + page_content[#page_content + 1] = [[ return NextResponse.json({ status: "ok", test });]] + page_content[#page_content + 1] = [[ } catch (error) {]] + page_content[#page_content + 1] = [[ return NextResponse.json({ err: (error as any).toString() });]] + page_content[#page_content + 1] = [[ }]] + page_content[#page_content + 1] = [[};]] + vim.fn.mkdir('src/app/api/' .. pagename, 'p') + vim.fn.writefile(page_content, page_path) + vim.cmd('e ' .. page_path) +end + +function NextJSNewApiPost(pagename) + local page_path = 'src/app/api/' .. pagename .. '/route.ts' + local page_content = {} + page_content[#page_content + 1] = [[import { NextRequest, NextResponse } from "next/server";]] + page_content[#page_content + 1] = [[// export const runtime = "edge";]] + page_content[#page_content + 1] = [[]] + page_content[#page_content + 1] = [[export const OPTIONS = async () => {]] + page_content[#page_content + 1] = [[ return NextResponse.json({]] + page_content[#page_content + 1] = [[ status: "ok",]] + page_content[#page_content + 1] = [[ });]] + page_content[#page_content + 1] = [[};]] + page_content[#page_content + 1] = [[]] + page_content[#page_content + 1] = [[export const POST = async (]] + page_content[#page_content + 1] = [[ req: NextRequest,]] + page_content[#page_content + 1] = [[ { params }: { params: { [s: string]: string } }]] + page_content[#page_content + 1] = [[) => {]] + page_content[#page_content + 1] = [[ try {]] + page_content[#page_content + 1] = [[ const body = await req.json();]] + page_content[#page_content + 1] = [[ const {}: { [key: string]: string } = body;]] + page_content[#page_content + 1] = [[ const {} = params;]] + page_content[#page_content + 1] = [[]] + page_content[#page_content + 1] = [[ return NextResponse.json({ status: "ok", body });]] + page_content[#page_content + 1] = [[ } catch (error) {]] + page_content[#page_content + 1] = [[ return NextResponse.json({ err: (error as any).toString() });]] + page_content[#page_content + 1] = [[ }]] + page_content[#page_content + 1] = [[};]] + vim.fn.mkdir('src/app/api/' .. pagename, 'p') + vim.fn.writefile(page_content, page_path) + vim.cmd('e ' .. page_path) +end + +function SvelteKitNewPage(pagename) + local page_path = 'src/routes/' .. pagename .. '/+page.svelte' + local page_content = {} + vim.fn.mkdir('src/routes/' .. pagename, 'p') + vim.fn.writefile(page_content, page_path) + vim.cmd('e ' .. page_path) +end + +function SvelteKitNewAPIPost(pagename) + local page_path = 'src/routes/api/' .. pagename .. '/+server.ts' + local page_content = {} + page_content[#page_content + 1] = [[import { json } from "@sveltejs/kit";]] + page_content[#page_content + 1] = [[import type { RequestHandler } from "./$types";]] + page_content[#page_content + 1] = [[]] + page_content[#page_content + 1] = [[const headers = {]] + page_content[#page_content + 1] = [[ "Access-Control-Allow-Origin": "*",]] + page_content[#page_content + 1] = [[ "Access-Control-Allow-Methods": "GET,HEAD,PUT,PATCH,POST,DELETE",]] + page_content[#page_content + 1] = [[ "Access-Control-Allow-Headers": "Content-Type,authorization",]] + page_content[#page_content + 1] = [[};]] + page_content[#page_content + 1] = [[]] + page_content[#page_content + 1] = [[export const OPTIONS: RequestHandler = () => {]] + page_content[#page_content + 1] = [[ return new Response("", {]] + page_content[#page_content + 1] = [[ status: 200,]] + page_content[#page_content + 1] = [[ headers,]] + page_content[#page_content + 1] = [[ });]] + page_content[#page_content + 1] = [[};]] + page_content[#page_content + 1] = [[export const POST: RequestHandler = async ({ request, cookies }) => {]] + page_content[#page_content + 1] = [[ const { something } = await request.json();]] + page_content[#page_content + 1] = [[]] + page_content[#page_content + 1] = [[ return json({ something }, { status: 200, headers });]] + page_content[#page_content + 1] = [[};]] + vim.fn.mkdir('src/routes/api/' .. pagename, 'p') + vim.fn.writefile(page_content, page_path) + vim.cmd('e ' .. page_path) +end + +function SvelteKitNewAPIGet(pagename) + local page_path = 'src/routes/api/' .. pagename .. '/+server.ts' + local page_content = {} + page_content[#page_content + 1] = [[import { json } from "@sveltejs/kit";]] + page_content[#page_content + 1] = [[import type { RequestHandler } from "./$types";]] + page_content[#page_content + 1] = [[]] + page_content[#page_content + 1] = [[const headers = {]] + page_content[#page_content + 1] = [[ "Access-Control-Allow-Origin": "*",]] + page_content[#page_content + 1] = [[ "Access-Control-Allow-Methods": "GET,HEAD,PUT,PATCH,POST,DELETE",]] + page_content[#page_content + 1] = [[ "Access-Control-Allow-Headers": "Content-Type,authorization",]] + page_content[#page_content + 1] = [[};]] + page_content[#page_content + 1] = [[]] + page_content[#page_content + 1] = [[export const OPTIONS: RequestHandler = () => {]] + page_content[#page_content + 1] = [[ return new Response("", {]] + page_content[#page_content + 1] = [[ status: 200,]] + page_content[#page_content + 1] = [[ headers,]] + page_content[#page_content + 1] = [[ });]] + page_content[#page_content + 1] = [[};]] + page_content[#page_content + 1] = [[]] + page_content[#page_content + 1] = [[export const GET: RequestHandler = ({ url, params }) => {]] + page_content[#page_content + 1] = [[ const q = url.searchParams.get("q");]] + page_content[#page_content + 1] = [[ // const slug = params.slug;]] + page_content[#page_content + 1] = [[ const number = Math.floor(Math.random() * 6) + 1;]] + page_content[#page_content + 1] = [[]] + page_content[#page_content + 1] = [[ return json({ number }, {status:200, headers});]] + page_content[#page_content + 1] = [[};]] + vim.fn.mkdir('src/routes/api/' .. pagename, 'p') + vim.fn.writefile(page_content, page_path) + vim.cmd('e ' .. page_path) +end + +-- NPM +function Npm_install() + local package_lock_exists = vim.fn.filereadable 'package-lock.json' == 1 + local yarn_lock_exists = vim.fn.filereadable 'yarn.lock' == 1 + local pnpm_lock_exists = vim.fn.filereadable 'pnpm-lock.yaml' == 1 + if package_lock_exists then + RunCommandInNewTab 'npm install --legacy-peer-deps' + elseif yarn_lock_exists then + RunCommandInNewTab 'yarn' + elseif pnpm_lock_exists then + RunCommandInNewTab 'pnpm install' + else + RunCommandInNewTab 'npm install --legacy-peer-deps' + end +end + +function GetFileType() + local filename = vim.fn.expand '%:t' + local extension = vim.fn.fnamemodify(filename, ':e') + + if extension == 'js' or extension == 'jsx' then + return 'javascript' + elseif extension == 'ts' or extension == 'tsx' then + return 'typescript' + elseif extension == 'cpp' or extension == 'c' then + return 'cpp' + elseif extension == 'sh' then + return 'shell' + else + return 'unknown' + end +end + +function fileExists(fileName) + local file = io.open(fileName, 'r') + if file then + file:close() + return true + else + return false + end +end + +function BuildAndNotify() + vim.notify('Building Project...', vim.log.levels.INFO, { + title = 'NPM', + timeout = 36000000, + }) + + vim.fn.jobstart('npm run build', { + on_stdout = function(id, data, e) + notif(id, data, e, 4000) + end, + on_stderr = function(id, data, e) + notif(id, data, e, 4000) + end, + on_exit = function(id, data, e) + notif(id, data, e, 4000) + end, + }) +end + +function RunCommandInNewTab(command) + vim.cmd(':-1tabnew | te ' .. command) +end + +function RunCommandAndNotify(command, timeout, title) + if timeout == nil then + timeout = 5000 -- 5 seconds instead of 10 hours! + end + if title == nil then + title = 'Run Command' + end + vim.notify(title, vim.log.levels.INFO, { + title = title, + timeout = timeout, + }) + + vim.fn.jobstart(command, { + on_stdout = function(id, data, e) + notif(id, data, e, 4000) + end, + on_stderr = function(id, data, e) + notif(id, data, e, 4000) + end, + on_exit = function(id, data, e) + notif(id, data, e, 4000) + end, + }) +end + +function CloseHiddenBuffers() + local all_buffers = vim.api.nvim_list_bufs() + local visible_buffers = {} + local closed_count = 0 + + -- Get all visible buffers from all tabs and windows + for _, tabpage in ipairs(vim.api.nvim_list_tabpages()) do + for _, win in ipairs(vim.api.nvim_tabpage_list_wins(tabpage)) do + local buf = vim.api.nvim_win_get_buf(win) + visible_buffers[buf] = true + end + end + + -- Close buffers that are not visible in any window + for _, buf in ipairs(all_buffers) do + if not visible_buffers[buf] and vim.api.nvim_buf_is_loaded(buf) then + local buf_name = vim.api.nvim_buf_get_name(buf) + if buf_name ~= '' and not vim.api.nvim_buf_get_option(buf, 'modified') then + vim.api.nvim_buf_delete(buf, { force = false }) + closed_count = closed_count + 1 + end + end + end + + vim.notify('Closed ' .. closed_count .. ' hidden buffers', vim.log.levels.INFO, { + title = 'Buffer Cleanup', + timeout = 2000, + }) +end + +return {} diff --git a/lua/custom/plugins/01-opts.lua b/lua/custom/plugins/01-opts.lua new file mode 100644 index 00000000000..1ab4fca3890 --- /dev/null +++ b/lua/custom/plugins/01-opts.lua @@ -0,0 +1,176 @@ +-- noswap +vim.o.swapfile = false +vim.o.guifont = 'JetBrainsMono NFM:h14:sb' +vim.o.list = false + +-- disable spell for pandoc +vim.api.nvim_set_var('pandoc#spell#enabled', 0) + +-- markdown multi table format +vim.g.table_mode_corner_corner = '+' +vim.g.table_mode_header_fillchar = '=' + +-- markdown bullet and numbering indent +vim.o.breakindentopt = 'list:-1' + +-- lsp border +vim.o.winborder = 'rounded' + +sysname = vim.loop.os_uname().sysname +isWindows = sysname == 'Windows_NT' +isMac = sysname == 'Darwin' +isLinux = sysname == 'Linux' + +-- neovide auto focus +if vim.g.neovide then + vim.defer_fn(function() vim.cmd 'NeovideFocus' end, 200) + + if isWindows then + -- new neovide window in Windows + vim.keymap.set('n', '', ':silent !neovide', { + desc = 'Python', + noremap = true, + silent = true, + }) + vim.keymap.set('i', '', ':silent !neovide', { + desc = 'Python', + noremap = true, + silent = true, + }) + else + -- new neovide window in MACOS + vim.keymap.set('n', '', ':silent !neovide', { + desc = 'Python', + noremap = true, + silent = true, + }) + vim.keymap.set('i', '', ':silent !neovide', { + desc = 'Python', + noremap = true, + silent = true, + }) + end +else + -- new nvim-qt window in Android + vim.keymap.set('n', '', ':silent !nvim-qt', { + desc = 'Python', + noremap = true, + silent = true, + }) +end + +-- auto cd to current directory +vim.api.nvim_create_autocmd("VimEnter", { + callback = function() + if vim.fn.isdirectory(vim.fn.expand("%:p")) == 0 then + vim.cmd("cd %:p:h") + end + end, +}) + +if isWindows then vim.g.python3_host_prog = 'C:\\Users\\yokow\\miniforge3\\envs\\labs\\python.exe' end + +-- independent clipboard +vim.opt.clipboard = '' + +-- set autoindent expandtab tabstop=2 shiftwidth=2 +vim.o.autoindent = true +vim.o.expandtab = true +vim.o.tabstop = 2 +vim.o.shiftwidth = 2 +vim.o.smartindent = true + +vim.o.foldlevel = 20 + +vim.opt.confirm = true +vim.g.have_nerd_font = true + +-- Enable line numbers (both absolute and relative) +vim.wo.relativenumber = true + +-- "Keep it Centered +-- Create nnoremap mappings +vim.api.nvim_set_keymap('n', 'n', 'nzzzv', { + noremap = true, + silent = true, +}) +vim.api.nvim_set_keymap('n', 'N', 'Nzzzv', { + noremap = true, + silent = true, +}) +vim.o.hlsearch = true + +vim.api.nvim_set_keymap('n', 'cpr', ':CphReceive', { + noremap = true, + silent = false, + desc = '[C]ompetitive [P]rogramming [R]eceive', +}) + +vim.api.nvim_set_keymap('n', 'cpt', ':CphTest', { + noremap = true, + silent = false, + desc = '[C]ompetitive [P]rogramming [T]est', +}) + +-- save Cursor +vim.cmd [[ + autocmd BufReadPost * + \ if @% !~# '\.git[\/\\]COMMIT_EDITMSG$' && + \ line("'\"") > 1 && + \ line("'\"") <= line("$") | + \ exe "normal! g`\"" | + \ endif +]] + +vim.o.encoding = 'utf-8' + +vim.g.markdown_fenced_languages = { 'html', 'python', 'lua', 'vim', 'typescript', 'javascript' } + +-- session options +vim.opt.sessionoptions = { + 'buffers', -- save all loaded buffers + 'curdir', -- save current directory + 'tabpages', -- save tab pages + 'winsize', -- save window sizes + 'terminal', -- save terminal state +} + + +-- Folding +vim.o.foldmethod = 'indent' + +-- Save folds between sessions +local viewdir = vim.fn.stdpath 'state' .. '/view' +vim.o.viewdir = viewdir +vim.o.viewoptions = 'cursor,folds' +vim.fn.mkdir(viewdir, 'p') + +-- Close certain windows with x +vim.api.nvim_create_autocmd('FileType', { + pattern = { 'checkhealth', 'fugitive*', 'git', 'help', 'lspinfo', 'netrw', 'notify', 'qf', 'query' }, + callback = function() + vim.keymap.set('n', 'x', vim.cmd.close, { + desc = 'Close the current buffer', + buffer = true, + }) + end, +}) + +-- Remember folds between sessions +vim.api.nvim_create_augroup('remember_folds', { clear = true }) +vim.api.nvim_create_autocmd('BufWinLeave', { + group = 'remember_folds', + pattern = '*', + callback = function() + vim.cmd 'silent! mkview' + end, +}) +vim.api.nvim_create_autocmd('BufWinEnter', { + group = 'remember_folds', + pattern = '*', + callback = function() + pcall(vim.cmd, 'silent! loadview') + end, +}) + +return {} diff --git a/lua/custom/plugins/50-git.lua b/lua/custom/plugins/50-git.lua new file mode 100644 index 00000000000..514ce14beef --- /dev/null +++ b/lua/custom/plugins/50-git.lua @@ -0,0 +1,213 @@ +-- NEOGIT +require('neogit').setup { + integrations = { + telescope = true, + diffview = true, + }, + sections = { + untracked = { folded = false }, + unstaged = { folded = false }, + staged = { folded = false }, + }, +} + +-- "Git Mapping +function GitPullAndNotify() + vim.notify('Pull Processing...', vim.log.levels.INFO, { + title = 'Git', + timeout = 5000, -- 5 seconds instead of 10 hours + }) + + vim.fn.jobstart('git fetch --all && git pull --rebase', { + on_stdout = function(id, data, e) + notif(id, data, e, 4000) + end, + on_stderr = function(id, data, e) + notif(id, data, e, 4000) + end, + on_exit = function(id, data, e) + notif(id, data, e, 4000) + end, + }) +end + +function GitPushAndNotify() + vim.notify('Push Processing...', vim.log.levels.INFO, { + title = 'Git', + timeout = 5000, -- 5 seconds instead of 10 hours + }) + + vim.fn.jobstart('git pull --rebase && git push', { + on_stdout = function(id, data, e) + notif(id, data, e, 4000) + end, + on_stderr = function(id, data, e) + notif(id, data, e, 4000) + end, + on_exit = function(id, data, e) + notif(id, data, e, 4000) + end, + }) +end + +function OpenGitStatus() + -- Check if neogit is already open + local neogit_open = false + for _, buf in ipairs(vim.api.nvim_list_bufs()) do + local name = vim.api.nvim_buf_get_name(buf) + if name:match 'NeogitStatus' then + neogit_open = true + vim.api.nvim_buf_delete(buf, { force = true }) + break + end + end + + if not neogit_open then + vim.cmd [[Neotree close]] + vim.cmd [[Neogit]] + end +end + +function CreateBranchAndPush(branchName) + RunCommandAndNotify('git checkout -b ' .. branchName .. ' && git push -u origin ' .. branchName) +end + +vim.keymap.set('n', '', OpenGitStatus, { + desc = '[G]it [S]tatus', +}) + +function GitCommit(commitMessage) + RunCommandAndNotify('git add . && git commit -m "' .. commitMessage .. '"') +end + +function RevertToCommitUnderCursor() + local commit = vim.fn.expand '' + + if commit == nil or commit == '' then + print 'No word under cursor.' + return + end + + local answer = vim.fn.input("Reset to commit '" .. commit .. "' and force push? (yes/no): ") + + if answer ~= 'yes' then + print 'Cancelled.' + return + end + + local cmd = string.format('git reset --hard %s && git push --force', commit) + RunCommandInNewTab(cmd) +end + +function UndoCommit() + local n = vim.fn.input 'Enter number of commits to undo: ' + RunCommandAndNotify('git reset --soft HEAD~' .. n) +end + +vim.keymap.set('n', 'gx', UndoCommit, { desc = 'Discard changes in last commit (Undo Commit)' }) +vim.keymap.set('n', 'gr', RevertToCommitUnderCursor, { desc = 'Reset HEAD to commit under cursor + force push' }) + +vim.keymap.set('n', 'ga', function() + local branchName = vim.fn.input 'Enter commit message: ' + if branchName == '' then + return + end + + CreateBranchAndPush(branchName) +end, { + desc = '[G]it [A]dd Branch', + noremap = true, + silent = false, +}) + +vim.keymap.set('n', 'gc', function() + local commitMessage = vim.fn.input 'Enter commit message: ' + if commitMessage == '' then + return + end + + GitCommit(commitMessage) +end, { + desc = '[G]it [C]ommit', + noremap = true, + silent = false, +}) + +vim.keymap.set('n', 'gh', ':Telescope git_bcommits', { + desc = '[G]it File [H]istory', + noremap = true, + silent = true, +}) + +vim.keymap.set('n', 'gp', GitPushAndNotify, { + desc = '[G]it [P]ush', + noremap = true, + silent = true, +}) + +vim.keymap.set('n', 'gu', GitPullAndNotify, { + desc = '[G]it P[u]ll', + noremap = true, + silent = true, +}) + +vim.keymap.set('n', 'gd', 'Neogit diff', { + desc = '[G]it [D]iff', + noremap = true, + silent = true, +}) + +vim.keymap.set('n', 'gb', 'Neogit branch', { + desc = '[G]it [B]ranch', + noremap = true, + silent = true, +}) + +vim.keymap.set('n', 'gv', 'DiffviewOpen', { + desc = '[G]it [V]iew Diff (current file)', + noremap = true, + silent = true, +}) + +vim.keymap.set('n', 'gl', ':Telescope git_commits', { + desc = '[G]it [L]og', + noremap = true, + silent = true, +}) + +vim.api.nvim_create_user_command('GitInitPush', function() + local username = 'yokowasis' + local repo = vim.fn.fnamemodify(vim.loop.cwd(), ':t') + if repo == '' then + print 'Could not determine repository name from current directory' + return + end + local remote = 'https://github.com/' .. username .. '/' .. repo .. '.git' + local cmd = 'git init && git add . && git commit -m "Initial commit" && git branch -M main && gh repo create ' + .. repo + .. ' --private --source=. --remote=origin --push' + vim.cmd('terminal ' .. cmd) +end, {}) + +vim.keymap.set('n', 'gi', ':GitInitPush', { + desc = '[G]it [I]nit and Push', + noremap = true, + silent = true, +}) + +vim.keymap.set('n', 'coo', function() + -- Get current line and extract branch name, then checkout with neogit + local line = vim.api.nvim_get_current_line() + local branch = line:match 'origin/(.+)' + if branch then + vim.cmd('Neogit branch checkout ' .. branch) + else + vim.notify('No origin branch found on current line', vim.log.levels.WARN) + end +end, { + desc = 'Checkout Origin Branch', + noremap = true, + silent = true, +}) + +return {} diff --git a/lua/custom/plugins/51-navigation.lua b/lua/custom/plugins/51-navigation.lua new file mode 100644 index 00000000000..74dac7eaaca --- /dev/null +++ b/lua/custom/plugins/51-navigation.lua @@ -0,0 +1,77 @@ +-- Smart buffer delete function (for ) +local function smart_buffer_delete() + local buffers = vim.fn.getbufinfo { buflisted = 1 } + local listed_buffers = {} + + -- Count only listed buffers (exclude help, quickfix, etc.) + for _, buf in ipairs(buffers) do + if buf.listed == 1 then + table.insert(listed_buffers, buf) + end + end + + -- If this is the last buffer, quit Neovim + if #listed_buffers <= 1 then + vim.cmd 'quit' + else + vim.cmd 'bdelete' + end +end + +-- "Tab Navigation +vim.keymap.set('n', '', ':tabnew', { + desc = 'New Tab', + noremap = true, + silent = true, +}) +vim.keymap.set('n', 'tn', ':-1tabnew', { + desc = 'New Tab To The Left', + noremap = true, + silent = true, +}) +vim.keymap.set('n', '', ':tabnext', { + desc = 'Next Tab', + noremap = true, + silent = true, +}) +vim.keymap.set('n', '', ':tabprevious', { + desc = 'Previous Tab', + noremap = true, + silent = true, +}) +vim.keymap.set('n', '', ':tabclose', { + desc = 'Close Tab', + noremap = true, + silent = true, +}) + +-- Window splitting +vim.keymap.set('n', 'sv', ':vsplit', { + desc = '[S]plit [V]ertical', + noremap = true, + silent = true, +}) +vim.keymap.set('n', 'sh', ':split', { + desc = '[S]plit [H]orizontal', + noremap = true, + silent = true, +}) +vim.keymap.set('n', 'sq', 'q', { + desc = '[S]plit [Q]uit Window', + noremap = true, + silent = true, +}) + +-- nerdtree +vim.keymap.set('n', '', ':Neotree toggle', { + desc = 'Toggle File Explorer', + noremap = true, + silent = true, +}) +vim.keymap.set('i', '', ':Neotree toggle', { + desc = 'Toggle File Explorer', + noremap = true, + silent = true, +}) + +return {} diff --git a/lua/custom/plugins/52-terminal.lua b/lua/custom/plugins/52-terminal.lua new file mode 100644 index 00000000000..a5d28637a89 --- /dev/null +++ b/lua/custom/plugins/52-terminal.lua @@ -0,0 +1,56 @@ +TerminalShell = '' + +if isWindows then + vim.cmd [[command! SaveInitVim :tabnew | exe ':te git -C '. stdpath("config") .' add . & git -C ' . stdpath("config") . ' commit -m save & git -C ' . stdpath("config") . ' push']] + vim.cmd [[command! SaveGlobalSnippets :tabnew | exe ':te git -C '. stdpath("config") .'/../../../git/friendly-snippets add . & git -C '. stdpath("config") .'/../../../git/friendly-snippets commit -m save & git -C '. stdpath("config") .'/../../../git/friendly-snippets push']] + vim.cmd [[command! LoadGlobalSnippets :tabnew | exe ':te git -C '. stdpath("config") .'/../../../git/friendly-snippets pull']] + + TerminalShell = 'pwsh' +else + vim.cmd [[command! SaveInitVim :tabnew | exe ':te git -C '. stdpath("config") .' add . && git -C ' . stdpath("config") . ' commit -m save && git -C ' . stdpath("config") . ' push']] + vim.cmd [[command! SaveGlobalSnippets :tabnew | exe ':te git -C ~/git/friendly-snippets add . && git -C ~/git/friendly-snippets commit -m save && git -C ~/git/friendly-snippets push']] + vim.cmd [[command! LoadGlobalSnippets :tabnew | exe ':te git -C ~/git/friendly-snippets pull']] + + TerminalShell = 'bash' +end + +vim.cmd [[command! LoadInitVim :tabnew | exe ':te git -C '. stdpath("config") .' pull' ]] +vim.cmd [[command! EditInitVim :tabnew | exe 'edit '. stdpath('config').'/lua/custom/plugins/00-init.lua']] +vim.cmd [[command! EditSnippets :lua require("luasnip.loaders").edit_snippet_files()]] + +-- open terminal +vim.keymap.set('n', '``', ':horizontal terminal ' .. TerminalShell .. 'J-----', { + desc = 'Open Terminal', + noremap = false, + silent = true, +}) + +-- vertical terminal +vim.keymap.set('n', '`v', 'v:terminal ' .. TerminalShell .. '', { + desc = 'Open Terminal [V]ertical', + noremap = false, + silent = true, +}) + +-- close terminal +vim.keymap.set('t', '`', ':q', { + desc = '', + noremap = true, + silent = true, +}) + +-- switch window +vim.keymap.set('t', '', '', { + desc = '', + noremap = true, + silent = true, +}) + +-- esc to normal mode in terminal +vim.keymap.set('t', '', '', { + desc = '', + noremap = true, + silent = true, +}) + +return {} diff --git a/lua/custom/plugins/53-window.lua b/lua/custom/plugins/53-window.lua new file mode 100644 index 00000000000..7126e687ec0 --- /dev/null +++ b/lua/custom/plugins/53-window.lua @@ -0,0 +1,23 @@ +-- "RESIZE WINDOW +vim.keymap.set('n', '.', ':vertical resize -10', { + desc = '', + noremap = true, + silent = true, +}) +vim.keymap.set('n', ',', ':vertical resize +5', { + desc = '', + noremap = true, + silent = true, +}) +vim.keymap.set('n', "'", ':horizontal resize -5', { + desc = '', + noremap = true, + silent = true, +}) +vim.keymap.set('n', ';', ':horizontal resize +2', { + desc = '', + noremap = true, + silent = true, +}) + +return {} diff --git a/lua/custom/plugins/55-startup.lua b/lua/custom/plugins/55-startup.lua new file mode 100644 index 00000000000..17894e949e9 --- /dev/null +++ b/lua/custom/plugins/55-startup.lua @@ -0,0 +1,13 @@ +if vim.fn.argc() == 0 then + vim.defer_fn(function() + local session_name = vim.fn.fnamemodify(vim.fn.getcwd(), ':t') .. '.vim' + local session_path = vim.fn.expand('~/' .. session_name) + if vim.fn.filereadable(session_path) == 1 then + vim.cmd('silent! source ' .. vim.fn.fnameescape(session_path)) + vim.notify('Session loaded: ' .. session_name, vim.log.levels.INFO) + vim.cmd 'silent! GuessIndent' + end + end, 300) -- Delay the session load by 100ms +end + +return {} diff --git a/lua/custom/plugins/98-bookmarks.lua b/lua/custom/plugins/98-bookmarks.lua new file mode 100644 index 00000000000..a564707544f --- /dev/null +++ b/lua/custom/plugins/98-bookmarks.lua @@ -0,0 +1 @@ +return {} diff --git a/lua/custom/plugins/99-keymaps.lua b/lua/custom/plugins/99-keymaps.lua new file mode 100644 index 00000000000..2e0f922db5b --- /dev/null +++ b/lua/custom/plugins/99-keymaps.lua @@ -0,0 +1,477 @@ +-- Create a mapping for compiling and running code +vim.keymap.set('n', 'cr', CompileAndRun, { + noremap = true, + silent = false, + desc = '[C]ompile and [R]un', +}) + +-- emmet +vim.api.nvim_set_keymap('i', '', '(emmet-expand-abbr)', { + noremap = true, + silent = true, +}) + +-- "Copy Paste from OS Clipboard +vim.keymap.set('v', '', '"+p:silent! %s/\\r//g', { + desc = '[P]aste from system clipboard', + noremap = true, + silent = true, +}) +vim.keymap.set('n', '', '"+p:silent! %s/\\r//g', { + desc = '[P]aste from system clipboard', + noremap = true, + silent = true, +}) +vim.keymap.set('i', '', '"+p:silent! %s/\\r//ga', { + desc = '[P]aste from system clipboard', + noremap = true, + silent = true, +}) + +vim.keymap.set('n', '', '"+p:silent! %s/\\r//g', { + desc = '[P]aste from system clipboard', + noremap = true, + silent = true, +}) +vim.keymap.set('i', '', '*:silent! %s/\\r//g', { + desc = '[P]aste from system clipboard', + noremap = true, + silent = true, +}) + +vim.keymap.set('x', '', '"+y', { + desc = '[Y]ank to system clipboard', + noremap = true, + silent = true, +}) +vim.keymap.set('x', '', '"+y', { + desc = '[Y]ank to system clipboard', + noremap = true, + silent = true, +}) + +-- Map Ctrl+S to save +vim.keymap.set('n', '', ':w', { + desc = '[^s] Save Current File', + noremap = true, + silent = true, +}) +vim.keymap.set('i', '', ':wa', { + desc = '[^s] Save Current File', + noremap = true, + silent = true, +}) + +-- "Toggle Wrap +vim.keymap.set('n', 'ww', ':set wrap!', { + desc = '[W]ord [W]rap', + noremap = true, + silent = true, +}) + +-- +-- "keep visual mode after indent +vim.keymap.set('v', '>', '>gv', { + desc = '', + noremap = true, + silent = true, +}) + +vim.keymap.set('v', '<', '', '"_d', { + desc = 'Black Hole Delete', + noremap = true, + silent = true, +}) +vim.keymap.set('x', '', '"_d', { + desc = 'Black Hole Delete', + noremap = true, + silent = true, +}) + +-- telescope keymap +vim.keymap.set('n', '?', ':Telescope keymaps', { + desc = 'Show Keymaps', + noremap = true, + silent = true, +}) + +-- macos arrow navigation +vim.api.nvim_set_keymap('', '', '', { + noremap = true, +}) +vim.api.nvim_set_keymap('', '', '', { + noremap = true, +}) + +vim.api.nvim_set_keymap('i', '', 'b', { + noremap = true, + silent = false, +}) +vim.api.nvim_set_keymap('i', '', 'w', { + noremap = true, + silent = false, +}) +vim.api.nvim_set_keymap('x', '', 'b', { + noremap = true, + silent = false, +}) +vim.api.nvim_set_keymap('x', '', 'w', { + noremap = true, + silent = false, +}) +vim.api.nvim_set_keymap('n', '', 'b', { + noremap = true, + silent = false, +}) +vim.api.nvim_set_keymap('n', '', 'w', { + noremap = true, + silent = false, +}) + +-- macos, neovide, alacritty terminal +vim.api.nvim_set_keymap('i', '', '"*pa', { + noremap = true, + silent = false, +}) +vim.api.nvim_set_keymap('n', '', '"*p', { + noremap = true, + silent = false, +}) + +vim.api.nvim_set_keymap('n', '', '', { + noremap = true, + silent = false, +}) +vim.api.nvim_set_keymap('n', '', '', { + noremap = true, + silent = false, +}) +vim.api.nvim_set_keymap('i', '', '', { + noremap = true, + silent = false, +}) +vim.api.nvim_set_keymap('i', '', '', { + noremap = true, + silent = false, +}) +vim.api.nvim_set_keymap('x', '', '', { + noremap = true, + silent = false, +}) +vim.api.nvim_set_keymap('x', '', '', { + noremap = true, + silent = false, +}) +vim.api.nvim_set_keymap('n', '', 'gg', { + noremap = true, + silent = false, +}) +vim.api.nvim_set_keymap('n', '', 'G', { + noremap = true, + silent = false, +}) +vim.api.nvim_set_keymap('i', '', 'gg', { + noremap = true, + silent = false, +}) +vim.api.nvim_set_keymap('i', '', 'G', { + noremap = true, + silent = false, +}) +vim.api.nvim_set_keymap('x', '', 'gg', { + noremap = true, + silent = false, +}) +vim.api.nvim_set_keymap('x', '', 'G', { + noremap = true, + silent = false, +}) + +vim.keymap.set('n', '', ':w', { + desc = '[^s] Save Current File', + noremap = true, + silent = true, +}) +vim.keymap.set('i', '', ':wa', { + desc = '[^s] Save Current File', + noremap = true, + silent = true, +}) + +-- npm / yarn operation +vim.keymap.set('n', 'rb', function() RunCommandAndNotify 'npm run build' end, { + noremap = true, + silent = false, + desc = '[R]un [B]uild', +}) +vim.keymap.set('n', 'rd', function() RunCommandInNewTab 'npm run dev' end, { + noremap = true, + silent = false, + desc = '[R]un [D]ev', +}) +vim.keymap.set('n', 'ri', Npm_install, { + noremap = true, + silent = false, + desc = '[R]un npm [I]nstall', +}) +vim.keymap.set('n', 'rl', function() RunCommandInNewTab 'five-server' end, { + noremap = true, + silent = false, + desc = '[R]un npm [L]ive Server', +}) + +-- clear highlight after search by pressing return +vim.api.nvim_set_keymap('n', 'cl', ':noh:%s/\r//g', { + noremap = true, + silent = true, + desc = '[C][l]ear Search and NewLine Character', +}) + +-- cd to current directory +vim.api.nvim_set_keymap('n', 'cd', ':cd %:p:h:pwd', { + noremap = true, + silent = false, + desc = '[C]hange [D]irectory to current file', +}) + +-- Session +vim.api.nvim_set_keymap('n', 'sel', ":execute 'source ' . fnameescape(expand('~/' . fnamemodify(getcwd(), ':t') . '.vim'))", { + noremap = true, + silent = false, + desc = '[Se]ssion [L]oad', +}) + +vim.api.nvim_set_keymap('n', 'nq', ":execute 'mksession! ' . fnameescape(expand('~/' . fnamemodify(getcwd(), ':t') . '.vim')):qa!", { + noremap = true, + silent = false, + desc = '[N]vim [Q]uit', +}) + +-- vim signature help +vim.keymap.set('n', 'k', vim.lsp.buf.signature_help, { + noremap = true, + silent = true, +}) + +vim.keymap.set('n', 'sne', ':EditSnippets', { + noremap = true, + silent = false, + desc = '[Sn]ippets [E]dit', +}) + +-- "Snippet Format" +vim.keymap.set('n', 'snf', function() + local lines = vim.api.nvim_buf_get_lines(0, 0, -1, false) + + for i, line in ipairs(lines) do + line = line:gsub('\\', '\\\\') -- escape backslashes + line = line:gsub('"', '\\"') -- escape quotes + line = line:gsub("%$", "\\\\$") + line = line:gsub("\\\\\\\\", "\\\\\\\\\\\\") + + lines[i] = '"' .. line .. '",' + end + + vim.api.nvim_buf_set_lines(0, 0, -1, false, lines) +end, { + desc = '[Sn]ippet [F]ormat', +}) + +-- Noice Notification +vim.keymap.set('n', 'snn', ':NoiceAll', { + noremap = true, + silent = false, + desc = '[S]how [N]oice [N]otification', +}) + +-- auto format +vim.keymap.set('n', 'fmf', 'gg=G', { + noremap = true, + silent = false, + desc = '[F]ormat [M]anual [F]ormat', +}) + +-- Search and Replace +vim.keymap.set('n', 'sar', ':%s///g', { + noremap = true, + silent = false, + desc = '[S]earch [A]nd [R]eplace', +}) + +-- Search and Replace +vim.keymap.set('v', 'sar', '"zy:%s/z//g', { + noremap = true, + silent = false, + desc = '[S]earch [A]nd [R]eplace', +}) + +-- Search and Replace with Number of rows +vim.keymap.set('v', 'san', function() + -- Get the selected text + vim.cmd 'normal! "zy' + local selected = vim.fn.getreg 'z' + + -- Ask for number of rows + local rows = vim.fn.input 'Number of rows to affect: ' + if rows == '' then + print 'Operation cancelled' + return + end + + -- Get current line number + local current_line = vim.fn.line '.' + local end_line = current_line + tonumber(rows) - 1 + + -- Generate the command but don't execute it + local cmd = ':' .. current_line .. ',' .. end_line .. 's/' .. vim.fn.escape(selected, '/') .. '//g' + vim.fn.feedkeys(cmd .. vim.api.nvim_replace_termcodes('', true, false, true)) +end, { + noremap = true, + silent = false, + desc = '[S]earch [A]nd Replace with [N]umber of rows starting from current line', +}) + +-- Search and Visual Replace +vim.keymap.set('v', 'svr', ':s/"//g', { + noremap = true, + silent = false, + desc = '[S]earch And [V]isual [R]eplace', +}) + +-- Search and Visual Replace +vim.keymap.set('v', 'sk', ':s/\\(.*\\)/\\1/g', { + noremap = true, + silent = false, + desc = '[S]earch [K]irby', +}) + +vim.keymap.set('n', 'fnp', function() NextJSNewPage(vim.fn.input 'Enter Page Name: ') end, { + noremap = true, + silent = false, + desc = 'New [P]age', +}) +vim.keymap.set('n', 'fnr', function() NextJSNewApiPost(vim.fn.input 'Enter Route Name: ') end, { + noremap = true, + silent = false, + desc = 'New API [R]oute POST', +}) +vim.keymap.set('n', 'fng', function() NextJSNewApiGet(vim.fn.input 'Enter Route Name: ') end, { + noremap = true, + silent = false, + desc = 'New [G]et Route', +}) +vim.keymap.set('n', 'fsp', function() SvelteKitNewPage(vim.fn.input 'Enter Page Name: ') end, { + noremap = true, + silent = false, + desc = 'New [P]age', +}) +vim.keymap.set('n', 'fsr', function() SvelteKitNewAPIPost(vim.fn.input 'Enter Route Name: ') end, { + noremap = true, + silent = false, + desc = 'New Post [R]oute', +}) +vim.keymap.set('n', 'fsg', function() SvelteKitNewAPIGet(vim.fn.input 'Enter Route Name: ') end, { + noremap = true, + silent = false, + desc = 'New [G]et Route', +}) + +vim.keymap.set( + 'n', + '', + function() SearchAndReplace(vim.fn.input 'Enter Search Term: ', vim.fn.input 'Enter Replace Term: ') end, + -- ":%s/vim.fn.input('Enter Search Term: ')/vim.fn.input('Enter Replace Term: ')/g", + { + noremap = true, + silent = false, + desc = '[S]earch and [R]eplace', + } +) + +vim.keymap.set('n', 'sg', ':Telescope live_grep', { + desc = '[S]earch by [G]rep', + noremap = true, + silent = false, +}) + +vim.keymap.set('n', 'sc', customSearchGrep, { + desc = '[S]earch by [G]rep [C]ustom', + noremap = true, + silent = false, +}) + +-- close other windows except this one +vim.keymap.set('n', 'x', ':on', { + desc = 'Close all other windows', + noremap = true, + silent = true, +}) + +vim.keymap.set('n', 'rr', ':e!', { + noremap = true, + silent = false, + desc = '[R]eload [R]esource', +}) + +vim.keymap.set('n', 'rp', ':LspRestart', { + noremap = true, + silent = false, + desc = '[R]eload LS[P]', +}) + +-- code companion +vim.keymap.set('n', 'ct', ':CodeCompanionChat', { + noremap = true, + silent = false, + desc = '[C]odeCompanion [T]alk', +}) +vim.keymap.set('n', 'cc', ':CodeCompanion #{buffer} ', { + noremap = true, + silent = false, + desc = '[C]ode [C]ompanion', +}) +vim.keymap.set('v', 'cc', ':CodeCompanion ', { + noremap = true, + silent = false, + desc = '[C]ode [C]ompanion', +}) + +vim.keymap.set('n', 'fc', function() + vim.fn.setreg('+', vim.fn.expand '%:p') + print('Copied filename to clipboard: ' .. vim.fn.expand '%:p') +end, { + noremap = true, + silent = true, + desc = '[F]ile [C]opy current file path to clipboard', +}) + +vim.keymap.set('n', 'fe', function() os.execute 'explorer.exe .' end, { + noremap = true, + silent = true, + desc = '[F]ile [E]xplorer on current file folder', +}) + +vim.keymap.set('n', 'gd', require('telescope.builtin').lsp_definitions, { noremap = true, silent = true }) + +-- Close all hidden/background buffers +vim.keymap.set('n', 'bo', CloseHiddenBuffers, { + noremap = true, + silent = false, + desc = '[B]uffer [O]nly - Close all hidden buffers', +}) + +-- "Database Toggle UI" +vim.keymap.set('n', 'db', ':DBUIToggle', { + desc = '[D]ata[b]ase', + noremap = true, + silent = true, +}) + +return {} diff --git a/lua/kickstart/plugins/debug.lua b/lua/kickstart/plugins/debug.lua index db5448c2cfc..f48cbab18bd 100644 --- a/lua/kickstart/plugins/debug.lua +++ b/lua/kickstart/plugins/debug.lua @@ -18,10 +18,13 @@ vim.pack.add { -- Basic debugging keymaps, feel free to change to your liking! vim.keymap.set('n', '', function() require('dap').continue() end, { desc = 'Debug: Start/Continue' }) vim.keymap.set('n', '', function() require('dap').step_into() end, { desc = 'Debug: Step Into' }) -vim.keymap.set('n', '', function() require('dap').step_over() end, { desc = 'Debug: Step Over' }) +vim.keymap.set('n', '', function() require('dap').step_over() end, { desc = 'Debug: Step Over' }) vim.keymap.set('n', '', function() require('dap').step_out() end, { desc = 'Debug: Step Out' }) -vim.keymap.set('n', 'b', function() require('dap').toggle_breakpoint() end, { desc = 'Debug: Toggle Breakpoint' }) -vim.keymap.set('n', 'B', function() require('dap').set_breakpoint(vim.fn.input 'Breakpoint condition: ') end, { desc = 'Debug: Set Breakpoint' }) +vim.keymap.set('n', 'ba', function() require('dap').toggle_breakpoint() end, { desc = 'Debug: Toggle Breakpoint' }) +vim.keymap.set('n', 'Ba', function() require('dap').set_breakpoint(vim.fn.input 'Breakpoint condition: ') end, { desc = 'Debug: Set Breakpoint' }) +vim.keymap.set('n', 'bt', function() require('dapui').toggle() end, { desc = 'Debug: Toggle UI' }) +vim.keymap.set('n', '', function() require('dap').terminate() end, { desc = 'Debug: Stop Debugging' }) + -- Toggle to see last session result. Without this, you can't see session output in case of unhandled exception. vim.keymap.set('n', '', function() require('dapui').toggle() end, { desc = 'Debug: See last session result.' }) @@ -40,8 +43,8 @@ require('mason-nvim-dap').setup { -- You'll need to check that you have the required things installed -- online, please don't ask me how to install them :) ensure_installed = { - -- Update this to ensure that you have the debuggers for the langs you want 'delve', + 'js-debug-adapter', }, } @@ -93,3 +96,83 @@ require('dap-go').setup { detached = vim.fn.has 'win32' == 0, }, } + +-- ========================================== +-- JavaScript / TypeScript / Next.js Setup +-- ========================================== + +-- 1. Define the adapters using the js-debug-adapter installed by Mason +-- We use the direct path to dapDebugServer.js to avoid PATH/binary linking issues. +local js_debug_adapter_path = vim.fs.joinpath( + vim.fn.stdpath('data'), + 'mason', + 'packages', + 'js-debug-adapter', + 'js-debug', + 'src', + 'dapDebugServer.js' +) + +local node_terminal = { + type = 'server', + host = 'localhost', + port = '${port}', + executable = { + command = 'node', + args = { + js_debug_adapter_path, + '${port}', + }, + }, +} + +local chrome = { + type = 'server', + host = 'localhost', + port = '${port}', + executable = { + command = 'node', + args = { + js_debug_adapter_path, + '${port}', + }, + }, +} + +require('dap').adapters['pwa-node'] = node_terminal +require('dap').adapters['node_terminal'] = node_terminal + +require('dap').adapters['pwa-chrome'] = chrome +require('dap').adapters['chrome'] = chrome + +-- 2. Define configurations for TS/JS +local js_based_languages = { 'typescript', 'javascript', 'typescriptreact' } + +for _, language in ipairs(js_based_languages) do + require('dap').configurations[language] = { + -- Server-side Next.js debugging + { + type = 'pwa-node', + request = 'launch', + name = 'Nvim: Debug JS Server', + runtimeExecutable = 'npm', + runtimeArgs = { 'run', 'dev' }, + cwd = '${workspaceFolder}', + -- 'integratedTerminal' launches a Neovim terminal split and runs the command there + console = 'integratedTerminal', + -- sourceMaps = true, -- Uncomment if breakpoints in `.next` aren't mapping correctly + }, + -- Client-side Next.js debugging + { + type = 'pwa-chrome', + request = 'launch', + name = 'Nvim: Debug JS Client', + url = 'http://localhost:3000', + webRoot = '${workspaceFolder}', + -- By default, pwa-chrome uses a clean, isolated Chrome profile. + -- Uncomment the line below if you want it to use your default Chrome profile (so you can use your extensions). + -- userDataDir = false, + -- sourceMaps = true, + }, + } +end diff --git a/lua/kickstart/plugins/neo-tree.lua b/lua/kickstart/plugins/neo-tree.lua index 549629ae020..223d2dde8ec 100644 --- a/lua/kickstart/plugins/neo-tree.lua +++ b/lua/kickstart/plugins/neo-tree.lua @@ -11,6 +11,10 @@ vim.keymap.set('n', '\\', 'Neotree reveal', { desc = 'NeoTree reveal', require('neo-tree').setup { filesystem = { + follow_current_file = { + enabled = true, -- This finds and focuses the file in the active buffer every time a new file is opened + leave_dirs_open = false, -- Closes folders when you leave them (set to true if you prefer keeping them open) + }, window = { mappings = { ['\\'] = 'close_window', diff --git a/test.js b/test.js new file mode 100644 index 00000000000..c4c2cdf2398 --- /dev/null +++ b/test.js @@ -0,0 +1,5 @@ +console.log("Hello World"); + +for (i = 0; i <= 10; i++) { + console.log(i); +} diff --git a/test.ts b/test.ts new file mode 100644 index 00000000000..434b5120f43 --- /dev/null +++ b/test.ts @@ -0,0 +1,4 @@ +let a = "100" + +a = 10; +