aboutsummaryrefslogtreecommitdiff
path: root/.nvim.lua
blob: ba8f78b60f06994988c6b8f63ef9d3e98af05353 (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
local workspace_folder = vim.fn.getcwd()

local function safe_require(module)
  local ok, mod = pcall(require, module)
  if not ok then return nil end
  return mod
end

-- C++
local default_clangd_config = vim.deepcopy(vim.lsp.config["clangd"]) or {}
default_clangd_config.cmd = {
  "clangd",
  "--background-index",
  "--clang-tidy",
  "--header-insertion=iwyu",
  "--completion-style=detailed",
  string.format("--compile-commands-dir=%s/build", workspace_folder),
  "--query-driver=**/x86_64-pc-elf-g++"
}

vim.lsp.config("clangd", default_clangd_config)

vim.filetype.add({
  pattern = {
    [".*/kstd/include/kstd/.*"] = "cpp",
  }
})

-- Debugging
local dap = require("dap")
local qemu_job_id = nil
local qemu_bufnr = nil

local function resolve_build_paths(artifact_path)
  local base_path = string.gsub(artifact_path, "%.[%w]+$", "")
  local build_type = artifact_path:match("bin/([^/]+)/") or "Debug"
  return {
    iso = base_path .. ".iso",
    elf = base_path .. ".elf",
    sym = base_path .. ".sym",
    build_type = build_type,
  }
end

local function launch_qemu(artifact_path, is_debug)
  if qemu_job_id then
    vim.fn.jobstop(qemu_job_id)
    qemu_job_id = nil
  end

  local paths = resolve_build_paths(artifact_path)
  local debug_flag = is_debug and "1" or "0"
  local shell_cmd = string.format("%s/scripts/qemu-wrapper.sh '%s' '%s' '%s' '%s'",
    workspace_folder, workspace_folder, paths.build_type, paths.iso, debug_flag)

  vim.cmd("botright vsplit | enew")
  qemu_bufnr = vim.api.nvim_get_current_buf()
  vim.api.nvim_buf_set_name(qemu_bufnr, "TeachOS QEMU (" .. paths.build_type .. ")")
  vim.opt_local.number = false
  vim.opt_local.relativenumber = false
  vim.opt_local.signcolumn = "no"

  qemu_job_id = vim.fn.termopen(shell_cmd, {
    on_exit = function() qemu_job_id = nil end
  })

  vim.cmd("wincmd p")
end

dap.adapters.teachos_qemu_mi = function(callback, config)
  local artifact_path = config.program
  if not artifact_path then
    vim.notify("Fatal: No artifact path resolved by CMake", vim.log.levels.ERROR)
    return
  end

  launch_qemu(artifact_path, true)

  local paths = resolve_build_paths(artifact_path)
  config.setupCommands = {
    { description = "Enable pretty-printing for gdb", text = "-enable-pretty-printing" },
    { description = "Load code", text = string.format("-file-exec-file %s", paths.elf) },
    { description = "Load symbols", text = string.format("-file-exec-and-symbols %s", paths.sym) },
  }
  config.program = paths.sym

  vim.defer_fn(function()
    callback({
      type = "executable",
      command = vim.fn.stdpath("data") .. "/mason/bin/OpenDebugAD7",
      id = "cppdbg",
    })
  end, 500)
end

local function teardown_qemu()
  if qemu_job_id then
    vim.fn.jobstop(qemu_job_id)
    qemu_job_id = nil
  end

  if qemu_bufnr and vim.api.nvim_buf_is_valid(qemu_bufnr) then
    vim.api.nvim_buf_delete(qemu_bufnr, { force = true })
    qemu_bufnr = nil
  end
end

dap.listeners.after.event_terminated["teachos_qemu_teardown"] = teardown_qemu
dap.listeners.after.event_exited["teachos_qemu_teardown"] = teardown_qemu
dap.listeners.after.disconnect["teachos_qemu_teardown"] = teardown_qemu

require("cmake-tools").setup({
  cmake_dap_configuration = {
    name = "(gdb) QEMU MI Attach",
    type = "teachos_qemu_mi",
    request = "launch",
    MIMode = "gdb",
    cwd = workspace_folder,
    miDebuggerServerAddress = "localhost:1234",
    miDebuggerPath = "x86_64-pc-elf-gdb",
    stopAtEntry = true,
  }
})

vim.api.nvim_create_user_command("TeachOSRun", function()
  local cmake = safe_require("cmake-tools")
  if not cmake then return end
  
  local is_ready, target = pcall(cmake.get_launch_target_path)
  if is_ready and target then
    launch_qemu(target, false)
  else
    vim.notify("Fatal: Cannot determine CMake target path.", vim.log.levels.ERROR)
  end
end, {})

vim.keymap.set('n', '<S-F5>', '<cmd>TeachOSRun<CR>', { noremap = true, desc = "Run TeachOS QEMU (No Debug)" })