From a55d14e8989cf959f3c3b92a8be555b2fecb717a Mon Sep 17 00:00:00 2001
From: Chris Griffing <cmgriffing@gmail.com>
Date: Sat, 13 Apr 2024 18:12:42 -0700
Subject: [PATCH] feat: add max file size config (#49)

---
 README.md                   | 13 ++++++++++++
 lua/nvim-biscuits/init.lua  | 42 +++++++++++++++++++++++++++++++++++++
 lua/nvim-biscuits/utils.lua |  8 ++++++-
 lua/vendor/parse.lua        | 42 +++++++++++++++++++++++++++++++++++++
 4 files changed, 104 insertions(+), 1 deletion(-)
 create mode 100644 lua/vendor/parse.lua

diff --git a/README.md b/README.md
index 47d3588..73d392f 100644
--- a/README.md
+++ b/README.md
@@ -20,6 +20,7 @@ Plug 'nvim-treesitter/nvim-treesitter', {'do': ':TSUpdate'}
 Plug 'code-biscuits/nvim-biscuits'
 call plug#end()
 ```
+
 Using Packer:
 
 ```lua
@@ -174,6 +175,18 @@ require('nvim-biscuits').setup({
 EOF
 ```
 
+## Configuration (Max File Size)
+
+You can set a maximum file size to bail out of biscuits if you think they are slowing down your editor. The value can be a string evaluating to a human readable file size or a number in bytes. Values are 1024 based. Supported case-insensitive suffixes: b, kb, kib, mb, mib, gb, gib, tb, tib, pb, pib
+
+```lua
+lua <<EOF
+require('nvim-biscuits').setup({
+  max_file_size = '100kb'
+})
+EOF
+```
+
 ## Supported Languages
 
 We currently support all the languages supported in tree-sitter. Not all languages have specialized support, though most will probably need some.
diff --git a/lua/nvim-biscuits/init.lua b/lua/nvim-biscuits/init.lua
index 6a943cb..70c68a5 100644
--- a/lua/nvim-biscuits/init.lua
+++ b/lua/nvim-biscuits/init.lua
@@ -2,9 +2,34 @@ require('nvim-treesitter')
 local utils = require("nvim-biscuits.utils")
 local config = require("nvim-biscuits.config")
 local languages = require("nvim-biscuits.languages")
+local parse = require("vendor.parse")
 
 local final_config = config.default_config()
 
+local function is_file_too_big()
+    local file_size = vim.fn.wordcount().bytes
+
+    local max_file_size = final_config.max_file_size
+    if final_config.max_file_size == nil then
+        max_file_size = 0
+    end
+
+    local original_max_file_size = max_file_size
+
+    if type(max_file_size) == "string" then
+        max_file_size = parse.file_size(max_file_size)
+    else
+        return nil
+    end
+
+    if max_file_size == nil then
+        vim.notify("nvim-biscuits: max_file_size is invalid. Valid case-insensitive values include: b, kb, kib, mb, mib, gb, gib, tb, tib, pb, pib")
+        max_file_size = 0
+    end
+
+    return max_file_size > 0 and file_size > max_file_size
+end
+
 local has_ts, _ = pcall(require, 'nvim-treesitter')
 if not has_ts then error("nvim-treesitter must be installed") end
 
@@ -12,6 +37,7 @@ local ts_parsers = require('nvim-treesitter.parsers')
 local ts_utils = require('nvim-treesitter.ts_utils')
 local nvim_biscuits = {should_render_biscuits = true}
 
+
 local make_biscuit_hl_group_name =
     function(lang)
         return 'BiscuitColor' .. lang
@@ -59,20 +85,26 @@ nvim_biscuits.decorate_nodes = function(bufnr, lang)
 
             local should_decorate = true
 
+            -- bail out of empty text
             if text == '' then should_decorate = false end
 
+            -- bail out of short text
             if string.len(text) <= 1 then should_decorate = false end
 
+            -- bail out if start line and end line are the same
             if start_line == end_line then should_decorate = false end
 
+            -- bail out distance is less than minimum distance
             if end_line - start_line < final_config.min_distance then
                 should_decorate = false
             end
 
+            -- bail out if this node should not be decorated based on language specific filters
             if languages.should_decorate(lang, node, text, bufnr) == false then
                 should_decorate = false
             end
 
+            -- bail out if the user has cursor line only on and we are not on their cursor line
             local cursor = vim.api.nvim_win_get_cursor(0)
             local should_clear = false
             if final_config.cursor_line_only and end_line + 1 ~= cursor[1] then
@@ -154,6 +186,11 @@ nvim_biscuits.BufferAttach = function(bufnr, lang)
                                 { noremap = false, desc = "toggle biscuits" })
     end
 
+    if is_file_too_big() then
+        vim.notify_once("nvim-biscuits: File is larger than configured max_file_size")
+        return
+    end
+
     local on_lines = function() nvim_biscuits.decorate_nodes(bufnr, lang) end
 
     if lang then
@@ -230,6 +267,11 @@ nvim_biscuits.setup = function(user_config)
 end
 
 nvim_biscuits.toggle_biscuits = function()
+    if is_file_too_big() then
+        vim.notify("nvim-biscuits: File is larger than configured max_file_size")
+        return
+    end
+
     nvim_biscuits.should_render_biscuits =
         not nvim_biscuits.should_render_biscuits
     local bufnr = vim.api.nvim_get_current_buf()
diff --git a/lua/nvim-biscuits/utils.lua b/lua/nvim-biscuits/utils.lua
index 1d90dd3..4c22b74 100644
--- a/lua/nvim-biscuits/utils.lua
+++ b/lua/nvim-biscuits/utils.lua
@@ -10,8 +10,14 @@ end
 
 utils.clear_log = function() if is_debug_mode then Dev.clear_log() end end
 
+utils.clone_table = function(_table)
+    local new_table = { }
+    for k, v in pairs(_table) do new_table[k] = v end
+    return setmetatable(new_table, getmetatable(_table))
+end
+
 utils.merge_arrays = function(a, b)
-    local result = {unpack(a)}
+    local result = utils.clone_table(a)
     for i = 1, #b do result[#a + i] = b[i] end
     return result
 end
diff --git a/lua/vendor/parse.lua b/lua/vendor/parse.lua
new file mode 100644
index 0000000..53a5b5a
--- /dev/null
+++ b/lua/vendor/parse.lua
@@ -0,0 +1,42 @@
+-- Generated by Twitch viewer AusCryptor using OpanAI ChatGPT
+
+local parse = {}
+
+function parse_file_size(sizeStr)
+  -- Trim the string to avoid whitespace issues
+  local trimmed = sizeStr:lower():match("^%s*(.-)%s*$")
+
+  -- Match the numeric part and the unit
+  local num, unit = trimmed:match("^(%d+%.?%d*)%s*([kmgtpi].b?)$")
+  num = tonumber(num)
+
+  -- Return nil if there is no numeric part or unit
+  if not num or not unit then return nil end
+
+  -- Define the multipliers for each unit
+  local multipliers = {
+    b = 1,
+    kb = 1024,
+    kib = 1024,
+    mb = 1024 ^ 2,
+    mib = 1024 ^ 2,
+    gb = 1024 ^ 3,
+    gib = 1024 ^ 3,
+    tb = 1024 ^ 4,
+    tib = 1024 ^ 4,
+    pb = 1024 ^ 5,
+    pib = 1024 ^ 5 -- adding petabyte for completeness
+  }
+
+  -- Calculate the number of bytes
+  local multiplier = multipliers[unit]
+  if not multiplier then
+    return nil
+  end
+
+  return num * multiplier
+end
+
+parse.file_size = parse_file_size
+
+return parse
\ No newline at end of file