summaryrefslogtreecommitdiff
path: root/dot_config/nvim/lua/ibrahim/keymaps.lua
blob: feb84daa23f54103c5a67b7d93fc4dbbaae5b19c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
-- Set leader key as Space
vim.g.mapleader = " "

local function map(mode, left, right, opts)
    local default_opts = {
        noremap = true,
        silent = true,
    }
    opts = opts or {}
    -- "keep" mode preserves the values from the leftmost table,
    -- so prioritize any options provided over the defaults
    local full_opts = vim.tbl_extend("keep", opts, default_opts)
    vim.keymap.set(mode, left, right, full_opts)
end

-- Clear any highlighted searches when pressing Esc
-- This lets me leave hlsearch on by default while having an easy way to clear
-- it again.
map({ "i", "n" }, "<esc>", "<cmd>noh<cr><esc>", { desc = "Escape and clear hlsearch" })

-- Move lines while in visual mode with J and K
map("v", "J", ":m '>+1<CR>gv=gv")
map("v", "K", ":m '<-2<CR>gv=gv")

-- Easier execution of Lua code
map("n", "<leader>x", "<cmd>.lua<CR>", { desc = "Execute the current line" })
map("n", "<leader><leader>x", "<cmd>source %<CR>", { desc = "Execute the current file" })

-- Keep cursor in the same place when using J to join lines
map("n", "J", "mzJ`z")

-- Center the screen when jumping around with C-d and C-u
map("n", "<C-d>", "<C-d>zz")
map("n", "<C-u>", "<C-u>zz")

-- Center the screen when jumping to next / previous search terms
map("n", "n", "nzzzv")
map("n", "N", "Nzzzv")

-- Quick maps to paste/delete without overwriting the current buffer
map("x", "<leader>p", '"_dP')
map({ "n", "v" }, "<leader>d", '"_dP')

-- Easier quickfix naviagion
map("n", "<C-k>", "<cmd>cprev<cr>", { desc = "Quickfix previous item" })
map("n", "<C-j>", "<cmd>cnext<cr>", { desc = "Quickfix next item" })

-- System clipboard
map({ "n", "v" }, "<leader>cd", '"+d', { desc = "Clipboard delete" })
map({ "n", "v" }, "<leader>cp", '"+p', { desc = "Clipboard paste" })
map({ "n", "v" }, "<leader>cy", '"+y', { desc = "Clipboard yank" })

-- Map g- to netrw (temporary placeholder for oil)
-- map("n", "g-", vim.cmd.Ex, { desc = "Open netrw" })

map("n", "<leader>gx", function()
    local command = "go run " .. vim.fn.expand("%")
    local f = assert(io.popen(command, "r"))
    local s = assert(f:read("*a"))
    f:close()
    s = string.gsub(s, "^%s+", "")
    s = string.gsub(s, "%s+$", "")
    s = string.gsub(s, "[\n\r]+", " ")
    print(s)
end, { desc = "Execute current go file" })


-- Create a GitHub URL for the current file and line number, and copy it
-- to the clipboard.
map("n", "<leader>yfg", function()
    local remote_url = vim.fn.system("git config --get remote.origin.url")
    if not remote_url:find("github.com") then
        vim.notify("This is not a GitHub repository")
        return
    end

    local trimmed_remote_url = remote_url:gsub("%.git", ""):gsub("%s+", ""):gsub("\n", "")
    local branch_name = vim.fn.system("git rev-parse --abbrev-ref HEAD"):gsub("\n", "")

    -- Now construct the link in this format:
    -- <remote>/blob/<branch>/<file>#L<line>

    local filepath = vim.fn.expand("%:."):gsub("\\", "/")

    local line = vim.fn.line(".")
    local result = trimmed_remote_url .. "/blob/" .. branch_name .. "/" .. filepath .. "#L" .. line

    vim.fn.setreg("+", result)
    vim.notify("Copied GitHub URL to clipboard: " .. result)
end, { desc = "Yank GitHub URL to clipboard", expr = true })


-- LSP specific keybindings
vim.api.nvim_create_autocmd("LspAttach", {
    group = vim.api.nvim_create_augroup("IbrahimLspConfig", {}),
    callback = function(evt)
        local function lsp_map(mode, lhs, rhs, desc)
            local opts = { buffer = evt.buf, desc = "LSP: " .. (desc or "") }
            map(mode, lhs, rhs, opts)
        end

        local has_telescope, _ = pcall(require, "telescope")
        local function lsp_telescope_map(mode, lhs, with_telescope_rhs, no_telescope_rhs, desc)
            if has_telescope then
                desc = desc .. " (Telescope)"
                lsp_map(mode, lhs, with_telescope_rhs, desc)
            else
                lsp_map(mode, lhs, no_telescope_rhs, desc)
            end
        end
        local function tele_builtin(name, opts)
            return function()
                require("telescope.builtin")[name](opts)
            end
        end

        -- Navigation
        lsp_map("n", "gd", vim.lsp.buf.definition, "[G]oto [D]efinition")
        lsp_map("n", "gt", vim.lsp.buf.type_definition, "[G]oto [t]ype Definition")
        lsp_map("n", "gD", vim.lsp.buf.declaration, "[G]oto [D]eclaration")
        lsp_map("n", "gr", vim.lsp.buf.references, "[G]oto [R]eferences")
        lsp_map("n", "gI", vim.lsp.buf.implementation, "[G]oto [I]mplementation")

        lsp_telescope_map("n", "gr", tele_builtin("lsp_references"), vim.lsp.buf.references, "Go to references")
        lsp_telescope_map(
            "n",
            "<leader>sn",
            tele_builtin("lsp_document_symbols"),
            vim.lsp.buf.document_symbol,
            "Search document symbols"
        )
        lsp_telescope_map(
            "n",
            "<leader>sN",
            tele_builtin("lsp_dynamic_workspace_symbols"),
            vim.lsp.buf.workspace_symbol,
            "Search workspace symbols"
        )

        -- Code changes
        lsp_map("n", "<leader>cr", vim.lsp.buf.rename, "Rename")
        -- <leader>ca is being overwritten by the 'actions-preview' plugin
        -- lsp_map("n", "<leader>ca", vim.lsp.buf.code_action, "Code actions")

        -- Diagnostics
        lsp_map("n", "<leader>ds", vim.diagnostic.open_float, "[s]how [d]iagnostic window")
        lsp_map("n", "<leader>dn", function()
            vim.diagnostic.jump({ count = 1, float = true })
        end, "Go to [n]ext [d]iagnostic")
        lsp_map("n", "<leader>dp", function()
            vim.diagnostic.jump({ count = -1, float = true })
        end, "Go to [p]revious [d]iagnostic")

        -- See `:help K` for why this keymap
        lsp_map("n", "K", function ()
            vim.lsp.buf.hover { border = "single", max_height = 25, max_width = 120 }
        end, "Hover Documentation")
        lsp_map("n", "<C-S-k>", vim.lsp.buf.signature_help, "Signature Documentation")

        -- Workspace
        lsp_map("n", "<leader>wa", vim.lsp.buf.add_workspace_folder, "[W]orkspace [A]dd Folder")
        lsp_map("n", "<leader>wr", vim.lsp.buf.remove_workspace_folder, "[W]orkspace [R]emove Folder")
        lsp_map("n", "<leader>wl", function()
            print(vim.inspect(vim.lsp.buf.list_workspace_folders()))
        end, "[W]orkspace [L]ist Folders")
    end,
})