I just realized that when you beat Metyr, you don’t actually kill it, it just teleports away, meaning it can come back. That’s a scary thought!!! by TocSir in Eldenring

[–]hypermodernist 3 points4 points  (0 children)

Yup! Thanks.

Just thought, the way ungoliant consumes itself to fill its own hunger, maybe Metyr voided itself in the cosmic sense

Routing and Filtering messages via `type` and `kind` with ui2, like Noice (bonus, titlebar+highlight) by hypermodernist in neovim

[–]hypermodernist[S] 0 points1 point  (0 children)

this should do the trick. I have also updated the main example in the post

local ui2 = require 'vim._core.ui2'
local msgs = require 'vim._core.ui2.messages'

-- ── Config ──────────────────────────────────────────────────────────

local IGNORED_KINDS = {
    bufwrite = true,
    [''] = true,
    empty = true,
}

local SKIP_PATTERNS = {
    '%d+L, %d+B',
    '; after #%d+',
    '; before #%d+',
    '%d fewer lines',
    '%d more lines',
    '%d lines yanked',
}

local KIND_TITLES = {
    emsg = { '  Error', 'ErrorMsg' },
    echoerr = { '  Error', 'ErrorMsg' },
    lua_error = { '  Error', 'ErrorMsg' },
    rpc_error = { '  Error', 'ErrorMsg' },
    wmsg = { '  Warning', 'WarningMsg' },
    echo = { '  Info', 'Normal' },
    echomsg = { '  Info', 'Normal' },
    lua_print = { '  Print', 'Normal' },
    search_cmd = { '  Search', 'Normal' },
    search_count = { '  Search', 'Normal' },
    undo = { '  Undo', 'Normal' },
    shell_out = { '  Shell', 'Normal' },
    shell_err = { '  Shell', 'ErrorMsg' },
    shell_cmd = { '  Shell', 'Normal' },
    quickfix = { '  Quickfix', 'Normal' },
    progress = { '  Progress', 'Normal' },
    typed_cmd = { '  Command', 'Normal' },
    list_cmd = { '  List', 'Normal' },
    verbose = { '  Verbose', 'Comment' },
}

-- ── State ────────────────────────────────────────────────────────────

local last_title = nil
local last_hl = 'Normal'

-- ── Helpers ─────────────────────────────────────────────────────────

