-
-
Notifications
You must be signed in to change notification settings - Fork 56
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Export location based consult results to grep buffer. #560
Export location based consult results to grep buffer. #560
Conversation
@oantolin , what would be your recommendation for a more granular configuration to keep other tools like consult-outline, etc. , still using |
Thank you for this. It is probably a good idea to provide alternative exporters. However I have two questions or counter points I'd like to see discussed or sorted out first:
Isearch also exports to occur, we cannot argue the grep/occur distinction away. Embark/Consult and the other packages are somewhat opionated. We try to avoid needless duplications and stay minimal. Therefore I wonder what specific aspects of grep are preferrable for you. Are there strong technical reasons? You can probably configure both occur and grep to behave similarly, if this is only about key bindings. I am kind of sceptical regarding arguments based on taste in contrast to technical reasons. Also note that the grep buffer is weaker out of the box than the occur buffer, if wgrep doesn't exist. Otherwise my suggestion would be to add this to the wiki.
Using grep/wgrep on open buffers worries me a bit and may even lead to inconsistencies between the file and buffer. Are you sure that this behaves correctly? What happens if you use consult-line on a modified buffer and export? What happens then if you wgrep? What happens for buffers which are not backed by a file? |
Thanks for pointing out great questions and detailed write-up, @minad. I totally support a minimalistic approach and focused nature of the Consult and Embark.
All in all, I can easily survive with I think adding a check about saved buffer, in that case, is a good idea in a similar fashion Magit does it. I'm happy to polish the PR and add more docs if you and @oantolin will consider the exporter useful. Otherwise, I'll maintain it in my configs as my own little hack and pray for no bigger API changes:) Offtopic: |
I'll read through this conversation carefully later, but my first reaction is that it doesn't really make sense to have Of course, if you do not want the capability of exporting |
On second thought, if we keep occur as the default and document the limitations of exporting to grep, I don't see why we couldn't keep both exporters. |
OK, I'm reading the conversation here now (which is not as long as I thought it was, there is a large screenshot which made me overestimate the length :)).
I'd suggest using marginalia to have I see @minad brought up the same concern I have. I'm also curious about what is better about
So either something is a little off in your configuration (and we can certainly try to figure out what), or you meant a third thing by "multiline edit". Continuing, you say "I had to dig into google search and docs to figure out inline editing with occur", which is a perfectly valid way of finding out about it, but I want to point out that: (1) that would be the same for I'm glad you looked into @minad's questions, and your answers would form the backbone of documenting the pitfalls of using I think that on balance, the first thing to figure out is why whatever you meant by "multiline edits" are not working for you with |
My initial reaction was also to reject because of the separation grep/occur and file/buffer. However if grep+wgrep work well and the grep export can be seen as a generalization of the occur export somehow. Then why not? However I see it as a requirement that we don't introduce bugs by adding this (handling non file backed buffers, buffer/file out of sync, ...). The exporter must be sufficiently robust in most (or all) scenarios. Not sure if we had this discussion before but maybe we also need a way to select between multiple exporters. |
@oantolin Iirc there was a feature request for export with context lines to occur. |
Forgot to answer this: I do that fairly often. I use it when I need to make a bunch of changes everywhere some string appears, for example, if I'm programming and changed a function signature and need to consider how best to update each call-site, or if I'm writing some math and decided to change the name of a concept I'm defining. What I like about using occur for these situations is that the occur buffer works like a temporary todo list containing all the spots where I need to change something; and I can navigate among the spots with Of course, in these use cases I'm editing an actual file so grep would do just as well. But I do sometimes use |
@minad said:
You mean selecting at export time? That could be a nice to have. A first idea on the UI would be that if
Yes, there was, and I do think that's a good idea, I just forgot about it. I guess a first step would be to pass the prefix argument to the exporter function somehow, probably just as the value of |
@oantolin Yes, I'd also like to understand the real value of this addition better and why @artemkovalyov isn't happy with occur and occur-edit-mode. I don't think you can "run away" from occur given that it is also baked into isearch. Just adding a grep export because we can and because of some consistency details doesn't seem justified (we have the wiki for that), considering that we introduce new problems given non-file backed buffers and given that wgrep is needed to reach parity with occur. |
@oantolin, I think you didn't get what multi-line edit means. It's about the ability to add lines in an exported buffer that are committed to the original buffer (file). Here are examples with Wgrep and occure-edit |
@artemkovalyov That's indeed an interesting feature! I wasn't aware of that. I think occur-edit-mode should be improved such that this is also supported. |
You're absolutely right that I hadn't understood what you meant, @artemkovalyov! (I suspected as much.) That is a cool feature I did not know wgrep had! Like @minad, I think the right approach is to enhance occur-edit-mode to support this, but in the meantime, I do think that for that feature it is worth having the grep exporter even if it only works properly for file-backed buffers. |
embark-consult.el
Outdated
embark-consult-revert-map | ||
(current-local-map))) | ||
(setq-local wgrep-header/footer-parser #'ignore) | ||
(when (fboundp 'wgrep-setup) (wgrep-setup))) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there some code here which could be shared with embark-consult-export-grep
? Maybe one could introduce a helper function embark-consult--export-grep
which sets up the grep buffer is passed a function as argument. The function argument should insert the actual content into the buffer.
(defun embark-consult--export-grep (insert)
(let ((buf (generate-new-buffer "*Embark Export Grep*")))
(with-current-buffer buf
(insert (propertize "Exported grep results:\n\n" 'wgrep-header t))
(funcall insert)
(goto-char (point-min))
(grep-mode)
;; Make this buffer current for next/previous-error
(setq next-error-last-buffer buf)
;; Set up keymap before possible wgrep-setup, so that wgrep
;; restores our binding too when the user finishes editing.
(use-local-map (make-composed-keymap
embark-consult-revert-map
(current-local-map)))
(setq-local wgrep-header/footer-parser #'ignore)
(when (fboundp 'wgrep-setup) (wgrep-setup)))
(pop-to-buffer buf)))
(defun embark-consult-export-grep (lines)
...)
If we share the code, this addition will be very small. We don't add complexity and avoid complicating maintenance.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that instead of the function you propose @minad, with an insert
function argument, that this new export function should just build a grep-formatted list of lines and then call the existing embark-consult-export-grep
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thought a callback would be more efficient, since we can write directly to the buffer. Building an intermediate list requires allocations, which can be costly if we have many candidates. It would be even worse to build many intermediate strings.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're right, of course. I just thought it shouldn't be a problem since I'd expect few matching lines compared to the number of lines in the buffer, so the slow step would actually be the initial gathering of candidates in consult-line. I mostly wanted to reuse more code, in particular to reuse the line insertion loop, so maybe the best option is a callback but one that is called per line.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
embark-consult.el
Outdated
@@ -181,6 +181,37 @@ This function is meant to be added to `embark-collect-mode-hook'." | |||
(when (fboundp 'wgrep-setup) (wgrep-setup))) | |||
(pop-to-buffer buf))) | |||
|
|||
(defun embark-consult-export-lines-to-grep (lines) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Any ideas for a better name?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll update the name after refactoring. This was my "code name" because I was looking for a solution specifically for lines. I didn't draw much difference from consult-location
group back when I started my initial solution discovery.
On 11/22/22 18:10, Omar Antolín Camarena wrote:
***@***.**** commented on this pull request.
------------------------------------------------------------------------
In embark-consult.el
<#560 (comment)>:
> + (contents (propertize (embark-consult--strip line)))
+ (this-buf (marker-buffer loc)))
+ (unless (eq this-buf last-buf)
+ (insert (propertize "Exported grep results:\n\n" 'wgrep-header t))
+ (setq last-buf this-buf))
+ (insert (concat (file-name-nondirectory (buffer-file-name this-buf)) ":" lineno contents "\n"))))
+ (goto-char (point-min))
+ (grep-mode)
+ (setq next-error-last-buffer buf)
+ ;; Set up keymap before possible wgrep-setup, so that wgrep
+ ;; restores our binding too when the user finishes editing.
+ (use-local-map (make-composed-keymap
+ embark-consult-revert-map
+ (current-local-map)))
+ (setq-local wgrep-header/footer-parser #'ignore)
+ (when (fboundp 'wgrep-setup) (wgrep-setup)))
You're right, of course. I just thought it shouldn't be a problem since
I'd expect few matching lines compared to the number of lines in the
buffer, so the slow step would actually be the initial gathering of
candidates in consult-line. I mostly wanted to reuse more code, in
particular to reuse the line insertion loop, so maybe the best option is
a callback but one that is called per line.
Hmm, I would probably go with the most efficient solution, a single
call. I often export many candidates from consult-grep/ripgrep. As an
alternative we could also use a macro with a BODY.
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the productive discussions. I'll work on updating the PR.
embark-consult.el
Outdated
embark-consult-revert-map | ||
(current-local-map))) | ||
(setq-local wgrep-header/footer-parser #'ignore) | ||
(when (fboundp 'wgrep-setup) (wgrep-setup))) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
embark-consult.el
Outdated
@@ -181,6 +181,37 @@ This function is meant to be added to `embark-collect-mode-hook'." | |||
(when (fboundp 'wgrep-setup) (wgrep-setup))) | |||
(pop-to-buffer buf))) | |||
|
|||
(defun embark-consult-export-lines-to-grep (lines) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll update the name after refactoring. This was my "code name" because I was looking for a solution specifically for lines. I didn't draw much difference from consult-location
group back when I started my initial solution discovery.
Oh, @artemkovalyov have you signed the FSF copyright assignment papers? |
|
@minad, @oantolin, please, take another look at the implementation. I'm not an experienced LISPer but I tried to follow your recommendations. I had to create wrappers for actual exporters to preserve their APIs but split the implementation into a buffer setup and processing of results to make them reusable. If you have better ideas, please, share. I also renamed an exporter to |
@minad, I made sure the buffers exported to grep buffer are visiting a file. Here are a couple of screenshots: |
Sure, if you don't have time to fix the issues in my code review, I can do that for you, I just wanted to give you a chance to do that first, @artemkovalyov. Or did you fix them and just not mark them as done? I'll check. EDIT: It seems like you still haven't fixed them. |
embark-consult.el
Outdated
(setq last-buf this-buf)) | ||
(insert (concat lineno contents nl)))))))) | ||
(occur-mode) | ||
(pop-to-buffer buf)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This uses the variable buf, but is outside the let.
embark-consult.el
Outdated
The elements of LINES are assumed to be values of category `consult-location'." | ||
(let ((buf (generate-new-buffer "*Embark Export Grep*")) | ||
(count 0) | ||
prop) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you don't use this variable at all.
embark-consult.el
Outdated
lineno | ||
":" | ||
contents "\n" )) | ||
(add-to-list 'not-saved-buffers this-buf)))) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
add-to-list isn't meant to work on lexical variables, use push (handling duplicates yourself) or cl-pushnew.
Oh, boy, I think I had not submitted the review so that means that all these months you hadn't even seen it! (If I recall correctly I did the review at the end of April after minad's comment.) I'm very sorry, it's the first time I ever do a code review (I'd always used the "add a single comment" feature before), and I did not know I had to submit it or where to click to submit. |
@oantolin, it happened to the best of us :) I'll take a look at your comments and suggestions. It's so sad I'm not coding LISP daily although using Emacs extensively. |
Any news on this one? |
Not on my end. I'm stil hoping @artemkovalyov fixes those issues I brought up. |
I suspect that @artemkovalyov followed your example and forgot to click the "submit commits" button. ;) |
Well, I didn't forget to submit: I didn't know you had too! And also didn't notice the submit button. 😬 I don't know if this is better or worse than forgetting to submit when you know you have to. |
26efd01
to
99484b0
Compare
@oantolin, I took a quick look at how to provide a choice of a desired exporting format for With your expertise, I guess you can propose a beautiful solution here. I can attempt another PR then if this one is accepted and I could figure that out. Otherwise, as before one can choose their exporter via config and keep it stupid simple. |
I'm feeling super dull, but I didn't manage to figure out how to make a function that would create a prompt based on a defined keymap. All those targets and indicators are getting me lost... |
Thanks for fixing the things I pointed out! And congratulations on the twins, I can certainly understand that they make hobby coding a very low priority, since I went through the same thing (with one half of the number of toddlers).
I don't think that's a good idea or even necessary, I think most people will always want occur export or always want grep, so it's much better as a setting in the user's configuration. The code you gave is exactly what I had in mind: (setf (alist-get 'consult-location embark-exporters-alist) #'embark-consult-export-location-grep) I'll test the new code later today and merge. Thanks again! |
There is a whole lot of duplication between |
Another small issue: the new function does not count the matches so it does not set the |
I like that the new function prints the file names invisibly and has a header for each file that is visible but marked as ignored by wgrep. EDIT: On second thought, I don't like that: it makes it too unlike the |
- Almost all shared code has been moved to a new function embark-consult--export-grep, which takes care of putting the buffer in grep mode and preparing the header and footer for wgrep. - The result format for the new grep exporter for consult-location has been uniformized with the grep exporter for consult-grep and with the built-in grep and rgrep commands. - A couple of bugs in the new grep exporter for consult-location have been fixed: the matches were not counted and the list of non-file buffers was not computed correctly.
OK, I'm done with my changes. It looks ready to merge on my end. I'll maybe test a little bit more, then merge. |
OK, done with testing. Will merge now. |
Thank you for the collaboration, @oantolin, and for bothering to create embark :) |
I prefer
wgrep
overoccur-edit-mode
. I created an alternative exporter forconsult-lines
to use grep mode buffer.The benefits are:
I prefer a grep buffer for
consult-lines
because I use it a lot for narrowing down searches in an open buffer as opposed to grep-based searching tools from consult that constantly search over a directory. In-place editing is richer with wgrep and using one tool makes you ponder less about key combinations and how you enable in-place editing.Related issues: