diff --git a/GUIDE.md b/GUIDE.md index ac90f01..8e03999 100644 --- a/GUIDE.md +++ b/GUIDE.md @@ -232,8 +232,8 @@ Navigate between fields and rows with familiar keyboard shortcuts: -- Horizontal navigation jump_next_field_end = { "", mode = { "n", "v" } }, jump_prev_field_end = { "", mode = { "n", "v" } }, - - -- Vertical navigation + + -- Vertical navigation jump_next_row = { "", mode = { "n", "v" } }, jump_prev_row = { "", mode = { "n", "v" } }, }, @@ -247,8 +247,8 @@ Navigate between fields and rows with familiar keyboard shortcuts: keymaps = { -- Select field content (inner) textobject_field_inner = { "if", mode = { "o", "x" } }, - - -- Select field including delimiter (outer) + + -- Select field including delimiter (outer) textobject_field_outer = { "af", mode = { "o", "x" } }, }, } @@ -377,18 +377,45 @@ Jane,30,LA Only the data rows (`name,age,city`, `John,25,NYC`, `Jane,30,LA`) will be displayed in the table format. +### Fixed Header Comment Lines + +For files with a fixed number of metadata lines at the top, use `comment_lines`: + +```lua +{ + parser = { + comment_lines = 2, -- First 2 lines are always treated as comments + }, +} +``` + +This is useful for files like: + +```csv +Generated: 2024-01-15 +Source: database_export +name,age,city +John,25,NYC +Jane,30,LA +``` + +The first 2 lines will be treated as comments regardless of their content. + ### Command-line Usage ```vim " Enable hash comments :CsvViewEnable comment=# -" Enable C++ style comments +" Enable C++ style comments :CsvViewEnable comment=// " Enable SQL style comments :CsvViewEnable comment=-- +" Treat first N lines as comments +:CsvViewEnable comment_lines=2 + " Multiple comment types (requires Lua configuration) ``` @@ -414,14 +441,14 @@ local jump = require("csvview.jump") -- Precise field navigation jump.field(bufnr, { pos = { row, col }, -- Target position (1-based) - mode = "absolute", -- "absolute" or "relative" + mode = "absolute", -- "absolute" or "relative" anchor = "start", -- "start" or "end" col_wrap = true, -- Wrap at row boundaries }) -- Convenience functions jump.next_field_start(bufnr?) -- Like 'w' motion -jump.prev_field_start(bufnr?) -- Like 'b' motion +jump.prev_field_start(bufnr?) -- Like 'b' motion jump.next_field_end(bufnr?) -- Like 'e' motion jump.prev_field_end(bufnr?) -- Like 'ge' motion ``` @@ -452,4 +479,3 @@ local info = util.get_cursor(bufnr) -- text = "field content" -- } ``` - diff --git a/README.md b/README.md index d9b599e..3ed89b0 100644 --- a/README.md +++ b/README.md @@ -150,6 +150,15 @@ lua require('csvview').setup() -- "//", }, + --- The number of lines at the beginning of the file to treat as comments. + --- Lines from 1 to this number will be treated as comment lines regardless of their content. + --- This is useful for files that have a fixed header/metadata section at the top. + --- You can also specify it on the command line. + --- e.g: + --- :CsvViewEnable comment_lines=2 + --- @type integer? + comment_lines = nil, + --- Maximum lookahead for multi-line fields --- This limits how many lines ahead the parser will look when trying to find --- the closing quote of a multi-line field. Setting this too high may cause diff --git a/lua/csvview/config.lua b/lua/csvview/config.lua index 761eb55..2620735 100644 --- a/lua/csvview/config.lua +++ b/lua/csvview/config.lua @@ -5,6 +5,7 @@ local M = {} ---@field delimiter? CsvView.Options.Parser.Delimiter ---@field quote_char? string ---@field comments? string[] +---@field comment_lines? integer ---@field max_lookahead? integer ---@alias CsvView.Options.Parser.Delimiter string | {ft: table, fallbacks: string[]}| fun(bufnr:integer): string @@ -105,6 +106,15 @@ M.defaults = { -- "//", }, + --- The number of lines at the beginning of the file to treat as comments. + --- Lines from 1 to this number will be treated as comment lines regardless of their content. + --- This is useful for files that have a fixed header/metadata section at the top. + --- You can also specify it on the command line. + --- e.g: + --- :CsvViewEnable comment_lines=2 + --- @type integer? + comment_lines = nil, + --- Maximum lookahead for multi-line fields --- This limits how many lines ahead the parser will look when trying to find --- the closing quote of a multi-line field. Setting this too high may cause diff --git a/lua/csvview/parser.lua b/lua/csvview/parser.lua index 5359138..6fd809e 100644 --- a/lua/csvview/parser.lua +++ b/lua/csvview/parser.lua @@ -139,7 +139,7 @@ end ---@field private _quote_char integer ---@field private _delim_bytes integer[] ---@field private _delim_str string ----@field private _comments string[] +---@field private _is_comment_line fun(lnum:integer, line:string): boolean ---@field private _max_lookahead integer ---@field private _source CsvView.Parser.Source local CsvViewParser = {} @@ -152,46 +152,33 @@ CsvViewParser.__index = CsvViewParser ---@param delimiter string Delimiter string. ---@return CsvView.Parser function CsvViewParser:new(bufnr, opts, quote_char, delimiter) - local obj = setmetatable({}, self) - obj._quote_char = quote_char:byte() - obj._delim_bytes = { delimiter:byte(1, #delimiter) } - obj._delim_str = delimiter - obj._comments = opts.parser.comments - obj._max_lookahead = opts.parser.max_lookahead - obj._source = new_buffer_source(bufnr, 1000) - return obj + return CsvViewParser:new_with_source( + quote_char:byte(), + delimiter, + util.create_is_comment(opts), + opts.parser.max_lookahead, + new_buffer_source(bufnr, 1000) + ) end --- Create a new CsvView.Parser from lines. ---@param quote_char integer Quote character byte. ---@param delimiter string Delimiter string. ----@param comments string[] Comment prefixes. +---@param is_comment fun(lnum:integer, line:string): boolean ---@param max_lookahead integer Maximum number of lines to look ahead for multi-line fields. ---@param source CsvView.Parser.Source Source for getting lines. ---@return CsvView.Parser -function CsvViewParser:new_with_source(quote_char, delimiter, comments, max_lookahead, source) +function CsvViewParser:new_with_source(quote_char, delimiter, is_comment, max_lookahead, source) local obj = setmetatable({}, self) obj._quote_char = quote_char obj._delim_bytes = { delimiter:byte(1, #delimiter) } obj._delim_str = delimiter - obj._comments = comments or {} + obj._is_comment_line = is_comment obj._max_lookahead = max_lookahead obj._source = source return obj end ---- Check if line is a comment ----@param line string ----@return boolean -function CsvViewParser:_is_comment_line(line) - for _, comment in ipairs(self._comments) do - if vim.startswith(line, comment) then - return true - end - end - return false -end - function CsvViewParser:invalidate_cache() if self._source.invalidate then self._source.invalidate() @@ -208,7 +195,7 @@ function CsvViewParser:parse_record(lnum, events) end -- Comment Check - if self:_is_comment_line(line) then + if self._is_comment_line(lnum, line) then events.comment(lnum) return end diff --git a/lua/csvview/sniffer.lua b/lua/csvview/sniffer.lua index bf71a1b..ff80252 100644 --- a/lua/csvview/sniffer.lua +++ b/lua/csvview/sniffer.lua @@ -19,11 +19,11 @@ end ---@param sample_lines string[] Sample lines to use instead of the buffer ---@param delimiter string The delimiter character ---@param quote_char string The quote character ----@param comments string[] Comments to ignores +---@param comment fun(lnum: integer, line: string): boolean Function to determine if a line is a comment ---@param max_lookahead integer Maximum lookahead for parsing ---@return CsvView.Parser parser The parser instance -local function create_parser(sample_lines, delimiter, quote_char, comments, max_lookahead) - return require("csvview.parser"):new_with_source(quote_char:byte(), delimiter, comments, max_lookahead, { +local function create_parser(sample_lines, delimiter, quote_char, comment, max_lookahead) + return require("csvview.parser"):new_with_source(quote_char:byte(), delimiter, comment, max_lookahead, { get_line = function(lnum) return sample_lines[lnum] end, @@ -37,12 +37,12 @@ end ---@param sample_lines string[] Sample lines to analyze ---@param delimiter string The delimiter character ---@param quote_char string The quote character ----@param comments string[] Comments to ignore +---@param comment fun(lnum: integer, line: string): boolean Function to determine if a line is a comment ---@param max_lookahead integer Maximum lookahead for parsing ---@return number score Consistency score (0-1, higher is better) -function M._calculate_consistency_score(sample_lines, delimiter, quote_char, comments, max_lookahead) +function M._calculate_consistency_score(sample_lines, delimiter, quote_char, comment, max_lookahead) local lines_to_check = #sample_lines - local parser = create_parser(sample_lines, delimiter, quote_char, comments, max_lookahead) + local parser = create_parser(sample_lines, delimiter, quote_char, comment, max_lookahead) local field_counts = {} ---@type integer[] local total_fields = 0 @@ -149,16 +149,16 @@ end ---@param sample_lines string[] Sample lines to analyze ---@param delimiters? string[] Possible delimiter characters ---@param quote_char string The quote character to use ----@param comments string[] Comments to ignore +---@param comment fun(lnum: integer, line: string): boolean Function to determine if a line is a comment ---@param max_lookahead integer Maximum lookahead for parsing ---@return string delimiter The detected delimiter character -function M.detect_delimiter(sample_lines, delimiters, quote_char, comments, max_lookahead) +function M.detect_delimiter(sample_lines, delimiters, quote_char, comment, max_lookahead) delimiters = delimiters or DEFAULT_DELIMITERS local delimiter_scores = {} ---@type table -- Store scores for each delimiter for _, delimiter in ipairs(delimiters) do local consistency_score = - M._calculate_consistency_score(sample_lines, delimiter, quote_char, comments, max_lookahead) + M._calculate_consistency_score(sample_lines, delimiter, quote_char, comment, max_lookahead) delimiter_scores[delimiter] = consistency_score end @@ -375,16 +375,16 @@ end ---@param sample_lines string[] Sample lines to analyze ---@param delimiter string The delimiter character ---@param quote_char string The quote character ----@param comments string[] Comments to ignore +---@param comment fun(lnum: integer, line: string): boolean Function to determine if a line is a comment ---@param max_lookahead integer Maximum lookahead for parsing ---@return integer? header_lnum The line number of the header row, if detected -function M.detect_header(sample_lines, delimiter, quote_char, comments, max_lookahead) +function M.detect_header(sample_lines, delimiter, quote_char, comment, max_lookahead) local line_count = #sample_lines if line_count < 2 then return nil end - local parser = create_parser(sample_lines, delimiter, quote_char, comments, max_lookahead) + local parser = create_parser(sample_lines, delimiter, quote_char, comment, max_lookahead) -- Find the first non-comment line as a header candidate local first_valid_lnum ---@type integer? @@ -469,15 +469,15 @@ end --- Detects the delimiter for a buffer by sampling lines ---@param bufnr integer Buffer number to analyze ---@param quote_char string Quote character to use ----@param comments string[] Comments to ignore +---@param comment fun(lnum: integer, line: string): boolean Function to determine if a line is a comment ---@param max_lookahead integer Maximum lookahead for parsing ---@param candidates string[]? Possible delimiters to check ---@param n_samples integer? Number of lines to sample ---@return string delimiter The detected delimiter character -function M.buf_detect_delimiter(bufnr, quote_char, comments, max_lookahead, candidates, n_samples) +function M.buf_detect_delimiter(bufnr, quote_char, comment, max_lookahead, candidates, n_samples) n_samples = n_samples or DEFAULT_BUF_N_SAMPLES local sample_lines = vim.api.nvim_buf_get_lines(bufnr, 0, n_samples, false) - return M.detect_delimiter(sample_lines, candidates, quote_char, comments, max_lookahead) + return M.detect_delimiter(sample_lines, candidates, quote_char, comment, max_lookahead) end --- Detects the quote character for a buffer by sampling lines @@ -495,14 +495,14 @@ end ---@param bufnr integer Buffer number to analyze ---@param delimiter string The delimiter character to use ---@param quote_char string The quote character to use ----@param comments string[] Comments to ignore +---@param comment fun(lnum: integer, line: string): boolean Function to determine if a line is a comment ---@param max_lookahead integer Maximum lookahead for parsing ---@param n_samples integer? Number of lines to sample ---@return integer? header_lnum The line number of the header row, if detected -function M.buf_detect_header(bufnr, delimiter, quote_char, comments, max_lookahead, n_samples) +function M.buf_detect_header(bufnr, delimiter, quote_char, comment, max_lookahead, n_samples) n_samples = n_samples or DEFAULT_BUF_N_SAMPLES local sample_lines = vim.api.nvim_buf_get_lines(bufnr, 0, n_samples, false) - return M.detect_header(sample_lines, delimiter, quote_char, comments, max_lookahead) + return M.detect_header(sample_lines, delimiter, quote_char, comment, max_lookahead) end return M diff --git a/lua/csvview/util.lua b/lua/csvview/util.lua index c393e1c..160afb4 100644 --- a/lua/csvview/util.lua +++ b/lua/csvview/util.lua @@ -253,6 +253,35 @@ M.print_structured_error = vim.schedule_wrap(function(header, err) }) end) +--- Create a comment detection function based on parser options. +--- +--- The returned function checks if a line is a comment by: +--- 1. Line number check: If `opts.parser.comment_lines` is set, any line with +--- lnum <= comment_lines is considered a comment (useful for header rows). +--- 2. Prefix check: If the line starts with any prefix in `opts.parser.comments`, +--- it is considered a comment (e.g., "#", "//"). +--- +---@param opts CsvView.InternalOptions +---@return fun(lnum: integer, line: string): boolean +function M.create_is_comment(opts) + local comment_lines = opts.parser.comment_lines + local comments = opts.parser.comments + + return function(lnum, line) + -- check comment section + if comment_lines and lnum <= comment_lines then + return true + end + + for _, comment in ipairs(comments) do + if vim.startswith(line, comment) then + return true + end + end + return false + end +end + --- Resolve delimiter character ---@param bufnr integer ---@param opts CsvView.InternalOptions @@ -279,7 +308,7 @@ function M.resolve_delimiter(bufnr, opts, quote_char) char = require("csvview.sniffer").buf_detect_delimiter( bufnr, quote_char, - opts.parser.comments, + M.create_is_comment(opts), opts.parser.max_lookahead, delim.fallbacks ) @@ -326,7 +355,7 @@ function M.resolve_header_lnum(bufnr, opts, delimiter, quote_char) bufnr, delimiter, quote_char, - opts.parser.comments, + M.create_is_comment(opts), opts.parser.max_lookahead ) else diff --git a/plugin/csvview.lua b/plugin/csvview.lua index 74b3b9b..900cb5d 100644 --- a/plugin/csvview.lua +++ b/plugin/csvview.lua @@ -26,6 +26,14 @@ local cmdline = Cmdline:new({ options.parser.comments = { value } end, }, + { + name = "comment_lines", + ---@param options CsvView.Options + ---@param value string + set = function(options, value) + options.parser.comment_lines = tonumber(value) + end, + }, { name = "display_mode", ---@param options CsvView.Options diff --git a/tests/parser_spec.lua b/tests/parser_spec.lua index 927e555..f14e0d9 100644 --- a/tests/parser_spec.lua +++ b/tests/parser_spec.lua @@ -268,6 +268,83 @@ local cases = { }, }, }, + { + it = "should treat first N lines as comments with comment_lines option", + opts = { parser = { comment_lines = 2, comments = {} } }, + lines = { + "File: test.csv", + "Date: 2024-01-01", + "name,age,city", + "John,25,New York", + }, + expected = { + { + is_comment = true, + fields = {}, + }, + { + is_comment = true, + fields = {}, + }, + { + is_comment = false, + fields = { + { start_pos = 1, text = "name" }, + { start_pos = 6, text = "age" }, + { start_pos = 10, text = "city" }, + }, + }, + { + is_comment = false, + fields = { + { start_pos = 1, text = "John" }, + { start_pos = 6, text = "25" }, + { start_pos = 9, text = "New York" }, + }, + }, + }, + }, + { + it = "should combine comment_lines and comment prefix detection", + opts = { parser = { comment_lines = 2, comments = { "#" } } }, + lines = { + "File: test.csv", + "Date: 2024-01-01", + "# This is also a comment", + "name,age,city", + "John,25,New York", + }, + expected = { + { + is_comment = true, + fields = {}, + }, + { + is_comment = true, + fields = {}, + }, + { + is_comment = true, + fields = {}, + }, + { + is_comment = false, + fields = { + { start_pos = 1, text = "name" }, + { start_pos = 6, text = "age" }, + { start_pos = 10, text = "city" }, + }, + }, + { + is_comment = false, + fields = { + { start_pos = 1, text = "John" }, + { start_pos = 6, text = "25" }, + { start_pos = 9, text = "New York" }, + }, + }, + }, + }, { it = "should parse multi-line quoted fields", lines = { diff --git a/tests/sniffer_spec.lua b/tests/sniffer_spec.lua index 8b49ecc..21920ec 100644 --- a/tests/sniffer_spec.lua +++ b/tests/sniffer_spec.lua @@ -1,12 +1,14 @@ local sniffer = require("csvview.sniffer") local testutil = require("tests.testutil") +local util = require("csvview.util") describe("csvview.sniffer", function() local opts = { - comments = { "#" }, max_lookahead = 50, } + local is_comment = util.create_is_comment({ parser = { comments = { "#" } } }) + describe("detect_delimiter", function() it("should detect comma delimiter", function() local lines = { @@ -15,7 +17,7 @@ describe("csvview.sniffer", function() "Jane,30,Los Angeles", } - local delimiter = sniffer.detect_delimiter(lines, { ",", "\t", ";", "|" }, '"', opts.comments, opts.max_lookahead) + local delimiter = sniffer.detect_delimiter(lines, { ",", "\t", ";", "|" }, '"', is_comment, opts.max_lookahead) assert.equals(",", delimiter) end) @@ -26,7 +28,7 @@ describe("csvview.sniffer", function() "Jane\t30\tLos Angeles", } - local delimiter = sniffer.detect_delimiter(lines, { ",", "\t", ";", "|" }, '"', opts.comments, opts.max_lookahead) + local delimiter = sniffer.detect_delimiter(lines, { ",", "\t", ";", "|" }, '"', is_comment, opts.max_lookahead) assert.equals("\t", delimiter) end) @@ -37,7 +39,7 @@ describe("csvview.sniffer", function() "Jane;30;Los Angeles", } - local delimiter = sniffer.detect_delimiter(lines, { ",", "\t", ";", "|" }, '"', opts.comments, opts.max_lookahead) + local delimiter = sniffer.detect_delimiter(lines, { ",", "\t", ";", "|" }, '"', is_comment, opts.max_lookahead) assert.equals(";", delimiter) end) @@ -48,7 +50,7 @@ describe("csvview.sniffer", function() "Jane|30|Los Angeles", } - local delimiter = sniffer.detect_delimiter(lines, { ",", "\t", ";", "|" }, '"', opts.comments, opts.max_lookahead) + local delimiter = sniffer.detect_delimiter(lines, { ",", "\t", ";", "|" }, '"', is_comment, opts.max_lookahead) assert.equals("|", delimiter) end) @@ -59,7 +61,7 @@ describe("csvview.sniffer", function() 'Jane,30,"Los Angeles, CA"', } - local delimiter = sniffer.detect_delimiter(lines, { ",", "\t", ";", "|" }, '"', opts.comments, opts.max_lookahead) + local delimiter = sniffer.detect_delimiter(lines, { ",", "\t", ";", "|" }, '"', is_comment, opts.max_lookahead) assert.equals(",", delimiter) end) @@ -71,7 +73,7 @@ describe("csvview.sniffer", function() "Bob,35;Chicago", } - local delimiter = sniffer.detect_delimiter(lines, { ",", "\t", ";", "|" }, '"', opts.comments, opts.max_lookahead) + local delimiter = sniffer.detect_delimiter(lines, { ",", "\t", ";", "|" }, '"', is_comment, opts.max_lookahead) -- Should prefer comma over semicolon due to better consistency assert.equals(",", delimiter) end) @@ -83,12 +85,12 @@ describe("csvview.sniffer", function() "Jane:30:Los Angeles", } - local delimiter = sniffer.detect_delimiter(lines, { ",", ":" }, '"', opts.comments, opts.max_lookahead) + local delimiter = sniffer.detect_delimiter(lines, { ",", ":" }, '"', is_comment, opts.max_lookahead) assert.equals(":", delimiter) end) it("should return default delimiter for empty buffer", function() - local delimiter = sniffer.detect_delimiter({}, { ",", "\t", ";", "|" }, '"', opts.comments, opts.max_lookahead) + local delimiter = sniffer.detect_delimiter({}, { ",", "\t", ";", "|" }, '"', is_comment, opts.max_lookahead) assert.equals(",", delimiter) end) @@ -97,7 +99,7 @@ describe("csvview.sniffer", function() { "single line" }, { ",", "\t", ";", "|" }, '"', - opts.comments, + is_comment, opts.max_lookahead ) assert.equals(",", delimiter) @@ -159,10 +161,51 @@ describe("csvview.sniffer", function() "Bob,35,70000", } - local header_lnum = sniffer.detect_header(lines, ",", '"', opts.comments, opts.max_lookahead) + local header_lnum = sniffer.detect_header(lines, ",", '"', is_comment, opts.max_lookahead) assert.equals(1, header_lnum) end) + it("should detect header with comment_lines option", function() + local lines = { + "File: data.csv", + "Created: 2024-01-01", + "name,age,salary", + "John,25,50000", + "Jane,30,60000", + } + + local is_comment_with_lines = util.create_is_comment({ + parser = { + comments = {}, + comment_lines = 2, + }, + }) + + local header_lnum = sniffer.detect_header(lines, ",", '"', is_comment_with_lines, opts.max_lookahead) + assert.equals(3, header_lnum) + end) + + it("should detect header with combined comment_lines and comment prefix", function() + local lines = { + "Metadata line 1", + "Metadata line 2", + "# Additional comment", + "name,age,salary", + "John,25,50000", + "Jane,30,60000", + } + + local is_comment_combined = util.create_is_comment({ + parser = { + comments = { "#" }, + comment_lines = 2, + }, + }) + + local header_lnum = sniffer.detect_header(lines, ",", '"', is_comment_combined, opts.max_lookahead) + assert.equals(4, header_lnum) + end) + it("should not detect header when first row is numeric", function() local lines = { "1,25,50000", @@ -170,7 +213,7 @@ describe("csvview.sniffer", function() "3,35,70000", } - local header_lnum = sniffer.detect_header(lines, ",", '"', opts.comments, opts.max_lookahead) + local header_lnum = sniffer.detect_header(lines, ",", '"', is_comment, opts.max_lookahead) assert.is_nil(header_lnum) end) @@ -182,7 +225,7 @@ describe("csvview.sniffer", function() "3,Bob,true", } - local header_lnum = sniffer.detect_header(lines, ",", '"', opts.comments, opts.max_lookahead) + local header_lnum = sniffer.detect_header(lines, ",", '"', is_comment, opts.max_lookahead) assert.equals(1, header_lnum) end) @@ -195,7 +238,7 @@ describe("csvview.sniffer", function() "3,Bob,true", } - local header_lnum = sniffer.detect_header(lines, ",", '"', opts.comments, opts.max_lookahead) + local header_lnum = sniffer.detect_header(lines, ",", '"', is_comment, opts.max_lookahead) assert.equals(2, header_lnum) end) @@ -207,7 +250,7 @@ describe("csvview.sniffer", function() "Bob,1992-06-08,11:45:00", } - local header_lnum = sniffer.detect_header(lines, ",", '"', opts.comments, opts.max_lookahead) + local header_lnum = sniffer.detect_header(lines, ",", '"', is_comment, opts.max_lookahead) assert.equals(1, header_lnum) end) @@ -220,7 +263,7 @@ describe("csvview.sniffer", function() "shoes,sold,medium", } - local header_lnum = sniffer.detect_header(lines, ",", '"', opts.comments, opts.max_lookahead) + local header_lnum = sniffer.detect_header(lines, ",", '"', is_comment, opts.max_lookahead) assert.is_nil(header_lnum) end) @@ -232,7 +275,7 @@ describe("csvview.sniffer", function() "Bob,1,y", } - local header_lnum = sniffer.detect_header(lines, ",", '"', opts.comments, opts.max_lookahead) + local header_lnum = sniffer.detect_header(lines, ",", '"', is_comment, opts.max_lookahead) assert.equals(1, header_lnum) end) @@ -244,17 +287,17 @@ describe("csvview.sniffer", function() "Tool,45.00,0.09", } - local header_lnum = sniffer.detect_header(lines, ",", '"', opts.comments, opts.max_lookahead) + local header_lnum = sniffer.detect_header(lines, ",", '"', is_comment, opts.max_lookahead) assert.equals(1, header_lnum) end) it("should return nil for single line", function() - local header_lnum = sniffer.detect_header({ "name,age,city" }, ",", '"', opts.comments, opts.max_lookahead) + local header_lnum = sniffer.detect_header({ "name,age,city" }, ",", '"', is_comment, opts.max_lookahead) assert.is_nil(header_lnum) end) it("should return nil for empty buffer", function() - local header_lnum = sniffer.detect_header({}, ",", '"', opts.comments, opts.max_lookahead) + local header_lnum = sniffer.detect_header({}, ",", '"', is_comment, opts.max_lookahead) assert.is_nil(header_lnum) end) @@ -267,7 +310,7 @@ describe("csvview.sniffer", function() "Alice,28,Boston", } - local header_lnum = sniffer.detect_header(lines, ",", '"', opts.comments, opts.max_lookahead) + local header_lnum = sniffer.detect_header(lines, ",", '"', is_comment, opts.max_lookahead) assert.equals(1, header_lnum) end) @@ -279,7 +322,7 @@ describe("csvview.sniffer", function() "15,16,17,18,19,20,21", } - local header_lnum = sniffer.detect_header(lines, ",", '"', opts.comments, opts.max_lookahead) + local header_lnum = sniffer.detect_header(lines, ",", '"', is_comment, opts.max_lookahead) assert.equals(1, header_lnum) end) @@ -291,7 +334,7 @@ describe("csvview.sniffer", function() '"Widget C",39.99,true', } - local header_lnum = sniffer.detect_header(lines, ",", '"', opts.comments, opts.max_lookahead) + local header_lnum = sniffer.detect_header(lines, ",", '"', is_comment, opts.max_lookahead) assert.equals(1, header_lnum) end) end) @@ -307,8 +350,8 @@ describe("csvview.sniffer", function() local quote_char = sniffer.detect_quote_char(lines, { '"', "'" }) local delimiter = - sniffer.detect_delimiter(lines, { ",", "\t", ";", "|" }, quote_char, opts.comments, opts.max_lookahead) - local header_lnum = sniffer.detect_header(lines, delimiter, quote_char, opts.comments, opts.max_lookahead) + sniffer.detect_delimiter(lines, { ",", "\t", ";", "|" }, quote_char, is_comment, opts.max_lookahead) + local header_lnum = sniffer.detect_header(lines, delimiter, quote_char, is_comment, opts.max_lookahead) assert.equals(",", delimiter) assert.equals('"', quote_char) @@ -325,8 +368,8 @@ describe("csvview.sniffer", function() local quote_char = sniffer.detect_quote_char(lines, { '"', "'" }) local delimiter = - sniffer.detect_delimiter(lines, { ",", "\t", ";", "|" }, quote_char, opts.comments, opts.max_lookahead) - local header_lnum = sniffer.detect_header(lines, delimiter, quote_char, opts.comments, opts.max_lookahead) + sniffer.detect_delimiter(lines, { ",", "\t", ";", "|" }, quote_char, is_comment, opts.max_lookahead) + local header_lnum = sniffer.detect_header(lines, delimiter, quote_char, is_comment, opts.max_lookahead) assert.equals("\t", delimiter) assert.equals('"', quote_char) @@ -343,8 +386,8 @@ describe("csvview.sniffer", function() local quote_char = sniffer.detect_quote_char(lines, { '"', "'" }) local delimiter = - sniffer.detect_delimiter(lines, { ",", "\t", ";", "|" }, quote_char, opts.comments, opts.max_lookahead) - local header_lnum = sniffer.detect_header(lines, delimiter, quote_char, opts.comments, opts.max_lookahead) + sniffer.detect_delimiter(lines, { ",", "\t", ";", "|" }, quote_char, is_comment, opts.max_lookahead) + local header_lnum = sniffer.detect_header(lines, delimiter, quote_char, is_comment, opts.max_lookahead) assert.equals(",", delimiter) assert.equals('"', quote_char) @@ -358,8 +401,8 @@ describe("csvview.sniffer", function() local quote_char = sniffer.detect_quote_char(lines, { '"', "'" }) local delimiter = - sniffer.detect_delimiter(lines, { ",", "\t", ";", "|" }, quote_char, opts.comments, opts.max_lookahead) - local header_lnum = sniffer.detect_header(lines, delimiter, quote_char, opts.comments, opts.max_lookahead) + sniffer.detect_delimiter(lines, { ",", "\t", ";", "|" }, quote_char, is_comment, opts.max_lookahead) + local header_lnum = sniffer.detect_header(lines, delimiter, quote_char, is_comment, opts.max_lookahead) assert.equals(",", delimiter) assert.equals('"', quote_char) @@ -371,8 +414,8 @@ describe("csvview.sniffer", function() local quote_char = sniffer.detect_quote_char(lines, { '"', "'" }) local delimiter = - sniffer.detect_delimiter(lines, { ",", "\t", ";", "|" }, quote_char, opts.comments, opts.max_lookahead) - local header_lnum = sniffer.detect_header(lines, delimiter, quote_char, opts.comments, opts.max_lookahead) + sniffer.detect_delimiter(lines, { ",", "\t", ";", "|" }, quote_char, is_comment, opts.max_lookahead) + local header_lnum = sniffer.detect_header(lines, delimiter, quote_char, is_comment, opts.max_lookahead) assert.equals("\t", delimiter) assert.equals('"', quote_char) @@ -384,8 +427,8 @@ describe("csvview.sniffer", function() local quote_char = sniffer.detect_quote_char(lines, { '"', "'" }) local delimiter = - sniffer.detect_delimiter(lines, { ",", "\t", ";", "|" }, quote_char, opts.comments, opts.max_lookahead) - local header_lnum = sniffer.detect_header(lines, delimiter, quote_char, opts.comments, opts.max_lookahead) + sniffer.detect_delimiter(lines, { ",", "\t", ";", "|" }, quote_char, is_comment, opts.max_lookahead) + local header_lnum = sniffer.detect_header(lines, delimiter, quote_char, is_comment, opts.max_lookahead) assert.equals(",", delimiter) assert.equals('"', quote_char)