mirror of
https://github.com/zoriya/jj.nvim.git
synced 2026-08-15 23:53:18 +00:00
feat(editor): Add the possibility to configure a window for the editor like in the terminal allowing for "hsplit"/"vsplit"/"tab"/"floating" (#114)
This commit is contained in:
@@ -435,6 +435,14 @@ revision via `jj diffedit`. Immutable revisions show an error on write.
|
|||||||
-- When true, automatically enter insert mode only if the description is empty.
|
-- When true, automatically enter insert mode only if the description is empty.
|
||||||
-- If a description already exists, stay in normal mode.
|
-- If a description already exists, stay in normal mode.
|
||||||
auto_insert = false,
|
auto_insert = false,
|
||||||
|
|
||||||
|
-- Configure the describe/commit editor buffer window
|
||||||
|
window = {
|
||||||
|
type = "hsplit", -- Type of window (hsplit/vsplit/floating/tab)
|
||||||
|
split_size = 0.5, -- Size % of split (height for hsplit, width for vsplit)
|
||||||
|
floating_width = 0.99, -- Width % for floating window (0.1 to 1.0)
|
||||||
|
floating_height = 0.95, -- Height % for floating window (0.1 to 1.0)
|
||||||
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
-- Customize syntax highlighting colors for the describe buffer
|
-- Customize syntax highlighting colors for the describe buffer
|
||||||
@@ -646,6 +654,29 @@ require("jj").setup({
|
|||||||
})
|
})
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### `editor.window`
|
||||||
|
|
||||||
|
Control where the describe/commit editor buffer opens:
|
||||||
|
|
||||||
|
- `type`: `"hsplit" | "vsplit" | "floating" | "tab"`
|
||||||
|
- `split_size`: split ratio for `hsplit`/`vsplit` (default `0.5`)
|
||||||
|
- `floating_width`: width ratio for floating windows (default `0.99`)
|
||||||
|
- `floating_height`: height ratio for floating windows (default `0.95`)
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
```lua
|
||||||
|
require("jj").setup({
|
||||||
|
editor = {
|
||||||
|
window = {
|
||||||
|
type = "floating",
|
||||||
|
floating_width = 0.9,
|
||||||
|
floating_height = 0.8,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
### Highlight Customization
|
### Highlight Customization
|
||||||
|
|
||||||
The `highlights` option allows you to customize the colors used in the describe buffer's file status display. Each highlight accepts standard Neovim highlight attributes:
|
The `highlights` option allows you to customize the colors used in the describe buffer's file status display. Each highlight accepts standard Neovim highlight attributes:
|
||||||
|
|||||||
@@ -467,4 +467,21 @@ function M.set_cursor(buf, pos, opts)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Given an input string resolves the split direction
|
||||||
|
--- @param type? "hsplit"|"vsplit"|"floating"|"tab" Type of window the terminal is displayed in
|
||||||
|
--- @return string split_type One of "horizontal", "vertical", "floating", "tab"
|
||||||
|
function M.resolve_split(type)
|
||||||
|
if type == "hsplit" then
|
||||||
|
return "horizontal"
|
||||||
|
elseif type == "vsplit" then
|
||||||
|
return "vertical"
|
||||||
|
elseif type == "floating" then
|
||||||
|
return "floating"
|
||||||
|
elseif type == "tab" then
|
||||||
|
return "tab"
|
||||||
|
else
|
||||||
|
return "horizontal" -- default to horizontal if not specified or unrecognized
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
return M
|
return M
|
||||||
|
|||||||
@@ -38,10 +38,7 @@ local utils = require("jj.utils")
|
|||||||
---@field rev string the revision to diff against
|
---@field rev string the revision to diff against
|
||||||
|
|
||||||
---@type jj.diff.config
|
---@type jj.diff.config
|
||||||
M.config = {
|
M.config = {}
|
||||||
backend = "native",
|
|
||||||
backends = {},
|
|
||||||
}
|
|
||||||
|
|
||||||
---@type table<string, jj.diff.BackendImpl>
|
---@type table<string, jj.diff.BackendImpl>
|
||||||
local backends = {}
|
local backends = {}
|
||||||
|
|||||||
+13
-6
@@ -27,6 +27,12 @@ M.config = {
|
|||||||
},
|
},
|
||||||
editor = {
|
editor = {
|
||||||
auto_insert = false,
|
auto_insert = false,
|
||||||
|
window = {
|
||||||
|
type = "hsplit",
|
||||||
|
split_size = 0.5,
|
||||||
|
floating_width = 0.99,
|
||||||
|
floating_height = 0.95,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
highlights = {
|
highlights = {
|
||||||
editor = {
|
editor = {
|
||||||
@@ -38,8 +44,12 @@ M.config = {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
terminal = {
|
terminal = {
|
||||||
|
cursor_render_delay = 10,
|
||||||
window = {
|
window = {
|
||||||
type = "hsplit",
|
type = "hsplit",
|
||||||
|
split_size = 0.5,
|
||||||
|
floating_width = 0.99,
|
||||||
|
floating_height = 0.95,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
diff = {
|
diff = {
|
||||||
@@ -55,12 +65,9 @@ function M.setup(opts)
|
|||||||
|
|
||||||
-- Setup for sub-modules
|
-- Setup for sub-modules
|
||||||
picker.setup(M.config.picker)
|
picker.setup(M.config.picker)
|
||||||
editor.setup({
|
editor.setup(M.config.editor)
|
||||||
highlights = M.config.highlights.editor,
|
cmd.setup(M.config.cmd)
|
||||||
auto_insert = M.config.editor.auto_insert,
|
terminal.setup(M.config.terminal)
|
||||||
})
|
|
||||||
cmd.setup(M.config.cmd or {})
|
|
||||||
terminal.setup(M.config.terminal or {})
|
|
||||||
diff.setup(M.config.diff)
|
diff.setup(M.config.diff)
|
||||||
|
|
||||||
-- Register the commands form the different modules
|
-- Register the commands form the different modules
|
||||||
|
|||||||
+80
-45
@@ -3,67 +3,70 @@ local M = {}
|
|||||||
|
|
||||||
local buffer = require("jj.core.buffer")
|
local buffer = require("jj.core.buffer")
|
||||||
|
|
||||||
|
--- @class jj.ui.editor.opts
|
||||||
|
--- @field auto_insert? boolean Smart insert: enter insert mode when description is empty, stay in normal mode when one exists
|
||||||
|
--- @field highlights? jj.ui.editor.highlights
|
||||||
|
--- @field window? jj.ui.editor.window
|
||||||
|
|
||||||
--- @class jj.ui.editor.highlights
|
--- @class jj.ui.editor.highlights
|
||||||
---@field added? table Highlight settings for added lines
|
---@field added? table Highlight settings for added lines
|
||||||
---@field modified? table Highlight settings for modified lines
|
---@field modified? table Highlight settings for modified lines
|
||||||
---@field deleted? table Highlight settings for deleted lines
|
---@field deleted? table Highlight settings for deleted lines
|
||||||
---@field renamed? table Highlight settings for renamed lines
|
---@field renamed? table Highlight settings for renamed lines
|
||||||
|
|
||||||
--- @class jj.ui.editor.opts
|
--- @class jj.ui.editor.window
|
||||||
---@field auto_insert? boolean Smart insert: enter insert mode when description is empty, stay in normal mode when one exists
|
--- @field type? "hsplit"|"vsplit"|"floating"|"tab" Type of window the terminal is displayed in
|
||||||
|
--- @field split_size? number Size % of the split window, either height (hsplit) or width (vsplit) (between 0.1 and 1.0)
|
||||||
|
--- @field floating_width? number Width % of the floating window (between 0.1 and 1.0)
|
||||||
|
--- @field floating_height? number Height % of the floating window (between 0.1 and 1.0)
|
||||||
|
|
||||||
M.highlights = {
|
--- @type jj.ui.editor.opts
|
||||||
-- Only init this one by default since it's not handled natively by neovim
|
M.opts = {
|
||||||
renamed = { fg = "#d29922", ctermfg = "Yellow" },
|
highlights = {
|
||||||
|
-- Only init this one by default since it's not handled natively by neovim
|
||||||
|
renamed = { fg = "#d29922", ctermfg = "Yellow" },
|
||||||
|
},
|
||||||
|
auto_insert = true,
|
||||||
}
|
}
|
||||||
M.highlights_initialized = false
|
|
||||||
M.auto_insert = true
|
--- Private module state to track highlights initialization
|
||||||
|
local highlights_initialized = false
|
||||||
|
|
||||||
-- Initialize highlight groups once
|
-- Initialize highlight groups once
|
||||||
local function init_highlights()
|
local function init_highlights()
|
||||||
if M.highlights_initialized then
|
if highlights_initialized then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Override the highlight groups if user provided custom settings
|
-- Override the highlight groups if user provided custom settings
|
||||||
if M.highlights.added then
|
if M.opts.highlights.added then
|
||||||
vim.api.nvim_set_hl(0, "Added", M.highlights.added)
|
vim.api.nvim_set_hl(0, "Added", M.opts.highlights.added)
|
||||||
end
|
end
|
||||||
|
|
||||||
if M.highlights.modified then
|
if M.opts.highlights.modified then
|
||||||
vim.api.nvim_set_hl(0, "Changed", M.highlights.modified)
|
vim.api.nvim_set_hl(0, "Changed", M.opts.highlights.modified)
|
||||||
end
|
end
|
||||||
|
|
||||||
if M.highlights.deleted then
|
if M.opts.highlights.deleted then
|
||||||
vim.api.nvim_set_hl(0, "Removed", M.highlights.deleted)
|
vim.api.nvim_set_hl(0, "Removed", M.opts.highlights.deleted)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- this one will always be executed since the default nvim highlight group does not exist for renames
|
-- this one will always be executed since the default nvim highlight group does not exist for renames
|
||||||
if M.highlights.renamed then
|
if M.opts.highlights.renamed then
|
||||||
vim.api.nvim_set_hl(0, "jjRenamed", M.highlights.renamed)
|
vim.api.nvim_set_hl(0, "jjRenamed", M.opts.highlights.renamed)
|
||||||
end
|
end
|
||||||
|
|
||||||
M.highlights_initialized = true
|
highlights_initialized = true
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Setup function to configure highlights and other options
|
--- Setup function to configure highlights and other options
|
||||||
---@param opts? { highlights: jj.ui.editor.highlights, auto_insert?: boolean } Configuration options
|
---@param user_opts? jj.ui.editor.opts Configuration options
|
||||||
function M.setup(opts)
|
function M.setup(user_opts)
|
||||||
opts = opts or {}
|
M.opts = vim.tbl_deep_extend("force", M.opts, user_opts or {})
|
||||||
|
|
||||||
-- Merge user highlights with defaults
|
|
||||||
if opts.highlights then
|
|
||||||
M.highlights = vim.tbl_deep_extend("force", M.highlights, opts.highlights)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Store auto_insert option
|
|
||||||
if opts.auto_insert ~= nil then
|
|
||||||
M.auto_insert = opts.auto_insert
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Reset highlights flag to force re-initialization with new highlights
|
-- Reset highlights flag to force re-initialization with new highlights
|
||||||
if M.highlights_initialized then
|
if highlights_initialized then
|
||||||
M.highlights_initialized = false
|
highlights_initialized = false
|
||||||
init_highlights()
|
init_highlights()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -115,27 +118,18 @@ function M.open_editor(initial_text, on_write, on_unload, keymaps)
|
|||||||
end
|
end
|
||||||
|
|
||||||
-- Create buffer
|
-- Create buffer
|
||||||
local buf = buffer.create({
|
local buf = M.create_buffer()
|
||||||
name = "jujutsu:///DESCRIBE_EDITMSG",
|
-- Set keymaps before setting content to avoid triggering them during setup
|
||||||
split = "horizontal",
|
buffer.set_keymaps(buf, keymaps or {})
|
||||||
size = math.floor(vim.o.lines / 2),
|
|
||||||
filetype = "jjdescription",
|
|
||||||
buftype = "acwrite",
|
|
||||||
modifiable = true,
|
|
||||||
keymaps = keymaps,
|
|
||||||
})
|
|
||||||
|
|
||||||
-- Set buffer content
|
-- Set buffer content
|
||||||
vim.api.nvim_buf_set_lines(buf, 0, -1, false, initial_text)
|
vim.api.nvim_buf_set_lines(buf, 0, -1, false, initial_text)
|
||||||
|
|
||||||
-- Set bufhidden after creation
|
|
||||||
vim.bo[buf].bufhidden = "wipe"
|
|
||||||
|
|
||||||
-- Apply highlights initially
|
-- Apply highlights initially
|
||||||
apply_highlights(buf)
|
apply_highlights(buf)
|
||||||
|
|
||||||
-- Smart insert mode: insert when description is empty, normal mode otherwise
|
-- Smart insert mode: insert when description is empty, normal mode otherwise
|
||||||
if M.auto_insert then
|
if M.opts.auto_insert then
|
||||||
vim.schedule(function()
|
vim.schedule(function()
|
||||||
if not vim.api.nvim_buf_is_valid(buf) then
|
if not vim.api.nvim_buf_is_valid(buf) then
|
||||||
return
|
return
|
||||||
@@ -184,4 +178,45 @@ function M.open_editor(initial_text, on_write, on_unload, keymaps)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Create the buffer based on the module options.
|
||||||
|
--- @return number buf Buffer number of the created buffer
|
||||||
|
function M.create_buffer()
|
||||||
|
if M.opts.window.type == "floating" then
|
||||||
|
local buf, _ = buffer.create_float({
|
||||||
|
title = "JJ editor",
|
||||||
|
title_pos = "center",
|
||||||
|
filetype = "jjdescription",
|
||||||
|
buftype = "acwrite",
|
||||||
|
bufhidden = "wipe",
|
||||||
|
enter = true,
|
||||||
|
modifiable = true,
|
||||||
|
height = math.floor(vim.o.lines * M.opts.window.floating_height),
|
||||||
|
width = math.floor(vim.o.columns * M.opts.window.floating_width),
|
||||||
|
win_options = {
|
||||||
|
wrap = true,
|
||||||
|
number = false,
|
||||||
|
relativenumber = false,
|
||||||
|
cursorline = false,
|
||||||
|
signcolumn = "no",
|
||||||
|
winfixbuf = true,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
return buf
|
||||||
|
else
|
||||||
|
-- Get the lines/columns based on the direction of the split
|
||||||
|
local full_size = M.opts.window.type == "hsplit" and vim.o.lines or vim.o.columns
|
||||||
|
|
||||||
|
return buffer.create({
|
||||||
|
name = "jj:///DESCRIBE_EDITMSG",
|
||||||
|
filetype = "jjdescription",
|
||||||
|
buftype = "acwrite",
|
||||||
|
bufhidden = "wipe",
|
||||||
|
modifiable = true,
|
||||||
|
split = buffer.resolve_split(M.opts.window.type),
|
||||||
|
size = math.floor(full_size * M.opts.window.split_size),
|
||||||
|
})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
return M
|
return M
|
||||||
|
|||||||
+2
-14
@@ -16,16 +16,7 @@ local utils = require("jj.utils")
|
|||||||
local buffer = require("jj.core.buffer")
|
local buffer = require("jj.core.buffer")
|
||||||
|
|
||||||
--- @type jj.ui.terminal.opts
|
--- @type jj.ui.terminal.opts
|
||||||
local opts = {
|
local opts = {}
|
||||||
cursor_render_delay = 10,
|
|
||||||
|
|
||||||
window = {
|
|
||||||
type = "hsplit",
|
|
||||||
split_size = 0.5,
|
|
||||||
floating_width = 0.99,
|
|
||||||
floating_height = 0.95,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
--- @class jj.ui.terminal.state
|
--- @class jj.ui.terminal.state
|
||||||
local state = {
|
local state = {
|
||||||
@@ -501,12 +492,9 @@ function M.run(cmd, keymaps)
|
|||||||
end
|
end
|
||||||
|
|
||||||
-- Create new terminal buffer
|
-- Create new terminal buffer
|
||||||
local split_type = opts.window.type == "hsplit" and "horizontal"
|
|
||||||
or opts.window.type == "vsplit" and "vertical"
|
|
||||||
or opts.window.type == "tab" and "tab"
|
|
||||||
local full_size = opts.window.type == "hsplit" and vim.o.lines or vim.o.columns
|
local full_size = opts.window.type == "hsplit" and vim.o.lines or vim.o.columns
|
||||||
state.buf = buffer.create({
|
state.buf = buffer.create({
|
||||||
split = split_type,
|
split = buffer.resolve_split(opts.window.type),
|
||||||
size = math.floor(full_size * opts.window.split_size),
|
size = math.floor(full_size * opts.window.split_size),
|
||||||
on_exit = function(buf)
|
on_exit = function(buf)
|
||||||
if state.buf == buf then
|
if state.buf == buf then
|
||||||
|
|||||||
Reference in New Issue
Block a user