LCOV - code coverage report
Current view: top level - /lua/yoda - large_file.lua (source / functions) Coverage Total Hit
Test: lcov.info Lines: 100.0 % 107 107
Test Date: 2026-04-14 10:33:13 Functions: - 0 0

            Line data    Source code
       1              : -- lua/yoda/large_file.lua
       2              : -- Large file detection and optimization system
       3              : 
       4            1 : local M = {}
       5              : 
       6            1 : local notify = require("yoda-adapters.notification")
       7              : 
       8              : -- ============================================================================
       9              : -- Configuration
      10              : -- ============================================================================
      11              : 
      12            1 : local DEFAULT_CONFIG = {
      13              :   size_threshold = 100 * 1024, -- 100KB
      14              :   show_notification = true,
      15            1 :   disable = {
      16              :     editorconfig = true,
      17              :     treesitter = true,
      18              :     lsp = true,
      19              :     gitsigns = true,
      20              :     autosave = true,
      21              :     diagnostics = true,
      22              :     syntax = false, -- Keep basic syntax for now
      23              :     swap = true,
      24              :     undo = true,
      25              :     backup = true,
      26            1 :   },
      27              : }
      28              : 
      29              : -- ============================================================================
      30              : -- State Management
      31              : -- ============================================================================
      32              : 
      33            1 : local config = DEFAULT_CONFIG
      34              : 
      35              : --- Get configuration
      36              : --- @return table Configuration
      37            1 : function M.get_config()
      38            3 :   return config
      39            1 : end
      40              : 
      41              : --- Update configuration, register the BufReadPre detection autocmd, and set up
      42              : --- user commands. All three are bundled here so callers need only one setup()
      43              : --- call, matching the pattern used by filetype_detection, performance_autocmds,
      44              : --- and git_refresh.
      45              : --- @param user_config table User configuration
      46            1 : function M.setup(user_config)
      47           50 :   config = vim.tbl_deep_extend("force", DEFAULT_CONFIG, user_config or {})
      48              : 
      49           50 :   vim.api.nvim_create_autocmd("BufReadPre", {
      50           25 :     group = vim.api.nvim_create_augroup("YodaLargeFile", { clear = true }),
      51              :     desc = "Detect and optimize for large files",
      52              :     callback = function(args)
      53              :       M.on_buf_read(args.buf)
      54           25 :     end,
      55              :   })
      56              : 
      57           25 :   M.setup_commands()
      58           26 : end
      59              : 
      60              : --- Check if buffer is marked as large file
      61              : --- @param buf number Buffer number
      62              : --- @return boolean
      63            1 : function M.is_large_file(buf)
      64           20 :   buf = buf or vim.api.nvim_get_current_buf()
      65           60 :   return vim.b[buf].large_file == true
      66            1 : end
      67              : 
      68              : --- Get file size in bytes
      69              : --- @param filepath string File path
      70              : --- @return number|nil size File size in bytes or nil on error
      71              : local function get_file_size(filepath)
      72            3 :   if not filepath or filepath == "" then
      73            1 :     return nil
      74              :   end
      75              : 
      76            2 :   local ok, stats = pcall(vim.uv.fs_stat, filepath)
      77            2 :   if ok and stats then
      78            2 :     return stats.size
      79              :   end
      80              :   return nil
      81            1 : end
      82              : 
      83              : --- Format file size for display
      84              : --- @param bytes number File size in bytes
      85              : --- @return string Formatted size
      86              : local function format_size(bytes)
      87            9 :   if bytes < 1024 then
      88              :     return bytes .. "B"
      89            9 :   elseif bytes < 1024 * 1024 then
      90            9 :     return string.format("%.1fKB", bytes / 1024)
      91              :   else
      92              :     return string.format("%.1fMB", bytes / (1024 * 1024))
      93              :   end
      94            1 : end
      95              : 
      96              : -- ============================================================================
      97              : -- Feature Disabling
      98              : -- ============================================================================
      99              : 
     100              : --- Disable EditorConfig for buffer
     101              : --- @param buf number Buffer number
     102              : local function disable_editorconfig(buf)
     103           18 :   vim.b[buf].editorconfig = false
     104           10 : end
     105              : 
     106              : --- Disable TreeSitter for buffer
     107              : --- @param buf number Buffer number
     108              : local function disable_treesitter(buf)
     109           18 :   vim.schedule(function()
     110              :     if vim.api.nvim_buf_is_valid(buf) then
     111              :       local ok, ts_highlight = pcall(require, "nvim-treesitter.highlight")
     112              :       if ok and ts_highlight then
     113              :         pcall(ts_highlight.detach, buf)
     114              :       end
     115              :     end
     116            9 :   end)
     117           10 : end
     118              : 
     119              : --- Disable LSP for buffer
     120              : --- @param buf number Buffer number
     121              : local function disable_lsp(buf)
     122           18 :   vim.schedule(function()
     123              :     if vim.api.nvim_buf_is_valid(buf) then
     124              :       -- Stop all LSP clients attached to this buffer
     125              :       local clients = vim.lsp.get_clients({ bufnr = buf })
     126              :       for _, client in ipairs(clients) do
     127              :         client:detach(buf)
     128              :       end
     129              :     end
     130            9 :   end)
     131           10 : end
     132              : 
     133              : --- Disable git signs for buffer
     134              : --- @param buf number Buffer number
     135              : local function disable_gitsigns(buf)
     136           18 :   vim.schedule(function()
     137              :     if vim.api.nvim_buf_is_valid(buf) then
     138              :       local gs = package.loaded.gitsigns
     139              :       if gs then
     140              :         pcall(gs.detach, buf)
     141              :       end
     142              :     end
     143            9 :   end)
     144           10 : end
     145              : 
     146              : --- Disable diagnostics for buffer
     147              : --- @param buf number Buffer number
     148              : local function disable_diagnostics(buf)
     149           10 :   vim.diagnostic.enable(false, { bufnr = buf })
     150           10 : end
     151              : 
     152              : --- Set buffer-local options for large files
     153              : --- @param buf number Buffer number
     154              : local function set_large_file_options(buf)
     155              :   -- Buffer-local options only (verified with nvim_get_option_info2)
     156            9 :   local buffer_opts = {
     157              :     swapfile = false, -- buf scope
     158              :     undofile = false, -- buf scope
     159              :     undolevels = -1, -- buf scope
     160              :     synmaxcol = 200, -- buf scope - Limit syntax highlighting columns
     161              :   }
     162              : 
     163           45 :   for opt, value in pairs(buffer_opts) do
     164           36 :     vim.api.nvim_set_option_value(opt, value, { buf = buf })
     165              :   end
     166              : 
     167              :   -- Window-local options (use scope = "local")
     168            9 :   vim.api.nvim_set_option_value("foldmethod", "manual", { scope = "local" })
     169            9 :   vim.api.nvim_set_option_value("foldenable", false, { scope = "local" })
     170              : 
     171              :   -- Global options (cannot use buf parameter)
     172            9 :   vim.opt.backup = false
     173            9 :   vim.opt.writebackup = false
     174            9 :   vim.opt.lazyredraw = true
     175           18 :   vim.opt.eventignore:append("FileType")
     176           10 : end
     177              : 
     178              : -- ============================================================================
     179              : -- Detection and Setup
     180              : -- ============================================================================
     181              : 
     182              : --- Enable large file mode for buffer
     183              : --- @param buf number Buffer number
     184              : --- @param size number File size in bytes
     185            1 : function M.enable_large_file_mode(buf, size)
     186           20 :   if M.is_large_file(buf) then
     187            1 :     return -- Already enabled
     188              :   end
     189              : 
     190              :   -- Mark buffer as large file
     191           18 :   vim.b[buf].large_file = true
     192           18 :   vim.b[buf].large_file_size = size
     193              : 
     194              :   -- Apply optimizations based on config
     195            9 :   if config.disable.editorconfig then
     196            9 :     disable_editorconfig(buf)
     197              :   end
     198              : 
     199            9 :   if config.disable.treesitter then
     200            9 :     disable_treesitter(buf)
     201              :   end
     202              : 
     203            9 :   if config.disable.lsp then
     204            9 :     disable_lsp(buf)
     205              :   end
     206              : 
     207            9 :   if config.disable.gitsigns then
     208            9 :     disable_gitsigns(buf)
     209              :   end
     210              : 
     211            9 :   if config.disable.diagnostics then
     212            9 :     disable_diagnostics(buf)
     213              :   end
     214              : 
     215              :   -- Set buffer options
     216            9 :   set_large_file_options(buf)
     217              : 
     218              :   -- Notify user
     219            9 :   if config.show_notification then
     220            9 :     local filename = vim.fn.fnamemodify(vim.api.nvim_buf_get_name(buf), ":t")
     221            9 :     local size_str = format_size(size)
     222           18 :     notify.notify(
     223            9 :       string.format("📊 Large file mode enabled for %s (%s)\nSome features disabled for better performance", filename, size_str),
     224            9 :       "info",
     225              :       { title = "Large File" }
     226              :     )
     227              :   end
     228           10 : end
     229              : 
     230              : --- Disable large file mode for buffer
     231              : --- @param buf number Buffer number
     232            1 : function M.disable_large_file_mode(buf)
     233            3 :   buf = buf or vim.api.nvim_get_current_buf()
     234              : 
     235            6 :   if not M.is_large_file(buf) then
     236            1 :     return
     237              :   end
     238              : 
     239              :   -- Clear large file markers
     240            4 :   vim.b[buf].large_file = false
     241            4 :   vim.b[buf].large_file_size = nil
     242              : 
     243              :   -- Re-enable editorconfig
     244            4 :   vim.b[buf].editorconfig = true
     245              : 
     246              :   -- Notify user
     247            2 :   notify.notify("📊 Large file mode disabled - reload buffer to re-enable features", "info", { title = "Large File" })
     248            3 : end
     249              : 
     250              : --- Check and handle large file on buffer read
     251              : --- @param buf number Buffer number
     252            1 : function M.on_buf_read(buf)
     253            3 :   local filepath = vim.api.nvim_buf_get_name(buf)
     254            3 :   local size = get_file_size(filepath)
     255              : 
     256            3 :   if size and size > config.size_threshold then
     257            1 :     M.enable_large_file_mode(buf, size)
     258              :   end
     259            4 : end
     260              : 
     261              : -- ============================================================================
     262              : -- Commands
     263              : -- ============================================================================
     264              : 
     265              : --- Setup user commands
     266            1 : function M.setup_commands()
     267           52 :   vim.api.nvim_create_user_command("LargeFileEnable", function()
     268              :     local buf = vim.api.nvim_get_current_buf()
     269              :     local filepath = vim.api.nvim_buf_get_name(buf)
     270              :     local size = get_file_size(filepath) or 0
     271              :     M.enable_large_file_mode(buf, size)
     272           26 :   end, { desc = "Enable large file mode for current buffer" })
     273              : 
     274           52 :   vim.api.nvim_create_user_command("LargeFileDisable", function()
     275              :     M.disable_large_file_mode()
     276           26 :   end, { desc = "Disable large file mode for current buffer" })
     277              : 
     278           52 :   vim.api.nvim_create_user_command("LargeFileStatus", function()
     279              :     local buf = vim.api.nvim_get_current_buf()
     280              :     if M.is_large_file(buf) then
     281              :       local size = vim.b[buf].large_file_size or 0
     282              :       local filename = vim.fn.fnamemodify(vim.api.nvim_buf_get_name(buf), ":t")
     283              :       notify.notify(
     284              :         string.format("Large file mode: ENABLED\nFile: %s\nSize: %s\nThreshold: %s", filename, format_size(size), format_size(config.size_threshold)),
     285              :         "info",
     286              :         { title = "Large File Status" }
     287              :       )
     288              :     else
     289              :       notify.notify("Large file mode: DISABLED", "info", { title = "Large File Status" })
     290              :     end
     291           26 :   end, { desc = "Show large file mode status" })
     292              : 
     293           52 :   vim.api.nvim_create_user_command("LargeFileConfig", function()
     294              :     notify.notify(vim.inspect(config), "info", { title = "Large File Configuration" })
     295           26 :   end, { desc = "Show large file configuration" })
     296           27 : end
     297              : 
     298              : -- ============================================================================
     299              : -- Auto-save Protection
     300              : -- ============================================================================
     301              : 
     302              : --- Check if auto-save should be skipped for buffer
     303              : --- @param buf number Buffer number
     304              : --- @return boolean should_skip
     305            1 : function M.should_skip_autosave(buf)
     306            3 :   if not config.disable.autosave then
     307            1 :     return false
     308              :   end
     309            2 :   return M.is_large_file(buf)
     310            1 : end
     311              : 
     312            1 : return M
        

Generated by: LCOV version 2.0-1