diff --git a/.github/workflows/docgen.yml b/.github/workflows/docgen.yml index ec7d8c9..ecde5b3 100644 --- a/.github/workflows/docgen.yml +++ b/.github/workflows/docgen.yml @@ -16,12 +16,6 @@ jobs: path: build key: ${{ runner.os }}-appimage-${{ hashFiles('todays-date') }} - - name: Restore cache for tree-sitter - uses: actions/cache@v2 - with: - path: _ts - key: ${{ runner.os }}-ts-${{ hashFiles('todays-date') }} - - name: Prepare run: | test -d build || { @@ -30,41 +24,36 @@ jobs: chmod +x nvim.appimage mv nvim.appimage ./build/nvim } - test -d _ts || { - # Pining version. Not sure if we should actually do that - mkdir -p _ts - wget https://github.com/tree-sitter/tree-sitter/releases/download/0.17.3/tree-sitter-linux-x64.gz - gzip -d tree-sitter-linux-x64 - chmod +x tree-sitter-linux-x64 - mv tree-sitter-linux-x64 ./_ts/tree-sitter - } mkdir -p ~/.local/share/nvim/site/pack/vendor/start + git clone --depth 1 https://github.com/nvim-lua/plenary.nvim ~/.local/share/nvim/site/pack/vendor/start/plenary.nvim git clone --depth 1 https://github.com/tjdevries/tree-sitter-lua ~/.local/share/nvim/site/pack/vendor/start/tree-sitter-lua ln -s $(pwd) ~/.local/share/nvim/site/pack/vendor/start - name: Build parser run: | # We have to build the parser every single time to keep up with parser changes - export PATH="${PWD}/_ts/:${PATH}" cd ~/.local/share/nvim/site/pack/vendor/start/tree-sitter-lua mkdir -p build parser - make build_parser + cc -o ./build/parser.so -I./src src/parser.c src/scanner.cc -shared -Os -lstdc++ -fPIC ln -s ../build/parser.so parser/lua.so - cd + cd - + + - name: Generating docs + run: | + export PATH="${PWD}/build/:${PATH}" + make docgen # inspired by nvim-lspconfigs - - name: Generating docs + - name: Update documentation env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} COMMIT_MSG: | - [Actions] Generate Documentation + [docgen] Update doc/telescope.txt skip-checks: true run: | - export PATH="${PWD}/build/:${PATH}" git config user.email "actions@github" git config user.name "Github Actions" git remote set-url origin https://x-access-token:${GITHUB_TOKEN}@github.com/${GITHUB_REPOSITORY}.git - make docgen git add doc/ # Only commit and push if we have changes git diff --quiet && git diff --staged --quiet || (git commit -m "${COMMIT_MSG}"; git push origin HEAD:${GITHUB_REF}) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 7ad008d..a4ec991 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -2,47 +2,58 @@ is generating docs based on the tree sitter syntax tree. TJ wrote a grammar that includes the documentation in this syntax tree so we can do take this function header documentation and transform it into vim documentation. All documentation will be exported that is part of the returning module. So example: +```lua local m = {} --- Test Header --@return 1: Returns always 1 -function m.a() +function m.a() -- or m:a() return 1 end -return m +--- Documentation +function m.__b() -- or m:__b() + return 2 +end -Something like this. -What is missing? +--- Documentation +local c = function() + return 2 +end + +return m +``` + +This will export function `a` with header documentation and the return value. Module function `b` and local function `c` will not be exported. + +## What is missing? The docgen has some problems on which people can work. This would happen in https://github.com/tjdevries/tree-sitter-lua and documentation of some modules here. I would suggest we are documenting lua/telescope/builtin/init.lua rather than the files itself. We can use that init.lua file as "header" file, so we are not cluttering the other files. -How to do it: - +How to help out with documentation: ## Auto-updates from CI -The easy way would be after this PR is merged +The easy way would be: - write some docs - commit and push - wait a minute until the CI generates a new commit with the changes - Look at this commit and the changes - And apply new changes with git commit --amend and git push --force to remove that github ci commit again. - Repeat until done +- write some docs +- commit, push and create draft PR +- wait a minute until the CI generates a new commit with the changes +- Look at this commit and the changes +- Modify documentation until its perfect. You can do `git commit --amend` and `git push --force` to remove the github ci commit again ## Generate on your local machine The other option would be setting up https://github.com/tjdevries/tree-sitter-lua - Install Treesitter, either with package manager or with github release - Install plugin as usual - cd to plugin - mkdir -p build parser Sadly does doesn't exist laughing - make build_parser - ln -s ../build/parser.so parser/lua.so We need the so in parser/ so it gets picked up by neovim. Either copy or symbolic link - Make sure that nvim-treesitter lua parser is not installed and also delete the lua queries in that repository. queries/lua/*. If you are not doing that you will have a bad time - cd into this project - Write doc - Run make docgen - Repeat last two steps +- Install Treesitter, either with package manager or with github release +- Install plugin as usual +- cd to plugin +- `mkdir -p build parser` sadly does doesn't exist +- `make build_parser` +- `ln -s ../build/parser.so parser/lua.so` We need the shared object in parser/ so it gets picked up by neovim. Either copy or symbolic link +- Make sure that nvim-treesitter lua parser is not installed and also delete the lua queries in that repository. `queries/lua/*`. If you are not doing that you will have a bad time! +- cd into this project +- Write doc +- Run `make docgen` +- Repeat last two steps diff --git a/README.md b/README.md index c4cb584..ebc93aa 100644 --- a/README.md +++ b/README.md @@ -139,7 +139,9 @@ require('telescope').setup{ '--smart-case' }, prompt_position = "bottom", - prompt_prefix = ">", + prompt_prefix = "> ", + selection_caret = "> ", + entry_prefix = " ", initial_mode = "insert", selection_strategy = "reset", sorting_strategy = "descending", @@ -191,6 +193,8 @@ EOF |------------------------|-------------------------------------------------------|----------------------------| | `prompt_position` | Where the prompt should be located. | top/bottom | | `prompt_prefix` | What should the prompt prefix be. | string | +| `selection_caret` | What should the selection caret be. | string | +| `entry_prefix` | What should be shown in front of every entry. (current selection excluded) | string| | `initial_mode` | The initial mode when a prompt is opened. | insert/normal | | `sorting_strategy` | Where first selection should be located. | descending/ascending | | `layout_strategy` | How the telescope is drawn. | [supported layouts](https://github.com/nvim-telescope/telescope.nvim/wiki/Layouts) | @@ -202,7 +206,7 @@ EOF | `results_width` | TODO | NUM | | `borderchars` | The border chars, it gives border telescope window | dict | | `color_devicons` | Whether to color devicons or not | boolean | -| `use_less` | Whether to use less with bat or less/cat if bat not installed | boolean | +| `use_less` | Whether to use less with bat or less/cat if bat not installed | boolean | | `set_env` | Set environment variables for previewer | dict | | `scroll_strategy` | How to behave when the when there are no more item next/prev | cycle, nil | | `file_previewer` | What telescope previewer to use for files. | [Previewers](#previewers) | @@ -333,6 +337,14 @@ require('telescope.builtin').fd({ -- or new custom picker's attach_mappings fiel return true end, }) +------------------------------ +-- More practical example of adding a new mapping +require'telescope.builtin'.git_branches({ attach_mappings = function(_, map) + map('i', '', actions.git_delete_branch) -- this action already exist + map('n', '', actions.git_delete_branch) -- this action already exist + -- for more actions look at lua/telescope/actions/init.lua + return true +end}) ``` For more info, see [./developers.md](./developers.md) @@ -400,7 +412,7 @@ Built-in functions. Ready to be bound to any key you like. :smile: |-------------------------------------|---------------------------------------------------------------------------------------------| | `builtin.git_commits` | Lists git commits with diff preview and on enter checkout the commit. | | `builtin.git_bcommits` | Lists buffer's git commits with diff preview and checkouts it out on enter. | -| `builtin.git_branches` | Lists all branches with log preview and checkout action. | +| `builtin.git_branches` | Lists all branches with log preview, checkout action (), track action () and rebase action(). | | `builtin.git_status` | Lists current changes per file with diff preview and add action. (Multiselection still WIP) | | .................................. | Your next awesome picker function here :D | diff --git a/doc/telescope.txt b/doc/telescope.txt index d37db92..c80b093 100644 --- a/doc/telescope.txt +++ b/doc/telescope.txt @@ -7,6 +7,11 @@ filter, find and pick things in Lua. To find out more: https://github.com/nvim-telescope/telescope.nvim + :h telescope.setup + :h telescope.builtin + :h telescope.layout + :h telescope.actions + telescope.extensions() *telescope.extensions()* Use telescope.extensions to reference any extensions within your @@ -43,6 +48,18 @@ telescope.setup({opts}) *telescope.setup()* Valid keys for {opts.defaults} + *telescope.defaults.entry_prefix* + entry_prefix: ~ + Prefix in front of each result entry. Current selection not included. + + Default: ' ' + + *telescope.defaults.prompt_prefix* + prompt_prefix: ~ + Will be shown in front of the prompt. + + Default: '> ' + *telescope.defaults.scroll_strategy* scroll_strategy: ~ Determines what happens you try to scroll past view of the picker. @@ -51,6 +68,12 @@ telescope.setup({opts}) *telescope.setup()* - "cycle" (default) - "limit" + *telescope.defaults.selection_caret* + selection_caret: ~ + Will be shown in front of the selection. + + Default: '> ' + *telescope.defaults.selection_strategy* selection_strategy: ~ Determines how the cursor acts after each sort iteration. diff --git a/lua/telescope/actions/init.lua b/lua/telescope/actions/init.lua index bf6bd4f..2fa7ce2 100644 --- a/lua/telescope/actions/init.lua +++ b/lua/telescope/actions/init.lua @@ -264,7 +264,72 @@ actions.git_checkout = function(prompt_bufnr) local cwd = action_state.get_current_picker(prompt_bufnr).cwd local selection = action_state.get_selected_entry() actions.close(prompt_bufnr) - utils.get_os_command_output({ 'git', 'checkout', selection.value }, cwd) + local _, ret, stderr = utils.get_os_command_output({ 'git', 'checkout', selection.value }, cwd) + if ret == 0 then + print("Checked out: " .. selection.value) + else + print(string.format( + 'Error when checking out: %s. Git returned: "%s"', + selection.value, + table.concat(stderr, ' ') + )) + end +end + +actions.git_track_branch = function(prompt_bufnr) + local cwd = action_state.get_current_picker(prompt_bufnr).cwd + local selection = action_state.get_selected_entry() + actions.close(prompt_bufnr) + local _, ret, stderr = utils.get_os_command_output({ 'git', 'checkout', '--track', selection.value }, cwd) + if ret == 0 then + print("Tracking branch: " .. selection.value) + else + print(string.format( + 'Error when tracking branch: %s. Git returned: "%s"', + selection.value, + table.concat(stderr, ' ') + )) + end +end + +actions.git_delete_branch = function(prompt_bufnr) + local cwd = action_state.get_current_picker(prompt_bufnr).cwd + local selection = action_state.get_selected_entry() + + local confirmation = vim.fn.input('Do you really wanna delete branch ' .. selection.value .. '? [Y/n] ') + if confirmation ~= '' and string.lower(confirmation) ~= 'y' then return end + + actions.close(prompt_bufnr) + local _, ret, stderr = utils.get_os_command_output({ 'git', 'branch', '-D', selection.value }, cwd) + if ret == 0 then + print("Deleted branch: " .. selection.value) + else + print(string.format( + 'Error when deleting branch: %s. Git returned: "%s"', + selection.value, + table.concat(stderr, ' ') + )) + end +end + +actions.git_rebase_branch = function(prompt_bufnr) + local cwd = action_state.get_current_picker(prompt_bufnr).cwd + local selection = action_state.get_selected_entry() + + local confirmation = vim.fn.input('Do you really wanna delete branch ' .. selection.value .. '? [Y/n] ') + if confirmation ~= '' and string.lower(confirmation) ~= 'y' then return end + + actions.close(prompt_bufnr) + local _, ret, stderr = utils.get_os_command_output({ 'git', 'rebase', selection.value }, cwd) + if ret == 0 then + print("Rebased branch: " .. selection.value) + else + print(string.format( + 'Error when rebasing branch: %s. Git returned: "%s"', + selection.value, + table.concat(stderr, ' ') + )) + end end actions.git_staging_toggle = function(prompt_bufnr) diff --git a/lua/telescope/builtin/git.lua b/lua/telescope/builtin/git.lua index a296517..c333159 100644 --- a/lua/telescope/builtin/git.lua +++ b/lua/telescope/builtin/git.lua @@ -79,20 +79,15 @@ end git.branches = function(opts) local output = utils.get_os_command_output({ 'git', 'branch', '--all' }, opts.cwd) - local tmp_results = {} + local results = {} for _, v in ipairs(output) do if not string.match(v, 'HEAD') and v ~= '' then v = string.gsub(v, '.* ', '') - v = string.gsub(v, '^remotes/[^/]*/', '') - tmp_results[v] = true + v = string.gsub(v, '^remotes/', '') + table.insert(results, v) end end - local results = {} - for k, _ in pairs(tmp_results) do - table.insert(results, k) - end - pickers.new(opts, { prompt_title = 'Git Branches', finder = finders.new_table { @@ -103,8 +98,13 @@ git.branches = function(opts) }, previewer = previewers.git_branch_log.new(opts), sorter = conf.file_sorter(opts), - attach_mappings = function() + attach_mappings = function(_, map) actions.select_default:replace(actions.git_checkout) + map('i', '', actions.git_track_branch) + map('n', '', actions.git_track_branch) + + map('i', '', actions.git_rebase_branch) + map('n', '', actions.git_rebase_branch) return true end }):find() @@ -155,14 +155,14 @@ local set_opts_cwd = function(opts) end -- Find root of git directory and remove trailing newline characters - local git_root = vim.fn.systemlist("git -C " .. opts.cwd .. " rev-parse --show-toplevel")[1] + local git_root, ret = utils.get_os_command_output({ "git", "rev-parse", "--show-toplevel" }, opts.cwd) local use_git_root = utils.get_default(opts.use_git_root, true) - if vim.v.shell_error ~= 0 then + if ret ~= 0 then error(opts.cwd .. ' is not a git directory') else if use_git_root then - opts.cwd = git_root + opts.cwd = git_root[1] end end end diff --git a/lua/telescope/builtin/lsp.lua b/lua/telescope/builtin/lsp.lua index 93fcfd2..28ecf60 100644 --- a/lua/telescope/builtin/lsp.lua +++ b/lua/telescope/builtin/lsp.lua @@ -151,8 +151,11 @@ lsp.workspace_symbols = function(opts) local params = {query = opts.query or ''} local results_lsp = vim.lsp.buf_request_sync(0, "workspace/symbol", params, opts.timeout or 10000) - if not results_lsp or vim.tbl_isempty(results_lsp) then - print("No results from workspace/symbol") + -- Clangd returns { { result = {} } } for query='' + if not results_lsp or vim.tbl_isempty(results_lsp) or + vim.tbl_isempty(results_lsp[1]) or vim.tbl_isempty(results_lsp[1].result) then + print("No results from workspace/symbol. Maybe try a different query: " .. + "Telescope lsp_workspace_symbols query=example") return end @@ -167,7 +170,6 @@ lsp.workspace_symbols = function(opts) return end - opts.ignore_filename = utils.get_default(opts.ignore_filename, false) opts.hide_filename = utils.get_default(opts.hide_filename, false) diff --git a/lua/telescope/config.lua b/lua/telescope/config.lua index 9b749ed..de6d544 100644 --- a/lua/telescope/config.lua +++ b/lua/telescope/config.lua @@ -75,7 +75,21 @@ function config.set_defaults(defaults) set("results_height", 1) set("results_width", 0.8) - set("prompt_prefix", ">") + set("prompt_prefix", "> ", [[ + Will be shown in front of the prompt. + + Default: '> ' + ]]) + set("selection_caret", "> ", [[ + Will be shown in front of the selection. + + Default: '> ' + ]]) + set("entry_prefix", " ", [[ + Prefix in front of each result entry. Current selection not included. + + Default: ' ' + ]]) set("initial_mode", "insert") set("border", {}) diff --git a/lua/telescope/init.lua b/lua/telescope/init.lua index 2269efe..cca1a4c 100644 --- a/lua/telescope/init.lua +++ b/lua/telescope/init.lua @@ -14,12 +14,11 @@ local telescope = {} --- --- To find out more: --- https://github.com/nvim-telescope/telescope.nvim --- --- :h telescope.setup --- :h telescope.builtin --- :h telescope.layout --- :h telescope.actions --- +--- +--- :h telescope.setup +--- :h telescope.builtin +--- :h telescope.layout +--- :h telescope.actions ---@brief ]] ---@tag telescope.nvim diff --git a/lua/telescope/pickers.lua b/lua/telescope/pickers.lua index 7dc89ae..c04ce17 100644 --- a/lua/telescope/pickers.lua +++ b/lua/telescope/pickers.lua @@ -57,6 +57,8 @@ function Picker:new(opts) preview_title = get_default(opts.preview_title, "Preview"), prompt_prefix = get_default(opts.prompt_prefix, config.values.prompt_prefix), + selection_caret = get_default(opts.selection_caret, config.values.selection_caret), + entry_prefix = get_default(opts.entry_prefix, config.values.entry_prefix), initial_mode = get_default(opts.initial_mode, config.values.initial_mode), default_text = opts.default_text, @@ -112,7 +114,6 @@ function Picker:new(opts) preview_cutoff = get_default(opts.preview_cutoff, config.values.preview_cutoff), }, self) - obj.scroller = p_scroller.create( get_default(opts.scroll_strategy, config.values.scroll_strategy), obj.sorting_strategy @@ -375,10 +376,6 @@ function Picker:find() local prompt_prefix = self.prompt_prefix if prompt_prefix ~= '' then a.nvim_buf_set_option(prompt_bufnr, 'buftype', 'prompt') - - if not vim.endswith(prompt_prefix, " ") then - prompt_prefix = prompt_prefix .. " " - end vim.fn.prompt_setprompt(prompt_bufnr, prompt_prefix) end self.prompt_prefix = prompt_prefix @@ -655,9 +652,6 @@ function Picker:change_prompt_prefix(new_prefix, hl_group) if not new_prefix then return end if new_prefix ~= '' then - if not vim.endswith(new_prefix, " ") then - new_prefix = new_prefix .. " " - end vim.fn.prompt_setprompt(self.prompt_bufnr, new_prefix) else vim.api.nvim_buf_set_text(self.prompt_bufnr, 0, 0, 0, #self.prompt_prefix, {}) @@ -733,21 +727,21 @@ function Picker:set_selection(row) local display, display_highlights = entry_display.resolve(self, self._selection_entry) if display then - display = ' ' .. display + display = self.entry_prefix .. display a.nvim_buf_set_lines(results_bufnr, self._selection_row, self._selection_row + 1, false, {display}) - self.highlighter:hi_display(self._selection_row, ' ', display_highlights) + self.highlighter:hi_display(self._selection_row, self.entry_prefix, display_highlights) self.highlighter:hi_sorter(self._selection_row, prompt, display) self.highlighter:hi_multiselect(self._selection_row, self._selection_entry) end end - local caret = '>' + local caret = self.selection_caret -- local display = string.format('%s %s', caret, -- (a.nvim_buf_get_lines(results_bufnr, row, row + 1, false)[1] or ''):sub(3) -- ) local display, display_highlights = entry_display.resolve(self, entry) - display = caret .. ' ' .. display + display = caret .. display -- TODO: You should go back and redraw the highlights for this line from the sorter. -- That's the only smart thing to do. @@ -757,8 +751,9 @@ function Picker:set_selection(row) end a.nvim_buf_set_lines(results_bufnr, row, row + 1, false, {display}) - self.highlighter:hi_selection(row, caret) - self.highlighter:hi_display(row, ' ', display_highlights) + -- don't highlight the ' ' at the end of caret + self.highlighter:hi_selection(row, caret:sub(1, -2)) + self.highlighter:hi_display(row, caret, display_highlights) self.highlighter:hi_sorter(row, prompt, display) self.highlighter:hi_multiselect(row, entry) end) @@ -809,7 +804,7 @@ function Picker:entry_adder(index, entry, _, insert) -- This is the two spaces to manage the '> ' stuff. -- Maybe someday we can use extmarks or floaty text or something to draw this and not insert here. -- until then, insert two spaces - local prefix = ' ' + local prefix = self.entry_prefix display = prefix .. display self:_increment("displayed") @@ -1109,7 +1104,7 @@ end function Picker:_get_prompt() return vim.trim( - vim.api.nvim_buf_get_lines(self.prompt_bufnr, 0, 1, false)[1]:sub(#self.prompt_prefix) + vim.api.nvim_buf_get_lines(self.prompt_bufnr, 0, 1, false)[1]:sub(#self.prompt_prefix + 1) ) end diff --git a/lua/telescope/previewers/buffer_previewer.lua b/lua/telescope/previewers/buffer_previewer.lua index a6e2322..6fa25de 100644 --- a/lua/telescope/previewers/buffer_previewer.lua +++ b/lua/telescope/previewers/buffer_previewer.lua @@ -466,40 +466,23 @@ previewers.git_branch_log = defaulter(function(opts) end end - local remotes = utils.get_os_command_output({ 'git', 'remote' }, opts.cwd) return previewers.new_buffer_previewer { get_buffer_by_name = function(_, entry) return entry.value end, define_preview = function(self, entry, status) - local current_remote = 1 + local cmd = { 'git', '--no-pager', 'log', '--graph', '--pretty=format:%h -%d %s (%cr)', + '--abbrev-commit', '--date=relative', entry.value } - local gen_cmd = function(v) - return { 'git', '--no-pager', 'log', '--graph', '--pretty=format:%h -%d %s (%cr)', - '--abbrev-commit', '--date=relative', v } - end - - local handle_results - handle_results = function(bufnr, content) - if content and table.getn(content) == 0 then - if current_remote <= table.getn(remotes) then - local value = 'remotes/' .. remotes[current_remote] .. '/' .. entry.value - current_remote = current_remote + 1 - putils.job_maker(gen_cmd(value), bufnr, { cwd = opts.cwd, callback = handle_results }) - else - vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, { "No log found for branch: " .. entry.value }) - end - elseif content and table.getn(content) > 1 then - highlight_buffer(bufnr, content) - end - end - - putils.job_maker(gen_cmd(entry.value), self.state.bufnr, { + putils.job_maker(cmd, self.state.bufnr, { value = entry.value, bufname = self.state.bufname, cwd = opts.cwd, - callback = handle_results + callback = function(bufnr, content) + if not content then return end + highlight_buffer(bufnr, content) + end }) end } diff --git a/lua/telescope/utils.lua b/lua/telescope/utils.lua index ecd7fd4..4470c56 100644 --- a/lua/telescope/utils.lua +++ b/lua/telescope/utils.lua @@ -199,7 +199,11 @@ function utils.get_os_command_output(cmd, cwd) return {} end local command = table.remove(cmd, 1) - return Job:new({ command = command, args = cmd, cwd = cwd }):sync() + local stderr = {} + local stdout, ret = Job:new({ command = command, args = cmd, cwd = cwd, on_stderr = function(_, data) + table.insert(stderr, data) + end }):sync() + return stdout, ret, stderr end utils.strdisplaywidth = (function()