all repos

gopher.nvim @ 27ba078f14dd39fcd5e8a57d7009cdd77450ebbb

Minimalistic plugin for Go development

gopher.nvim/lua/gopher/json2go.lua(view raw)

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
---@toc_entry json2go
---@tag gopher.nvim-json2go
---@text
--- Convert json to go type annotations.
---
---@usage
--- `:GoJson` opens a temporary buffer where you can paste or write JSON.
--- Saving the buffer (`:w` or `:wq`) automatically closes it and inserts the
--- generated Go struct into the original buffer at the cursor position.
---
--- Alternatively, you can pass JSON directly as an argument:
--- >vim
---    :GoJson {"name": "Alice", "age": 30}
--- <

local c = require "gopher.config"
local log = require "gopher._utils.log"
local u = require "gopher._utils"
local r = require "gopher._utils.runner"
local json2go = {}

---@dochide
---@param bufnr integer
---@param cpos integer
---@param type_ string
local function apply(bufnr, cpos, type_)
  local lines = vim.api.nvim_buf_get_lines(bufnr, 0, -1, false)
  local input_lines = u.remove_empty_lines(vim.split(type_, "\n"))
  for i, line in pairs(input_lines) do
    table.insert(lines, cpos + i, line)
  end
  vim.api.nvim_buf_set_lines(bufnr, 0, -1, true, lines)
end

-- Convert json string to go type.
---
---@param json_str string Json string that is going to be converted to go type.
---@return string? Go type, or nil if failed.
function json2go.transform(json_str)
  local cmd = { c.commands.json2go }
  if c.json2go.type_name then
    table.insert(cmd, "-type", c.json2go.type_name)
  end

  local rs = r.sync(cmd, { stdin = json_str })
  if rs.code ~= 0 then
    u.notify("json2go: got this error: " .. rs.stdout, vim.log.levels.ERROR)
    log.error("json2go: got this error: " .. rs.stdout)
    return
  end
  return rs.stdout
end

---@dochide
---@param ocpos integer
local function interactive(ocpos)
  local obuf = vim.api.nvim_get_current_buf()
  local owin = vim.api.nvim_get_current_win()

  -- setup the input window
  local buf = vim.api.nvim_create_buf(false, true)
  vim.cmd(c.json2go.interactive_cmd)

  local win = vim.api.nvim_get_current_win()
  vim.api.nvim_win_set_buf(win, buf)
  vim.api.nvim_buf_set_name(buf, "[GoJson input]")
  vim.api.nvim_set_option_value("filetype", "jsonc", { buf = buf })
  vim.api.nvim_set_option_value("buftype", "acwrite", { buf = buf })
  vim.api.nvim_set_option_value("swapfile", false, { buf = buf })
  vim.api.nvim_set_option_value("bufhidden", "delete", { buf = buf })
  vim.api.nvim_buf_set_lines(buf, 0, -1, false, {
    "// Write your json here.",
    "// Writing and quitting (:wq), will generate go struct under the cursor.",
    "",
    "",
  })

  vim.api.nvim_create_autocmd("BufLeave", { buffer = buf, command = "stopinsert" })
  vim.api.nvim_create_autocmd("BufWriteCmd", {
    buffer = buf,
    once = true,
    callback = function()
      local input = vim.api.nvim_buf_get_lines(buf, 0, -1, true)
      local inp = table.concat(
        vim
          .iter(input)
          :filter(function(line)
            local found = string.find(line, "^//.*")
            return (not found) or (line == "")
          end)
          :totable(),
        "\n"
      )

      local go_type = json2go.transform(inp)
      if not go_type then
        error "cound't convert json to go type"
      end

      vim.api.nvim_set_option_value("modified", false, { buf = buf })
      apply(obuf, ocpos, go_type)

      vim.api.nvim_set_current_win(owin)
      vim.api.nvim_win_set_cursor(owin, { ocpos + 1, 0 })

      vim.schedule(function()
        pcall(vim.api.nvim_win_close, win, true)
        pcall(vim.api.nvim_buf_delete, buf, {})
      end)
    end,
  })

  vim.cmd "normal! G"
  vim.cmd "startinsert"
end

--- Converts json string to go type, and puts result under the cursor. If
--- [json_str] is nil, will open an interactive prompt (with cmd set in
--- config).
---
---@param json_str? string
function json2go.json2go(json_str)
  local cur_line = vim.api.nvim_win_get_cursor(0)[1]
  if not json_str then
    interactive(cur_line)
    return
  end

  local go_type = json2go.transform(json_str)
  if not go_type then
    error "cound't convert json to go type"
  end

  apply(0, cur_line, go_type)
end

return json2go