diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..ae7da07 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "wiki"] + path = wiki + url = https://github.com/renerocksai/telekasten.nvim.wiki.git diff --git a/README.md b/README.md index 14b973f..c628c1e 100644 --- a/README.md +++ b/README.md @@ -320,6 +320,8 @@ require('telekasten').setup({ -- except for notes/with/subdirs/in/title. new_note_location = "smart", + -- should all links be updated when a file is renamed + rename_update_links = true, }) END ``` @@ -359,6 +361,7 @@ END | | - `#tag` (default) | | | | - `:tag:` | | | | - `yaml-bare` | | +| `rename_update_links` | update links when a file is renamed | true | | | see [2.1 Tag notation](#24-tag-notation)| | | `command_palette_theme` | theme (layout) of the command palette| ivy | | | - `ivy` (default): bottom panel overlay | | @@ -484,6 +487,7 @@ the list for a more detailed description: - `insert_img_link` : Browse images / media files and insert a link to the selected one - `preview_img` : preview image under the cursor - `browse_media` : Browse images / media files +- `rename_note` : Rename current note and update the links pointing to it The Telekasten command supports sub-command completion, in my case by pressing TAB. @@ -579,6 +583,7 @@ The plugin defines the following functions: - `setup(opts)`: used for configuring paths, file extension, etc. - `panel()` : brings up the command palette - `show_tags()` : brings up the tag list. From there you can select a tag to search for tagged notes - or yank or insert the tag +- `rename_note()` : rename the current note and update the links pointing to it To use one of the functions above, just run them with the `:lua ...` command. @@ -830,6 +835,7 @@ nnoremap zp :lua require('telekasten').preview_img() nnoremap zm :lua require('telekasten').browse_media() nnoremap za :lua require('telekasten').show_tags() nnoremap # :lua require('telekasten').show_tags() +nnoremap zr :lua require('telekasten').rename_note() " on hesitation, bring up the panel nnoremap z :lua require('telekasten').panel() diff --git a/doc/telekasten.txt b/doc/telekasten.txt index 1ed71f0..3f34ff4 100644 --- a/doc/telekasten.txt +++ b/doc/telekasten.txt @@ -316,6 +316,12 @@ telekasten.setup({opts}) Default: `smart` + *telekasten.settings.rename_update_links* + rename_update_links:~ + If `true`, telekasten will automatically update the links after a file + has been renamed. + + Default: `true` *telekasten.calendar_opts* ----------------------------------- Valid keys for {opts.calendar_opts} diff --git a/lua/telekasten.lua b/lua/telekasten.lua index 52bbf5d..9c06fe6 100644 --- a/lua/telekasten.lua +++ b/lua/telekasten.lua @@ -124,6 +124,9 @@ M.Cfg = { -- present or else in home -- except for notes/with/subdirs/in/title. new_note_location = "smart", + + -- should all links be updated when a file is renamed + rename_update_links = true, } local function file_exists(fname) @@ -205,6 +208,67 @@ local function make_config_path_absolute(path) ret = M.Cfg.home .. "/" .. path end return ret + +-- sanitize strings +local escape_chars = function(string) + return string.gsub(string, "[%(|%)|\\|%[|%]|%-|%{%}|%?|%+|%*|%^|%$|%/]", { + ["\\"] = "\\\\", + ["-"] = "\\-", + ["("] = "\\(", + [")"] = "\\)", + ["["] = "\\[", + ["]"] = "\\]", + ["{"] = "\\{", + ["}"] = "\\}", + ["?"] = "\\?", + ["+"] = "\\+", + ["*"] = "\\*", + ["^"] = "\\^", + ["$"] = "\\$", + }) +end + +local function recursive_substitution(dir, old, new) + if not global_dir_check() then + return + end + + if vim.fn.executable("sed") == 0 then + vim.api.nvim_err_write("Sed not installed!\n") + return + end + + old = escape_chars(old) + new = escape_chars(new) + + local sedcommand = "sed -i" + if vim.fn.has("mac") == 1 then + sedcommand = "sed -i ''" + end + + local replace_cmd = "rg -l -t markdown '" + .. old + .. "' " + .. dir + .. " | xargs " + .. sedcommand + .. " 's|" + .. old + .. "|" + .. new + .. "|g' >/dev/null 2>&1" + os.execute(replace_cmd) +end + +local function save_all_tk_buffers() + for i = 1, vim.fn.bufnr("$") do + if + vim.fn.getbufvar(i, "&filetype") == "telekasten" + and vim.fn.getbufvar(i, "&mod") == 1 + then + vim.cmd(i .. "bufdo w") + end + end end -- ---------------------------------------------------------------------------- @@ -1407,6 +1471,76 @@ local function YankLink() print("yanked " .. title) end +-- +-- RenameNote: +-- ----------- +-- +-- Prompt for new note title, rename the note and update all links. +-- +local function RenameNote() + local oldfile = Pinfo:new({ filepath = vim.fn.expand("%:p"), M.Cfg }) + + local newname = vim.fn.input("New name: ") + newname = newname:gsub("[" .. M.Cfg.extension .. "]+$", "") + local newpath = newname:match("(.*/)") or "" + newpath = M.Cfg.home .. "/" .. newpath + + -- If no subdir specified, place the new note in the same place as old note + if + M.Cfg.subdirs_in_links == true + and newpath == M.Cfg.home .. "/" + and oldfile.sub_dir ~= "" + then + newname = oldfile.sub_dir .. "/" .. newname + end + + local fname = M.Cfg.home .. "/" .. newname .. M.Cfg.extension + local fexists = file_exists(fname) + if fexists then + print_error("File alreay exists. Renaming abandonned") + return + end + + -- Savas newfile, delete buffer of old one and remove old file + if newname ~= "" and newname ~= oldfile.title then + if not (check_dir_and_ask(newpath, "Renamed file")) then + return + end + + vim.cmd("saveas " .. M.Cfg.home .. "/" .. newname .. M.Cfg.extension) + vim.cmd("bdelete " .. oldfile.title .. M.Cfg.extension) + os.execute( + "rm " .. M.Cfg.home .. "/" .. oldfile.title .. M.Cfg.extension + ) + end + + if M.Cfg.rename_update_links == true then + -- Only look for the first part of the link, so we do not touch to #heading or #^paragraph + -- Should use regex instead to ensure it is a proper link + local oldlink = "[[" .. oldfile.title + local newlink = "[[" .. newname + + -- Save open telekasten buffers before looking for links to replace + if + #(vim.fn.getbufinfo({ bufmodified = 1 })) > 1 + and M.Cfg.auto_set_filetype == true + then + local answer = vim.fn.input( + "Telekasten.nvim:" + .. "Save all telekasten buffers before updating links? [Y/n]" + ) + answer = vim.fn.trim(answer) + if answer ~= "n" and answer ~= "N" then + save_all_tk_buffers() + end + end + + recursive_substitution(M.Cfg.home, oldlink, newlink) + recursive_substitution(M.Cfg.dailies, oldlink, newlink) + recursive_substitution(M.Cfg.weeklies, oldlink, newlink) + end +end + -- -- GotoDate: -- ---------- @@ -1592,7 +1726,7 @@ local function SearchNotes(opts) prompt_title = "Search in notes", cwd = M.Cfg.home, search_dirs = { M.Cfg.home }, - default_text = vim.fn.expand(""), + default_text = opts.default_text or vim.fn.expand(""), find_command = M.Cfg.find_command, attach_mappings = function(_, map) actions.select_default:replace(picker_actions.select_default) @@ -2586,6 +2720,7 @@ M.new_note = CreateNote M.goto_thisweek = GotoThisWeek M.find_weekly_notes = FindWeeklyNotes M.yank_notelink = YankLink +M.rename_note = RenameNote M.new_templated_note = CreateNoteSelectTemplate M.show_calendar = ShowCalendar M.CalendarSignDay = CalendarSignDay @@ -2614,6 +2749,7 @@ local TelekastenCmd = { { "goto thisweek", "goto_thisweek", M.goto_thisweek }, { "find weekly notes", "find_weekly_notes", M.find_weekly_notes }, { "yank link to note", "yank_notelink", M.yank_notelink }, + { "rename note", "rename_note", M.rename_note }, { "new templated note", "new_templated_note", diff --git a/wiki b/wiki new file mode 160000 index 0000000..542099b --- /dev/null +++ b/wiki @@ -0,0 +1 @@ +Subproject commit 542099b8930b74c9294650351b1826bd628625ba