From 0fd21fab2eba8eb15ec07313a121f112f84d3dbe Mon Sep 17 00:00:00 2001 From: Ethan Rooke Date: Tue, 25 Jan 2022 18:38:07 -0600 Subject: [PATCH 1/7] Add file opening functionality This is a real rough first draft at opening files specified in the bibtex entry. To call it one runs `:Telescope bibtex`. The selected entry can be opened by using ``. ``` require('telescope').setup { extensions = { bibtex = { reader = { 'evince' }, } } } ``` would open the file in evince --- lua/telescope/_extensions/bibtex.lua | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/lua/telescope/_extensions/bibtex.lua b/lua/telescope/_extensions/bibtex.lua index 8fb2f67..7f6fbc3 100644 --- a/lua/telescope/_extensions/bibtex.lua +++ b/lua/telescope/_extensions/bibtex.lua @@ -12,6 +12,7 @@ local previewers = require('telescope.previewers') local conf = require('telescope.config').values local scan = require('plenary.scandir') local path = require('plenary.path') +local job = require('plenary.job') local putils = require('telescope.previewers.utils') local loop = vim.loop @@ -28,6 +29,7 @@ local user_files = {} local files_initialized = false local files = {} local search_keys = { 'author', 'year', 'title' } +local reader = nil local function table_contains(table, element) for _, value in pairs(table) do @@ -187,6 +189,7 @@ local function bibtex_picker(opts) attach_mappings = function(_, map) actions.select_default:replace(key_append(format_string)) map("i", "", entry_append) + map("i", "", open_file) return true end, }):find() @@ -216,8 +219,29 @@ entry_append = function(prompt_bufnr) end end +open_file = function(prompt_bufnr) + local entry = action_state.get_selected_entry().id.content + for _, line in pairs(entry) do + local match_base = '%f[%w]file' + local s = line:match(match_base .. '%s*=%s*%b{}') or line:match(match_base .. '%s*=%s*%b""') or line:match(match_base .. '%s*=%s*%d+') + if s ~= nil then + s = s:match('%b{}') or s:match('%b""') or s:match('%d+') + s = s:gsub('["{}\n]', ""):gsub('%s%s+', ' ') + s = s:match('%b::') + s = s:gsub(':', '') + job:new({ + command = reader[1], + args = { s }, + }):start() + break + end + end + actions.close(prompt_bufnr) +end + return telescope.register_extension { setup = function(ext_config) + reader = ext_config.reader or reader depth = ext_config.depth or depth local custom_formats = ext_config.custom_formats or {} for _, format in pairs(custom_formats) do From 852041f9390232cb1e837a6e1e8af70791dbca94 Mon Sep 17 00:00:00 2001 From: Ethan Rooke Date: Wed, 26 Jan 2022 10:25:49 -0600 Subject: [PATCH 2/7] Spawn the reader in a detached state --- lua/telescope/_extensions/bibtex.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/lua/telescope/_extensions/bibtex.lua b/lua/telescope/_extensions/bibtex.lua index 7f6fbc3..a94f0d7 100644 --- a/lua/telescope/_extensions/bibtex.lua +++ b/lua/telescope/_extensions/bibtex.lua @@ -232,6 +232,7 @@ open_file = function(prompt_bufnr) job:new({ command = reader[1], args = { s }, + detached = true, }):start() break end From 65bcca100b8a6eb535a32b4827887a7f47cb45ba Mon Sep 17 00:00:00 2001 From: Ethan Rooke Date: Wed, 26 Jan 2022 12:30:28 -0600 Subject: [PATCH 3/7] Allow for multiple readers based on the file type Configuration now looks like ``` require('telescope').setup { extensions = { bibtex = { reader = { djvu = 'evince', pdf = 'zathura' }, } } } ``` This would open djvu files in evince and pdf files in zathura --- lua/telescope/_extensions/bibtex.lua | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/lua/telescope/_extensions/bibtex.lua b/lua/telescope/_extensions/bibtex.lua index a94f0d7..4cb7726 100644 --- a/lua/telescope/_extensions/bibtex.lua +++ b/lua/telescope/_extensions/bibtex.lua @@ -219,6 +219,16 @@ entry_append = function(prompt_bufnr) end end + +-- Split a string using the seperator +local split = function(str, sep) + local result={} + for item in string.gmatch(str, "([^"..sep.."]+)") do + table.insert(result, item) + end + return result +end + open_file = function(prompt_bufnr) local entry = action_state.get_selected_entry().id.content for _, line in pairs(entry) do @@ -227,11 +237,11 @@ open_file = function(prompt_bufnr) if s ~= nil then s = s:match('%b{}') or s:match('%b""') or s:match('%d+') s = s:gsub('["{}\n]', ""):gsub('%s%s+', ' ') - s = s:match('%b::') - s = s:gsub(':', '') + file = split(s, ":") + extension = string.gsub(file[3], '%s+', '') job:new({ - command = reader[1], - args = { s }, + command = reader[extension], + args = { file[2] }, detached = true, }):start() break From 2b63aec6f4cb5dfdf48e68cb38c72f96f1eb6e79 Mon Sep 17 00:00:00 2001 From: Ethan Rooke Date: Wed, 26 Jan 2022 21:53:08 -0600 Subject: [PATCH 4/7] Parse file lists more thoroughly Implemented a basic parser instead of using luas string substitution to deal with file lists. In theory we can now deal with : and ; being in file names. It now parses two styles of entries: - `{/path/to/file}` - `{name:/path/to/file:ext}` and can do a list of entires with mixed styles. Currently the first one is opened instead of actually dealing with the list of entries. --- lua/telescope/_extensions/bib_parsers.lua | 102 ++++++++++++++++++++++ lua/telescope/_extensions/bibtex.lua | 22 ++--- 2 files changed, 110 insertions(+), 14 deletions(-) create mode 100644 lua/telescope/_extensions/bib_parsers.lua diff --git a/lua/telescope/_extensions/bib_parsers.lua b/lua/telescope/_extensions/bib_parsers.lua new file mode 100644 index 0000000..c727ea2 --- /dev/null +++ b/lua/telescope/_extensions/bib_parsers.lua @@ -0,0 +1,102 @@ +local State = { + name = 1, + path = 2, + ext = 3, + done = 4 +} + +local Commit = { + name = 1, + path = 2, + ext = 3, +} + +-- P for parser + +P = {} + +P.file_list = function(str) + result = {} + table.insert(result, {}) + start = 1 + index = 1 + for c in str:gmatch"." do + + if state == nil then + if c == "{" then + state = State.name + goto continue + end + return nil + end + + skip = false + commit = nil + + if state == State.name then + if c == "}" then + state = State.done + commit = Commit.path + elseif c == ";" then + commit = Commit.path + elseif c == ":" then + state = State.path + commit = Commit.name + else + skip = (c == "\\") + end + + elseif state == State.path then + if c == ":" then + state = State.ext + commit = Commit.path + elseif c == "}" or c == ";" then + state = State.err + else + skip = ( c == "\\" ) + end + + elseif state == State.ext then + if c == ";" then + state = State.name + commit = Commit.ext + elseif c == "}" then + state = State.done + commit = Commit.ext + end + + end + + if commit == nil then + goto continue + end + + term = result[#result] + word = str:sub(start+1, index-1) + start = index + + if commit == Commit.name then + term.name = word + + elseif commit == Commit.path then + term.path = word + if term.name == nil then + table.insert(result, {}) + end + + elseif commit == Commit.ext then + term.ext = word + table.insert(result, {}) + end + + if state == State.done then + return result + end + + ::continue:: + + index = index + 1 + end +end + +return P diff --git a/lua/telescope/_extensions/bibtex.lua b/lua/telescope/_extensions/bibtex.lua index 4cb7726..ed4089c 100644 --- a/lua/telescope/_extensions/bibtex.lua +++ b/lua/telescope/_extensions/bibtex.lua @@ -15,6 +15,7 @@ local path = require('plenary.path') local job = require('plenary.job') local putils = require('telescope.previewers.utils') local loop = vim.loop +local parser = require('telescope._extensions.bib_parsers') local depth = 1 local formats = {} @@ -219,16 +220,6 @@ entry_append = function(prompt_bufnr) end end - --- Split a string using the seperator -local split = function(str, sep) - local result={} - for item in string.gmatch(str, "([^"..sep.."]+)") do - table.insert(result, item) - end - return result -end - open_file = function(prompt_bufnr) local entry = action_state.get_selected_entry().id.content for _, line in pairs(entry) do @@ -236,12 +227,15 @@ open_file = function(prompt_bufnr) local s = line:match(match_base .. '%s*=%s*%b{}') or line:match(match_base .. '%s*=%s*%b""') or line:match(match_base .. '%s*=%s*%d+') if s ~= nil then s = s:match('%b{}') or s:match('%b""') or s:match('%d+') - s = s:gsub('["{}\n]', ""):gsub('%s%s+', ' ') - file = split(s, ":") - extension = string.gsub(file[3], '%s+', '') + files = parser.file_list(s) + if #files > 1 then + print("TODO deal with multiple entries") + end + file = files[1] + extension = file.extension or "pdf" job:new({ command = reader[extension], - args = { file[2] }, + args = { file.path }, detached = true, }):start() break From 977f867d6eb860cc66ce08f2845c31761ba35b3a Mon Sep 17 00:00:00 2001 From: Ethan Rooke Date: Thu, 27 Jan 2022 09:40:25 -0600 Subject: [PATCH 5/7] Use xdg-open as default reader --- lua/telescope/_extensions/bibtex.lua | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/lua/telescope/_extensions/bibtex.lua b/lua/telescope/_extensions/bibtex.lua index ed4089c..66e0e2e 100644 --- a/lua/telescope/_extensions/bibtex.lua +++ b/lua/telescope/_extensions/bibtex.lua @@ -30,7 +30,7 @@ local user_files = {} local files_initialized = false local files = {} local search_keys = { 'author', 'year', 'title' } -local reader = nil +local reader = {} local function table_contains(table, element) for _, value in pairs(table) do @@ -232,9 +232,8 @@ open_file = function(prompt_bufnr) print("TODO deal with multiple entries") end file = files[1] - extension = file.extension or "pdf" job:new({ - command = reader[extension], + command = reader[file.extension] or "xdg-open", args = { file.path }, detached = true, }):start() From 6720fb10a126c12970c0bfef7ab5dc782e3add0f Mon Sep 17 00:00:00 2001 From: Ethan Rooke Date: Thu, 27 Jan 2022 10:23:10 -0600 Subject: [PATCH 6/7] bugfix: parser only worked once The parser remembered its state between invocations which caused it to fail to parse a second time. Declared variables as local to fix this problem. --- lua/telescope/_extensions/bib_parsers.lua | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/lua/telescope/_extensions/bib_parsers.lua b/lua/telescope/_extensions/bib_parsers.lua index c727ea2..164f309 100644 --- a/lua/telescope/_extensions/bib_parsers.lua +++ b/lua/telescope/_extensions/bib_parsers.lua @@ -16,10 +16,11 @@ local Commit = { P = {} P.file_list = function(str) - result = {} + local result = {} table.insert(result, {}) - start = 1 - index = 1 + local start = 1 + local index = 1 + local state = nil for c in str:gmatch"." do if state == nil then From 6ba6d01954400aeef41041760bff11286cb2fad8 Mon Sep 17 00:00:00 2001 From: Ethan Rooke Date: Thu, 27 Jan 2022 10:26:41 -0600 Subject: [PATCH 7/7] bugfix: parser returned too many items The parser always appended a single empty item to the end of every parse. This has been fixed. --- lua/telescope/_extensions/bib_parsers.lua | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/lua/telescope/_extensions/bib_parsers.lua b/lua/telescope/_extensions/bib_parsers.lua index 164f309..3656b15 100644 --- a/lua/telescope/_extensions/bib_parsers.lua +++ b/lua/telescope/_extensions/bib_parsers.lua @@ -81,13 +81,17 @@ P.file_list = function(str) elseif commit == Commit.path then term.path = word - if term.name == nil then + + if term.name == nil and state ~= State.done then table.insert(result, {}) end elseif commit == Commit.ext then term.ext = word - table.insert(result, {}) + + if state ~= State.done then + table.insert(result, {}) + end end if state == State.done then