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
|
vim.opt.exrc = false
vim.g.autoformat = true
vim.g.load_doxygen_syntax = true
vim.opt.fixeol = false
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 = {
[".*/include/kstd/.*"] = function(path, _)
if not path:match("%.[^/]+$") then
return "cpp"
end
end
}
})
-- 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_compile_commands_options = {
action = "copy",
target = string.format("%s/build", workspace_folder),
},
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)" })
|