syntax highlighting
This commit is contained in:
34
after/syntax/gitea.vim
Normal file
34
after/syntax/gitea.vim
Normal file
@@ -0,0 +1,34 @@
|
||||
" quit when a syntax file was already loaded
|
||||
if exists("b:current_syntax")
|
||||
finish
|
||||
endif
|
||||
|
||||
if !exists('main_syntax')
|
||||
let main_syntax = 'gitea'
|
||||
endif
|
||||
|
||||
runtime! syntax/markdown.vim ftplugin/markdown.vim ftplugin/markdown_*.vim ftplugin/markdown/*.vim
|
||||
unlet! b:current_syntax
|
||||
|
||||
" Emoji conceal, similar to octo.nvim but for 'gitea'
|
||||
call matchadd('Conceal', ':heart:', 10, -1, {'conceal':'❤️'})
|
||||
call matchadd('Conceal', ':+1:', 10, -1, {'conceal':'👍'})
|
||||
call matchadd('Conceal', ':see_no_evil:', 10, -1, {'conceal':'🙈'})
|
||||
call matchadd('Conceal', ':laughing:', 10, -1, {'conceal':'😆'})
|
||||
call matchadd('Conceal', ':thinking_face:', 10, -1, {'conceal':'🤔'})
|
||||
call matchadd('Conceal', ':thinking:', 10, -1, {'conceal':'🤔'})
|
||||
call matchadd('Conceal', ':ok_hand:', 10, -1, {'conceal':'👌'})
|
||||
call matchadd('Conceal', ':upside_down_face:', 10, -1, {'conceal':'🙃'})
|
||||
call matchadd('Conceal', ':grimacing:', 10, -1, {'conceal':'😬'})
|
||||
call matchadd('Conceal', ':rocket:', 10, -1, {'conceal':'🚀'})
|
||||
call matchadd('Conceal', ':blush:', 10, -1, {'conceal':'😊'})
|
||||
call matchadd('Conceal', ':tada:', 10, -1, {'conceal':'🎉'})
|
||||
call matchadd('Conceal', ':shrug:', 10, -1, {'conceal':'🤷'})
|
||||
call matchadd('Conceal', ':man_shrugging:', 10, -1, {'conceal':'🤷'})
|
||||
call matchadd('Conceal', ':face_palm:', 10, -1, {'conceal':'🤦'})
|
||||
call matchadd('Conceal', ':man_facepalmin:', 10, -1, {'conceal':'🤦'})
|
||||
|
||||
let b:current_syntax = "gitea"
|
||||
if main_syntax ==# 'gitea'
|
||||
unlet main_syntax
|
||||
endif
|
||||
@@ -3,8 +3,11 @@ local M = {}
|
||||
local config = require("gitea.config")
|
||||
local api = require("gitea.api")
|
||||
local auth = require("gitea.auth")
|
||||
local highlights = require("gitea.highlights") -- we still require highlights
|
||||
|
||||
-- We'll keep detect_owner_repo() from before
|
||||
------------------------------------------------------------------------------
|
||||
-- DETECT OWNER/REPO
|
||||
------------------------------------------------------------------------------
|
||||
local function detect_owner_repo()
|
||||
local cmd = "git config remote.origin.url"
|
||||
local url = vim.fn.systemlist(cmd)[1]
|
||||
@@ -29,39 +32,69 @@ local function detect_owner_repo()
|
||||
return nil, nil
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
--- Data Structures to track what's in the ephemeral buffer
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
-- We'll store some metadata for each "segment" in the buffer:
|
||||
-- - The issue's title line range
|
||||
-- - The issue's body line range
|
||||
-- - Each existing comment (with start/end line range)
|
||||
-- - Possibly space for a new comment
|
||||
--
|
||||
-- On save (:w), we compare what's changed and do the appropriate API calls.
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- BUFFER METADATA
|
||||
------------------------------------------------------------------------------
|
||||
local function create_issue_buffer_metadata(issue)
|
||||
-- track lines for the title, the body, each comment
|
||||
local meta = {
|
||||
return {
|
||||
issue_number = issue.number,
|
||||
-- will fill in fields once we place them in the buffer
|
||||
title_start = nil,
|
||||
title_end = nil,
|
||||
body_start = nil,
|
||||
body_end = nil,
|
||||
comments = {}, -- array of { id, start, end }
|
||||
new_comment_start = nil, -- where user can type a new comment
|
||||
comments = {}, -- each = { id, start_line, end_line }
|
||||
new_comment_start = nil,
|
||||
}
|
||||
return meta
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
--- RENDER ISSUE INTO BUFFER
|
||||
--------------------------------------------------------------------------------
|
||||
------------------------------------------------------------------------------
|
||||
-- APPLY HIGHLIGHTS
|
||||
------------------------------------------------------------------------------
|
||||
local function apply_issue_highlights(bufnr, meta)
|
||||
-- The first line in the file is line 0 in Lua’s API, so we subtract 1
|
||||
-- from meta.* to convert to 0-based indexing.
|
||||
|
||||
------------------------------------------------------------------------
|
||||
-- Lines #0 & #1 hold meta info (“# Gitea Issue #...”, “# STATE: ...”)
|
||||
------------------------------------------------------------------------
|
||||
vim.api.nvim_buf_add_highlight(bufnr, 0, "GiteaIssueMeta", 0, 0, -1)
|
||||
vim.api.nvim_buf_add_highlight(bufnr, 0, "GiteaIssueMeta", 1, 0, -1)
|
||||
|
||||
------------------------------------------------------------------------
|
||||
-- Title
|
||||
------------------------------------------------------------------------
|
||||
local title_line_0 = meta.title_start - 1
|
||||
vim.api.nvim_buf_add_highlight(bufnr, 0, "GiteaIssueTitle", title_line_0, 0, -1)
|
||||
|
||||
------------------------------------------------------------------------
|
||||
-- Body lines
|
||||
------------------------------------------------------------------------
|
||||
-- meta.body_start .. meta.body_end (inclusive, 1-based)
|
||||
for line = meta.body_start, meta.body_end do
|
||||
local line_0 = line - 1
|
||||
vim.api.nvim_buf_add_highlight(bufnr, 0, "GiteaCommentBody", line_0, 0, -1)
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------
|
||||
-- Comment headings & bodies
|
||||
------------------------------------------------------------------------
|
||||
for _, c in ipairs(meta.comments) do
|
||||
-- The heading line has “COMMENT #123 by user”
|
||||
local heading_line_0 = c.start_line - 1
|
||||
vim.api.nvim_buf_add_highlight(bufnr, 0, "GiteaCommentHeading", heading_line_0, 0, -1)
|
||||
|
||||
-- The actual comment text is lines [heading_line_0+1 .. c.end_line-1]
|
||||
for text_line = (c.start_line + 1), c.end_line do
|
||||
local text_line_0 = text_line - 1
|
||||
vim.api.nvim_buf_add_highlight(bufnr, 0, "GiteaCommentBody", text_line_0, 0, -1)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- RENDER ISSUE INTO BUFFER
|
||||
------------------------------------------------------------------------------
|
||||
local function render_issue_into_buf(bufnr, issue, comments)
|
||||
-- We assume the buffer is empty and ephemeral.
|
||||
local lines = {}
|
||||
table.insert(lines, string.format("# Gitea Issue #%d: %s", issue.number, issue.title))
|
||||
table.insert(lines, "# STATE: " .. (issue.state or "unknown"))
|
||||
@@ -69,17 +102,12 @@ local function render_issue_into_buf(bufnr, issue, comments)
|
||||
table.insert(lines, "# On save (:w), changes to the title/body will be updated; changes to comment lines will be updated, and new text at the bottom becomes a new comment.")
|
||||
table.insert(lines, "")
|
||||
|
||||
-- store line index references for metadata
|
||||
local meta = create_issue_buffer_metadata(issue)
|
||||
|
||||
-- place the "title line"
|
||||
meta.title_start = #lines + 1
|
||||
table.insert(lines, issue.title or "")
|
||||
meta.title_end = #lines
|
||||
|
||||
-- a blank line
|
||||
table.insert(lines, "")
|
||||
-- place the "body lines"
|
||||
meta.body_start = #lines + 1
|
||||
if issue.body then
|
||||
local body_lines = vim.split(issue.body, "\n", true)
|
||||
@@ -95,19 +123,16 @@ local function render_issue_into_buf(bufnr, issue, comments)
|
||||
end
|
||||
meta.body_end = #lines
|
||||
|
||||
-- spacing
|
||||
table.insert(lines, "")
|
||||
table.insert(lines, "# --- Comments ---")
|
||||
|
||||
local line_count = #lines
|
||||
local comment_meta = {}
|
||||
for _, c in ipairs(comments) do
|
||||
table.insert(lines, "")
|
||||
local start_line = #lines + 1
|
||||
-- We'll place a small header: e.g. "Comment (ID=12345) by username"
|
||||
local author = c.user and c.user.login or c.user and c.user.username or c.user or "?"
|
||||
local author = c.user and (c.user.login or c.user.username) or "?"
|
||||
table.insert(lines, string.format("COMMENT #%d by %s", c.id, author))
|
||||
-- Then the actual comment body lines
|
||||
|
||||
local c_body_lines = vim.split(c.body or "", "\n", true)
|
||||
if #c_body_lines == 0 then
|
||||
table.insert(lines, "")
|
||||
@@ -124,85 +149,57 @@ local function render_issue_into_buf(bufnr, issue, comments)
|
||||
})
|
||||
end
|
||||
|
||||
-- place a blank line for user to add a new comment
|
||||
table.insert(lines, "")
|
||||
table.insert(lines, "# --- Add a new comment below this line. If you leave it blank, no new comment is created. ---")
|
||||
local new_comment_start = #lines+1
|
||||
table.insert(lines, "") -- an empty line to start from
|
||||
meta.new_comment_start = #lines + 1
|
||||
table.insert(lines, "")
|
||||
|
||||
-- Save comment meta
|
||||
meta.comments = comment_meta
|
||||
|
||||
-- Put all lines into the buffer
|
||||
vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, lines)
|
||||
|
||||
-- store metadata
|
||||
local b_meta = {
|
||||
issue_number = issue.number,
|
||||
title_start = meta.title_start,
|
||||
title_end = meta.title_end,
|
||||
body_start = meta.body_start,
|
||||
body_end = meta.body_end,
|
||||
comments = comment_meta,
|
||||
new_comment_start = new_comment_start,
|
||||
}
|
||||
return b_meta
|
||||
-- Now apply highlight groups
|
||||
apply_issue_highlights(bufnr, meta)
|
||||
|
||||
return meta
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
--- Parse buffer changes and do API updates on save
|
||||
--------------------------------------------------------------------------------
|
||||
------------------------------------------------------------------------------
|
||||
-- ON SAVE (BufWriteCmd)
|
||||
------------------------------------------------------------------------------
|
||||
local function on_issue_buf_write(bufnr, metadata, owner, repo)
|
||||
-- read all buffer lines
|
||||
local new_lines = vim.api.nvim_buf_get_lines(bufnr, 0, -1, false)
|
||||
|
||||
----------------- Title update check -----------------
|
||||
local new_title = table.concat(vim.list_slice(new_lines, metadata.title_start, metadata.title_end), "\n")
|
||||
-- remove trailing newlines just in case
|
||||
new_title = new_title:gsub("%s+$", "")
|
||||
-- we do a get_issue call to see the current title
|
||||
|
||||
local current_issue_data = api.get_issue(owner, repo, metadata.issue_number)
|
||||
if not current_issue_data then
|
||||
vim.notify("[gitea.nvim] Could not re-fetch the issue to verify updates", vim.log.levels.ERROR)
|
||||
return
|
||||
end
|
||||
|
||||
local changed_title = false
|
||||
if (current_issue_data.title or "") ~= new_title then
|
||||
changed_title = true
|
||||
end
|
||||
|
||||
----------------- Body update check ------------------
|
||||
local changed_title = (current_issue_data.title or "") ~= new_title
|
||||
local new_body_lines = vim.list_slice(new_lines, metadata.body_start, metadata.body_end)
|
||||
local new_body = table.concat(new_body_lines, "\n")
|
||||
local changed_body = false
|
||||
if (current_issue_data.body or "") ~= new_body then
|
||||
changed_body = true
|
||||
end
|
||||
local changed_body = (current_issue_data.body or "") ~= new_body
|
||||
|
||||
----------------- Comments update check -------------
|
||||
local changed_comments = {}
|
||||
for _, cmeta in ipairs(metadata.comments) do
|
||||
local c_lines = vim.list_slice(new_lines, cmeta.start_line, cmeta.end_line)
|
||||
-- The first line is "COMMENT #<id> by <author>"
|
||||
-- The rest is the actual body
|
||||
-- e.g. `COMMENT #112 by alice`
|
||||
local first_line = c_lines[1] or ""
|
||||
-- first line => "COMMENT #<id> by <author>"
|
||||
local c_body = {}
|
||||
for i = 2, #c_lines do
|
||||
table.insert(c_body, c_lines[i])
|
||||
end
|
||||
local new_comment_body = table.concat(c_body, "\n")
|
||||
-- We fetch the current comment from the server to check if changed
|
||||
-- But Gitea's issue comment API does not necessarily let us get a single comment by ID easily.
|
||||
-- Instead, we do "issue_data, with comments" or store old body in memory.
|
||||
|
||||
-- For simplicity, let's store the old body in an extmark or in a table. But let's just do a naive approach:
|
||||
-- We'll assume if the line is changed, we want to patch it. We have no big reference of old body, so let's do it.
|
||||
|
||||
table.insert(changed_comments, {
|
||||
id = cmeta.id,
|
||||
new_body = new_comment_body
|
||||
})
|
||||
end
|
||||
|
||||
----------------- New comment check ------------------
|
||||
local new_comment_body_lines = {}
|
||||
for i = metadata.new_comment_start, #new_lines do
|
||||
table.insert(new_comment_body_lines, new_lines[i])
|
||||
@@ -210,7 +207,7 @@ local function on_issue_buf_write(bufnr, metadata, owner, repo)
|
||||
local new_comment_body = table.concat(new_comment_body_lines, "\n"):gsub("^%s+", ""):gsub("%s+$", "")
|
||||
local create_new_comment = (#new_comment_body > 0)
|
||||
|
||||
-------------- Perform the updates --------------
|
||||
-- Edit issue if title or body changed
|
||||
if changed_title or changed_body then
|
||||
local updated, st = api.edit_issue(owner, repo, metadata.issue_number, {
|
||||
title = changed_title and new_title or current_issue_data.title,
|
||||
@@ -223,9 +220,7 @@ local function on_issue_buf_write(bufnr, metadata, owner, repo)
|
||||
end
|
||||
end
|
||||
|
||||
-- for each changed comment, attempt to patch
|
||||
-- We do not do a diff, so we always do a "PATCH" if we suspect changes
|
||||
-- => If the user changed nothing, Gitea might respond 200 anyway, no big deal
|
||||
-- Edit each comment
|
||||
for _, cupd in ipairs(changed_comments) do
|
||||
local updated_comment, st = api.edit_issue_comment(owner, repo, metadata.issue_number, cupd.id, cupd.new_body)
|
||||
if not updated_comment then
|
||||
@@ -235,6 +230,7 @@ local function on_issue_buf_write(bufnr, metadata, owner, repo)
|
||||
end
|
||||
end
|
||||
|
||||
-- Possibly add a new comment
|
||||
if create_new_comment then
|
||||
local created, st = api.comment_issue(owner, repo, metadata.issue_number, new_comment_body)
|
||||
if created then
|
||||
@@ -245,9 +241,9 @@ local function on_issue_buf_write(bufnr, metadata, owner, repo)
|
||||
end
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
--- Open a single ephemeral buffer for the entire Issue with comments
|
||||
--------------------------------------------------------------------------------
|
||||
------------------------------------------------------------------------------
|
||||
-- OPEN ISSUE BUFFER
|
||||
------------------------------------------------------------------------------
|
||||
local function open_full_issue_buffer(owner, repo, number)
|
||||
local issue_data, status = api.get_issue(owner, repo, number)
|
||||
if not issue_data then
|
||||
@@ -255,9 +251,6 @@ local function open_full_issue_buffer(owner, repo, number)
|
||||
return
|
||||
end
|
||||
|
||||
-- get all existing comments from the Gitea API
|
||||
-- for Gitea, we can do: GET /repos/{owner}/{repo}/issues/{index}/comments
|
||||
-- The plugin's `api` might have a function for that, or we can add it quickly
|
||||
local all_comments, cstatus = api.get_issue_comments(owner, repo, number)
|
||||
if not all_comments then
|
||||
vim.notify(string.format("[gitea.nvim] Error retrieving issue #%d comments (HTTP %s).", number, cstatus or "?"), vim.log.levels.ERROR)
|
||||
@@ -266,12 +259,18 @@ local function open_full_issue_buffer(owner, repo, number)
|
||||
|
||||
local buf = vim.api.nvim_create_buf(false, true)
|
||||
vim.api.nvim_buf_set_option(buf, "buftype", "acwrite")
|
||||
vim.api.nvim_buf_set_option(buf, "filetype", "markdown")
|
||||
|
||||
-- Use our new "gitea" filetype, so after/syntax/gitea.vim will load
|
||||
vim.api.nvim_buf_set_option(buf, "filetype", "gitea")
|
||||
|
||||
vim.api.nvim_buf_set_name(buf, string.format("gitea_issue_full_%d", number))
|
||||
|
||||
-- Load highlight definitions (e.g. GiteaIssueTitle, GiteaCommentBody, etc.)
|
||||
highlights.setup()
|
||||
|
||||
local metadata = render_issue_into_buf(buf, issue_data, all_comments)
|
||||
|
||||
-- We create an autocmd on BufWriteCmd to parse changes and do updates
|
||||
-- Auto command to handle saving
|
||||
vim.api.nvim_create_autocmd("BufWriteCmd", {
|
||||
buffer = buf,
|
||||
callback = function()
|
||||
@@ -282,9 +281,9 @@ local function open_full_issue_buffer(owner, repo, number)
|
||||
vim.api.nvim_set_current_buf(buf)
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
--- SUBCOMMANDS
|
||||
--------------------------------------------------------------------------------
|
||||
------------------------------------------------------------------------------
|
||||
-- SUBCOMMANDS
|
||||
------------------------------------------------------------------------------
|
||||
local subcommands = {}
|
||||
|
||||
subcommands.issue = {
|
||||
@@ -294,8 +293,7 @@ subcommands.issue = {
|
||||
vim.notify("[gitea.nvim] Could not detect owner/repo.", vim.log.levels.ERROR)
|
||||
return
|
||||
end
|
||||
-- use the same telescope approach as before:
|
||||
local has_telescope, tele = pcall(require, "telescope")
|
||||
local has_telescope, _ = pcall(require, "telescope")
|
||||
if not has_telescope then
|
||||
vim.notify("[gitea.nvim] telescope.nvim is not installed", vim.log.levels.ERROR)
|
||||
return
|
||||
@@ -333,7 +331,6 @@ subcommands.issue = {
|
||||
if not selection or not selection.value then
|
||||
return
|
||||
end
|
||||
-- Instead of just editing, we now open the full timeline buffer
|
||||
open_full_issue_buffer(owner, repo, selection.value.number)
|
||||
end
|
||||
map("i", "<CR>", select_issue)
|
||||
@@ -344,7 +341,6 @@ subcommands.issue = {
|
||||
end,
|
||||
|
||||
show = function(args)
|
||||
-- Alternative: show a single issue by number
|
||||
local number = tonumber(args[1])
|
||||
if not number then
|
||||
vim.notify("[gitea.nvim] Usage: :Gitea issue show <number>", vim.log.levels.ERROR)
|
||||
@@ -357,19 +353,15 @@ subcommands.issue = {
|
||||
end
|
||||
open_full_issue_buffer(owner, repo, number)
|
||||
end,
|
||||
|
||||
-- The rest of your commands can remain or be removed as needed
|
||||
-- but presumably we can just use "show" for everything
|
||||
-- or keep an existing minimal create command, etc.
|
||||
}
|
||||
|
||||
subcommands.pr = {
|
||||
-- We'll leave your existing PR commands as is or remove for brevity
|
||||
-- your other PR-related commands, if any
|
||||
}
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
--- REGISTER
|
||||
--------------------------------------------------------------------------------
|
||||
------------------------------------------------------------------------------
|
||||
-- REGISTER COMMAND
|
||||
------------------------------------------------------------------------------
|
||||
function M.register()
|
||||
vim.api.nvim_create_user_command("Gitea", function(cmd_opts)
|
||||
auth.ensure_token()
|
||||
|
||||
58
lua/gitea/highlights.lua
Normal file
58
lua/gitea/highlights.lua
Normal file
@@ -0,0 +1,58 @@
|
||||
local M = {}
|
||||
|
||||
-- A small Dracula-like palette, adapt or extend if needed
|
||||
local palette = {
|
||||
bg = "#282A36",
|
||||
fg = "#F8F8F2",
|
||||
selection = "#44475A",
|
||||
comment = "#6272A4",
|
||||
cyan = "#8BE9FD",
|
||||
green = "#50FA7B",
|
||||
orange = "#FFB86C",
|
||||
pink = "#FF79C6",
|
||||
purple = "#BD93F9",
|
||||
red = "#FF5555",
|
||||
yellow = "#F1FA8C",
|
||||
}
|
||||
|
||||
function M.setup()
|
||||
-- Title of an issue or PR
|
||||
vim.api.nvim_set_hl(0, "GiteaIssueTitle", {
|
||||
fg = palette.pink,
|
||||
bold = true,
|
||||
})
|
||||
|
||||
-- Meta lines, e.g. status lines or extra info
|
||||
vim.api.nvim_set_hl(0, "GiteaIssueMeta", {
|
||||
fg = palette.comment,
|
||||
italic = true,
|
||||
})
|
||||
|
||||
-- Heading for each comment block
|
||||
vim.api.nvim_set_hl(0, "GiteaCommentHeading", {
|
||||
fg = palette.orange,
|
||||
bold = true,
|
||||
})
|
||||
|
||||
-- The actual comment body text
|
||||
vim.api.nvim_set_hl(0, "GiteaCommentBody", {
|
||||
fg = palette.fg,
|
||||
bg = nil, -- or palette.bg if you want a background
|
||||
})
|
||||
|
||||
-- Something for a user mention
|
||||
vim.api.nvim_set_hl(0, "GiteaUser", {
|
||||
fg = palette.cyan,
|
||||
bold = true,
|
||||
})
|
||||
|
||||
-- If you'd like comment lines in a faint color
|
||||
vim.api.nvim_set_hl(0, "GiteaInlineComment", {
|
||||
fg = palette.comment,
|
||||
italic = true,
|
||||
})
|
||||
|
||||
-- ...Add or tweak any other highlight groups you need...
|
||||
end
|
||||
|
||||
return M
|
||||
Reference in New Issue
Block a user