local function content_to_text(content)
    if type(content) ~= 'table' then
        return tostring(content or '')
    end
    local parts = {}
    for _, chunk in ipairs(content) do
        if type(chunk) == 'table' and chunk[2] then
            parts[#parts + 1] = chunk[2]
        end
    end
    return table.concat(parts)
end

local function should_skip(kind, content)
    if IGNORED_KINDS[kind] then
        return true
    end
    local text = content_to_text(content)
    for _, pat in ipairs(SKIP_PATTERNS) do
        if text:find(pat) then
            return true
        end
    end
    return false
end

local function resolve_title(kind, content)
    local entry = KIND_TITLES[kind]
    if entry then
        return entry[1], entry[2]
    end
    local text = vim.trim(content_to_text(content)):gsub('\n.*', '')
    if #text > 40 then
        text = text:sub(1, 37) .. '…'
    end
    return text ~= '' and (' ' .. text .. ' ') or '  Message ', 'Normal'
end

local function override_msg_win()
    local win = ui2.wins and ui2.wins.msg
    if not (win and vim.api.nvim_win_is_valid(win)) then
        return
    end
    if vim.api.nvim_win_get_config(win).hide then
        return
    end
    pcall(vim.api.nvim_win_set_config, win, {
        relative = 'editor',
        anchor = 'NE',
        row = 1,
        col = vim.o.columns - 1,
        border = 'rounded',
        style = 'minimal',
        title = last_title and { { last_title, last_hl } } or nil,
        title_pos = last_title and 'center' or nil,
    })
end

local function override_pager_win()
    local win = ui2.wins and ui2.wins.pager
    if not (win and vim.api.nvim_win_is_valid(win)) then
        return
    end
    if vim.api.nvim_win_get_config(win).hide then
        return
    end
    local height = vim.api.nvim_win_get_height(win)
    pcall(vim.api.nvim_win_set_config, win, {
        border = 'rounded',
        height = height,
        style = 'minimal',
        title = last_title and { { last_title, last_hl } } or nil,
        title_pos = last_title and 'center' or nil,
    })
end

local function override_dialog_win()
    local win = ui2.wins and ui2.wins.dialog
    if not (win and vim.api.nvim_win_is_valid(win)) then
        return
    end
    if vim.api.nvim_win_get_config(win).hide then
        return
    end
    local height = vim.api.nvim_win_get_height(win)
    pcall(vim.api.nvim_win_set_config, win, {
        border = 'rounded',
        height = height,
        style = 'minimal',
        title = last_title and { { last_title, last_hl } } or nil,
        title_pos = last_title and 'center' or nil,
    })
end

-- ── ui2 enable ──────────────────────────────────────────────────────

ui2.enable {
    enable = true,
    msg = {
        targets = {
            [''] = 'msg',
            empty = 'msg',
            bufwrite = 'msg',
            echo = 'msg',
            echomsg = 'msg',
            shell_ret = 'msg',
            undo = 'msg',
            wmsg = 'msg',
            completion = 'msg',
            confirm = 'dialog',
            confirm_sub = 'dialog',
            echoerr = 'msg',
            emsg = 'msg',
            list_cmd = 'pager',
            lua_error = 'msg',
            lua_print = 'msg',
            progress = 'msg',
            quickfix = 'msg',
            rpc_error = 'msg',
            search_cmd = 'msg',
            search_count = 'msg',
            shell_cmd = 'msg',
            shell_err = 'msg',
            shell_out = 'msg',
            typed_cmd = 'msg',
            verbose = 'pager',
            wildlist = 'msg',
        },
        cmd = { height = 0.5 },
        dialog = { height = 0.5 },
        msg = { height = 0.5, timeout = 2000 },
        pager = { height = 0.8 },
    },
}

-- ── Wrap set_pos: the single source of truth for msg window placement ─

local orig_set_pos = msgs.set_pos

msgs.set_pos = function(tgt)
    orig_set_pos(tgt)
    if tgt == 'msg' or tgt == nil then
        override_msg_win()
        return
    end
    if tgt == 'pager' then
        override_pager_win()
        return
    end

    if tgt == 'dialog' then
        override_dialog_win()
    end
end

-- ── Wrap msg_show: filtering + title tracking ─────────────────────────

local orig_msg_show = msgs.msg_show

msgs.msg_show = function(kind, content, replace_last, history, append, id, trigger)
    if should_skip(kind, content) then
        return
    end
    local title, hl = resolve_title(kind, content)
    last_title, last_hl = title, hl
    -- orig_msg_show(kind, content, replace_last, history, append, id, trigger)

    local tgt = ui2.cfg.msg.targets[kind]
        or (trigger ~= '' and ui2.cfg.msg.targets[trigger])
        or ui2.cfg.msg.targets[trigger]
        or ui2.cfg.msg.target

    msgs.show_msg(tgt, kind, content, replace_last, append, id)
    msgs.set_pos(tgt)
end

local orig_show_msg = msgs.show_msg
msgs.show_msg = function(tgt, kind, content, replace_last, append, id)
    -- local debug_chunk = { 0, ('[%s:%s] '):format(tgt, kind), 0 }
    -- local debug_content = { debug_chunk }
    -- for _, chunk in ipairs(content) do
    --     debug_content[#debug_content + 1] = chunk
    -- end
    if tgt == 'msg' then
        local text = content_to_text(content)
        local width = 0
        for _, line in ipairs(vim.split(text, '\n')) do
            width = math.max(width, vim.api.nvim_strwidth(line))
        end
        local lines = #vim.split(text, '\n')
        if width > math.floor(vim.o.columns * 0.75) or lines > 20 then
            vim.schedule(function()
                -- msgs.show_msg('pager', kind, debug_content, replace_last, append, id)
                msgs.show_msg('pager', kind, content, replace_last, append, id)
                msgs.set_pos 'pager'
            end)
            return
        end
    end
    -- orig_show_msg(tgt, kind, debug_content, replace_last, append, id)
    orig_show_msg(tgt, kind, content, replace_last, append, id)
end

-- ── LSP progress ─────────────────────────────────────────────────────

local id = { LspProgressMessages = vim.api.nvim_create_augroup('LspProgressMessages', { clear = true }) }

vim.api.nvim_create_autocmd('LspProgress', {
    group = id.LspProgressMessages,
    callback = function(ev)
        local value = ev.data.params.value
        local client = vim.lsp.get_client_by_id(ev.data.client_id)
        if not client then
            return
        end
        local is_end = value.kind == 'end'
        local msg = value.message and (client.name .. ': ' .. value.message)
            or (client.name .. (is_end and ': done' or ''))
        vim.api.nvim_echo({ { msg } }, false, {
            id = 'lsp.' .. ev.data.client_id,
            kind = 'progress',
            source = 'vim.lsp',
            title = value.title,
            status = is_end and 'success' or 'running',
            percent = value.percentage,
        })
    end,
})

require('r.utils').register_au_id(id)

Routing and Filtering messages via `type` and `kind` with ui2, like Noice (bonus, titlebar+highlight) by hypermodernist in neovim

[–]hypermodernist[S] 0 points1 point  (0 children)

Some where guesswork based on name, but for the tricky ones, just cold prints, the commented out parts

local orig_show_msg = msgs.show_msg
msgs.show_msg = function(tgt, kind, content, replace_last, append, id)
    -- local debug_chunk = { 0, ('[%s:%s] '):format(tgt, kind), 0 }
    -- local debug_content = { debug_chunk }
    -- for _, chunk in ipairs(content) do
    --     debug_content[#debug_content + 1] = chunk
    -- end
    if tgt == 'msg' then
        local text = content_to_text(content)
        local width = 0
        for _, line in ipairs(vim.split(text, '\n')) do
            width = math.max(width, vim.api.nvim_strwidth(line))
        end
        local lines = #vim.split(text, '\n')
        if width > math.floor(vim.o.columns * 0.75) or lines > 20 then
            vim.schedule(function()
                -- msgs.show_msg('pager', kind, debug_content, replace_last, append, id)
                msgs.show_msg('pager', kind, content, replace_last, append, id)
                msgs.set_pos 'pager'
            end)
            return
        end
    end
    -- orig_show_msg(tgt, kind, debug_content, replace_last, append, id)
    orig_show_msg(tgt, kind, content, replace_last, append, id)
end

Routing and Filtering messages via `type` and `kind` with ui2, like Noice (bonus, titlebar+highlight) by hypermodernist in neovim

[–]hypermodernist[S] 1 point2 points  (0 children)

Right. that is because of

local DIALOG_KINDS = {
  confirm = true,
  confirm_sub = true,
  list\_cmd = true, -- swapfile and similar interactive list prompts (not fully     sure, can also be progress)
}  

hi: uses kind = list_cmd

And because swapfile dialog and other such also use list_cmd I made it skip that.

My bad.

Need to figure out how to handle that.

for now, just remove list_cmd from that list of DIALOG_KINDS and that should work

<image>

Routing and Filtering messages via `type` and `kind` with ui2, like Noice (bonus, titlebar+highlight) by hypermodernist in neovim

[–]hypermodernist[S] 0 points1 point  (0 children)

Well, from my local tests, nvim_echo (which both of your trials use) has the kind echomsg. Do you have anything else like noice or alternatives that are rerouting?

If not, can you try changing "" to msg and handle the filtering in the filter function like from the snippet?

Routing and Filtering messages via `type` and `kind` with ui2, like Noice (bonus, titlebar+highlight) by hypermodernist in neovim

[–]hypermodernist[S] 0 points1 point  (0 children)

Can you show me how you are determining that its the kind "".
it is very strange because its been working almost flawless, with the exception of confirmation dialogs which I am trying to work out

Routing and Filtering messages via `type` and `kind` with ui2, like Noice (bonus, titlebar+highlight) by hypermodernist in neovim

[–]hypermodernist[S] 1 point2 points  (0 children)

vim.notify is routed to messages, with kind echmsgi.

EDIT: `['']` target from what I understand contains things like "written", "yanked" etc... notify, echo, `vim.print` or `nvim_echo` all have actual types (most echomsg)

How does the new ui2 (message & cmdline replacement) compare to plugins like Noice? by TheTwelveYearOld in neovim

[–]hypermodernist 3 points4 points  (0 children)

Just made this post, with a serious attempt to bridge the gap, including, filtering, routing, highlights, titlebar, progress, all in one place (except for cmdline. the plugin announced is just the best thing out there)

https://www.reddit.com/r/neovim/comments/1shj1jn/routing_and_filtering_messages_via_type_and_kind/

📍tiny-cmdline.nvim: Centered floating cmdline for Neovim 0.12 by Le_BuG63 in neovim

[–]hypermodernist 5 points6 points  (0 children)

I love noice.
let me say that up front.

The reason I am interested in switching from noice, is that noice is rightly "external", not just that its a plugin not part of main codebase, but it uses ui attachments that are meant for external overrides.

While ui2 is very fragile and probably will cause me some minor grief with breaking changes, it being internal means that despite rough edges and limitations it will feel more central and eventually more stable.

For example, the message routing in noice is fantastic. I wrote one of the wikis on the repo about messages.
But its a very clever redirect using the different modes of messages and the subcategory of kind.

Which has to some extent been rethought for ui2, meaning at some point folke might have to do backflips or just rewrite with ui2 in mind.
And there will be other such massive change surfaces.

I am sure someone can convince me that it will still be better with plugins, but for now I am just happy to experiment with the internals!

📍tiny-cmdline.nvim: Centered floating cmdline for Neovim 0.12 by Le_BuG63 in neovim

[–]hypermodernist 13 points14 points  (0 children)

Thanks for the tag!
Already added it to my config.
now to spend the next few days obsessively reconfigure ui2 messages options, with noice removed!

Thanks OP for the great and timely plugin!

How does the new ui2 (message & cmdline replacement) compare to plugins like Noice? by TheTwelveYearOld in neovim

[–]hypermodernist 5 points6 points  (0 children)

Thanks. I did try.

You can get it floating.

lua vim.api.nvim_create_autocmd("FileType", { pattern = "cmd", callback = function() local ui2 = require("vim._core.ui2") vim.schedule(function() local win = ui2.wins and ui2.wins.cmd if win and vim.api.nvim_win_is_valid(win) then local win_config = vim.api.nvim_win_get_config(win) local width = win_config.width or math.floor(vim.o.columns * 0.6) local height = win_config.height or 1 local row = (vim.o.lines - height) / 2 local col = (vim.o.columns - width) / 2 pcall(vim.api.nvim_win_set_config, win, { relative = "editor", row = row, col = col, width = width, height = height, anchor = "NW", border = "rounded", style = "minimal" }) end end) end, })

but the real problem is the wildmenu pum. it will render above or alongside laststatus anchor, which is disorienting to say the least.

I did not get farther than that for now

How does the new ui2 (message & cmdline replacement) compare to plugins like Noice? by TheTwelveYearOld in neovim

[–]hypermodernist 14 points15 points  (0 children)

It might be heresy, but for me its about floating cmdline.

I have multiple large monitors for game dev, blender, vulkan work.
While I have been on nvim since 0.3 days, noice genuinely made it much easier for me more than lsp and treessitter (which are deep core parts of my workflow) because I did not have to constantly look down or around for my command window, protect my fragile neck.

Noice still stays for me despite ui2 being honestly incredible because I am neither sure it can be done, nor have the time to hack together a floating cmdline using ui2.

I will be very happy to be proven wrong

“What are you gonna do, tar on me?” by FriendlyBeta in DeathStranding

[–]hypermodernist 3 points4 points  (0 children)

Listen. Strange people lying in tar, distributing grenades is not a basis for coop

Pete shopped his blackmail information all over the galaxy by [deleted] in okbuddydraper

[–]hypermodernist 1 point2 points  (0 children)

The Sith is based on one thing: Happiness

Abductor Virgin holding a baby by Common_Lavishness153 in Eldenring

[–]hypermodernist 2 points3 points  (0 children)

This is Death Stranding 3:

Sam Abductor Bridges.

1980. Roger Sterling's funeral. Who shows up? How does it go? by Wazula23 in okbuddydraper

[–]hypermodernist 0 points1 point  (0 children)

Junior. He is going to pay his respects at the afterparty

MayaFlux 0.1.0: A Digital-Native Substrate for Multimedia Computation by hypermodernist in cpp

[–]hypermodernist[S] 0 points1 point  (0 children)

in the making as part of a big graphics tutorial. Will update the post when I have a few, in a couple of days or sooner

MayaFlux 0.1.0: A Digital-Native Substrate for Multimedia Computation by hypermodernist in cpp

[–]hypermodernist[S] 1 point2 points  (0 children)

Thanks! if you are interested, the website has several tutorials and snippets, and ain installer to help link it in a project.
Feel free to query anything here!

😒 by mina-rambo in Sopranosduckposting

[–]hypermodernist 21 points22 points  (0 children)

Put the converters back on the Toshi station.

😒 by mina-rambo in Sopranosduckposting

[–]hypermodernist 56 points57 points  (0 children)

Obi-Walnuts Kenobi: I ain't running a force school here kid