neovim

Neovim text editor
git clone https://git.dasho.dev/neovim.git
Log | Files | Refs | README

osc52.lua (3585B)


      1 --- @class (private) TermFeatures
      2 --- @field osc52 boolean?
      3 
      4 local id = vim.api.nvim_create_augroup('nvim.osc52', { clear = true })
      5 vim.api.nvim_create_autocmd('UIEnter', {
      6  group = id,
      7  desc = 'Enable OSC 52 feature flag if a supporting TUI is attached',
      8  callback = function()
      9    -- If OSC 52 is explicitly disabled by the user then don't do anything
     10    if vim.g.termfeatures ~= nil and vim.g.termfeatures.osc52 == false then
     11      return
     12    end
     13 
     14    local tty = false
     15    for _, ui in ipairs(vim.api.nvim_list_uis()) do
     16      if ui.stdout_tty then
     17        tty = true
     18        break
     19      end
     20    end
     21 
     22    -- Do not query when no TUI is attached
     23    if not tty then
     24      return
     25    end
     26 
     27    -- Clear existing OSC 52 value, since this is a new UI we might be attached to a different
     28    -- terminal
     29    do
     30      local termfeatures = vim.g.termfeatures or {} ---@type TermFeatures
     31      termfeatures.osc52 = nil
     32      vim.g.termfeatures = termfeatures
     33    end
     34 
     35    -- Check DA1 first
     36    vim.api.nvim_create_autocmd('TermResponse', {
     37      group = id,
     38      nested = true,
     39      callback = function(args)
     40        local resp = args.data.sequence ---@type string
     41        local params = resp:match('^\027%[%?([%d;]+)c$')
     42        if params then
     43          -- Check termfeatures again, it may have changed between the query and response.
     44          if vim.g.termfeatures ~= nil and vim.g.termfeatures.osc52 ~= nil then
     45            return true
     46          end
     47 
     48          for param in string.gmatch(params, '%d+') do
     49            if param == '52' then
     50              local termfeatures = vim.g.termfeatures or {} ---@type TermFeatures
     51              termfeatures.osc52 = true
     52              vim.g.termfeatures = termfeatures
     53              return true
     54            end
     55          end
     56 
     57          -- Do not use XTGETTCAP on terminals that echo unknown sequences
     58          if vim.env.TERM_PROGRAM == 'Apple_Terminal' then
     59            return true
     60          end
     61 
     62          -- Fallback to XTGETTCAP
     63          require('vim.termcap').query('Ms', function(cap, found, seq)
     64            if not found then
     65              return
     66            end
     67 
     68            -- Check termfeatures again, it may have changed between the query and response.
     69            if vim.g.termfeatures ~= nil and vim.g.termfeatures.osc52 ~= nil then
     70              return
     71            end
     72 
     73            assert(cap == 'Ms')
     74 
     75            -- If the terminal reports a sequence other than OSC 52 for the Ms capability
     76            -- then ignore it. We only support OSC 52 (for now)
     77            if not seq or not seq:match('^\027%]52') then
     78              return
     79            end
     80 
     81            local termfeatures = vim.g.termfeatures or {} ---@type TermFeatures
     82            termfeatures.osc52 = true
     83            vim.g.termfeatures = termfeatures
     84          end)
     85 
     86          return true
     87        end
     88      end,
     89    })
     90 
     91    -- Write DA1 request
     92    vim.api.nvim_ui_send('\027[c')
     93  end,
     94 })
     95 
     96 vim.api.nvim_create_autocmd('UILeave', {
     97  group = id,
     98  desc = 'Reset OSC 52 feature flag if no TUIs are attached',
     99  callback = function()
    100    -- If OSC 52 is explicitly disabled by the user then don't do anything
    101    if vim.g.termfeatures ~= nil and vim.g.termfeatures.osc52 == false then
    102      return
    103    end
    104 
    105    -- If no TUI is connected to Nvim's stdout then reset the OSC 52 term features flag
    106    for _, ui in ipairs(vim.api.nvim_list_uis()) do
    107      if ui.stdout_tty then
    108        return
    109      end
    110    end
    111 
    112    local termfeatures = vim.g.termfeatures or {} ---@type TermFeatures
    113    termfeatures.osc52 = nil
    114    vim.g.termfeatures = termfeatures
    115  end,
    116 })