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 })